Files
FlaxEngine/Source/Engine/Physics/PhysicsStepper.h
2021-01-02 14:28:49 +01:00

219 lines
4.8 KiB
C++

// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Types.h"
#include "Engine/Core/Core.h"
#include <ThirdParty/PhysX/task/PxTask.h>
#include <ThirdParty/PhysX/foundation/PxSimpleTypes.h>
#include <ThirdParty/PhysX/foundation/PsSync.h>
class MultiThreadStepper;
class PhysicsStepper
{
public:
PhysicsStepper()
{
}
virtual ~PhysicsStepper()
{
}
public:
virtual bool advance(PxScene* scene, PxReal dt, void* scratchBlock, PxU32 scratchBlockSize) = 0;
virtual void wait(PxScene* scene) = 0;
virtual void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize) = 0;
virtual void setSubStepper(const PxReal stepSize, const PxU32 maxSteps)
{
}
virtual void renderDone()
{
}
};
class StepperTask : public PxLightCpuTask
{
public:
void setStepper(MultiThreadStepper* stepper)
{
mStepper = stepper;
}
MultiThreadStepper* getStepper()
{
return mStepper;
}
const MultiThreadStepper* getStepper() const
{
return mStepper;
}
public:
// [PxLightCpuTask]
const char* getName() const override
{
return "Stepper Task";
}
void run() override;
protected:
MultiThreadStepper* mStepper = nullptr;
};
/// <summary>
/// Physics simulation task used by the stepper.
/// </summary>
/// <seealso cref="StepperTask" />
class StepperTaskSimulate : public StepperTask
{
public:
/// <summary>
/// Initializes a new instance of the <see cref="StepperTaskSimulate"/> class.
/// </summary>
StepperTaskSimulate()
{
}
public:
// [StepperTask]
void run() override;
};
class MultiThreadStepper : public PhysicsStepper
{
public:
MultiThreadStepper()
: mFirstCompletionPending(false)
, mScene(nullptr)
, mSync(nullptr)
, mCurrentSubStep(0)
, mNbSubSteps(0)
{
mCompletion0.setStepper(this);
mCompletion1.setStepper(this);
mSimulateTask.setStepper(this);
}
~MultiThreadStepper();
bool advance(PxScene* scene, PxReal dt, void* scratchBlock, PxU32 scratchBlockSize) override;
virtual void substepDone(StepperTask* ownerTask);
void renderDone() override;
// if mNbSubSteps is 0 then the sync will never
// be set so waiting would cause a deadlock
void wait(PxScene* scene) override
{
if (mNbSubSteps && mSync)
mSync->wait();
}
virtual void shutdown();
virtual void reset() = 0;
void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize) override = 0;
virtual void simulate(PxBaseTask* ownerTask);
PxReal getSubStepSize() const
{
return mSubStepSize;
}
protected:
void substep(StepperTask& completionTask);
// we need two completion tasks because when multistepping we can't submit completion0 from the
// substepDone function which is running inside completion0
bool mFirstCompletionPending;
StepperTaskSimulate mSimulateTask;
StepperTask mCompletion0, mCompletion1;
PxScene* mScene;
shdfnd::Sync* mSync;
PxU32 mCurrentSubStep;
PxU32 mNbSubSteps;
PxReal mSubStepSize;
void* mScratchBlock;
PxU32 mScratchBlockSize;
};
// The way this should be called is:
// bool stepped = advance(dt)
//
// ... reads from the scene graph for rendering
//
// if(stepped) renderDone()
//
// ... anything that doesn't need access to the the physics scene
//
// if(stepped) sFixedStepper.wait()
//
// Note that per-substep callbacks to the sample need to be issued out of here,
// between fetchResults and simulate
class FixedStepper : public MultiThreadStepper
{
protected:
PxReal mAccumulator;
PxReal mFixedSubStepSize;
PxU32 mMaxSubSteps;
public:
/// <summary>
/// Initializes a new instance of the <see cref="FixedStepper"/> class.
/// </summary>
FixedStepper()
: MultiThreadStepper()
, mAccumulator(0)
, mFixedSubStepSize(0.013f)
, mMaxSubSteps(1)
{
}
public:
/// <summary>
/// Setups the specified step size and the maximum amount of them.
/// </summary>
/// <param name="stepSize">Size of the step (in seconds).</param>
/// <param name="maxSubsetps">The maximum amount of subsetps.</param>
void Setup(const float stepSize, const uint32 maxSubsetps = 1)
{
mFixedSubStepSize = stepSize;
mMaxSubSteps = maxSubsetps;
}
public:
// [MultiThreadStepper]
void substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize) override;
void reset() override
{
mAccumulator = 0.0f;
}
void setSubStepper(const PxReal stepSize, const PxU32 maxSteps) override
{
mFixedSubStepSize = stepSize;
mMaxSubSteps = maxSteps;
}
};