From 6a017b2238bf1293497902094da27598322b8d35 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Fri, 11 Apr 2025 00:34:39 +0200 Subject: [PATCH] refactor(physics): integrated physics world into workspace (likely for bugs to ensue. I'll deal with that later) --- client/src/main.cpp | 26 +++--- core/src/objects/base/instance.cpp | 14 ++- core/src/objects/base/instance.h | 3 +- core/src/objects/part.cpp | 18 ++-- core/src/objects/part.h | 2 +- core/src/objects/workspace.cpp | 130 ++++++++++++++++++++++++++ core/src/objects/workspace.h | 39 +++++++- core/src/physics/simulation.cpp | 141 ----------------------------- core/src/physics/simulation.h | 30 ------ editor/mainglwidget.cpp | 15 ++- editor/mainwindow.cpp | 15 +-- 11 files changed, 213 insertions(+), 220 deletions(-) delete mode 100644 core/src/physics/simulation.cpp delete mode 100644 core/src/physics/simulation.h diff --git a/client/src/main.cpp b/client/src/main.cpp index fbd62f3..58b025b 100644 --- a/client/src/main.cpp +++ b/client/src/main.cpp @@ -1,7 +1,6 @@ #include #include #include "objects/part.h" -#include "physics/simulation.h" #include "rendering/renderer.h" #include "common.h" @@ -34,7 +33,6 @@ int main() { glewInit(); gDataModel->Init(); - simulationInit(); renderInit(window, 1200, 900); // Baseplate @@ -56,7 +54,7 @@ int main() { for (InstanceRef inst : gWorkspace()->GetChildren()) { if (inst->GetClass()->className != "Part") continue; std::shared_ptr part = std::dynamic_pointer_cast(inst); - syncPartPhysics(part); + gWorkspace()->SyncPartPhysics(part); } float lastTime = glfwGetTime(); @@ -65,7 +63,7 @@ int main() { lastTime = glfwGetTime(); processInput(window); - physicsStep(deltaTime); + gWorkspace()->PhysicsStep(deltaTime); render(window); glfwSwapBuffers(window); @@ -103,15 +101,15 @@ void processInput(GLFWwindow* window) { shiftFactor *= deltaTime; if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) { // lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(1, 0, 0)); - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } if (glfwGetKey(window, GLFW_KEY_Y) == GLFW_PRESS) { // lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(0, 1, 0)); - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) { // lastPart->rotation *= glm::angleAxis(shiftFactor, glm::vec3(0, 0, 1)); - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } } } @@ -152,35 +150,35 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods .size = glm::vec3(1, 1, 1), .color = glm::vec3(1.0f, 0.5f, 0.31f), })); - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } 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; - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } if (key == GLFW_KEY_Y && action == GLFW_PRESS) { // lastPart->position.y += shiftFactor; - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } if (key == GLFW_KEY_Z && action == GLFW_PRESS) { // lastPart->position.z += shiftFactor; - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } } else if (mode == 1) { if (key == GLFW_KEY_X && action == GLFW_PRESS) { lastPart->size.x += shiftFactor; - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } if (key == GLFW_KEY_Y && action == GLFW_PRESS) { lastPart->size.y += shiftFactor; - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } if (key == GLFW_KEY_Z && action == GLFW_PRESS) { lastPart->size.z += shiftFactor; - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } } diff --git a/core/src/objects/base/instance.cpp b/core/src/objects/base/instance.cpp index bc66696..1cd287d 100644 --- a/core/src/objects/base/instance.cpp +++ b/core/src/objects/base/instance.cpp @@ -88,14 +88,12 @@ bool Instance::SetParent(std::optional> newParent) { this->_workspace = std::nullopt; } - // Algorithm for updating descendant's dataModel and workspace fields - if (oldDataModel != _dataModel || oldWorkspace != _workspace) - updateAncestry(); + updateAncestry(this->shared(), newParent); return true; } -void Instance::updateAncestry() { +void Instance::updateAncestry(std::optional> updatedChild, std::optional> newParent) { if (GetParent()) { this->_dataModel = GetParent().value()->GetClass() == &DataModel::TYPE ? std::make_optional(std::dynamic_pointer_cast(GetParent().value())) : GetParent().value()->dataModel(); this->_workspace = GetParent().value()->GetClass() == &Workspace::TYPE ? std::make_optional(std::dynamic_pointer_cast(GetParent().value())) : GetParent().value()->workspace(); @@ -104,9 +102,11 @@ void Instance::updateAncestry() { this->_workspace = std::nullopt; } + OnAncestryChanged(updatedChild, newParent); + // Update ancestry in descendants for (InstanceRef child : children) { - child->updateAncestry(); + child->updateAncestry(updatedChild, newParent); } } @@ -141,6 +141,10 @@ void Instance::OnParentUpdated(std::optional> oldParen // Empty stub } +void Instance::OnAncestryChanged(std::optional> child, std::optional> newParent) { + // Empty stub +} + // Properties tl::expected Instance::GetPropertyValue(std::string name) { diff --git a/core/src/objects/base/instance.h b/core/src/objects/base/instance.h index 667f7d5..7f25c88 100644 --- a/core/src/objects/base/instance.h +++ b/core/src/objects/base/instance.h @@ -61,7 +61,7 @@ private: std::optional> _workspace; bool ancestryContinuityCheck(std::optional> newParent); - void updateAncestry(); + void updateAncestry(std::optional> child, std::optional> newParent); protected: bool parentLocked = false; std::unique_ptr memberMap; @@ -70,6 +70,7 @@ protected: virtual ~Instance(); virtual void OnParentUpdated(std::optional> oldParent, std::optional> newParent); + virtual void OnAncestryChanged(std::optional> child, std::optional> newParent); // The root data model this object is a descendant of std::optional> dataModel(); diff --git a/core/src/objects/part.cpp b/core/src/objects/part.cpp index 00ea64b..b1f08d6 100644 --- a/core/src/objects/part.cpp +++ b/core/src/objects/part.cpp @@ -1,5 +1,6 @@ #include "part.h" #include "base/instance.h" +#include "common.h" #include "datatypes/base.h" #include "datatypes/cframe.h" #include "datatypes/color3.h" @@ -7,7 +8,6 @@ #include "objects/base/member.h" #include #include -#include "physics/simulation.h" using Data::Vector3; @@ -106,24 +106,26 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par }); } -// This feels wrong. Get access to PhysicsWorld somehow else? Part will need access to this often though, most likely... -extern rp::PhysicsWorld* world; Part::~Part() { // This relies on physicsCommon still existing. Be very careful. - if (this->rigidBody) - world->destroyRigidBody(rigidBody); + if (this->rigidBody && workspace()) + workspace().value()->DestroyRigidBody(rigidBody); } -void Part::OnParentUpdated(std::optional> oldParent, std::optional> newParent) { +void Part::OnAncestryChanged(std::optional> child, std::optional> newParent) { if (this->rigidBody) - this->rigidBody->setIsActive(newParent.has_value()); + this->rigidBody->setIsActive(workspace().has_value()); + + if (workspace()) + workspace().value()->SyncPartPhysics(std::dynamic_pointer_cast(this->shared_from_this())); // TODO: Sleeping bodies that touch this one also need to be updated } void Part::onUpdated(std::string property) { - syncPartPhysics(std::dynamic_pointer_cast(this->shared_from_this())); + if (workspace()) + workspace().value()->SyncPartPhysics(std::dynamic_pointer_cast(this->shared_from_this())); } // Expands provided extents to fit point diff --git a/core/src/objects/part.h b/core/src/objects/part.h index 6537b75..9c54074 100644 --- a/core/src/objects/part.h +++ b/core/src/objects/part.h @@ -24,7 +24,7 @@ struct PartConstructParams { class Part : public Instance { protected: - void OnParentUpdated(std::optional> oldParent, std::optional> newParent) override; + void OnAncestryChanged(std::optional> child, std::optional> newParent) override; void onUpdated(std::string); public: const static InstanceType TYPE; diff --git a/core/src/objects/workspace.cpp b/core/src/objects/workspace.cpp index d28e7ce..cafc2e3 100644 --- a/core/src/objects/workspace.cpp +++ b/core/src/objects/workspace.cpp @@ -1,5 +1,6 @@ #include "workspace.h" #include "objects/base/instance.h" +#include "physics/util.h" const InstanceType Workspace::TYPE = { .super = &Instance::TYPE, @@ -13,5 +14,134 @@ const InstanceType* Workspace::GetClass() { return &TYPE; } +static rp::PhysicsCommon physicsCommon; + Workspace::Workspace(): Service(&TYPE) { } + +Workspace::~Workspace() { + if (physicsWorld) + physicsCommon.destroyPhysicsWorld(physicsWorld); +} + +void Workspace::InitService() { + if (initialized) return; + initialized = true; + + physicsWorld = physicsCommon.createPhysicsWorld(); + + physicsWorld->setGravity(rp::Vector3(0, -196.2, 0)); + // world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS); + physicsWorld->setNbIterationsPositionSolver(2000); + physicsWorld->setNbIterationsVelocitySolver(2000); + + // physicsWorld->setEventListener(&eventListener); + + // Sync all parts + for (auto it = this->GetDescendantsStart(); it != this->GetDescendantsEnd(); it++) { + InstanceRef obj = *it; + if (obj->GetClass()->className != "Part") continue; // TODO: Replace this with a .IsA call instead of comparing the class name directly + std::shared_ptr part = std::dynamic_pointer_cast(obj); + this->SyncPartPhysics(part); + } +} + +void Workspace::SyncPartPhysics(std::shared_ptr part) { + if (!physicsWorld) return; + + glm::mat4 rotMat = glm::mat4(1.0f); + + rp::Transform transform = part->cframe; + if (!part->rigidBody) { + part->rigidBody = physicsWorld->createRigidBody(transform); + } else { + part->rigidBody->setTransform(transform); + } + + rp::BoxShape* shape = physicsCommon.createBoxShape(glmToRp(part->size * glm::vec3(0.5f))); + + if (part->rigidBody->getNbColliders() > 0) { + part->rigidBody->removeCollider(part->rigidBody->getCollider(0)); + } + + if (part->rigidBody->getNbColliders() == 0) + part->rigidBody->addCollider(shape, rp::Transform()); + part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC); + part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11); + + part->rigidBody->setUserData(&*part); +} + +void Workspace::PhysicsStep(float deltaTime) { + // Step the simulation a few steps + physicsWorld->update(std::min(deltaTime / 2, (1/60.f))); + + // 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 + for (auto it = this->GetDescendantsStart(); it != this->GetDescendantsEnd(); it++) { + InstanceRef obj = *it; + if (obj->GetClass()->className != "Part") continue; // TODO: Replace this with a .IsA call instead of comparing the class name directly + std::shared_ptr part = std::dynamic_pointer_cast(obj); + const rp::Transform& transform = part->rigidBody->getTransform(); + part->cframe = Data::CFrame(transform); + } +} + + +RaycastResult::RaycastResult(const rp::RaycastInfo& raycastInfo) + : worldPoint(raycastInfo.worldPoint) + , worldNormal(raycastInfo.worldNormal) + , hitFraction(raycastInfo.hitFraction) + , triangleIndex(raycastInfo.triangleIndex) + , body(raycastInfo.body) + , collider(raycastInfo.collider) {} + +class NearestRayHit : public rp::RaycastCallback { + rp::Vector3 startPos; + std::optional filter; + + std::optional nearestHit; + float nearestHitDistance = -1; + + // Order is not guaranteed, so we have to figure out the nearest object using a more sophisticated algorith, + rp::decimal notifyRaycastHit(const rp::RaycastInfo& raycastInfo) override { + // If the detected object is further away than the nearest object, continue. + int distance = (raycastInfo.worldPoint - startPos).length(); + if (nearestHitDistance != -1 && distance >= nearestHitDistance) + return 1; + + if (!filter) { + nearestHit = raycastInfo; + nearestHitDistance = distance; + return 1; + } + + std::shared_ptr part = partFromBody(raycastInfo.body); + FilterResult result = filter.value()(part); + if (result == FilterResult::BLOCK) { + nearestHit = std::nullopt; + nearestHitDistance = distance; + return 1; + } else if (result == FilterResult::TARGET) { + nearestHit = raycastInfo; + nearestHitDistance = distance; + return 1; + } + return 1; + }; + +public: + NearestRayHit(rp::Vector3 startPos, std::optional filter = std::nullopt) : startPos(startPos), filter(filter) {} + std::optional getNearestHit() { return nearestHit; }; +}; + +std::optional Workspace::CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional filter, unsigned short categoryMaskBits) { + rp::Ray ray(glmToRp(point), glmToRp(glm::normalize(rotation)) * maxLength); + NearestRayHit rayHit(glmToRp(point), filter); + physicsWorld->raycast(ray, &rayHit, categoryMaskBits); + return rayHit.getNearestHit(); +} + +void Workspace::DestroyRigidBody(rp::RigidBody* rigidBody) { + physicsWorld->destroyRigidBody(rigidBody); +} \ No newline at end of file diff --git a/core/src/objects/workspace.h b/core/src/objects/workspace.h index ba216f0..b675b84 100644 --- a/core/src/objects/workspace.h +++ b/core/src/objects/workspace.h @@ -1,17 +1,52 @@ #pragma once -#include "base.h" #include "objects/base/service.h" #include +#include +#include +#include + +struct RaycastResult { + rp::Vector3 worldPoint; + rp::Vector3 worldNormal; + rp::decimal hitFraction; + int triangleIndex; + rp::Body* body; + rp::Collider* collider; + + RaycastResult(const rp::RaycastInfo& raycastInfo); +}; + +enum FilterResult { + TARGET, // The object is captured + BLOCK, // The object blocks any objects behind it, but is not captured + PASS, // The object is transparent, ignore it +}; + +class Part; +typedef std::function)> RaycastFilter; class Workspace : public Service { -//private: + rp::PhysicsWorld *physicsWorld = nullptr; + +protected: + void InitService() override; + bool initialized = false; + public: const static InstanceType TYPE; Workspace(); + ~Workspace(); // static inline std::shared_ptr New() { return std::make_shared(); }; static inline std::shared_ptr Create() { return std::make_shared(); }; virtual const InstanceType* GetClass() override; + + void SyncPartPhysics(std::shared_ptr part); + void DestroyRigidBody(rp::RigidBody* rigidBody); + + void PhysicsStep(float deltaTime); + std::optional CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF); + }; \ No newline at end of file diff --git a/core/src/physics/simulation.cpp b/core/src/physics/simulation.cpp deleted file mode 100644 index b055538..0000000 --- a/core/src/physics/simulation.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../common.h" -#include "../objects/part.h" -#include "datatypes/cframe.h" -#include "util.h" - -#include "simulation.h" - -namespace rp = reactphysics3d; - -class PhysicsListener : public rp::EventListener { - void onContact(const CollisionCallback::CallbackData& /*callbackData*/) override { - // printf("Collision occurred!\n"); - } -}; - -rp::PhysicsCommon* physicsCommon; -rp::PhysicsWorld* world; -PhysicsListener eventListener; - -void simulationInit() { - physicsCommon = new rp::PhysicsCommon; // I allocate this on the heap to ensure it exists while Parts are getting destructed. This is probably not great - world = physicsCommon->createPhysicsWorld(); - - world->setGravity(rp::Vector3(0, -196.2, 0)); - // world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS); - world->setNbIterationsPositionSolver(2000); - world->setNbIterationsVelocitySolver(2000); - - world->setEventListener(&eventListener); -} - -void syncPartPhysics(std::shared_ptr part) { - glm::mat4 rotMat = glm::mat4(1.0f); - - 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->size * glm::vec3(0.5f))); - - if (part->rigidBody->getNbColliders() > 0) { - part->rigidBody->removeCollider(part->rigidBody->getCollider(0)); - } - - if (part->rigidBody->getNbColliders() == 0) - part->rigidBody->addCollider(shape, rp::Transform()); - part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC); - part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11); - - part->rigidBody->setUserData(&*part); -} - -void physicsStep(float deltaTime) { - // Step the simulation a few steps - world->update(std::min(deltaTime / 2, (1/60.f))); - - // 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 - for (auto it = gWorkspace()->GetDescendantsStart(); it != gWorkspace()->GetDescendantsEnd(); it++) { - InstanceRef obj = *it; - if (obj->GetClass()->className != "Part") continue; // TODO: Replace this with a .IsA call instead of comparing the class name directly - std::shared_ptr part = std::dynamic_pointer_cast(obj); - const rp::Transform& transform = part->rigidBody->getTransform(); - part->cframe = Data::CFrame(transform); - } -} - -RaycastResult::RaycastResult(const rp::RaycastInfo& raycastInfo) - : worldPoint(raycastInfo.worldPoint) - , worldNormal(raycastInfo.worldNormal) - , hitFraction(raycastInfo.hitFraction) - , triangleIndex(raycastInfo.triangleIndex) - , body(raycastInfo.body) - , collider(raycastInfo.collider) {} - -class NearestRayHit : public rp::RaycastCallback { - rp::Vector3 startPos; - std::optional filter; - - std::optional nearestHit; - float nearestHitDistance = -1; - - // Order is not guaranteed, so we have to figure out the nearest object using a more sophisticated algorith, - rp::decimal notifyRaycastHit(const rp::RaycastInfo& raycastInfo) override { - // If the detected object is further away than the nearest object, continue. - int distance = (raycastInfo.worldPoint - startPos).length(); - if (nearestHitDistance != -1 && distance >= nearestHitDistance) - return 1; - - if (!filter) { - nearestHit = raycastInfo; - nearestHitDistance = distance; - return 1; - } - - std::shared_ptr part = partFromBody(raycastInfo.body); - FilterResult result = filter.value()(part); - if (result == FilterResult::BLOCK) { - nearestHit = std::nullopt; - nearestHitDistance = distance; - return 1; - } else if (result == FilterResult::TARGET) { - nearestHit = raycastInfo; - nearestHitDistance = distance; - return 1; - } - return 1; - }; - -public: - NearestRayHit(rp::Vector3 startPos, std::optional filter = std::nullopt) : startPos(startPos), filter(filter) {} - std::optional getNearestHit() { return nearestHit; }; -}; - -std::optional castRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional filter, unsigned short categoryMaskBits) { - rp::Ray ray(glmToRp(point), glmToRp(glm::normalize(rotation)) * maxLength); - NearestRayHit rayHit(glmToRp(point), filter); - world->raycast(ray, &rayHit, categoryMaskBits); - return rayHit.getNearestHit(); -} \ No newline at end of file diff --git a/core/src/physics/simulation.h b/core/src/physics/simulation.h deleted file mode 100644 index 41dc100..0000000 --- a/core/src/physics/simulation.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "../objects/part.h" -#include -#include -#include - -struct RaycastResult { - rp::Vector3 worldPoint; - rp::Vector3 worldNormal; - rp::decimal hitFraction; - int triangleIndex; - rp::Body* body; - rp::Collider* collider; - - RaycastResult(const rp::RaycastInfo& raycastInfo); -}; - -enum FilterResult { - TARGET, // The object is captured - BLOCK, // The object blocks any objects behind it, but is not captured - PASS, // The object is transparent, ignore it -}; - -typedef std::function)> RaycastFilter; - -void simulationInit(); -void syncPartPhysics(std::shared_ptr part); -void physicsStep(float deltaTime); -std::optional castRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF); \ No newline at end of file diff --git a/editor/mainglwidget.cpp b/editor/mainglwidget.cpp index 5efcfcd..defe3bf 100644 --- a/editor/mainglwidget.cpp +++ b/editor/mainglwidget.cpp @@ -3,7 +3,6 @@ #include "mainglwidget.h" #include "common.h" #include "math_helper.h" -#include "physics/simulation.h" #include "physics/util.h" #include "rendering/renderer.h" #include "rendering/shader.h" @@ -112,7 +111,7 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) { QPoint position = evt->pos(); glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height())); - std::optional rayHit = castRayNearest(camera.cameraPos, pointDir, 50000, [](std::shared_ptr part) { + std::optional rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000, [](std::shared_ptr part) { return (part == draggingObject->lock()) ? FilterResult::PASS : FilterResult::TARGET; }); @@ -145,7 +144,7 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) { draggingObject->lock()->cframe = newFrame + unsinkOffset; - syncPartPhysics(draggingObject->lock()); + gWorkspace()->SyncPartPhysics(draggingObject->lock()); } inline glm::vec3 vec3fy(glm::vec4 vec) { @@ -222,7 +221,7 @@ void MainGLWidget::handleLinearTransform(QMouseEvent* evt) { if (mainWindow()->editSoundEffects && (oldSize != part->size) && QFile::exists("./assets/excluded/switch.wav")) playSound("./assets/excluded/switch.wav"); - syncPartPhysics(std::dynamic_pointer_cast(editorToolHandles->adornee->lock())); + gWorkspace()->SyncPartPhysics(std::dynamic_pointer_cast(editorToolHandles->adornee->lock())); } // Also implemented based on Godot: [c7ea8614](godot/editor/plugins/canvas_item_editor_plugin.cpp#L1490) @@ -264,7 +263,7 @@ void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) { part->cframe = initialFrame * Data::CFrame::FromEulerAnglesXYZ(-angles); - syncPartPhysics(std::dynamic_pointer_cast(editorToolHandles->adornee->lock())); + gWorkspace()->SyncPartPhysics(std::dynamic_pointer_cast(editorToolHandles->adornee->lock())); } std::optional MainGLWidget::raycastHandle(glm::vec3 pointDir) { @@ -282,7 +281,7 @@ void MainGLWidget::handleCursorChange(QMouseEvent* evt) { return; }; - std::optional rayHit = castRayNearest(camera.cameraPos, pointDir, 50000); + std::optional rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000); if (rayHit && partFromBody(rayHit->body)->name != "Baseplate") { setCursor(Qt::OpenHandCursor); return; @@ -339,7 +338,7 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) { } // raycast part - std::optional rayHit = castRayNearest(camera.cameraPos, pointDir, 50000); + std::optional rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000); if (!rayHit || !partFromBody(rayHit->body)) return; std::shared_ptr part = partFromBody(rayHit->body); if (part->name == "Baseplate") return; @@ -416,7 +415,7 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) { .size = glm::vec3(1, 1, 1), .color = glm::vec3(1.0f, 0.5f, 0.31f), })); - syncPartPhysics(lastPart); + gWorkspace()->SyncPartPhysics(lastPart); } if (evt->key() == Qt::Key_U) diff --git a/editor/mainwindow.cpp b/editor/mainwindow.cpp index 007e434..506641f 100644 --- a/editor/mainwindow.cpp +++ b/editor/mainwindow.cpp @@ -1,7 +1,6 @@ #include "mainwindow.h" #include "./ui_mainwindow.h" #include "common.h" -#include "physics/simulation.h" #include #include #include @@ -160,9 +159,6 @@ MainWindow::MainWindow(QWidget *parent) gDataModel->Init(); ui->explorerView->updateRoot(gDataModel); - // TODO: Remove this and use a proper fix. This *WILL* cause a leak and memory issues in the future - simulationInit(); - // Baseplate gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({ .position = glm::vec3(0, -5, 0), @@ -172,7 +168,7 @@ MainWindow::MainWindow(QWidget *parent) .anchored = true, })); ui->mainWidget->lastPart->name = "Baseplate"; - syncPartPhysics(ui->mainWidget->lastPart); + gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart); }); connect(ui->actionSave, &QAction::triggered, this, [&]() { @@ -201,6 +197,7 @@ MainWindow::MainWindow(QWidget *parent) // simulationInit(); std::shared_ptr newModel = DataModel::LoadFromFile(path.value()); gDataModel = newModel; + newModel->Init(); ui->explorerView->updateRoot(newModel); }); @@ -333,8 +330,6 @@ MainWindow::MainWindow(QWidget *parent) // ui->explorerView->Init(ui); - simulationInit(); - // Baseplate gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({ .position = glm::vec3(0, -5, 0), @@ -344,7 +339,7 @@ MainWindow::MainWindow(QWidget *parent) .anchored = true, })); ui->mainWidget->lastPart->name = "Baseplate"; - syncPartPhysics(ui->mainWidget->lastPart); + gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart); gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({ .position = glm::vec3(0), @@ -352,7 +347,7 @@ MainWindow::MainWindow(QWidget *parent) .size = glm::vec3(4, 1.2, 2), .color = glm::vec3(0.639216f, 0.635294f, 0.647059f), })); - syncPartPhysics(ui->mainWidget->lastPart); + gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart); } void MainWindow::closeEvent(QCloseEvent* evt) { @@ -399,7 +394,7 @@ void MainWindow::timerEvent(QTimerEvent* evt) { lastTime = std::chrono::steady_clock::now(); if (simulationPlaying) - physicsStep(deltaTime); + gWorkspace()->PhysicsStep(deltaTime); ui->mainWidget->update(); ui->mainWidget->updateCycle(); }