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

210 lines
7.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ClothingSimulationInterface.h"
#include "Math/BoxSphereBounds.h"
#include "UObject/ObjectMacros.h"
#include "UObject/ObjectPtr.h"
#include "ClothingSimulationInstance.generated.h"
#define UE_API CLOTHINGSYSTEMRUNTIMEINTERFACE_API
struct FClothSimulData;
class UClothingSimulationFactory;
class UClothingSimulationInteractor;
class USkeletalMesh;
class USkeletalMeshComponent;
class USkinnedMeshComponent;
/**
* Clothing simulation objects.
* Facade to the simulation interfaces to allow for a simplified implementation and multiple simulations to coexist with each other.
*/
USTRUCT()
struct FClothingSimulationInstance
{
public:
GENERATED_BODY()
/**
* Factory asset group.
* Group of clothing data that run under the same simulation type, and the clothing simulation factory associated with them.
* The group storage array always matches the order of the SkeletalMesh clothing data so that the indices are the same,
* with a nullptr entry into the array to signify that the asset is part of a different group.
* This is to avoid an additional array of indices, knowing that most Skeletal Meshes have rarely more than half a dozen clothing data.
*/
struct FFactoryAssetGroup
{
public:
FFactoryAssetGroup(UClothingSimulationFactory* InClothingSimulationFactory, const int32 NumTotalClothAssets)
: ClothingSimulationFactory(InClothingSimulationFactory)
{
check(ClothingSimulationFactory);
ClothingAssets.SetNumZeroed(NumTotalClothAssets);
}
void AddClothingAsset(const UClothingAssetBase* ClothingAsset, const int32 Index)
{
ClothingAssets[Index] = ClothingAsset;
}
const UClothingSimulationFactory* GetClothingSimulationFactory() const
{
return ClothingSimulationFactory;
}
private:
friend FClothingSimulationInstance;
UClothingSimulationFactory* ClothingSimulationFactory;
TArray<const UClothingAssetBase*> ClothingAssets;
};
/** Construct a new clothing simulation instance for the specified asset group and component. */
UE_API FClothingSimulationInstance(USkeletalMeshComponent* SkeletalMeshComponent, const FFactoryAssetGroup& FactoryAssetGroup);
UE_API FClothingSimulationInstance();
UE_API ~FClothingSimulationInstance();
FClothingSimulationInstance(const FClothingSimulationInstance&) = delete;
FClothingSimulationInstance(FClothingSimulationInstance&&) = default;
FClothingSimulationInstance& operator=(const FClothingSimulationInstance&) = delete;
FClothingSimulationInstance& operator=(FClothingSimulationInstance&&) = default;
/** Return the clothing simulation factory used to initialize this clothing simulation instance. */
UClothingSimulationFactory* GetClothingSimulationFactory() const
{
return ClothingSimulationFactory;
}
/** Return the clothing simulation pointer. */
const IClothingSimulationInterface* GetClothingSimulation() const
{
return ClothingSimulation;
}
/** Return the clothing simulation pointer. */
IClothingSimulationInterface* GetClothingSimulation()
{
return ClothingSimulation;
}
/** Return the clothing simulation context. */
const IClothingSimulationContext* GetClothingSimulationContext() const
{
return ClothingSimulationContext;
}
/** Return the clothing simulation context. */
IClothingSimulationContext* GetClothingSimulationContext()
{
return ClothingSimulationContext;
}
/** Return a non const version of the clothing interactor (non const methods are used to update simulation parameters). */
UClothingSimulationInteractor* GetClothingSimulationInteractor() const
{
return ClothingSimulationInteractor;
}
/** Remove all actors. */
UE_API void RemoveAllClothingActors();
/** Synchronize the simulation with the changes requested by the interactor. */
UE_API void SyncClothingInteractor();
/** Hard reset the cloth simulation */
void HardResetSimulation()
{
ClothingSimulation->HardResetSimulation(static_cast<const IClothingSimulationContext*>(ClothingSimulationContext));
}
/** Return the collision data from this simulation instance. */
void GetCollisions(FClothCollisionData& Collisions, bool bIncludeExternal) const
{
ClothingSimulation->GetCollisions(Collisions, bIncludeExternal);
}
/** Append unique collision data from this simulation instance to the specified collision data. */
UE_API void AppendUniqueCollisions(FClothCollisionData& OutCollisions, bool bIncludeExternal) const;
/** Add external dynamic collisions. */
void AddExternalCollisions(const FClothCollisionData& Collisions)
{
ClothingSimulation->AddExternalCollisions(Collisions);
}
/** Remove all dynamically added external collisions. */
void ClearExternalCollisions()
{
ClothingSimulation->ClearExternalCollisions();
}
/** Fill the simulation context and do any other related game-thread initialization. */
UE_API void FillContextAndPrepareTick(const USkeletalMeshComponent* OwnerComponent, float DeltaTime, bool bIsInitialization);
/** Advance the simulation. This method may be called asynchronously. */
void Simulate()
{
if (ClothingSimulation->ShouldSimulateLOD(CurrentOwnerLODIndex))
{
ClothingSimulation->Simulate_AnyThread(static_cast<const IClothingSimulationContext*>(ClothingSimulationContext));
}
else
{
ClothingSimulation->ForceClothNextUpdateTeleportAndReset_AnyThread();
}
}
/** Append the simulation data. */
void AppendSimulationData(TMap<int32, FClothSimulData>& CurrentSimulationData, const USkeletalMeshComponent* OwnerComponent, const USkinnedMeshComponent* LeaderPoseComponent) const
{
if (ClothingSimulation->ShouldSimulateLOD(CurrentOwnerLODIndex))
{
ClothingSimulation->AppendSimulationData(CurrentSimulationData, OwnerComponent, LeaderPoseComponent);
}
}
/** Return this simulation bounds. */
FBoxSphereBounds GetBounds(const USkeletalMeshComponent* OwnerComponent) const
{
if (ClothingSimulation->ShouldSimulateLOD(CurrentOwnerLODIndex))
{
return ClothingSimulation->GetBounds(OwnerComponent);
}
return FBoxSphereBounds(ForceInit);
}
private:
/** ClothingSimulations are responsible for maintaining and simulating clothing actors. */
IClothingSimulationInterface* ClothingSimulation = nullptr;
/** ClothingSimulationContexts are a datastore for simulation data sent to the clothing thread. */
IClothingSimulationContext* ClothingSimulationContext = nullptr;
/**
* Objects responsible for interacting with the clothing simulation.
* Blueprints and code can call/set data on this from the game thread and the next time
* it is safe to do so the interactor will sync to the simulation context.
*/
UPROPERTY(Transient)
TObjectPtr<UClothingSimulationInteractor> ClothingSimulationInteractor;
/** Simulation factory. */
UPROPERTY(Transient)
TObjectPtr<UClothingSimulationFactory> ClothingSimulationFactory;
int32 CurrentOwnerLODIndex = INDEX_NONE; // This is populated by FillContextAndPrepareTick
};
template<>
struct TStructOpsTypeTraits<FClothingSimulationInstance> : public TStructOpsTypeTraitsBase2<FClothingSimulationInstance>
{
enum
{
WithCopy = false
};
};
#undef UE_API