From 4c0f24066c2b75b4de55084aef4a50c19cb4e8ad Mon Sep 17 00:00:00 2001 From: maelstrom Date: Tue, 19 Aug 2025 19:58:59 +0200 Subject: [PATCH] refactor(physics): refactored joint code --- core/src/handles.cpp | 12 +++--- core/src/handles.h | 2 +- core/src/objects/joint/jointinstance.cpp | 54 ++++++++++++------------ core/src/objects/joint/jointinstance.h | 7 ++- core/src/objects/joint/rotate.cpp | 27 ++---------- core/src/objects/joint/rotate.h | 3 -- core/src/objects/joint/rotatev.cpp | 29 ++----------- core/src/objects/joint/rotatev.h | 3 -- core/src/objects/joint/snap.cpp | 22 ++-------- core/src/objects/joint/snap.h | 3 -- core/src/objects/joint/weld.cpp | 22 ++-------- core/src/objects/joint/weld.h | 3 -- core/src/objects/part/basepart.cpp | 3 +- core/src/objects/part/wedgepart.cpp | 2 +- core/src/objects/service/workspace.cpp | 11 ----- core/src/objects/service/workspace.h | 5 ++- core/src/physics/world.cpp | 44 ++++++++++++++++++- core/src/physics/world.h | 22 +++++++++- editor/mainglwidget.cpp | 2 +- 19 files changed, 123 insertions(+), 153 deletions(-) diff --git a/core/src/handles.cpp b/core/src/handles.cpp index ca101ea..950b736 100644 --- a/core/src/handles.cpp +++ b/core/src/handles.cpp @@ -24,8 +24,8 @@ std::array HandleFace::Faces { HandleFace::XPos, HandleFace::XNeg static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1)); // Shitty solution -static rp3d::PhysicsCommon common; -static rp3d::PhysicsWorld* world = common.createPhysicsWorld(); +static rp::PhysicsCommon common; +static rp::PhysicsWorld* world = common.createPhysicsWorld(); std::shared_ptr getHandleAdornee() { std::shared_ptr selection = gDataModel->GetService(); @@ -52,15 +52,15 @@ CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos) { return adornee->cframe.Rotation() + newPartPos; } -std::optional raycastHandle(rp3d::Ray ray) { +std::optional raycastHandle(rp::Ray ray) { for (HandleFace face : HandleFace::Faces) { CFrame cframe = getHandleCFrame(face); // Implement manual detection via boxes instead of... this shit // This code also hardly works, and is not good at all... Hooo nope. - rp3d::RigidBody* body = world->createRigidBody(CFrame::IDENTITY + cframe.Position()); - body->addCollider(common.createBoxShape((cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs()), rp3d::Transform::identity()); + rp::RigidBody* body = world->createRigidBody(CFrame::IDENTITY + cframe.Position()); + body->addCollider(common.createBoxShape((cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs()), rp::Transform::identity()); - rp3d::RaycastInfo info; + rp::RaycastInfo info; if (body->raycast(ray, info)) { world->destroyRigidBody(body); return face; diff --git a/core/src/handles.h b/core/src/handles.h index f98c79d..7f05bee 100644 --- a/core/src/handles.h +++ b/core/src/handles.h @@ -40,7 +40,7 @@ std::shared_ptr getHandleAdornee(); CFrame getHandleCFrame(HandleFace face); CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos); Vector3 handleSize(HandleFace face); -std::optional raycastHandle(rp3d::Ray ray); +std::optional raycastHandle(rp::Ray ray); // Gets the cframe of the handle local to the center of the selected objects CFrame getLocalHandleCFrame(HandleFace face); diff --git a/core/src/objects/joint/jointinstance.cpp b/core/src/objects/joint/jointinstance.cpp index 06425b6..8e2148a 100644 --- a/core/src/objects/joint/jointinstance.cpp +++ b/core/src/objects/joint/jointinstance.cpp @@ -18,40 +18,40 @@ JointInstance::~JointInstance() { } void JointInstance::OnAncestryChanged(nullable std::shared_ptr, nullable std::shared_ptr) { - // Destroy and rebuild the joint, it's the simplest solution that actually works - - breakJoint(); - buildJoint(); + Update(); } -void JointInstance::onUpdated(std::string property) { - // Add ourselves to the attached parts, or remove, if applicable +void JointInstance::Update() { + // To keep it simple compared to our previous algorithm, this one is pretty barebones: + // 1. Every time we update, (whether our parent changed, or a property), destroy the current joints + // 2. If the new configuration is valid, rebuild our joints - // Parts differ, delete - if (part0 != oldPart0 && !oldPart0.expired()) { - oldPart0.lock()->untrackJoint(shared()); + if (!jointWorkspace.expired()) { + jointWorkspace.lock()->DestroyJoint(joint); + if (!oldPart0.expired()) + oldPart0.lock()->untrackJoint(shared()); + if (!oldPart1.expired()) + oldPart1.lock()->untrackJoint(shared()); } - if (part1 != oldPart1 && !oldPart1.expired()) { - oldPart1.lock()->untrackJoint(shared()); - } - - // Parts differ, add - if (part0 != oldPart0 && !part0.expired()) { - part0.lock()->trackJoint(shared()); - } - - if (part1 != oldPart1 && !part1.expired()) { - part1.lock()->trackJoint(shared()); - } - - // Destroy and rebuild the joint, if applicable - - breakJoint(); - buildJoint(); - oldPart0 = part0; oldPart1 = part1; + + // Don't build the joint if we're not part of either a workspace or JointsService + if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && !workspace()) return; + + // If either part is invalid or they are part of separate worlds, fail + if (part0.expired() + || part1.expired() + || !workspaceOfPart(part0.lock()) + || !workspaceOfPart(part1.lock()) + || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock()) + ) return; + + // TODO: Add joint continuity check here + + // Finally, build the joint + buildJoint(); } nullable std::shared_ptr JointInstance::workspaceOfPart(std::shared_ptr part) { diff --git a/core/src/objects/joint/jointinstance.h b/core/src/objects/joint/jointinstance.h index c89ec8e..95bec5d 100644 --- a/core/src/objects/joint/jointinstance.h +++ b/core/src/objects/joint/jointinstance.h @@ -5,6 +5,7 @@ #include #include #include "datatypes/cframe.h" +#include "physics/world.h" //this is necessary ebcause we use std::weak_ptr without including it in this file #ifdef __AUTOGEN_EXTRA_INCLUDES__ @@ -22,14 +23,16 @@ class DEF_INST_ABSTRACT JointInstance : public Instance { protected: // The workspace the joint was created in, if it exists std::weak_ptr jointWorkspace; + PhysJoint joint; void OnAncestryChanged(nullable std::shared_ptr, nullable std::shared_ptr) override; nullable std::shared_ptr workspaceOfPart(std::shared_ptr); - void onUpdated(std::string property); + inline void onUpdated(std::string property) { Update(); }; + virtual void buildJoint() = 0; - virtual void breakJoint() = 0; public: + void Update(); DEF_PROP_(on_update=onUpdated) std::weak_ptr part0; DEF_PROP_(on_update=onUpdated) std::weak_ptr part1; diff --git a/core/src/objects/joint/rotate.cpp b/core/src/objects/joint/rotate.cpp index 61df92a..ce03180 100644 --- a/core/src/objects/joint/rotate.cpp +++ b/core/src/objects/joint/rotate.cpp @@ -13,35 +13,16 @@ Rotate::~Rotate() { static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1)); void Rotate::buildJoint() { - // Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint - if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return; - - // Don't build the joint if we're not part of either a workspace or JointsService - if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && workspace() != nullptr) return; - std::shared_ptr workspace = workspaceOfPart(part0.lock()); // Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it // used to be rather than specifying an anchor rotation, so whatever. CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse()); part1.lock()->cframe = newFrame; - workspace->SyncPartPhysics(part1.lock()); + part1.lock()->UpdateProperty("CFrame"); + // Do NOT use Abs() in this scenario. For some reason that breaks it - rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit()); - this->joint = dynamic_cast(workspace->CreateJoint(jointInfo)); + PhysJointHingeInfo jointInfo((part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit()); + this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock()); jointWorkspace = workspace; - - // part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10); - // part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10); - // part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01); - // part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01); -} - -// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger -void Rotate::breakJoint() { - // If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything - if (!this->joint || jointWorkspace.expired()) return; - - jointWorkspace.lock()->DestroyJoint(this->joint); - this->joint = nullptr; } \ No newline at end of file diff --git a/core/src/objects/joint/rotate.h b/core/src/objects/joint/rotate.h index 291829a..75f88ea 100644 --- a/core/src/objects/joint/rotate.h +++ b/core/src/objects/joint/rotate.h @@ -10,10 +10,7 @@ namespace reactphysics3d { class HingeJoint; } class DEF_INST Rotate : public JointInstance { AUTOGEN_PREAMBLE - reactphysics3d::HingeJoint* joint = nullptr; - virtual void buildJoint() override; - virtual void breakJoint() override; public: Rotate(); ~Rotate(); diff --git a/core/src/objects/joint/rotatev.cpp b/core/src/objects/joint/rotatev.cpp index 6af12a1..3b5ccff 100644 --- a/core/src/objects/joint/rotatev.cpp +++ b/core/src/objects/joint/rotatev.cpp @@ -15,39 +15,16 @@ RotateV::~RotateV() { static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1)); void RotateV::buildJoint() { - // Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint - if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return; - - // Don't build the joint if we're not part of either a workspace or JointsService - if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && workspace() != nullptr) return; - std::shared_ptr workspace = workspaceOfPart(part0.lock()); - // Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it // used to be rather than specifying an anchor rotation, so whatever. CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse()); part1.lock()->cframe = newFrame; - workspace->SyncPartPhysics(part1.lock()); + part1.lock()->UpdateProperty("CFrame"); // Do NOT use Abs() in this scenario. For some reason that breaks it - rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit()); + PhysJointMotorInfo jointInfo((part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit()); - jointInfo.isCollisionEnabled = false; - - this->joint = dynamic_cast(workspace->CreateJoint(jointInfo)); + this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock()); jointWorkspace = workspace; - - - // part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10); - // part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10); - // part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01); - // part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01); -} - -void RotateV::breakJoint() { - // If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything - if (!this->joint || jointWorkspace.expired()) return; - - jointWorkspace.lock()->DestroyJoint(this->joint); - this->joint = nullptr; } \ No newline at end of file diff --git a/core/src/objects/joint/rotatev.h b/core/src/objects/joint/rotatev.h index 945ac03..86ee231 100644 --- a/core/src/objects/joint/rotatev.h +++ b/core/src/objects/joint/rotatev.h @@ -9,10 +9,7 @@ namespace reactphysics3d { class HingeJoint; } class DEF_INST RotateV : public JointInstance { AUTOGEN_PREAMBLE - reactphysics3d::HingeJoint* joint = nullptr; - virtual void buildJoint() override; - virtual void breakJoint() override; public: RotateV(); ~RotateV(); diff --git a/core/src/objects/joint/snap.cpp b/core/src/objects/joint/snap.cpp index 55b510d..59d41ff 100644 --- a/core/src/objects/joint/snap.cpp +++ b/core/src/objects/joint/snap.cpp @@ -6,6 +6,7 @@ #include "objects/service/jointsservice.h" #include "objects/part/part.h" #include "objects/service/workspace.h" +#include "physics/world.h" #include #include #include @@ -17,30 +18,15 @@ Snap::~Snap() { } void Snap::buildJoint() { - // Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint - if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return; - - // Don't build the joint if we're not part of either a workspace or JointsService - if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && !workspace()) return; - std::shared_ptr workspace = workspaceOfPart(part0.lock()); // Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it // used to be rather than specifying an anchor rotation, so whatever. CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse()); part1.lock()->cframe = newFrame; - workspace->SyncPartPhysics(part1.lock()); + part1.lock()->UpdateProperty("CFrame"); - rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position()); - this->joint = dynamic_cast(workspace->CreateJoint(jointInfo)); + PhysJointSnapInfo jointInfo((c0.Inverse() * c1).Position()); + this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock()); jointWorkspace = workspace; -} - -// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger -void Snap::breakJoint() { - // If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything - if (!this->joint || jointWorkspace.expired()) return; - - jointWorkspace.lock()->DestroyJoint(this->joint); - this->joint = nullptr; } \ No newline at end of file diff --git a/core/src/objects/joint/snap.h b/core/src/objects/joint/snap.h index 13b5f76..e3b6232 100644 --- a/core/src/objects/joint/snap.h +++ b/core/src/objects/joint/snap.h @@ -10,10 +10,7 @@ namespace reactphysics3d { class FixedJoint; } class DEF_INST Snap : public JointInstance { AUTOGEN_PREAMBLE - reactphysics3d::FixedJoint* joint = nullptr; - virtual void buildJoint() override; - virtual void breakJoint() override; public: Snap(); ~Snap(); diff --git a/core/src/objects/joint/weld.cpp b/core/src/objects/joint/weld.cpp index 87826e6..e69c654 100644 --- a/core/src/objects/joint/weld.cpp +++ b/core/src/objects/joint/weld.cpp @@ -6,6 +6,7 @@ #include "objects/service/jointsservice.h" #include "objects/part/part.h" #include "objects/service/workspace.h" +#include "physics/world.h" #include #include #include @@ -17,30 +18,15 @@ Weld::~Weld() { } void Weld::buildJoint() { - // Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint - if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return; - - // Don't build the joint if we're not part of either a workspace or JointsService - if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && workspace() != nullptr) return; - std::shared_ptr workspace = workspaceOfPart(part0.lock()); // Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it // used to be rather than specifying an anchor rotation, so whatever. CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse()); part1.lock()->cframe = newFrame; - workspace->SyncPartPhysics(part1.lock()); + part1.lock()->UpdateProperty("CFrame"); - rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position()); - this->joint = dynamic_cast(workspace->CreateJoint(jointInfo)); + PhysJointWeldInfo jointInfo((c0.Inverse() * c1).Position()); + this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock()); jointWorkspace = workspace; -} - -// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger -void Weld::breakJoint() { - // If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything - if (!this->joint || jointWorkspace.expired()) return; - - jointWorkspace.lock()->DestroyJoint(this->joint); - this->joint = nullptr; } \ No newline at end of file diff --git a/core/src/objects/joint/weld.h b/core/src/objects/joint/weld.h index 2186199..a8e938d 100644 --- a/core/src/objects/joint/weld.h +++ b/core/src/objects/joint/weld.h @@ -10,10 +10,7 @@ namespace reactphysics3d { class FixedJoint; } class DEF_INST Weld : public JointInstance { AUTOGEN_PREAMBLE - reactphysics3d::FixedJoint* joint = nullptr; - virtual void buildJoint() override; - virtual void breakJoint() override; public: Weld(); ~Weld(); diff --git a/core/src/objects/part/basepart.cpp b/core/src/objects/part/basepart.cpp index 856e91d..c14e5a7 100644 --- a/core/src/objects/part/basepart.cpp +++ b/core/src/objects/part/basepart.cpp @@ -51,6 +51,7 @@ void BasePart::OnWorkspaceAdded(nullable std::shared_ptr oldWorkspace } void BasePart::OnWorkspaceRemoved(std::shared_ptr oldWorkspace) { + BreakJoints(); oldWorkspace->RemoveBody(shared()); } @@ -282,8 +283,6 @@ void BasePart::MakeJoints() { joint->c1 = contact1; dataModel()->GetService()->AddChild(joint); joint->UpdateProperty("Part0"); - - Logger::debugf("Made joint between %s and %s!\n", name.c_str(), otherPart->name.c_str()); } } } diff --git a/core/src/objects/part/wedgepart.cpp b/core/src/objects/part/wedgepart.cpp index 6623e45..7d877af 100644 --- a/core/src/objects/part/wedgepart.cpp +++ b/core/src/objects/part/wedgepart.cpp @@ -87,6 +87,6 @@ void WedgePart::createWedgeShape(rp::PhysicsCommon* common) { rp::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE); // Create the convex mesh - std::vector messages; + std::vector messages; // wedgePhysMesh = common->createConvexMesh(polygonVertexArray, messages); } \ No newline at end of file diff --git a/core/src/objects/service/workspace.cpp b/core/src/objects/service/workspace.cpp index 2813779..810bc8b 100644 --- a/core/src/objects/service/workspace.cpp +++ b/core/src/objects/service/workspace.cpp @@ -67,15 +67,4 @@ void Workspace::PhysicsStep(float deltaTime) { parent->Destroy(); } } -} - -void Workspace::DestroyJoint(rp::Joint* joint) { - // physicsWorld->destroyJoint(joint); -} - -rp::Joint* Workspace::CreateJoint(const rp::JointInfo& jointInfo) { - // rp::Joint* joint = physicsWorld->createJoint(jointInfo); - - // return joint; - return nullptr; } \ No newline at end of file diff --git a/core/src/objects/service/workspace.h b/core/src/objects/service/workspace.h index 9288ed6..1cd1a0a 100644 --- a/core/src/objects/service/workspace.h +++ b/core/src/objects/service/workspace.h @@ -32,6 +32,7 @@ class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service { std::mutex contactQueueLock; std::shared_ptr physicsWorld; + friend PhysWorld; protected: void InitService() override; void OnRun() override; @@ -52,8 +53,8 @@ public: inline void RemoveBody(std::shared_ptr part) { physicsWorld->removeBody(part); } void SyncPartPhysics(std::shared_ptr part); - rp::Joint* CreateJoint(const rp::JointInfo& jointInfo); - void DestroyJoint(rp::Joint* joint); + inline PhysJoint CreateJoint(PhysJointInfo& info, std::shared_ptr part0, std::shared_ptr part1) { return physicsWorld->createJoint(info, part0, part1); } + inline void DestroyJoint(PhysJoint joint) { physicsWorld->destroyJoint(joint); } void PhysicsStep(float deltaTime); inline std::optional CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF) { return physicsWorld->castRay(point, rotation, maxLength, filter, categoryMaskBits); } diff --git a/core/src/physics/world.cpp b/core/src/physics/world.cpp index 981bb66..6cd3301 100644 --- a/core/src/physics/world.cpp +++ b/core/src/physics/world.cpp @@ -4,15 +4,19 @@ #include "objects/joint/jointinstance.h" #include "objects/part/basepart.h" #include "physics/util.h" +#include +#include "reactphysics3d/constraint/HingeJoint.h" #include "timeutil.h" +#include +#include "objects/service/workspace.h" -rp3d::PhysicsCommon physicsCommon; +rp::PhysicsCommon physicsCommon; PhysWorld::PhysWorld() : physicsEventListener(this) { worldImpl = physicsCommon.createPhysicsWorld(); worldImpl->setGravity(rp::Vector3(0, -196.2, 0)); - // world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS); + // world->setContactsPositionCorrectionTechnique(rp::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS); // physicsWorld->setNbIterationsPositionSolver(2000); // physicsWorld->setNbIterationsVelocitySolver(2000); // physicsWorld->setSleepLinearVelocity(10); @@ -191,4 +195,40 @@ std::optional PhysWorld::castRay(Vector3 point, Vector3 rot NearestRayHit rayHit(glmToRp(point), filter); worldImpl->raycast(ray, &rayHit, categoryMaskBits); return rayHit.getNearestHit(); +} + +PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr part0, std::shared_ptr part1) { + // error checking + if (part0->rigidBody == nullptr + || part1->rigidBody == nullptr + || !part0->workspace() + || !part1->workspace() + || part0->workspace()->physicsWorld != shared_from_this() + || part1->workspace()->physicsWorld != shared_from_this() + ) { Logger::fatalError("Failed to create joint between two parts due to the call being invalid"); panic(); }; + + if (PhysJointGlueInfo* info = dynamic_cast(&type)) { + return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint)); + } else if (PhysJointWeldInfo* info = dynamic_cast(&type)) { + return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint)); + } else if (PhysJointSnapInfo* info = dynamic_cast(&type)) { + return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint)); + } else if (PhysJointHingeInfo* info = dynamic_cast(&type)) { + return worldImpl->createJoint(rp::HingeJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint, info->rotationAxis)); + } else if (PhysJointMotorInfo* info = dynamic_cast(&type)) { + auto implInfo = rp::HingeJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint, info->rotationAxis); + implInfo.isCollisionEnabled = false; + return worldImpl->createJoint(implInfo); + + // part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10); + // part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10); + // part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01); + // part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01); + } + + panic(); // Unreachable +} + +void PhysWorld::destroyJoint(PhysJoint joint) { + } \ No newline at end of file diff --git a/core/src/physics/world.h b/core/src/physics/world.h index 32514a4..588fbfb 100644 --- a/core/src/physics/world.h +++ b/core/src/physics/world.h @@ -39,7 +39,23 @@ class PhysicsEventListener : public rp::EventListener { void onTrigger(const rp::OverlapCallback::CallbackData&) override; }; -class PhysWorld : std::enable_shared_from_this { +struct PhysJointInfo { virtual ~PhysJointInfo() = default; protected: PhysJointInfo() = default; }; +struct PhysJointGlueInfo : PhysJointInfo { Vector3 anchorPoint; inline PhysJointGlueInfo(Vector3 anchorPoint) : anchorPoint(anchorPoint) {} }; +struct PhysJointWeldInfo : PhysJointInfo { Vector3 anchorPoint; inline PhysJointWeldInfo(Vector3 anchorPoint) : anchorPoint(anchorPoint) {} }; +struct PhysJointSnapInfo : PhysJointInfo { Vector3 anchorPoint; inline PhysJointSnapInfo(Vector3 anchorPoint) : anchorPoint(anchorPoint) {} }; +struct PhysJointHingeInfo : PhysJointInfo { Vector3 anchorPoint; Vector3 rotationAxis; inline PhysJointHingeInfo(Vector3 anchorPoint, Vector3 rotationAxis) : anchorPoint(anchorPoint), rotationAxis(rotationAxis) {} }; +struct PhysJointMotorInfo : PhysJointInfo { Vector3 anchorPoint; Vector3 rotationAxis; inline PhysJointMotorInfo(Vector3 anchorPoint, Vector3 rotationAxis) : anchorPoint(anchorPoint), rotationAxis(rotationAxis) {} }; + +class PhysWorld; +class PhysJoint { + rp::Joint* joint; + inline PhysJoint(rp::Joint* joint) : joint(joint) {} + friend PhysWorld; +public: + inline PhysJoint() {} +}; + +class PhysWorld : public std::enable_shared_from_this { rp::PhysicsWorld* worldImpl; PhysicsEventListener physicsEventListener; std::list> simulatedBodies; @@ -52,6 +68,10 @@ public: void addBody(std::shared_ptr); void removeBody(std::shared_ptr); + + PhysJoint createJoint(PhysJointInfo& type, std::shared_ptr part0, std::shared_ptr part1); + void destroyJoint(PhysJoint joint); + inline const std::list>& getSimulatedBodies() { return simulatedBodies; } void syncBodyProperties(std::shared_ptr); std::optional castRay(Vector3 point, Vector3 rotation, float maxLength, std::optional filter, unsigned short categoryMaskBits); diff --git a/editor/mainglwidget.cpp b/editor/mainglwidget.cpp index 61a322e..d178dfb 100755 --- a/editor/mainglwidget.cpp +++ b/editor/mainglwidget.cpp @@ -323,7 +323,7 @@ void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) { std::optional MainGLWidget::raycastHandle(glm::vec3 pointDir) { if (!editorToolHandles.active) return std::nullopt; - return ::raycastHandle(rp3d::Ray(glmToRp(camera.cameraPos), glmToRp(glm::normalize(pointDir)) * 50000)); + return ::raycastHandle(rp::Ray(glmToRp(camera.cameraPos), glmToRp(glm::normalize(pointDir)) * 50000)); } void MainGLWidget::handleCursorChange(QMouseEvent* evt) {