Projekt_Grafika/dependencies/physx-4.1/source/physx/src/NpBatchQuery.cpp

605 lines
23 KiB
C++

//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2019 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#include "common/PxProfileZone.h"
#include "geometry/PxGeometryQuery.h"
#include "NpBatchQuery.h"
#include "NpReadCheck.h"
#include "NpActor.h"
#include "NpShapeManager.h"
#include "NpScene.h"
#include "PsAtomic.h"
#include "PsFoundation.h"
#include "PsUtilities.h"
using namespace physx;
using namespace Sq;
using namespace Cm;
#if !PX_P64_FAMILY
PX_COMPILE_TIME_ASSERT(0==(sizeof(PxRaycastHit)& 0x0f));
PX_COMPILE_TIME_ASSERT(0==(sizeof(PxSweepHit)& 0x0f));
PX_COMPILE_TIME_ASSERT(0==(sizeof(PxOverlapHit)& 0x0f));
#endif
#define CHECK_RUNNING(QueryMessage) \
if(Ps::atomicCompareExchange(&mBatchQueryIsRunning, -1, 0) == 1)\
{\
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, QueryMessage); return;\
}
NpBatchQuery::NpBatchQuery(NpScene& owner, const PxBatchQueryDesc& d)
: mNpScene(&owner), mNbRaycasts(0), mNbOverlaps(0), mNbSweeps(0), mBatchQueryIsRunning(0), mDesc(d), mPrevOffset(PxU32(eTERMINAL))
{
mHasMtdSweep = false;
}
NpBatchQuery::~NpBatchQuery()
{
}
void NpBatchQuery::setUserMemory(const PxBatchQueryMemory& userMem)
{
if(Ps::atomicCompareExchange(&mBatchQueryIsRunning, 0, 0) != 0)
{
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::setUserMemory: This batch is still executing, skipping setUserMemory");
return;
}
PxBatchQueryDesc& desc = getDesc();
desc.queryMemory = userMem;
}
const PxBatchQueryMemory& NpBatchQuery::getUserMemory()
{
return getDesc().queryMemory;
}
// ROS abbreviates Raycast/Overlap/Sweep
struct QTypeROS { enum Enum { eRAYCAST = 0, eOVERLAP = 1, eSWEEP = 2 }; }; // AP: perhaps can be shared with some other code
namespace physx
{
struct BatchStreamHeader
{
BatchStreamHeader(
PxHitFlags aHitFlags, const PxQueryCache* aCache, const PxQueryFilterData& aFd,
void* aUserData, PxU16 aMaxTouchHits, QTypeROS::Enum aHitTypeId) :
hitFlags(aHitFlags), fd(aFd), userData(aUserData), cache(aCache),
maxTouchHits(aMaxTouchHits), hitTypeId(char(aHitTypeId))
{
nextQueryOffset = PxU32(NpBatchQuery::eTERMINAL);
}
BatchStreamHeader() {}
// TODO: possibly maintain 3 separate offset lists in the same array for raycasts/overlaps/sweeps
// offset of a 4-byte ptr to offset in the previously stored batch query in the stream, this is not a ptr because of reallocs
PxU32 nextQueryOffset;
PxHitFlags hitFlags;
PxQueryFilterData fd;
void* userData;
const PxQueryCache* cache;
PxU16 maxTouchHits;
char hitTypeId; // Sq::QTypeROS
};
} // namespace physx
static void writeGeom(BatchQueryStream& stream, const PxGeometry& geom)
{
PxGeometryType::Enum geomType = geom.getType();
stream.write<PxU32>(PxU32(geomType));
switch (geomType)
{
case PxGeometryType::eCAPSULE:
stream.write<PxCapsuleGeometry>(static_cast<const PxCapsuleGeometry&>(geom));
break;
case PxGeometryType::eSPHERE:
stream.write<PxSphereGeometry>(static_cast<const PxSphereGeometry&>(geom));
break;
case PxGeometryType::eCONVEXMESH:
stream.write<PxConvexMeshGeometry>(static_cast<const PxConvexMeshGeometry&>(geom));
break;
case PxGeometryType::eBOX:
stream.write<PxBoxGeometry>(static_cast<const PxBoxGeometry&>(geom));
break;
case PxGeometryType::ePLANE:
case PxGeometryType::eTRIANGLEMESH:
case PxGeometryType::eHEIGHTFIELD:
case PxGeometryType::eGEOMETRY_COUNT:
case PxGeometryType::eINVALID:
PX_ALWAYS_ASSERT_MESSAGE("Unsupported geometry type in writeGeom");
}
}
static PxGeometry* readGeom(BatchQueryStreamReader& reader)
{
PxU32 geomType = *reader.read<PxU32>();
PxGeometry* anyGeom = NULL;
switch (geomType)
{
case PxGeometryType::eCAPSULE:
anyGeom = reader.read<PxCapsuleGeometry>();
break;
case PxGeometryType::eSPHERE:
anyGeom = reader.read<PxSphereGeometry>();
break;
case PxGeometryType::eCONVEXMESH:
anyGeom = reader.read<PxConvexMeshGeometry>();
break;
case PxGeometryType::eBOX:
anyGeom = reader.read<PxBoxGeometry>();
break;
default:
PX_ALWAYS_ASSERT_MESSAGE("Unsupported geometry type in readGeom");
}
return anyGeom;
}
static void writeQueryInput(BatchQueryStream& stream, const MultiQueryInput& input)
{
stream.write<MultiQueryInput>(input);
if (input.rayOrigin)
stream.write<PxVec3>(input.rayOrigin);
if (input.unitDir)
stream.write<PxVec3>(input.unitDir);
if (input.pose)
stream.write<PxTransform>(input.pose);
if (input.geometry)
writeGeom(stream, *input.geometry);
}
static MultiQueryInput* readQueryInput(BatchQueryStreamReader& stream)
{
MultiQueryInput* input = stream.read<MultiQueryInput>();
if (input->rayOrigin)
input->rayOrigin = stream.read<PxVec3>();
if (input->unitDir)
input->unitDir = stream.read<PxVec3>();
if (input->pose)
input->pose = stream.read<PxTransform>();
if (input->geometry)
input->geometry = readGeom(stream);
return input;
}
template<typename ResultType, typename HitType>
void writeStatus(ResultType* aRes, const PxHitBuffer<HitType>& hits, void* userData, bool overflow)
{
ResultType* res = aRes;
res->userData = userData;
res->block = hits.block;
res->hasBlock = hits.hasBlock;
res->nbTouches = hits.nbTouches;
res->queryStatus = PxU8(overflow ? PxBatchQueryStatus::eOVERFLOW : PxBatchQueryStatus::eSUCCESS);
res->touches = (overflow && res->nbTouches == 0) ? NULL : hits.touches;
}
void NpBatchQuery::resetResultBuffers()
{
for (PxU32 i = 0; i<mNbRaycasts; i++)
{
mDesc.queryMemory.userRaycastResultBuffer[i].queryStatus = PxBatchQueryStatus::ePENDING;
mDesc.queryMemory.userRaycastResultBuffer[i].hasBlock = false;
mDesc.queryMemory.userRaycastResultBuffer[i].nbTouches = 0;
mDesc.queryMemory.userRaycastResultBuffer[i].touches = NULL;
mDesc.queryMemory.userRaycastResultBuffer[i].userData = NULL;
}
for (PxU32 i = 0; i<mNbOverlaps; i++)
{
mDesc.queryMemory.userOverlapResultBuffer[i].queryStatus = PxBatchQueryStatus::ePENDING;
mDesc.queryMemory.userOverlapResultBuffer[i].hasBlock = false;
mDesc.queryMemory.userOverlapResultBuffer[i].nbTouches = 0;
mDesc.queryMemory.userOverlapResultBuffer[i].touches = NULL;
mDesc.queryMemory.userOverlapResultBuffer[i].userData = NULL;
}
for (PxU32 i = 0; i<mNbSweeps; i++)
{
mDesc.queryMemory.userSweepResultBuffer[i].queryStatus = PxBatchQueryStatus::ePENDING;
mDesc.queryMemory.userSweepResultBuffer[i].hasBlock = false;
mDesc.queryMemory.userSweepResultBuffer[i].nbTouches = 0;
mDesc.queryMemory.userSweepResultBuffer[i].touches = NULL;
mDesc.queryMemory.userSweepResultBuffer[i].userData = NULL;
}
}
void NpBatchQuery::finalizeExecute()
{
mPrevOffset = PxU32(eTERMINAL); // reset the first BatchStreamHeader offset
mStream.rewind(); // clear out the executed queries - rewind the data stream so that the query object can be reused
mNbRaycasts = mNbOverlaps = mNbSweeps = 0; // also reset the counts so the query object can be reused
mHasMtdSweep = false; // reset the mtd flag
Ps::atomicExchange(&mBatchQueryIsRunning, 0);
}
// fixed memory buffer with extra single hit for overflow detection
template<typename HitType>
struct PxOverflowBuffer : PxHitBuffer<HitType>
{
bool overflow;
PxU32 saveNbTouches;
HitType extraHit;
HitType* saveTouches;
bool processCalled;
PxOverflowBuffer(HitType* hits, PxU32 count) : PxHitBuffer<HitType>(hits, count), overflow(false), processCalled(false)
{
}
virtual PxAgain processTouches(const HitType* /*hits*/, PxU32 /*count*/)
{
if (processCalled)
return false;
saveTouches = this->touches;
saveNbTouches = this->nbTouches;
processCalled = true;
this->touches = &extraHit;
this->maxNbTouches = 1;
return true;
}
virtual void finalizeQuery()
{
if (processCalled)
{
overflow = (this->nbTouches > 0);
this->nbTouches = saveNbTouches;
this->touches = saveTouches;
}
}
};
void NpBatchQuery::execute()
{
NP_READ_CHECK(mNpScene);
if(mNbRaycasts)
{
PX_CHECK_AND_RETURN(mDesc.queryMemory.userRaycastResultBuffer!=NULL, "PxBatchQuery execute: userRaycastResultBuffer is NULL");
PX_CHECK_AND_RETURN(mDesc.queryMemory.raycastTouchBufferSize > 0 ?
(mDesc.queryMemory.userRaycastTouchBuffer != NULL) : true, "PxBatchQuery execute: userRaycastTouchBuffer is NULL");
}
if(mNbOverlaps)
{
PX_CHECK_AND_RETURN(mDesc.queryMemory.userOverlapResultBuffer!=NULL, "PxBatchQuery execute: userOverlapResultBuffer is NULL");
PX_CHECK_AND_RETURN(mDesc.queryMemory.overlapTouchBufferSize > 0 ?
(mDesc.queryMemory.userOverlapTouchBuffer != NULL) : true, "PxBatchQuery execute: userOverlapTouchBuffer is NULL");
}
if(mNbSweeps)
{
PX_CHECK_AND_RETURN(mDesc.queryMemory.userSweepResultBuffer!=NULL, "PxBatchQuery execute: userSweepResultBuffer is NULL");
PX_CHECK_AND_RETURN(mDesc.queryMemory.sweepTouchBufferSize > 0 ?
(mDesc.queryMemory.userSweepTouchBuffer != NULL) : true, "PxBatchQuery execute: userSweepTouchBuffer is NULL");
}
PX_SIMD_GUARD;
PX_PROFILE_ZONE("BatchedSceneQuery.execute", mNpScene->getContextId());
PxI32 ret = Ps::atomicCompareExchange(&mBatchQueryIsRunning, 1, 0);
if(ret == 1)
{
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::execute: This batch is already executing");
return;
}
else if(ret == -1)
{
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::execute: Another thread is still adding queries to this batch");
return;
}
resetResultBuffers();
// If PVD is connected and IS_PVD_SQ_ENABLED, record the offsets for queries in pvd buffers and run the queries on PPU
bool isSqCollectorLocked = false;
PX_UNUSED(isSqCollectorLocked);
#if PX_SUPPORT_PVD
PxU32 pvdRayQstartIdx = 0;
PxU32 pvdOverlapQstartIdx = 0;
PxU32 pvdSweepQstartIdx = 0;
Vd::ScbScenePvdClient& pvdClient = mNpScene->mScene.getScenePvdClient();
const bool needUpdatePvd = pvdClient.checkPvdDebugFlag() && (pvdClient.getScenePvdFlagsFast() & PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES);
if(needUpdatePvd)
{
mNpScene->getBatchedSqCollector().getLock().lock();
isSqCollectorLocked = true;
pvdRayQstartIdx = mNpScene->getBatchedSqCollector().mAccumulatedRaycastQueries.size();
pvdOverlapQstartIdx = mNpScene->getBatchedSqCollector().mAccumulatedOverlapQueries.size();
pvdSweepQstartIdx = mNpScene->getBatchedSqCollector().mAccumulatedSweepQueries.size();
}
#endif
// setup local pointers to user provided output buffers
PxRaycastHit* raycastHits = mDesc.queryMemory.userRaycastTouchBuffer; PX_UNUSED(raycastHits);
PxRaycastQueryResult* raycastResults = mDesc.queryMemory.userRaycastResultBuffer; PX_UNUSED(raycastResults);
PxU32 raycastHitsSize = mDesc.queryMemory.raycastTouchBufferSize; PX_UNUSED(raycastHitsSize);
PxOverlapHit* overlapHits = mDesc.queryMemory.userOverlapTouchBuffer; PX_UNUSED(overlapHits);
PxOverlapQueryResult* overlapResults = mDesc.queryMemory.userOverlapResultBuffer; PX_UNUSED(overlapResults);
PxU32 overlapHitsSize = mDesc.queryMemory.overlapTouchBufferSize; PX_UNUSED(overlapHitsSize);
PxSweepHit* sweepHits = mDesc.queryMemory.userSweepTouchBuffer; PX_UNUSED(sweepHits);
PxSweepQueryResult* sweepResults = mDesc.queryMemory.userSweepResultBuffer; PX_UNUSED(sweepResults);
PxU32 sweepHitsSize = mDesc.queryMemory.sweepTouchBufferSize; PX_UNUSED(sweepHitsSize);
BatchQueryFilterData bfd(mDesc.filterShaderData, mDesc.filterShaderDataSize, mDesc.preFilterShader, mDesc.postFilterShader);
// data declarations for double buffering the input stream
PxU32 curQueryOffset = 0; // first query starts at 0
if (mPrevOffset == eTERMINAL) // except if zero queries were queued
{
finalizeExecute();
return;
}
PxU32 hitsSpaceLeft; PX_UNUSED(hitsSpaceLeft);
// ====================== parse and execute the batch query memory stream ======================
PxU32 queryCount = 0;
do {
// parse a query from the input stream, create a stream reader at current double buffer
BatchQueryStreamReader reader(mStream.begin()+curQueryOffset);
BatchStreamHeader& h = *reader.read<BatchStreamHeader>();
curQueryOffset = h.nextQueryOffset;
Ps::prefetchLine(mStream.begin() + curQueryOffset);
MultiQueryInput& input = *readQueryInput(reader);
// ====================== switch over query type - QTypeROS::eRAYCAST, eOVERLAP, eSWEEP =====================
switch (h.hitTypeId)
{
// =============== Current query is a raycast =====================
case QTypeROS::eRAYCAST:
{
PxU32 nbRaycastHits = PxU32(raycastHits - mDesc.queryMemory.userRaycastTouchBuffer);
PX_ASSERT(nbRaycastHits <= raycastHitsSize);
hitsSpaceLeft = raycastHitsSize - nbRaycastHits;
PxOverflowBuffer<PxRaycastHit> hits(raycastHits, PxMin<PxU32>(h.maxTouchHits, hitsSpaceLeft));
mNpScene->NpScene::multiQuery<PxRaycastHit>(input, hits, h.hitFlags, h.cache, h.fd, NULL, &bfd);
hits.overflow |= (hitsSpaceLeft == 0 && h.maxTouchHits > 0); // report overflow if 0 space left and maxTouchHits>0
writeStatus<PxRaycastQueryResult, PxRaycastHit>(raycastResults++, hits, h.userData, hits.overflow);
raycastHits += hits.nbTouches;
} break;
// ================ Current query is an overlap ====================
case QTypeROS::eOVERLAP:
{
PxU32 nbOverlapHits = PxU32(overlapHits - mDesc.queryMemory.userOverlapTouchBuffer);
PX_ASSERT(nbOverlapHits <= overlapHitsSize);
hitsSpaceLeft = overlapHitsSize - nbOverlapHits;
PxOverflowBuffer<PxOverlapHit> hits(overlapHits, PxMin<PxU32>(h.maxTouchHits, hitsSpaceLeft));
mNpScene->NpScene::multiQuery<PxOverlapHit>(input, hits, h.hitFlags, h.cache, h.fd, NULL, &bfd);
hits.overflow |= (hitsSpaceLeft == 0 && h.maxTouchHits > 0); // report overflow if 0 space left and maxTouchHits>0
writeStatus<PxOverlapQueryResult, PxOverlapHit>(overlapResults++, hits, h.userData, hits.overflow);
overlapHits += hits.nbTouches;
} break;
// ================== Current query is a sweep =========================
case QTypeROS::eSWEEP:
{
PxU32 nbSweepHits = PxU32(sweepHits - mDesc.queryMemory.userSweepTouchBuffer);
PX_ASSERT(nbSweepHits <= sweepHitsSize);
hitsSpaceLeft = sweepHitsSize - nbSweepHits;
PxOverflowBuffer<PxSweepHit> hits(sweepHits, PxMin<PxU32>(h.maxTouchHits, hitsSpaceLeft));
mNpScene->NpScene::multiQuery<PxSweepHit>(input, hits, h.hitFlags, h.cache, h.fd, NULL, &bfd);
hits.overflow |= (hitsSpaceLeft == 0 && h.maxTouchHits > 0); // report overflow if 0 space left and maxTouchHits>0
writeStatus<PxSweepQueryResult, PxSweepHit>(sweepResults++, hits, h.userData, hits.overflow);
sweepHits += hits.nbTouches;
} break;
default:
PX_ALWAYS_ASSERT_MESSAGE("Unexpected batch query type (raycast/overlap/sweep).");
}
if (h.nextQueryOffset == eTERMINAL) // end of stream
// AP: previously also had a break on hitCount==-1 which is aborted due to out of space
// abort stream parsing if we ran into an aborted query (hitCount==-1).. but it was easier to just continue
// the perf implications for aborted queries are not a significant consideration and this allows to avoid
// writing special case code for filling the query buffers after aborted query
break;
#undef MULTIQ
queryCount++;
} while (queryCount < 1000000);
#if PX_SUPPORT_PVD
if( isSqCollectorLocked && needUpdatePvd)
{
mNpScene->getBatchedSqCollector().collectAllBatchedHits( mDesc.queryMemory.userRaycastResultBuffer, mNbRaycasts, pvdRayQstartIdx,
mDesc.queryMemory.userOverlapResultBuffer, mNbOverlaps, pvdOverlapQstartIdx,
mDesc.queryMemory.userSweepResultBuffer, mNbSweeps, pvdSweepQstartIdx);
}
// Maybe connection is disconnected after the lock
if( isSqCollectorLocked )
{
mNpScene->getBatchedSqCollector().getLock().unlock();
isSqCollectorLocked = false;
}
#endif
finalizeExecute();
}
///////////////////////////////////////////////////////////////////////////////
void NpBatchQuery::writeBatchHeader(const BatchStreamHeader& h)
{
PxU32 streamPos = PxU32(mStream.getPos()); // save the stream pos before we write the header
mStream.write<BatchStreamHeader>(h);
// link into a list as offset
PxU32* prevPtr = (mPrevOffset == eTERMINAL) ? &mPrevOffset : reinterpret_cast<PxU32*>(mStream.begin()+mPrevOffset);
PxU32 headerPtr = streamPos+PX_OFFSET_OF(BatchStreamHeader, nextQueryOffset);
*prevPtr = headerPtr;
mPrevOffset = headerPtr;
}
///////////////////////////////////////////////////////////////////////////////
void NpBatchQuery::raycast(
const PxVec3& origin, const PxVec3& unitDir, PxReal distance, PxU16 maxTouchHits,
PxHitFlags hitFlags, const PxQueryFilterData& fd, void* userData, const PxQueryCache* cache)
{
PX_CHECK_AND_RETURN(distance>0, "PxBatchQuery::raycast: The maximum distance must be greater than zero!");
PX_CHECK_AND_RETURN(unitDir.isNormalized(), "PxBatchQuery::raycast: Direction must be normalized");
PX_CHECK_AND_RETURN(origin.isFinite(), "PxBatchQuery::raycast: origin is not valid");
if (mNbRaycasts >= mDesc.queryMemory.getMaxRaycastsPerExecute())
{
PX_CHECK_AND_RETURN(mNbRaycasts < mDesc.queryMemory.getMaxRaycastsPerExecute(),
"PxBatchQuery: number of raycast() calls exceeds PxBatchQueryMemory::raycastResultBufferSize, query discarded");
return;
}
CHECK_RUNNING("PxBatchQuery::raycast: This batch is still executing, skipping query.");
mNbRaycasts++;
writeBatchHeader(BatchStreamHeader(hitFlags, cache, fd, userData, maxTouchHits, QTypeROS::eRAYCAST));
writeQueryInput(mStream, MultiQueryInput(origin, unitDir, distance));
Ps::atomicExchange(&mBatchQueryIsRunning, 0);
}
///////////////////////////////////////////////////////////////////////////////
void NpBatchQuery::overlap(
const PxGeometry& geometry, const PxTransform& pose, PxU16 maxTouchHits,
const PxQueryFilterData& fd, void* userData, const PxQueryCache* cache)
{
PX_CHECK_AND_RETURN(pose.isValid(), "NpBatchQuery::overlapMultiple pose is not valid.");
if (mNbOverlaps >= mDesc.queryMemory.getMaxOverlapsPerExecute())
{
PX_CHECK_AND_RETURN(mNbOverlaps < mDesc.queryMemory.getMaxOverlapsPerExecute(),
"PxBatchQuery: number of overlap() calls exceeds PxBatchQueryMemory::overlapResultBufferSize, query discarded");
return;
}
CHECK_RUNNING("PxBatchQuery::overlap: This batch is still executing, skipping query.")
mNbOverlaps++;
writeBatchHeader(BatchStreamHeader(PxHitFlags(), cache, fd, userData, maxTouchHits, QTypeROS::eOVERLAP));
writeQueryInput(mStream, MultiQueryInput(&geometry, &pose));
Ps::atomicExchange(&mBatchQueryIsRunning, 0);
}
void NpBatchQuery::sweep(
const PxGeometry& geometry, const PxTransform& pose, const PxVec3& unitDir, const PxReal distance, PxU16 maxTouchHits,
PxHitFlags hitFlags, const PxQueryFilterData& fd, void* userData, const PxQueryCache* cache, const PxReal inflation)
{
PX_CHECK_AND_RETURN(pose.isValid(), "Batch sweep input check: pose is not valid.");
PX_CHECK_AND_RETURN(unitDir.isFinite(), "Batch sweep input check: unitDir is not valid.");
PX_CHECK_AND_RETURN(unitDir.isNormalized(), "Batch sweep input check: direction must be normalized");
PX_CHECK_AND_RETURN(distance >= 0.0f, "Batch sweep input check: distance cannot be negative");
PX_CHECK_AND_RETURN(distance != 0.0f || !(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP),
"Batch sweep input check: zero-length sweep only valid without the PxHitFlag::eASSUME_NO_INITIAL_OVERLAP flag");
#if PX_CHECKED
if(!PxGeometryQuery::isValid(geometry))
{
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Provided geometry is not valid");
return;
}
#endif // PX_CHECKED
if (mNbSweeps >= mDesc.queryMemory.getMaxSweepsPerExecute())
{
PX_CHECK_AND_RETURN(mNbSweeps < mDesc.queryMemory.getMaxSweepsPerExecute(),
"PxBatchQuery: number of sweep() calls exceeds PxBatchQueryMemory::sweepResultBufferSize, query discarded");
return;
}
CHECK_RUNNING("PxBatchQuery::sweep: This batch is still executing, skipping query.")
mNbSweeps++;
writeBatchHeader(BatchStreamHeader(hitFlags, cache, fd, userData, maxTouchHits, QTypeROS::eSWEEP));
//set the MTD flag
mHasMtdSweep |= !!(hitFlags & PxHitFlag::eMTD);
if((hitFlags & PxHitFlag::ePRECISE_SWEEP) && (hitFlags & PxHitFlag::eMTD))
{
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " Precise sweep doesn't support MTD. Perform MTD with default sweep");
hitFlags &= ~PxHitFlag::ePRECISE_SWEEP;
}
if((hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP) && (hitFlags & PxHitFlag::eMTD))
{
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " eMTD cannot be used in conjunction with eASSUME_NO_INITIAL_OVERLAP. eASSUME_NO_INITIAL_OVERLAP will be ignored");
hitFlags &= ~PxHitFlag::eASSUME_NO_INITIAL_OVERLAP;
}
PxReal realInflation = inflation;
if((hitFlags & PxHitFlag::ePRECISE_SWEEP)&& inflation > 0.0f)
{
realInflation = 0.0f;
Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, " Precise sweep doesn't support inflation, inflation will be overwritten to be zero");
}
writeQueryInput(mStream, MultiQueryInput(&geometry, &pose, unitDir, distance, realInflation));
Ps::atomicExchange(&mBatchQueryIsRunning, 0);
}
void NpBatchQuery::release()
{
if(Ps::atomicCompareExchange(&mBatchQueryIsRunning, 0, 0) != 0)
{
Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "PxBatchQuery::release: This batch is still executing, skipping release");
return;
}
mNpScene->releaseBatchQuery(this);
}
PxBatchQueryPreFilterShader NpBatchQuery::getPreFilterShader() const
{
return mDesc.preFilterShader;
}
PxBatchQueryPostFilterShader NpBatchQuery::getPostFilterShader() const
{
return mDesc.postFilterShader;
}
const void* NpBatchQuery::getFilterShaderData() const
{
return mDesc.filterShaderData;
}
PxU32 NpBatchQuery::getFilterShaderDataSize() const
{
return mDesc.filterShaderDataSize;
}