Compare commits
8 commits
8127d5b8f4
...
50f1466fe2
Author | SHA1 | Date | |
---|---|---|---|
50f1466fe2 | |||
fe0dca875c | |||
a3d2026a35 | |||
37aafe48f4 | |||
3c2eae2028 | |||
70f914bba0 | |||
5ee493dc97 | |||
c7ea5c5563 |
34 changed files with 954 additions and 120 deletions
|
@ -23,14 +23,15 @@ find_package(GLUT REQUIRED)
|
|||
include_directories(${GLUT_INCLUDE_DIRS})
|
||||
|
||||
find_package(glfw3 REQUIRED)
|
||||
|
||||
find_package(OpenGL)
|
||||
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
|
||||
find_package(assimp REQUIRED)
|
||||
|
||||
find_package(ReactPhysics3D REQUIRED)
|
||||
find_package(pugixml REQUIRED)
|
||||
|
||||
# PkgConfig packages
|
||||
# find_package(PkgConfig REQUIRED)
|
||||
# pkg_check_modules(PUGIXML REQUIRED pugixml)
|
||||
|
||||
file(MAKE_DIRECTORY bin)
|
||||
|
||||
|
@ -39,7 +40,7 @@ include_directories("include")
|
|||
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
|
||||
add_library(openblocks ${SOURCES})
|
||||
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
||||
target_link_libraries(openblocks ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D)
|
||||
target_link_libraries(openblocks ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} ${PUGIXML_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
||||
|
||||
# add_executable(client "client/src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
||||
# include_directories("src")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
add_executable(client "src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
||||
include_directories("../src")
|
||||
target_link_libraries(client ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D)
|
||||
target_link_libraries(client ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
|
@ -49,24 +49,16 @@ int main() {
|
|||
workspace()->AddChild(Part::New({
|
||||
.position = glm::vec3(0, -5, 0),
|
||||
.rotation = glm::vec3(0),
|
||||
.scale = glm::vec3(512, 1.2, 512),
|
||||
.material = Material {
|
||||
.diffuse = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 32.0f,
|
||||
},
|
||||
.size = glm::vec3(512, 1.2, 512),
|
||||
.color = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.anchored = true,
|
||||
}));
|
||||
|
||||
workspace()->AddChild(lastPart = Part::New({
|
||||
.position = glm::vec3(0),
|
||||
.rotation = glm::vec3(0),
|
||||
.scale = glm::vec3(4, 1.2, 2),
|
||||
.material = Material {
|
||||
.diffuse = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 32.0f,
|
||||
}
|
||||
.size = glm::vec3(4, 1.2, 2),
|
||||
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||
}));
|
||||
|
||||
for (InstanceRef inst : workspace()->GetChildren()) {
|
||||
|
@ -118,15 +110,15 @@ void processInput(GLFWwindow* window) {
|
|||
float shiftFactor = (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) ? -0.5 : 0.5;
|
||||
shiftFactor *= deltaTime;
|
||||
if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) {
|
||||
lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(1, 0, 0));
|
||||
// lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(1, 0, 0));
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
if (glfwGetKey(window, GLFW_KEY_Y) == GLFW_PRESS) {
|
||||
lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(0, 1, 0));
|
||||
// lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(0, 1, 0));
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) {
|
||||
lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(0, 0, 1));
|
||||
// lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(0, 0, 1));
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
}
|
||||
|
@ -165,12 +157,8 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods
|
|||
workspace()->AddChild(lastPart = Part::New({
|
||||
.position = camera.cameraPos + camera.cameraFront * glm::vec3(3),
|
||||
.rotation = glm::vec3(0),
|
||||
.scale = glm::vec3(1, 1, 1),
|
||||
.material = Material {
|
||||
.diffuse = glm::vec3(1.0f, 0.5f, 0.31f),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 32.0f,
|
||||
}
|
||||
.size = glm::vec3(1, 1, 1),
|
||||
.color = glm::vec3(1.0f, 0.5f, 0.31f),
|
||||
}));
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
|
@ -178,28 +166,28 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods
|
|||
float shiftFactor = (mods & GLFW_MOD_SHIFT) ? -0.2 : 0.2;
|
||||
if (mode == 0) {
|
||||
if (key == GLFW_KEY_X && action == GLFW_PRESS) {
|
||||
lastPart->position.x += shiftFactor;
|
||||
// lastPart->position.x += shiftFactor;
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
if (key == GLFW_KEY_Y && action == GLFW_PRESS) {
|
||||
lastPart->position.y += shiftFactor;
|
||||
// lastPart->position.y += shiftFactor;
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
if (key == GLFW_KEY_Z && action == GLFW_PRESS) {
|
||||
lastPart->position.z += shiftFactor;
|
||||
// lastPart->position.z += shiftFactor;
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
} else if (mode == 1) {
|
||||
if (key == GLFW_KEY_X && action == GLFW_PRESS) {
|
||||
lastPart->scale.x += shiftFactor;
|
||||
lastPart->size.x += shiftFactor;
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
if (key == GLFW_KEY_Y && action == GLFW_PRESS) {
|
||||
lastPart->scale.y += shiftFactor;
|
||||
lastPart->size.y += shiftFactor;
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
if (key == GLFW_KEY_Z && action == GLFW_PRESS) {
|
||||
lastPart->scale.z += shiftFactor;
|
||||
lastPart->size.z += shiftFactor;
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
}
|
||||
|
|
10
deps.txt
Normal file
10
deps.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
glm
|
||||
opengl
|
||||
assimp
|
||||
sdl2
|
||||
glfw
|
||||
glut
|
||||
glew
|
||||
qt6
|
||||
reactphysics3d
|
||||
pugixml
|
|
@ -66,7 +66,7 @@ else()
|
|||
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(editor PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D)
|
||||
target_link_libraries(editor PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
||||
|
||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||
# If you are developing for iOS or macOS you should consider setting an
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <reactphysics3d/collision/RaycastInfo.h>
|
||||
#include <vector>
|
||||
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "physics/util.h"
|
||||
#include "qcursor.h"
|
||||
#include "qevent.h"
|
||||
|
@ -74,8 +73,9 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
|||
});
|
||||
|
||||
if (!rayHit) return;
|
||||
draggingObject->lock()->position = rpToGlm(rayHit->worldPoint);
|
||||
draggingObject->lock()->position += rpToGlm(rayHit->worldNormal) * draggingObject->lock()->scale / 2.f;
|
||||
Data::Vector3 vec = rayHit->worldPoint;
|
||||
vec = vec + Data::Vector3(rpToGlm(rayHit->worldNormal) * draggingObject->lock()->size / 2.f);
|
||||
draggingObject->lock()->cframe = draggingObject->lock()->cframe.Rotation() + vec;
|
||||
syncPartPhysics(draggingObject->lock());
|
||||
}
|
||||
|
||||
|
@ -156,12 +156,8 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) {
|
|||
workspace()->AddChild(lastPart = Part::New({
|
||||
.position = camera.cameraPos + camera.cameraFront * glm::vec3(3),
|
||||
.rotation = glm::vec3(0),
|
||||
.scale = glm::vec3(1, 1, 1),
|
||||
.material = Material {
|
||||
.diffuse = glm::vec3(1.0f, 0.5f, 0.31f),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 32.0f,
|
||||
}
|
||||
.size = glm::vec3(1, 1, 1),
|
||||
.color = glm::vec3(1.0f, 0.5f, 0.31f),
|
||||
}));
|
||||
syncPartPhysics(lastPart);
|
||||
}
|
||||
|
|
|
@ -14,14 +14,19 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "editorcommon.h"
|
||||
#include "objects/base/instance.h"
|
||||
#include "objects/datamodel.h"
|
||||
#include "physics/simulation.h"
|
||||
#include "objects/part.h"
|
||||
#include "qfiledialog.h"
|
||||
#include "qitemselectionmodel.h"
|
||||
#include "qobject.h"
|
||||
#include "qsysinfo.h"
|
||||
|
||||
SelectedTool selectedTool;
|
||||
|
||||
bool simulationPlaying = false;
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
|
@ -32,20 +37,46 @@ 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<InstanceRef> 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(); });
|
||||
connect(ui->actionToolScale, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::SCALE : SelectedTool::SELECT; updateSelectedTool(); });
|
||||
connect(ui->actionToolRotate, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::ROTATE : SelectedTool::SELECT; updateSelectedTool(); });
|
||||
ui->actionToolSelect->setChecked(true);
|
||||
|
||||
connect(ui->actionToggleSimulation, &QAction::triggered, this, [&]() {
|
||||
simulationPlaying = !simulationPlaying;
|
||||
if (simulationPlaying) {
|
||||
ui->actionToggleSimulation->setText("Pause simulation");
|
||||
ui->actionToggleSimulation->setToolTip("Pause the simulation");
|
||||
ui->actionToggleSimulation->setIcon(QIcon::fromTheme("media-playback-pause"));
|
||||
} else {
|
||||
ui->actionToggleSimulation->setText("Resume simulation");
|
||||
ui->actionToggleSimulation->setToolTip("Resume the simulation");
|
||||
ui->actionToggleSimulation->setIcon(QIcon::fromTheme("media-playback-start"));
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->actionSave, &QAction::triggered, this, [&]() {
|
||||
std::optional<std::string> path;
|
||||
if (!dataModel->HasFile())
|
||||
path = QFileDialog::getSaveFileName(this, QString::fromStdString("Save " + dataModel->name), "", "*.obl").toStdString();
|
||||
if (path == "") return;
|
||||
|
||||
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<DataModel> newModel = DataModel::LoadFromFile(path);
|
||||
dataModel = newModel;
|
||||
delete ui->explorerView->selectionModel();
|
||||
ui->explorerView->reset();
|
||||
ui->explorerView->setModel(new ExplorerModel(dataModel));
|
||||
ConnectSelectionChangeHandler();
|
||||
});
|
||||
|
||||
// ui->explorerView->Init(ui);
|
||||
|
||||
|
@ -55,12 +86,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||
.position = glm::vec3(0, -5, 0),
|
||||
.rotation = glm::vec3(0),
|
||||
.scale = glm::vec3(512, 1.2, 512),
|
||||
.material = Material {
|
||||
.diffuse = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 32.0f,
|
||||
},
|
||||
.size = glm::vec3(512, 1.2, 512),
|
||||
.color = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.anchored = true,
|
||||
}));
|
||||
ui->mainWidget->lastPart->name = "Baseplate";
|
||||
|
@ -69,16 +96,23 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||
.position = glm::vec3(0),
|
||||
.rotation = glm::vec3(0),
|
||||
.scale = glm::vec3(4, 1.2, 2),
|
||||
.material = Material {
|
||||
.diffuse = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 32.0f,
|
||||
}
|
||||
.size = glm::vec3(4, 1.2, 2),
|
||||
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||
}));
|
||||
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<InstanceRef> 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()) {
|
||||
|
@ -89,7 +123,8 @@ void MainWindow::timerEvent(QTimerEvent* evt) {
|
|||
float deltaTime = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - lastTime).count();
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
|
||||
physicsStep(deltaTime);
|
||||
if (simulationPlaying)
|
||||
physicsStep(deltaTime);
|
||||
ui->mainWidget->update();
|
||||
ui->mainWidget->updateCycle();
|
||||
}
|
||||
|
|
|
@ -28,5 +28,6 @@ private:
|
|||
|
||||
void updateSelectedTool();
|
||||
void timerEvent(QTimerEvent*) override;
|
||||
void ConnectSelectionChangeHandler();
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -114,6 +114,8 @@
|
|||
<addaction name="actionToolMove"/>
|
||||
<addaction name="actionToolScale"/>
|
||||
<addaction name="actionToolRotate"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionToggleSimulation"/>
|
||||
</widget>
|
||||
<action name="actionAddPart">
|
||||
<property name="icon">
|
||||
|
@ -241,6 +243,20 @@
|
|||
<string>4</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionToggleSimulation">
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-start"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start Simulation</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Start the simulation</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F5</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
#include "propertiesmodel.h"
|
||||
#include "datatypes/base.h"
|
||||
#include "datatypes/cframe.h"
|
||||
#include "objects/base/member.h"
|
||||
#include "qnamespace.h"
|
||||
|
||||
PropertiesModel::PropertiesModel(InstanceRef selectedItem, QWidget *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
, selectedItem(selectedItem) {
|
||||
this->propertiesList = selectedItem->GetProperties();
|
||||
this->propertiesList.reserve(selectedItem->GetProperties().size());
|
||||
for (std::string name : selectedItem->GetProperties()) {
|
||||
PropertyMeta meta = selectedItem->GetPropertyMeta(name).value();
|
||||
// Don't show CFrames in properties
|
||||
if (meta.type == &Data::CFrame::TYPE) continue;
|
||||
|
||||
this->propertiesList.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
PropertiesModel::~PropertiesModel() = default;
|
||||
|
@ -31,7 +39,7 @@ QVariant PropertiesModel::data(const QModelIndex &index, int role) const {
|
|||
case Qt::CheckStateRole:
|
||||
if (index.column() == 0) return {};
|
||||
else if (index.column() == 1 && meta.type == &Data::Bool::TYPE)
|
||||
return selectedItem->GetPropertyValue(propertyName)->get<Data::Bool>().value ? Qt::Checked : Qt::Unchecked;
|
||||
return selectedItem->GetPropertyValue(propertyName)->get<Data::Bool>() ? Qt::Checked : Qt::Unchecked;
|
||||
return {};
|
||||
// case Qt::DecorationRole:
|
||||
// return iconOf(item->GetClass());
|
||||
|
@ -102,7 +110,7 @@ QModelIndex PropertiesModel::parent(const QModelIndex &index) const {
|
|||
}
|
||||
|
||||
int PropertiesModel::rowCount(const QModelIndex &parent) const {
|
||||
return !parent.isValid() ? selectedItem->GetProperties().size() : 0;
|
||||
return !parent.isValid() ? this->propertiesList.size() : 0;
|
||||
}
|
||||
|
||||
int PropertiesModel::columnCount(const QModelIndex &parent) const {
|
||||
|
|
|
@ -15,7 +15,7 @@ typedef std::function<void(std::vector<InstanceRefWeak> oldSelection, std::vecto
|
|||
|
||||
extern Camera camera;
|
||||
extern std::shared_ptr<DataModel> dataModel;
|
||||
inline std::shared_ptr<Workspace> workspace() { return dataModel->workspace; }
|
||||
inline std::shared_ptr<Workspace> workspace() { return std::dynamic_pointer_cast<Workspace>(dataModel->services["Workspace"]); }
|
||||
extern std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
|
||||
extern std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#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 WRAPPED_TYPE() { return value; } \
|
||||
const Data::TypeInfo Data::CLASS_NAME::TYPE = { .name = TYPE_NAME, }; \
|
||||
const Data::TypeInfo& Data::CLASS_NAME::GetType() const { return Data::CLASS_NAME::TYPE; };
|
||||
Data::CLASS_NAME::operator const WRAPPED_TYPE() const { return value; } \
|
||||
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())); }
|
||||
|
||||
Data::Base::~Base() {};
|
||||
|
||||
|
@ -12,30 +14,57 @@ 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; };
|
||||
|
||||
const Data::String Data::Null::ToString() const {
|
||||
return Data::String("null");
|
||||
}
|
||||
|
||||
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::Null::ToString() const {
|
||||
return Data::String("null");
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
|
@ -1,23 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <functional>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#define DEF_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE) class CLASS_NAME : public Data::Base { \
|
||||
public: \
|
||||
const WRAPPED_TYPE value; \
|
||||
public: \
|
||||
CLASS_NAME(WRAPPED_TYPE); \
|
||||
~CLASS_NAME(); \
|
||||
operator WRAPPED_TYPE(); \
|
||||
operator const WRAPPED_TYPE() const; \
|
||||
virtual const TypeInfo& GetType() const override; \
|
||||
static const TypeInfo TYPE; \
|
||||
\
|
||||
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<Data::Variant(pugi::xml_node*)> Deserializer;
|
||||
|
||||
struct TypeInfo {
|
||||
std::string name;
|
||||
Deserializer deserializer;
|
||||
TypeInfo(const TypeInfo&) = delete;
|
||||
};
|
||||
|
||||
|
@ -27,6 +34,7 @@ namespace Data {
|
|||
virtual ~Base();
|
||||
virtual const TypeInfo& GetType() const = 0;
|
||||
virtual const Data::String ToString() const = 0;
|
||||
virtual void Serialize(pugi::xml_node* node) const = 0;
|
||||
};
|
||||
|
||||
class Null : Base {
|
||||
|
@ -37,6 +45,8 @@ namespace Data {
|
|||
static const TypeInfo TYPE;
|
||||
|
||||
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)
|
||||
|
|
131
src/datatypes/cframe.cpp
Normal file
131
src/datatypes/cframe.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include "cframe.h"
|
||||
#include "datatypes/vector.h"
|
||||
#include "physics/util.h"
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <reactphysics3d/mathematics/Transform.h>
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/euler_angles.hpp>
|
||||
// #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)
|
||||
, rotation(rotation) {
|
||||
}
|
||||
|
||||
Data::CFrame::CFrame(Data::Vector3 position, glm::quat quat)
|
||||
: translation(position)
|
||||
, rotation(quat) {
|
||||
}
|
||||
|
||||
Data::CFrame::CFrame(const rp::Transform& transform) : Data::CFrame::CFrame(rpToGlm(transform.getPosition()), rpToGlm(transform.getOrientation())) {
|
||||
}
|
||||
|
||||
glm::mat3 lookAt(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up) {
|
||||
// https://github.com/sgorsten/glm/issues/29#issuecomment-743989030
|
||||
Data::Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
||||
Data::Vector3 u = up.Unit(); // Up
|
||||
Data::Vector3 s = f.Cross(u).Unit(); // Right
|
||||
u = s.Cross(u);
|
||||
|
||||
return {
|
||||
{ s.X(), u.X(), -f.X() },
|
||||
{ s.Y(), u.Y(), -f.Y() },
|
||||
{ s.Z(), u.Z(), -f.Z() },
|
||||
};
|
||||
}
|
||||
|
||||
Data::CFrame::CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up)
|
||||
: translation(position)
|
||||
, rotation(::lookAt(position, lookAt, up)) {
|
||||
}
|
||||
|
||||
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; };
|
||||
|
||||
const Data::String Data::CFrame::ToString() const {
|
||||
return std::to_string(X()) + ", " + std::to_string(Y()) + ", " + std::to_string(Z());
|
||||
}
|
||||
|
||||
Data::CFrame::operator glm::mat4() const {
|
||||
// Always make sure to translate the position first, then rotate. Matrices work backwards
|
||||
return glm::translate(glm::mat4(1.0f), this->translation) * glm::mat4(this->rotation);
|
||||
}
|
||||
|
||||
Data::CFrame::operator rp::Transform() const {
|
||||
return rp::Transform(glmToRp(translation), glmToRp(rotation));
|
||||
}
|
||||
|
||||
Data::Vector3 Data::CFrame::ToEulerAnglesXYZ() {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
glm::extractEulerAngleXYZ(glm::mat4(this->rotation), x, y, z);
|
||||
return Data::Vector3(x, y, z);
|
||||
}
|
||||
|
||||
Data::CFrame Data::CFrame::FromEulerAnglesXYZ(Data::Vector3 vector) {
|
||||
glm::mat3 mat = glm::eulerAngleXYZ(vector.X(), vector.Y(), vector.Z());
|
||||
return Data::CFrame(Data::Vector3::ZERO, glm::column(mat, 2), (Data::Vector3)glm::column(mat, 1)); // Getting LookAt (3rd) and Up (2nd) vectors
|
||||
}
|
||||
|
||||
// Operators
|
||||
|
||||
Data::CFrame Data::CFrame::operator +(Data::Vector3 vector) const {
|
||||
return CFrame { this->translation + glm::vec3(vector), this->rotation };
|
||||
}
|
||||
|
||||
Data::CFrame Data::CFrame::operator -(Data::Vector3 vector) const {
|
||||
return *this + -vector;
|
||||
}
|
||||
|
||||
// Serialization
|
||||
|
||||
void Data::CFrame::Serialize(pugi::xml_node* node) const {
|
||||
node->append_child("X").text().set(std::to_string(this->X()));
|
||||
node->append_child("Y").text().set(std::to_string(this->Y()));
|
||||
node->append_child("Z").text().set(std::to_string(this->Z()));
|
||||
node->append_child("R00").text().set(std::to_string(this->rotation[0][0]));
|
||||
node->append_child("R01").text().set(std::to_string(this->rotation[1][0]));
|
||||
node->append_child("R02").text().set(std::to_string(this->rotation[2][0]));
|
||||
node->append_child("R10").text().set(std::to_string(this->rotation[0][1]));
|
||||
node->append_child("R11").text().set(std::to_string(this->rotation[1][1]));
|
||||
node->append_child("R12").text().set(std::to_string(this->rotation[2][1]));
|
||||
node->append_child("R20").text().set(std::to_string(this->rotation[0][2]));
|
||||
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()
|
||||
);
|
||||
}
|
59
src/datatypes/cframe.h
Normal file
59
src/datatypes/cframe.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "datatypes/vector.h"
|
||||
#include <glm/ext/matrix_float3x3.hpp>
|
||||
#include <glm/ext/quaternion_geometric.hpp>
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <glm/fwd.hpp>
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <reactphysics3d/mathematics/Transform.h>
|
||||
#include <reactphysics3d/reactphysics3d.h>
|
||||
|
||||
namespace rp = reactphysics3d;
|
||||
|
||||
namespace Data {
|
||||
class CFrame : Base {
|
||||
glm::vec3 translation;
|
||||
glm::mat3 rotation;
|
||||
|
||||
CFrame(glm::vec3, glm::mat3);
|
||||
public:
|
||||
// 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));
|
||||
~CFrame();
|
||||
|
||||
virtual const TypeInfo& GetType() const override;
|
||||
static const TypeInfo TYPE;
|
||||
|
||||
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;
|
||||
|
||||
//inline static CFrame identity() { }
|
||||
inline Vector3 Position() const { return translation; }
|
||||
inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
||||
inline float X() const { return translation.x; }
|
||||
inline float Y() const { return translation.y; }
|
||||
inline float Z() const { return translation.z; }
|
||||
|
||||
inline Vector3 RightVector() { return glm::column(rotation, 0); }
|
||||
inline Vector3 UpVector() { return glm::column(rotation, 1); }
|
||||
inline Vector3 LookVector() { return glm::column(rotation, 2); }
|
||||
|
||||
Vector3 ToEulerAnglesXYZ();
|
||||
static CFrame FromEulerAnglesXYZ(Data::Vector3);
|
||||
|
||||
// Operators
|
||||
Data::CFrame operator +(Data::Vector3) const;
|
||||
Data::CFrame operator -(Data::Vector3) const;
|
||||
};
|
||||
}
|
52
src/datatypes/color3.cpp
Normal file
52
src/datatypes/color3.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include "color3.h"
|
||||
#include <algorithm>
|
||||
#include <glm/ext/quaternion_geometric.hpp>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include "meta.h" // IWYU pragma: keep
|
||||
|
||||
Data::Color3::Color3(float r, float g, float b) : r(std::clamp(r, 0.f, 1.f)), g(std::clamp(g, 0.f, 1.f)), b(std::clamp(b, 0.f, 1.f)) {};
|
||||
Data::Color3::Color3(const glm::vec3& vec) : r(std::clamp(vec.x, 0.f, 1.f)), g(std::clamp(vec.y, 0.f, 1.f)), b(std::clamp(vec.z, 0.f, 1.f)) {};
|
||||
|
||||
Data::Color3::~Color3() = default;
|
||||
const Data::TypeInfo Data::Color3::TYPE = {
|
||||
.name = "Color3",
|
||||
.deserializer = &Data::Color3::Deserialize,
|
||||
};
|
||||
|
||||
const Data::TypeInfo& Data::Color3::GetType() const { return Data::Color3::TYPE; };
|
||||
|
||||
const Data::String Data::Color3::ToString() const {
|
||||
return std::to_string(r) + ", " + std::to_string(g) + ", " + std::to_string(b);
|
||||
}
|
||||
|
||||
Data::Color3::operator glm::vec3() const { return glm::vec3(r, g, b); };
|
||||
|
||||
std::string Data::Color3::ToHex() const {
|
||||
std::stringstream ss;
|
||||
ss << "FF" << std::hex << std::uppercase << std::setfill('0')
|
||||
<< std::setw(2) << int(r*255)
|
||||
<< std::setw(2) << int(g*255)
|
||||
<< std::setw(2) << int(b*255);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
Data::Color3 Data::Color3::FromHex(std::string hex) {
|
||||
float r = float(std::stoi(hex.substr(2, 2), nullptr, 16)) / 255;
|
||||
float g = float(std::stoi(hex.substr(4, 2), nullptr, 16)) / 255;
|
||||
float b = float(std::stoi(hex.substr(6, 2), nullptr, 16)) / 255;
|
||||
|
||||
return Color3(r, g, b);
|
||||
}
|
||||
|
||||
// Serialization
|
||||
|
||||
void Data::Color3::Serialize(pugi::xml_node* node) const {
|
||||
node->text().set(this->ToHex());
|
||||
}
|
||||
|
||||
Data::Variant Data::Color3::Deserialize(pugi::xml_node* node) {
|
||||
return Color3::FromHex(node->text().get());
|
||||
}
|
37
src/datatypes/color3.h
Normal file
37
src/datatypes/color3.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include <glm/ext/quaternion_geometric.hpp>
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <reactphysics3d/reactphysics3d.h>
|
||||
|
||||
namespace rp = reactphysics3d;
|
||||
|
||||
namespace Data {
|
||||
class Color3 : Base {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
|
||||
public:
|
||||
Color3(float r, float g, float b);
|
||||
Color3(const glm::vec3&);
|
||||
~Color3();
|
||||
|
||||
static Color3 FromHex(std::string hex);
|
||||
|
||||
virtual const TypeInfo& GetType() const override;
|
||||
static const TypeInfo TYPE;
|
||||
|
||||
virtual const Data::String ToString() const override;
|
||||
std::string ToHex() const;
|
||||
virtual void Serialize(pugi::xml_node* node) const override;
|
||||
static Data::Variant Deserialize(pugi::xml_node* node);
|
||||
|
||||
operator glm::vec3() const;
|
||||
|
||||
inline float R() const { return r; }
|
||||
inline float G() const { return g; }
|
||||
inline float B() const { return b; }
|
||||
};
|
||||
}
|
|
@ -1,8 +1,37 @@
|
|||
#include "meta.h"
|
||||
#include "datatypes/base.h"
|
||||
#include "datatypes/cframe.h"
|
||||
#include <variant>
|
||||
|
||||
Data::String Data::Variant::ToString() const {
|
||||
return std::visit([](auto&& it) {
|
||||
return it.ToString();
|
||||
}, this->wrapped);
|
||||
}
|
||||
}
|
||||
|
||||
void Data::Variant::Serialize(pugi::xml_node* node) const {
|
||||
std::visit([&](auto&& it) {
|
||||
it.Serialize(node);
|
||||
}, this->wrapped);
|
||||
}
|
||||
|
||||
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<std::string, const Data::TypeInfo*> 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 },
|
||||
{ "Color3", &Data::Color3::TYPE },
|
||||
};
|
|
@ -1,7 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include <variant>
|
||||
#include <map>
|
||||
#include "base.h"
|
||||
#include "datatypes/color3.h"
|
||||
#include "vector.h"
|
||||
#include "cframe.h"
|
||||
|
||||
// #define __VARIANT_TYPE std::variant< \
|
||||
// Null, \
|
||||
|
@ -17,7 +21,10 @@ namespace Data {
|
|||
Bool,
|
||||
Int,
|
||||
Float,
|
||||
String
|
||||
String,
|
||||
Vector3,
|
||||
CFrame,
|
||||
Color3
|
||||
> __VARIANT_TYPE;
|
||||
|
||||
class Variant {
|
||||
|
@ -26,5 +33,11 @@ namespace Data {
|
|||
template <typename T> Variant(T obj) : wrapped(obj) {}
|
||||
template <typename T> T get() { return std::get<T>(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<std::string, const TypeInfo*> TYPE_MAP;
|
||||
}
|
58
src/datatypes/vector.cpp
Normal file
58
src/datatypes/vector.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include "vector.h"
|
||||
#include <glm/ext/quaternion_geometric.hpp>
|
||||
#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)) {};
|
||||
Data::Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {};
|
||||
|
||||
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; };
|
||||
|
||||
Data::Vector3 Data::Vector3::ZERO(0, 0, 0);
|
||||
Data::Vector3 Data::Vector3::ONE(1, 1, 1);
|
||||
|
||||
const Data::String Data::Vector3::ToString() const {
|
||||
return std::to_string(X()) + ", " + std::to_string(Y()) + ", " + std::to_string(Z());
|
||||
}
|
||||
|
||||
Data::Vector3::operator glm::vec3() const { return vector; };
|
||||
Data::Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
|
||||
|
||||
// Operators
|
||||
Data::Vector3 Data::Vector3::operator +(Data::Vector3 other) const {
|
||||
return Data::Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z());
|
||||
}
|
||||
|
||||
Data::Vector3 Data::Vector3::operator -(Data::Vector3 other) const {
|
||||
return Data::Vector3(this->X() - other.X(), this->Y() - other.Y(), this->Z() - other.Z());
|
||||
}
|
||||
|
||||
Data::Vector3 Data::Vector3::operator -() const {
|
||||
return Data::Vector3(-this->X(), -this->Y(), -this->Z());
|
||||
}
|
||||
|
||||
Data::Vector3 Data::Vector3::Cross(Data::Vector3 other) const {
|
||||
return glm::cross(this->vector, other.vector);
|
||||
}
|
||||
|
||||
float Data::Vector3::Dot(Data::Vector3 other) const {
|
||||
return glm::dot(this->vector, other.vector);
|
||||
}
|
||||
|
||||
// Serialization
|
||||
|
||||
void Data::Vector3::Serialize(pugi::xml_node* node) const {
|
||||
node->append_child("X").text().set(std::to_string(this->X()));
|
||||
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());
|
||||
}
|
47
src/datatypes/vector.h
Normal file
47
src/datatypes/vector.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include <glm/ext/quaternion_geometric.hpp>
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <reactphysics3d/reactphysics3d.h>
|
||||
|
||||
namespace rp = reactphysics3d;
|
||||
|
||||
namespace Data {
|
||||
class Vector3 : Base {
|
||||
glm::vec3 vector;
|
||||
|
||||
public:
|
||||
Vector3(float x, float y, float z);
|
||||
Vector3(const glm::vec3&);
|
||||
Vector3(const rp::Vector3&);
|
||||
~Vector3();
|
||||
|
||||
virtual const TypeInfo& GetType() const override;
|
||||
static const TypeInfo TYPE;
|
||||
|
||||
static Data::Vector3 ZERO;
|
||||
static Data::Vector3 ONE;
|
||||
|
||||
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;
|
||||
|
||||
inline float X() const { return vector.x; }
|
||||
inline float Y() const { return vector.y; }
|
||||
inline float Z() const { return vector.z; }
|
||||
inline float Magnitude() const { return glm::length(vector); }
|
||||
inline Data::Vector3 Unit() const { return glm::normalize(vector); }
|
||||
|
||||
Data::Vector3 Cross(Data::Vector3) const;
|
||||
float Dot(Data::Vector3) const;
|
||||
|
||||
// Operators
|
||||
Data::Vector3 operator +(Data::Vector3) const;
|
||||
Data::Vector3 operator -(Data::Vector3) const;
|
||||
Data::Vector3 operator -() const;
|
||||
};
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include "../../datatypes/meta.h"
|
||||
#include "datatypes/base.h"
|
||||
#include "objects/base/member.h"
|
||||
#include "objects/meta.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
|
@ -140,4 +141,62 @@ std::vector<std::string> Instance::GetProperties() {
|
|||
|
||||
cachedMemberList = memberList;
|
||||
return memberList;
|
||||
}
|
||||
|
||||
// Serialization
|
||||
|
||||
void Instance::Serialize(pugi::xml_node* parent) {
|
||||
pugi::xml_node node = parent->append_child("Item");
|
||||
node.append_attribute("class").set_value(this->GetClass()->className);
|
||||
|
||||
// Add properties
|
||||
pugi::xml_node propertiesNode = node.append_child("Properties");
|
||||
for (std::string name : GetProperties()) {
|
||||
PropertyMeta meta = GetPropertyMeta(name).value();
|
||||
if (meta.flags & PropertyFlags::PROP_NOSAVE) continue; // This property should not be serialized. Skip...
|
||||
|
||||
pugi::xml_node propertyNode = propertiesNode.append_child(meta.type->name);
|
||||
propertyNode.append_attribute("name").set_value(name);
|
||||
GetPropertyValue(name)->Serialize(&propertyNode);
|
||||
}
|
||||
|
||||
// Add children
|
||||
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;
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
#include <../include/expected.hpp>
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include "member.h"
|
||||
|
||||
|
@ -68,6 +69,10 @@ public:
|
|||
tl::expected<PropertyMeta, MemberNotFound> GetPropertyMeta(std::string name);
|
||||
// Returning a list of property names feels kinda janky. Is this really the way to go?
|
||||
std::vector<std::string> GetProperties();
|
||||
|
||||
// Serialization
|
||||
void Serialize(pugi::xml_node* parent);
|
||||
static std::shared_ptr<Instance> Deserialize(pugi::xml_node* node);
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Instance> InstanceRef;
|
||||
|
|
|
@ -15,21 +15,27 @@ struct FieldCodec {
|
|||
Data::Variant (*read)(void* source);
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
void _writeCodec(Data::Variant source, void* destination) {
|
||||
*(U*)destination = source.get<T>().value;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
Data::Variant _readCodec(void* source) {
|
||||
return T(*(U*)source);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr FieldCodec fieldCodecOf() {
|
||||
return FieldCodec {
|
||||
.write = &_writeCodec<T, U>,
|
||||
.read = &_readCodec<T, U>,
|
||||
.write = [](Data::Variant source, void* destination) {
|
||||
*(U*)destination = (U)source.get<T>();
|
||||
},
|
||||
.read = [](void* source) -> Data::Variant {
|
||||
return T(*(U*)source);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr FieldCodec fieldCodecOf() {
|
||||
return FieldCodec {
|
||||
.write = [](Data::Variant source, void* destination) {
|
||||
*(T*)destination = source.get<T>();
|
||||
},
|
||||
.read = [](void* source) -> Data::Variant {
|
||||
return *(T*)source;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,11 +44,17 @@ std::function<void(std::string name)> memberFunctionOf(void(T::*func)(std::strin
|
|||
return std::bind(func, obj, std::placeholders::_1);
|
||||
}
|
||||
|
||||
enum PropertyFlags {
|
||||
PROP_HIDDEN = 1 << 0, // Hidden from the editor
|
||||
PROP_NOSAVE = 1 << 1, // Do not serialize
|
||||
};
|
||||
|
||||
struct PropertyMeta {
|
||||
void* backingField;
|
||||
const Data::TypeInfo* type;
|
||||
FieldCodec codec;
|
||||
std::optional<std::function<void(std::string name)>> updateCallback;
|
||||
PropertyFlags flags;
|
||||
};
|
||||
|
||||
typedef std::variant<PropertyMeta> MemberMeta;
|
||||
|
|
|
@ -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 <cstdio>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
// 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::string, std::function<std::shared_ptr<Service>(std::weak_ptr<DataModel>)>> SERVICE_CONSTRUCTORS = {
|
||||
{ "Workspace", &Workspace::Create },
|
||||
};
|
||||
|
||||
const InstanceType DataModel::TYPE = {
|
||||
.super = &Instance::TYPE,
|
||||
|
@ -14,9 +26,95 @@ const InstanceType* DataModel::GetClass() {
|
|||
|
||||
DataModel::DataModel()
|
||||
: Instance(&TYPE) {
|
||||
this->name = "Place";
|
||||
}
|
||||
|
||||
void DataModel::Init() {
|
||||
this->workspace = std::make_shared<Workspace>(shared<DataModel>());
|
||||
this->workspace->InitService();
|
||||
// Create the workspace if it doesn't exist
|
||||
if (this->services.count("Workspace") == 0)
|
||||
this->services["Workspace"] = std::make_shared<Workspace>(shared<DataModel>());
|
||||
|
||||
// Init all services
|
||||
for (auto [_, service] : this->services) {
|
||||
service->InitService();
|
||||
}
|
||||
}
|
||||
|
||||
void DataModel::SaveToFile(std::optional<std::string> 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();
|
||||
}
|
||||
|
||||
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<DataModel>());
|
||||
|
||||
// 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<Service>(object);
|
||||
}
|
||||
|
||||
std::shared_ptr<DataModel> 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<DataModel> newModel = std::make_shared<DataModel>();
|
||||
|
||||
for (pugi::xml_node childNode : rootNode.children("Item")) {
|
||||
newModel->DeserializeService(&childNode);
|
||||
}
|
||||
|
||||
newModel->Init();
|
||||
|
||||
return newModel;
|
||||
}
|
|
@ -5,17 +5,44 @@
|
|||
|
||||
class Workspace;
|
||||
|
||||
class DataModel;
|
||||
class Service;
|
||||
extern std::map<std::string, std::function<std::shared_ptr<Service>(std::weak_ptr<DataModel>)>> 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> workspace;
|
||||
std::map<std::string, std::shared_ptr<Service>> services;
|
||||
|
||||
std::optional<std::string> currentFile;
|
||||
|
||||
DataModel();
|
||||
void Init();
|
||||
|
||||
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetService(std::string name) {
|
||||
if (services.count(name) != 0)
|
||||
return services[name];
|
||||
// TODO: Validate name
|
||||
services[name] = SERVICE_CONSTRUCTORS[name](shared<DataModel>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<std::shared_ptr<T>> 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<std::string> path = std::nullopt);
|
||||
static std::shared_ptr<DataModel> LoadFromFile(std::string path);
|
||||
};
|
10
src/objects/meta.cpp
Normal file
10
src/objects/meta.cpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include "meta.h"
|
||||
#include "objects/part.h"
|
||||
#include "objects/workspace.h"
|
||||
|
||||
std::map<std::string, const InstanceType*> INSTANCE_MAP = {
|
||||
{ "Instance", &Instance::TYPE },
|
||||
{ "Part", &Part::TYPE },
|
||||
{ "Workspace", &Workspace::TYPE },
|
||||
{ "DataModel", &DataModel::TYPE },
|
||||
};
|
8
src/objects/meta.h
Normal file
8
src/objects/meta.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "objects/base/instance.h"
|
||||
|
||||
// Map of all instance types to their class names
|
||||
extern std::map<std::string, const InstanceType*> INSTANCE_MAP;
|
|
@ -1,11 +1,50 @@
|
|||
#include "part.h"
|
||||
#include "base/instance.h"
|
||||
#include "datatypes/base.h"
|
||||
#include "datatypes/cframe.h"
|
||||
#include "datatypes/color3.h"
|
||||
#include "datatypes/vector.h"
|
||||
#include "objects/base/member.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include "physics/simulation.h"
|
||||
|
||||
// template <typename T, typename U>
|
||||
// constexpr FieldCodec fieldCodecOf() {
|
||||
// return FieldCodec {
|
||||
// .write = [](Data::Variant source, void* destination) {
|
||||
// *(U*)destination = (U)source.get<T>();
|
||||
// },
|
||||
// .read = [](void* source) -> Data::Variant {
|
||||
// return T(*(U*)source);
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
constexpr FieldCodec cframePositionCodec() {
|
||||
return FieldCodec {
|
||||
.write = [](Data::Variant source, void* destination) {
|
||||
Data::CFrame* cframe = static_cast<Data::CFrame*>(destination);
|
||||
*cframe = cframe->Rotation() + source.get<Data::Vector3>();
|
||||
},
|
||||
.read = [](void* source) -> Data::Variant {
|
||||
return *static_cast<Data::CFrame*>(source);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
constexpr FieldCodec cframeRotationCodec() {
|
||||
return FieldCodec {
|
||||
.write = [](Data::Variant source, void* destination) {
|
||||
Data::CFrame* cframe = static_cast<Data::CFrame*>(destination);
|
||||
*cframe = Data::CFrame::FromEulerAnglesXYZ(source.get<Data::Vector3>()) + cframe->Position();
|
||||
},
|
||||
.read = [](void* source) -> Data::Variant {
|
||||
return static_cast<Data::CFrame*>(source)->ToEulerAnglesXYZ();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const InstanceType Part::TYPE = {
|
||||
.super = &Instance::TYPE,
|
||||
.className = "Part",
|
||||
|
@ -17,15 +56,46 @@ const InstanceType* Part::GetClass() {
|
|||
return &TYPE;
|
||||
}
|
||||
|
||||
Part::Part(): Part(PartConstructParams {}) {
|
||||
Part::Part(): Part(PartConstructParams { .color = Data::Color3(0.639216f, 0.635294f, 0.647059f) }) {
|
||||
}
|
||||
|
||||
Part::Part(PartConstructParams params): Instance(&TYPE), position(params.position), rotation(params.rotation),
|
||||
scale(params.scale), material(params.material), anchored(params.anchored) {
|
||||
Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(params.position, params.rotation)),
|
||||
size(params.size), color(params.color), anchored(params.anchored) {
|
||||
this->memberMap = std::make_unique<MemberMap>(MemberMap {
|
||||
.super = std::move(this->memberMap),
|
||||
.members = {
|
||||
{ "Anchored", { .backingField = &anchored, .type = &Data::Bool::TYPE, .codec = fieldCodecOf<Data::Bool, bool>(), .updateCallback = memberFunctionOf(&Part::onUpdated, this) } }
|
||||
{ "Anchored", {
|
||||
.backingField = &anchored,
|
||||
.type = &Data::Bool::TYPE,
|
||||
.codec = fieldCodecOf<Data::Bool, bool>(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||
} }, { "Position", {
|
||||
.backingField = &cframe,
|
||||
.type = &Data::Vector3::TYPE,
|
||||
.codec = cframePositionCodec(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
.flags = PropertyFlags::PROP_NOSAVE
|
||||
} }, { "Rotation", {
|
||||
.backingField = &cframe,
|
||||
.type = &Data::Vector3::TYPE,
|
||||
.codec = cframeRotationCodec(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
.flags = PropertyFlags::PROP_NOSAVE
|
||||
} }, { "CFrame", {
|
||||
.backingField = &cframe,
|
||||
.type = &Data::CFrame::TYPE,
|
||||
.codec = fieldCodecOf<Data::CFrame>(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
} }, { "Size", {
|
||||
.backingField = &size,
|
||||
.type = &Data::Vector3::TYPE,
|
||||
.codec = fieldCodecOf<Data::Vector3, glm::vec3>(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||
} }, { "Color", {
|
||||
.backingField = &color,
|
||||
.type = &Data::Color3::TYPE,
|
||||
.codec = fieldCodecOf<Data::Color3>(),
|
||||
} }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/ext.hpp>
|
||||
#include "../rendering/material.h"
|
||||
#include "datatypes/cframe.h"
|
||||
#include "datatypes/color3.h"
|
||||
#include "datatypes/vector.h"
|
||||
#include <reactphysics3d/reactphysics3d.h>
|
||||
|
||||
namespace rp = reactphysics3d;
|
||||
|
@ -13,8 +16,8 @@ namespace rp = reactphysics3d;
|
|||
struct PartConstructParams {
|
||||
glm::vec3 position;
|
||||
glm::quat rotation = glm::identity<glm::quat>();
|
||||
glm::vec3 scale;
|
||||
Material material;
|
||||
glm::vec3 size;
|
||||
Data::Color3 color;
|
||||
|
||||
bool anchored = false;
|
||||
};
|
||||
|
@ -26,11 +29,9 @@ protected:
|
|||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
// TODO: Switch these over to our dedicated datatypes
|
||||
glm::vec3 position;
|
||||
glm::quat rotation = glm::identity<glm::quat>();
|
||||
glm::vec3 scale;
|
||||
Material material;
|
||||
Data::CFrame cframe;
|
||||
glm::vec3 size;
|
||||
Data::Color3 color;
|
||||
bool selected = false;
|
||||
|
||||
bool anchored = false;
|
||||
|
@ -44,4 +45,6 @@ public:
|
|||
static inline std::shared_ptr<Part> New(PartConstructParams params) { return std::make_shared<Part>(params); };
|
||||
static inline InstanceRef CreateGeneric() { return std::make_shared<Part>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
|
||||
inline Data::Vector3 position() { return cframe.Position(); }
|
||||
};
|
|
@ -12,6 +12,6 @@ public:
|
|||
Workspace(std::weak_ptr<DataModel> dataModel);
|
||||
|
||||
// static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); };
|
||||
// static inline InstanceRef Create() { return std::make_shared<Workspace>(); };
|
||||
static inline std::shared_ptr<Service> Create(std::weak_ptr<DataModel> parent) { return std::make_shared<Workspace>(parent); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -17,6 +17,7 @@
|
|||
#include <reactphysics3d/reactphysics3d.h>
|
||||
#include "../common.h"
|
||||
#include "../objects/part.h"
|
||||
#include "datatypes/cframe.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "simulation.h"
|
||||
|
@ -45,14 +46,14 @@ void simulationInit() {
|
|||
void syncPartPhysics(std::shared_ptr<Part> part) {
|
||||
glm::mat4 rotMat = glm::mat4(1.0f);
|
||||
|
||||
rp::Transform transform(glmToRp(part->position), glmToRp(part->rotation));
|
||||
rp::Transform transform = part->cframe;
|
||||
if (!part->rigidBody) {
|
||||
part->rigidBody = world->createRigidBody(transform);
|
||||
} else {
|
||||
part->rigidBody->setTransform(transform);
|
||||
}
|
||||
|
||||
rp::BoxShape* shape = physicsCommon->createBoxShape(glmToRp(part->scale * glm::vec3(0.5f)));
|
||||
rp::BoxShape* shape = physicsCommon->createBoxShape(glmToRp(part->size * glm::vec3(0.5f)));
|
||||
|
||||
if (part->rigidBody->getNbColliders() > 0) {
|
||||
part->rigidBody->removeCollider(part->rigidBody->getCollider(0));
|
||||
|
@ -76,9 +77,7 @@ void physicsStep(float deltaTime) {
|
|||
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);
|
||||
const rp::Transform& transform = part->rigidBody->getTransform();
|
||||
part->position = rpToGlm(transform.getPosition());
|
||||
// part.rotation = glm::eulerAngles(rpToGlm(transform.getOrientation()));
|
||||
part->rotation = rpToGlm(transform.getOrientation());
|
||||
part->cframe = Data::CFrame(transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <memory>
|
||||
#include <reactphysics3d/body/Body.h>
|
||||
#include <reactphysics3d/mathematics/Matrix3x3.h>
|
||||
#include <reactphysics3d/mathematics/Quaternion.h>
|
||||
#include <reactphysics3d/mathematics/Vector3.h>
|
||||
#include <reactphysics3d/mathematics/mathematics.h>
|
||||
|
@ -18,6 +19,10 @@ inline rp::Quaternion glmToRp(glm::quat quat) {
|
|||
return rp::Quaternion(quat.w, rp::Vector3(quat.x, quat.y, quat.z));
|
||||
}
|
||||
|
||||
// inline rp::Matrix3x3 glmToRp(glm::mat3 mat) {
|
||||
// return (rp::Quaternion)glmToRp((glm::quat)mat);
|
||||
// }
|
||||
|
||||
inline glm::vec3 rpToGlm(rp::Vector3 vec) {
|
||||
return glm::vec3(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "physics/util.h"
|
||||
#include "shader.h"
|
||||
#include "mesh.h"
|
||||
#include "defaultmeshes.h"
|
||||
|
@ -109,15 +110,32 @@ void renderParts() {
|
|||
if (inst->GetClass()->className != "Part") continue;
|
||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
||||
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
model = glm::translate(model, part->position);
|
||||
model = model * glm::mat4_cast(part->rotation);
|
||||
model = glm::scale(model, part->scale);
|
||||
// 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->size);
|
||||
shader->set("model", model);
|
||||
shader->set("material", part->material);
|
||||
shader->set("material", Material {
|
||||
.diffuse = part->color,
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 16.0f,
|
||||
});
|
||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
||||
shader->set("normalMatrix", normalMatrix);
|
||||
shader->set("texScale", part->scale);
|
||||
shader->set("texScale", part->size);
|
||||
|
||||
CUBE_MESH->bind();
|
||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||
|
|
Loading…
Add table
Reference in a new issue