220 lines
5.2 KiB
C++
220 lines
5.2 KiB
C++
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
|
|
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <Jolt/Physics/Collision/CollisionCollector.h>
|
|
#include <Jolt/Core/QuickSort.h>
|
|
|
|
JPH_NAMESPACE_BEGIN
|
|
|
|
/// Simple implementation that collects all hits and optionally sorts them on distance
|
|
template <class CollectorType>
|
|
class AllHitCollisionCollector : public CollectorType
|
|
{
|
|
public:
|
|
/// Redeclare ResultType
|
|
using ResultType = typename CollectorType::ResultType;
|
|
|
|
// See: CollectorType::Reset
|
|
virtual void Reset() override
|
|
{
|
|
CollectorType::Reset();
|
|
|
|
mHits.clear();
|
|
}
|
|
|
|
// See: CollectorType::AddHit
|
|
virtual void AddHit(const ResultType &inResult) override
|
|
{
|
|
mHits.push_back(inResult);
|
|
}
|
|
|
|
/// Order hits on closest first
|
|
void Sort()
|
|
{
|
|
QuickSort(mHits.begin(), mHits.end(), [](const ResultType &inLHS, const ResultType &inRHS) { return inLHS.GetEarlyOutFraction() < inRHS.GetEarlyOutFraction(); });
|
|
}
|
|
|
|
/// Check if any hits were collected
|
|
inline bool HadHit() const
|
|
{
|
|
return !mHits.empty();
|
|
}
|
|
|
|
Array<ResultType> mHits;
|
|
};
|
|
|
|
/// Simple implementation that collects the closest / deepest hit
|
|
template <class CollectorType>
|
|
class ClosestHitCollisionCollector : public CollectorType
|
|
{
|
|
public:
|
|
/// Redeclare ResultType
|
|
using ResultType = typename CollectorType::ResultType;
|
|
|
|
// See: CollectorType::Reset
|
|
virtual void Reset() override
|
|
{
|
|
CollectorType::Reset();
|
|
|
|
mHadHit = false;
|
|
}
|
|
|
|
// See: CollectorType::AddHit
|
|
virtual void AddHit(const ResultType &inResult) override
|
|
{
|
|
float early_out = inResult.GetEarlyOutFraction();
|
|
if (!mHadHit || early_out < mHit.GetEarlyOutFraction())
|
|
{
|
|
// Update early out fraction
|
|
CollectorType::UpdateEarlyOutFraction(early_out);
|
|
|
|
// Store hit
|
|
mHit = inResult;
|
|
mHadHit = true;
|
|
}
|
|
}
|
|
|
|
/// Check if this collector has had a hit
|
|
inline bool HadHit() const
|
|
{
|
|
return mHadHit;
|
|
}
|
|
|
|
ResultType mHit;
|
|
|
|
private:
|
|
bool mHadHit = false;
|
|
};
|
|
|
|
/// Implementation that collects the closest / deepest hit for each body and optionally sorts them on distance
|
|
template <class CollectorType>
|
|
class ClosestHitPerBodyCollisionCollector : public CollectorType
|
|
{
|
|
public:
|
|
/// Redeclare ResultType
|
|
using ResultType = typename CollectorType::ResultType;
|
|
|
|
// See: CollectorType::Reset
|
|
virtual void Reset() override
|
|
{
|
|
CollectorType::Reset();
|
|
|
|
mHits.clear();
|
|
mHadHit = false;
|
|
}
|
|
|
|
// See: CollectorType::OnBody
|
|
virtual void OnBody(const Body &inBody) override
|
|
{
|
|
// Store the early out fraction so we can restore it after we've collected all hits for this body
|
|
mPreviousEarlyOutFraction = CollectorType::GetEarlyOutFraction();
|
|
}
|
|
|
|
// See: CollectorType::AddHit
|
|
virtual void AddHit(const ResultType &inResult) override
|
|
{
|
|
float early_out = inResult.GetEarlyOutFraction();
|
|
if (!mHadHit || early_out < CollectorType::GetEarlyOutFraction())
|
|
{
|
|
// Update early out fraction to avoid spending work on collecting further hits for this body
|
|
CollectorType::UpdateEarlyOutFraction(early_out);
|
|
|
|
if (!mHadHit)
|
|
{
|
|
// First time we have a hit we append it to the array
|
|
mHits.push_back(inResult);
|
|
mHadHit = true;
|
|
}
|
|
else
|
|
{
|
|
// Closer hits will override the previous one
|
|
mHits.back() = inResult;
|
|
}
|
|
}
|
|
}
|
|
|
|
// See: CollectorType::OnBodyEnd
|
|
virtual void OnBodyEnd() override
|
|
{
|
|
if (mHadHit)
|
|
{
|
|
// Reset the early out fraction to the configured value so that we will continue
|
|
// to collect hits at any distance for other bodies
|
|
JPH_ASSERT(mPreviousEarlyOutFraction != -FLT_MAX); // Check that we got a call to OnBody
|
|
CollectorType::ResetEarlyOutFraction(mPreviousEarlyOutFraction);
|
|
mHadHit = false;
|
|
}
|
|
|
|
// For asserting purposes we reset the stored early out fraction so we can detect that OnBody was called
|
|
JPH_IF_ENABLE_ASSERTS(mPreviousEarlyOutFraction = -FLT_MAX;)
|
|
}
|
|
|
|
/// Order hits on closest first
|
|
void Sort()
|
|
{
|
|
QuickSort(mHits.begin(), mHits.end(), [](const ResultType &inLHS, const ResultType &inRHS) { return inLHS.GetEarlyOutFraction() < inRHS.GetEarlyOutFraction(); });
|
|
}
|
|
|
|
/// Check if any hits were collected
|
|
inline bool HadHit() const
|
|
{
|
|
return !mHits.empty();
|
|
}
|
|
|
|
Array<ResultType> mHits;
|
|
|
|
private:
|
|
// Store early out fraction that was initially configured for the collector
|
|
float mPreviousEarlyOutFraction = -FLT_MAX;
|
|
|
|
// Flag to indicate if we have a hit for the current body
|
|
bool mHadHit = false;
|
|
};
|
|
|
|
/// Simple implementation that collects any hit
|
|
template <class CollectorType>
|
|
class AnyHitCollisionCollector : public CollectorType
|
|
{
|
|
public:
|
|
/// Redeclare ResultType
|
|
using ResultType = typename CollectorType::ResultType;
|
|
|
|
// See: CollectorType::Reset
|
|
virtual void Reset() override
|
|
{
|
|
CollectorType::Reset();
|
|
|
|
mHadHit = false;
|
|
}
|
|
|
|
// See: CollectorType::AddHit
|
|
virtual void AddHit(const ResultType &inResult) override
|
|
{
|
|
// Test that the collector is not collecting more hits after forcing an early out
|
|
JPH_ASSERT(!mHadHit);
|
|
|
|
// Abort any further testing
|
|
CollectorType::ForceEarlyOut();
|
|
|
|
// Store hit
|
|
mHit = inResult;
|
|
mHadHit = true;
|
|
}
|
|
|
|
/// Check if this collector has had a hit
|
|
inline bool HadHit() const
|
|
{
|
|
return mHadHit;
|
|
}
|
|
|
|
ResultType mHit;
|
|
|
|
private:
|
|
bool mHadHit = false;
|
|
};
|
|
|
|
JPH_NAMESPACE_END
|