Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

171 lines
5.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Chaos/ArrayCollectionArray.h"
#include "Chaos/Framework/MultiBufferResource.h"
#include "Chaos/Framework/PhysicsProxy.h"
#include "Chaos/PBDJointConstraints.h"
#include "Chaos/GeometryParticlesfwd.h"
#include "Chaos/ParticleHandle.h"
#include "PhysicsCoreTypes.h"
#include "Chaos/Defines.h"
#include "JointConstraintProxyFwd.h"
#include "Framework/Threading.h"
#include "Chaos/PBDJointConstraintData.h"
#include "RewindData.h"
namespace Chaos
{
class FJointConstraint;
class FPBDRigidsEvolutionGBF;
struct FDirtyJointConstraintData;
template <bool bExternal>
class TThreadedJointConstraintPhysicsProxyBase;
using FJointConstraintHandle_External = TThreadedJointConstraintPhysicsProxyBase<true>;
using FJointConstraintHandle_Internal = TThreadedJointConstraintPhysicsProxyBase<false>;
class FJointConstraintPhysicsProxy : public IPhysicsProxyBase
{
using Base = IPhysicsProxyBase;
public:
FJointConstraintPhysicsProxy() = delete;
FJointConstraintPhysicsProxy(FJointConstraint* InConstraint, FPBDJointConstraintHandle* InHandle, UObject* InOwner = nullptr);
static FGeometryParticleHandle* GetParticleHandleFromProxy(IPhysicsProxyBase* ProxyBase);
//
// Lifespan Management
//
void CHAOS_API InitializeOnPhysicsThread(FPBDRigidsSolver* InSolver, FDirtyPropertiesManager& Manager, int32 DataIdx, FDirtyChaosProperties& RemoteData);
void CHAOS_API PushStateOnGameThread(FDirtyPropertiesManager& Manager, int32 DataIdx, FDirtyChaosProperties& RemoteData);
void CHAOS_API PushStateOnPhysicsThread(FPBDRigidsSolver* InSolver, const FDirtyPropertiesManager& Manager, int32 DataIdx, const FDirtyChaosProperties& RemoteData);
void CHAOS_API DestroyOnPhysicsThread(FPBDRigidsSolver* InSolver);
void CHAOS_API DestroyOnGameThread();
FORCEINLINE Chaos::FJointConstraintHandle_External& GetGameThreadAPI()
{
return (Chaos::FJointConstraintHandle_External&)*this;
}
FORCEINLINE const Chaos::FJointConstraintHandle_External& GetGameThreadAPI() const
{
return (const Chaos::FJointConstraintHandle_External&)*this;
}
//Note this is a pointer because the internal handle may have already been deleted
FORCEINLINE Chaos::FJointConstraintHandle_Internal* GetPhysicsThreadAPI()
{
return GetHandle() == nullptr ? nullptr : (Chaos::FJointConstraintHandle_Internal*)this;
}
//Note this is a pointer because the internal handle may have already been deleted
FORCEINLINE const Chaos::FJointConstraintHandle_Internal* GetPhysicsThreadAPI() const
{
return GetHandle() == nullptr ? nullptr : (const Chaos::FJointConstraintHandle_Internal*)this;
}
//
// Member Access
//
FPBDJointConstraintHandle* GetHandle() { return Constraint_PT; }
const FPBDJointConstraintHandle* GetHandle() const { return Constraint_PT; }
virtual void* GetHandleUnsafe() const override { return Constraint_PT; }
void SetHandle(FPBDJointConstraintHandle* InHandle) { Constraint_PT = InHandle; }
FJointConstraint* GetConstraint(){ return Constraint_GT; }
const FJointConstraint* GetConstraint() const { return Constraint_GT; }
//
// Threading API
//
/**/
void BufferPhysicsResults(FDirtyJointConstraintData& Buffer);
/**/
bool CHAOS_API PullFromPhysicsState(const FDirtyJointConstraintData& Buffer, const int32 SolverSyncTimestamp);
private:
FJointConstraint* Constraint_GT;
FPBDJointConstraintHandle* Constraint_PT;
FParticlePair OriginalParticleHandles_PT;
bool bInitialized = false;
};
/** Wrapper class that routes all reads and writes to the appropriate joint data. This is helpful for cases where we want to both write to a joint and a network buffer for example*/
template <bool bExternal>
class TThreadedJointConstraintPhysicsProxyBase : protected FJointConstraintPhysicsProxy
{
public:
#define CHAOS_INNER_JOINT_PROPERTY(OuterProp, FuncName, Inner, InnerType)\
const InnerType& Get##FuncName() const { return ReadRef([](const auto& Data){ return Data.Inner;}); }\
void Set##FuncName(const InnerType& Val) { Write([&Val](auto& Data){ Data.Inner = Val;}); }\
#include "Chaos/JointProperties.inl"
private:
void VerifyContext() const
{
#if PHYSICS_THREAD_CONTEXT
//Are you using the wrong API type for the thread this code runs in?
//GetGameThreadAPI should be used for gamethread, GetPhysicsThreadAPI should be used for callbacks and internal physics thread
//Note if you are using a ParallelFor you must use PhysicsParallelFor to ensure the right context is inherited from parent thread
if (bExternal)
{
//if proxy is registered with solver, we need a lock
if (GetSolverBase() != nullptr)
{
ensure(IsInGameThreadContext());
}
}
else
{
ensure(IsInPhysicsThreadContext());
}
#endif
}
template <typename TLambda>
const auto& ReadRef(const TLambda& Lambda) const { VerifyContext(); return bExternal ? Lambda(GetConstraint()) : Lambda(GetHandle()); }
template <typename TLambda>
void Write(const TLambda& Lambda)
{
VerifyContext();
if (bExternal)
{
Lambda(GetConstraint());
}
else
{
//Mark entire joint as dirty from PT. TODO: use property system
FPhysicsSolverBase* SolverBase = GetSolverBase(); //internal so must have solver already
if (FRewindData* RewindData = SolverBase->GetRewindData())
{
RewindData->MarkDirtyJointFromPT(*GetHandle());
}
Lambda(GetHandle());
}
}
};
}