refactor(physics): made physics single-threaded again
This commit is contained in:
parent
16f973c9c2
commit
d922dd3727
6 changed files with 5 additions and 101 deletions
|
@ -53,8 +53,6 @@ void BasePart::OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWor
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
void BasePart::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
||||||
if (simulationTicket.has_value())
|
|
||||||
oldWorkspace->RemoveBody(shared<BasePart>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::onUpdated(std::string property) {
|
void BasePart::onUpdated(std::string property) {
|
||||||
|
|
|
@ -34,12 +34,6 @@ struct PartConstructParams {
|
||||||
|
|
||||||
class Workspace;
|
class Workspace;
|
||||||
|
|
||||||
#ifndef __SIMULATION_TICKET
|
|
||||||
#define __SIMULATION_TICKET
|
|
||||||
class BasePart;
|
|
||||||
typedef std::list<std::shared_ptr<BasePart>>::iterator SimulationTicket;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class DEF_INST_ABSTRACT_(explorer_icon="part") BasePart : public PVInstance {
|
class DEF_INST_ABSTRACT_(explorer_icon="part") BasePart : public PVInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
protected:
|
protected:
|
||||||
|
@ -117,8 +111,6 @@ public:
|
||||||
DEF_SIGNAL SignalSource TouchEnded;
|
DEF_SIGNAL SignalSource TouchEnded;
|
||||||
|
|
||||||
rp::RigidBody* rigidBody = nullptr;
|
rp::RigidBody* rigidBody = nullptr;
|
||||||
std::optional<SimulationTicket> simulationTicket;
|
|
||||||
bool rigidBodyDirty = true;
|
|
||||||
|
|
||||||
inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); }
|
inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); }
|
||||||
float GetSurfaceParamA(Vector3 face);
|
float GetSurfaceParamA(Vector3 face);
|
||||||
|
|
|
@ -157,12 +157,7 @@ void Workspace::ProcessContactEvents() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::SyncPartPhysics(std::shared_ptr<BasePart> part) {
|
void Workspace::SyncPartPhysics(std::shared_ptr<BasePart> part) {
|
||||||
if (globalPhysicsLock.try_lock()) {
|
updatePartPhysics(part);
|
||||||
updatePartPhysics(part);
|
|
||||||
globalPhysicsLock.unlock();
|
|
||||||
} else {
|
|
||||||
part->rigidBodyDirty = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tu_time_t physTime;
|
tu_time_t physTime;
|
||||||
|
@ -172,28 +167,8 @@ void Workspace::PhysicsStep(float deltaTime) {
|
||||||
std::scoped_lock lock(globalPhysicsLock);
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
physicsWorld->update(std::min(deltaTime / 2, (1/60.f)));
|
physicsWorld->update(std::min(deltaTime / 2, (1/60.f)));
|
||||||
|
|
||||||
// Update queued objects
|
|
||||||
queueLock.lock();
|
|
||||||
for (QueueItem item : bodyQueue) {
|
|
||||||
if (item.action == QueueItem::QUEUEITEM_ADD) {
|
|
||||||
simulatedBodies.push_back(item.part);
|
|
||||||
item.part->simulationTicket = --simulatedBodies.end();
|
|
||||||
} else if (item.part->simulationTicket.has_value()) {
|
|
||||||
simulatedBodies.erase(item.part->simulationTicket.value());
|
|
||||||
item.part->simulationTicket = std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queueLock.unlock();
|
|
||||||
|
|
||||||
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
|
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
|
||||||
for (std::shared_ptr<BasePart> part : simulatedBodies) {
|
for (std::shared_ptr<BasePart> part : simulatedBodies) {
|
||||||
// If the part's body is dirty, update it now instead
|
|
||||||
if (part->rigidBodyDirty) {
|
|
||||||
updatePartPhysics(part);
|
|
||||||
part->rigidBodyDirty = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!part->rigidBody) continue;
|
if (!part->rigidBody) continue;
|
||||||
|
|
||||||
// Sync properties
|
// Sync properties
|
||||||
|
@ -300,14 +275,10 @@ rp::Joint* Workspace::CreateJoint(const rp::JointInfo& jointInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::AddBody(std::shared_ptr<BasePart> part) {
|
void Workspace::AddBody(std::shared_ptr<BasePart> part) {
|
||||||
queueLock.lock();
|
simulatedBodies.push_back(part);
|
||||||
bodyQueue.push_back({part, QueueItem::QUEUEITEM_ADD});
|
|
||||||
part->rigidBodyDirty = true;
|
|
||||||
queueLock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::RemoveBody(std::shared_ptr<BasePart> part) {
|
void Workspace::RemoveBody(std::shared_ptr<BasePart> part) {
|
||||||
queueLock.lock();
|
auto it = std::find(simulatedBodies.begin(), simulatedBodies.end(), part);
|
||||||
bodyQueue.push_back({part, QueueItem::QUEUEITEM_REMOVE});
|
simulatedBodies.erase(it);
|
||||||
queueLock.unlock();
|
|
||||||
}
|
}
|
|
@ -38,11 +38,6 @@ class Weld;
|
||||||
class Rotate;
|
class Rotate;
|
||||||
class RotateV;
|
class RotateV;
|
||||||
|
|
||||||
#ifndef __SIMULATION_TICKET
|
|
||||||
#define __SIMULATION_TICKET
|
|
||||||
typedef std::list<std::shared_ptr<BasePart>>::iterator SimulationTicket;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef std::function<FilterResult(std::shared_ptr<BasePart>)> RaycastFilter;
|
typedef std::function<FilterResult(std::shared_ptr<BasePart>)> RaycastFilter;
|
||||||
|
|
||||||
struct QueueItem {
|
struct QueueItem {
|
||||||
|
@ -79,7 +74,6 @@ class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
||||||
friend PhysicsEventListener;
|
friend PhysicsEventListener;
|
||||||
|
|
||||||
std::list<std::shared_ptr<BasePart>> simulatedBodies;
|
std::list<std::shared_ptr<BasePart>> simulatedBodies;
|
||||||
std::list<QueueItem> bodyQueue;
|
|
||||||
std::queue<ContactItem> contactQueue;
|
std::queue<ContactItem> contactQueue;
|
||||||
std::mutex contactQueueLock;
|
std::mutex contactQueueLock;
|
||||||
rp::PhysicsWorld* physicsWorld;
|
rp::PhysicsWorld* physicsWorld;
|
||||||
|
|
|
@ -23,36 +23,6 @@
|
||||||
#include "objects/service/selection.h"
|
#include "objects/service/selection.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
|
|
||||||
class PlaceDocumentPhysicsWorker {
|
|
||||||
public:
|
|
||||||
std::mutex sync;
|
|
||||||
std::thread thread;
|
|
||||||
std::condition_variable runningCond;
|
|
||||||
bool running = false;
|
|
||||||
bool quit = false;
|
|
||||||
|
|
||||||
PlaceDocumentPhysicsWorker() : thread(&PlaceDocumentPhysicsWorker::doWork, this) {}
|
|
||||||
private:
|
|
||||||
tu_time_t lastTime = tu_clock_micros();
|
|
||||||
void doWork() {
|
|
||||||
do {
|
|
||||||
tu_time_t deltaTime = tu_clock_micros() - lastTime;
|
|
||||||
lastTime = tu_clock_micros();
|
|
||||||
|
|
||||||
// First frame is always empty
|
|
||||||
if (deltaTime > 100) {
|
|
||||||
gWorkspace()->PhysicsStep(float(deltaTime)/1'000'000);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(16'667 - deltaTime));
|
|
||||||
|
|
||||||
std::unique_lock lock(sync);
|
|
||||||
runningCond.wait(lock, [&]{ return running || quit; });
|
|
||||||
lock.unlock();
|
|
||||||
} while (!quit);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PlaceDocument::PlaceDocument(QWidget* parent):
|
PlaceDocument::PlaceDocument(QWidget* parent):
|
||||||
QMdiSubWindow(parent) {
|
QMdiSubWindow(parent) {
|
||||||
placeWidget = new MainGLWidget;
|
placeWidget = new MainGLWidget;
|
||||||
|
@ -62,29 +32,15 @@ PlaceDocument::PlaceDocument(QWidget* parent):
|
||||||
|
|
||||||
_runState = RUN_STOPPED;
|
_runState = RUN_STOPPED;
|
||||||
updateSelectionListeners(gDataModel->GetService<Selection>());
|
updateSelectionListeners(gDataModel->GetService<Selection>());
|
||||||
|
|
||||||
worker = new PlaceDocumentPhysicsWorker();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PlaceDocument::~PlaceDocument() {
|
PlaceDocument::~PlaceDocument() {
|
||||||
worker->quit = true;
|
|
||||||
worker->runningCond.notify_all();
|
|
||||||
worker->thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlaceDocument::updatePhysicsWorker() {
|
|
||||||
{
|
|
||||||
std::lock_guard lock(worker->sync);
|
|
||||||
worker->running = _runState == RUN_RUNNING;
|
|
||||||
}
|
|
||||||
worker->runningCond.notify_all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaceDocument::setRunState(RunState newState) {
|
void PlaceDocument::setRunState(RunState newState) {
|
||||||
if (newState == RUN_RUNNING && _runState != RUN_RUNNING) {
|
if (newState == RUN_RUNNING && _runState != RUN_RUNNING) {
|
||||||
if (_runState == RUN_PAUSED) {
|
if (_runState == RUN_PAUSED) {
|
||||||
_runState = RUN_RUNNING;
|
_runState = RUN_RUNNING;
|
||||||
updatePhysicsWorker();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,8 +59,6 @@ void PlaceDocument::setRunState(RunState newState) {
|
||||||
gDataModel = editModeDataModel;
|
gDataModel = editModeDataModel;
|
||||||
updateSelectionListeners(gDataModel->GetService<Selection>());
|
updateSelectionListeners(gDataModel->GetService<Selection>());
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePhysicsWorker();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaceDocument::updateSelectionListeners(std::shared_ptr<Selection> selection) {
|
void PlaceDocument::updateSelectionListeners(std::shared_ptr<Selection> selection) {
|
||||||
|
@ -130,7 +84,6 @@ void PlaceDocument::closeEvent(QCloseEvent *closeEvent) {
|
||||||
closeEvent->ignore();
|
closeEvent->ignore();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<BasePart> shit;
|
|
||||||
void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
||||||
if (evt->timerId() != timer.timerId()) {
|
if (evt->timerId() != timer.timerId()) {
|
||||||
QWidget::timerEvent(evt);
|
QWidget::timerEvent(evt);
|
||||||
|
@ -140,6 +93,7 @@ void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
||||||
placeWidget->repaint();
|
placeWidget->repaint();
|
||||||
placeWidget->updateCycle();
|
placeWidget->updateCycle();
|
||||||
gDataModel->GetService<ScriptContext>()->RunSleepingThreads();
|
gDataModel->GetService<ScriptContext>()->RunSleepingThreads();
|
||||||
|
if (_runState == RUN_RUNNING) gDataModel->GetService<Workspace>()->PhysicsStep(0.033);
|
||||||
gDataModel->GetService<Workspace>()->ProcessContactEvents();
|
gDataModel->GetService<Workspace>()->ProcessContactEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
class Selection;
|
class Selection;
|
||||||
class PlaceDocumentPhysicsWorker;
|
|
||||||
|
|
||||||
enum RunState {
|
enum RunState {
|
||||||
RUN_STOPPED,
|
RUN_STOPPED,
|
||||||
|
@ -25,14 +24,10 @@ class PlaceDocument : public QMdiSubWindow {
|
||||||
QBasicTimer timer;
|
QBasicTimer timer;
|
||||||
RunState _runState;
|
RunState _runState;
|
||||||
|
|
||||||
PlaceDocumentPhysicsWorker* worker;
|
|
||||||
|
|
||||||
std::weak_ptr<SignalConnection> selectionConnection;
|
std::weak_ptr<SignalConnection> selectionConnection;
|
||||||
|
|
||||||
void timerEvent(QTimerEvent*) override;
|
void timerEvent(QTimerEvent*) override;
|
||||||
void updateSelectionListeners(std::shared_ptr<Selection>);
|
void updateSelectionListeners(std::shared_ptr<Selection>);
|
||||||
|
|
||||||
void updatePhysicsWorker();
|
|
||||||
public:
|
public:
|
||||||
MainGLWidget* placeWidget;
|
MainGLWidget* placeWidget;
|
||||||
PlaceDocument(QWidget* parent = nullptr);
|
PlaceDocument(QWidget* parent = nullptr);
|
||||||
|
|
Loading…
Add table
Reference in a new issue