diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/destructible/src/DestructibleStructureStressSolver.cpp | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'APEX_1.4/module/destructible/src/DestructibleStructureStressSolver.cpp')
| -rw-r--r-- | APEX_1.4/module/destructible/src/DestructibleStructureStressSolver.cpp | 1445 |
1 files changed, 1445 insertions, 0 deletions
diff --git a/APEX_1.4/module/destructible/src/DestructibleStructureStressSolver.cpp b/APEX_1.4/module/destructible/src/DestructibleStructureStressSolver.cpp new file mode 100644 index 00000000..b45db174 --- /dev/null +++ b/APEX_1.4/module/destructible/src/DestructibleStructureStressSolver.cpp @@ -0,0 +1,1445 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "DestructibleStructureStressSolver.h" +#include "DestructibleStructure.h" +#include "DestructibleActorImpl.h" +#include "PxProfiler.h" + +namespace +{ + const uint32_t InvalidLinkedChunkIndex = 0xFFFFFFFF; + const uint32_t MaxWarmingFrame = 200; + const uint32_t MaxLeaveInAdvaceWarmingWindow = 100; + const uint32_t MaxActiveCycle = 1000; + const float ShadowSceneDeltaTime = 0.001; +}; // namespace nameless + +namespace nvidia +{ +namespace destructible +{ +using namespace physx; + +// a helper data structure used to hold a [actor pointer] [chunk pointer] pair +struct ActorChunkPair +{ +public: + ActorChunkPair(const DestructibleActorImpl * actorAlias, const DestructibleStructure::Chunk * chunkAlias); + ~ActorChunkPair(); + + const DestructibleActorImpl * actorAlias; + const DestructibleStructure::Chunk * chunkAlias; +private: + ActorChunkPair(); +}; // struct ActorChunkPair + +ActorChunkPair::ActorChunkPair(const DestructibleActorImpl * actorAlias_, const DestructibleStructure::Chunk * chunkAlias_) + :actorAlias(actorAlias_) + ,chunkAlias(chunkAlias_) +{ + PX_ASSERT(NULL != actorAlias); + PX_ASSERT(NULL != chunkAlias); +} + +ActorChunkPair::~ActorChunkPair() +{ + chunkAlias = NULL; + actorAlias = NULL; +} + +StructureScratchBuffer::StructureScratchBuffer(uint8_t * const bufferStart_, uint32_t bufferCount_) + :bufferStart(bufferStart_) + ,bufferCount(bufferCount_) +{ + PX_ASSERT(NULL != bufferStart && 0 != bufferCount); + ::memset(static_cast<void*>(bufferStart), StructureScratchBuffer::ByteEmpty, bufferCount * sizeof(bufferStart[0])); +} + +StructureScratchBuffer::~StructureScratchBuffer() +{ +} + +bool StructureScratchBuffer::isOccupied(uint32_t index) const +{ + PX_ASSERT(index < bufferCount); + PX_ASSERT(StructureScratchBuffer::ByteEmpty == bufferStart[index] || StructureScratchBuffer::ByteExist == bufferStart[index]); + return StructureScratchBuffer::ByteExist == bufferStart[index]; +} + +void StructureScratchBuffer::setOccupied(uint32_t index) +{ + PX_ASSERT(index < bufferCount); + PX_ASSERT(StructureScratchBuffer::ByteEmpty == bufferStart[index]); + bufferStart[index] = StructureScratchBuffer::ByteExist; +} + +PeninsulaData::PeninsulaData() + :rootLinkedChunkIndex(InvalidLinkedChunkIndex) + ,peninsulaState(0x00) + ,chunkCount(0) + ,aggregateMass(0.0f) + ,geometricCenter(0.0f) +{ +} + +PeninsulaData::PeninsulaData(uint8_t peninsulaState_, uint32_t chunkCount_) + :rootLinkedChunkIndex(InvalidLinkedChunkIndex) + ,peninsulaState(peninsulaState_) + ,chunkCount(chunkCount_) + ,aggregateMass(0.0f) + ,geometricCenter(0.0f) +{ +} + +PeninsulaData::PeninsulaData(uint8_t peninsulaState_, uint32_t chunkCount_, float aggregateMass_, PxVec3 geometricCenter_) + :rootLinkedChunkIndex(InvalidLinkedChunkIndex) + ,peninsulaState(peninsulaState_) + ,chunkCount(chunkCount_) + ,aggregateMass(aggregateMass_) + ,geometricCenter(geometricCenter_) +{ +} + +PeninsulaData::~PeninsulaData() +{ +} + +bool PeninsulaData::isValid() const +{ + PX_ASSERT(peninsulaState < PeninsulaData::PeninsulaInvalidMaxFlag); + return (!hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport)); +} + +void PeninsulaData::resetData() +{ + chunkCount = 0; + aggregateMass = 0.0f; + geometricCenter = PxVec3(0.0f); +} + +void PeninsulaData::setFlag(PeninsulaData::PeninsulaFlag peninsulaFlag) +{ + PX_ASSERT(peninsulaFlag < PeninsulaData::PeninsulaInvalidMaxFlag); + PX_ASSERT(!hasFlag(peninsulaFlag)); + peninsulaState |= peninsulaFlag; + PX_ASSERT(peninsulaState < PeninsulaData::PeninsulaInvalidMaxFlag); +} + +void PeninsulaData::setLinkedChunkData(const ActorChunkPair & actorChunkPair, Int2Type<StressEvaluationType::EvaluateByCount>) +{ + PX_ASSERT(NULL != &actorChunkPair); + PX_ASSERT(peninsulaState < PeninsulaData::PeninsulaInvalidMaxFlag); + PX_ASSERT(0 == chunkCount); + PX_ASSERT(0.0f == aggregateMass); + PX_ASSERT(geometricCenter.isZero()); + chunkCount = 1; + PX_UNUSED(actorChunkPair); +} + +void PeninsulaData::setLinkedChunkData(const ActorChunkPair & actorChunkPair, Int2Type<StressEvaluationType::EvaluateByMoment>) +{ + PX_ASSERT(NULL != &actorChunkPair); + PX_ASSERT(peninsulaState < PeninsulaData::PeninsulaInvalidMaxFlag); + PX_ASSERT(0 == chunkCount); + PX_ASSERT(0.0f == aggregateMass); + PX_ASSERT(geometricCenter.isZero()); + chunkCount = 1; + aggregateMass = actorChunkPair.actorAlias->getChunkMass(actorChunkPair.chunkAlias->indexInAsset); + geometricCenter = actorChunkPair.actorAlias->getStructure()->getChunkWorldCentroid(*(actorChunkPair.chunkAlias)); +} + +void PeninsulaData::setRootLinkedChunkIndex(uint32_t linkedChunkIndex) +{ + PX_ASSERT(InvalidLinkedChunkIndex == rootLinkedChunkIndex); + rootLinkedChunkIndex = linkedChunkIndex; +} + +void PeninsulaData::assimilate(const PeninsulaData & that, Int2Type<StressEvaluationType::EvaluateByCount>) +{ + this->peninsulaState |= that.peninsulaState; + this->chunkCount += that.chunkCount; +} + +void PeninsulaData::assimilate(const PeninsulaData & that, Int2Type<StressEvaluationType::EvaluateByMoment>) +{ + this->peninsulaState |= that.peninsulaState; + this->chunkCount += that.chunkCount; + this->geometricCenter = ((this->geometricCenter * this->aggregateMass) + (that.geometricCenter * that.aggregateMass)) / (this->aggregateMass + that.aggregateMass); + this->aggregateMass += that.aggregateMass; +} + +bool PeninsulaData::hasFlag(PeninsulaData::PeninsulaFlag peninsulaFlag) const +{ + PX_ASSERT(peninsulaFlag < PeninsulaData::PeninsulaInvalidMaxFlag); + PX_ASSERT(peninsulaState < PeninsulaData::PeninsulaInvalidMaxFlag); + return (0 != (peninsulaState & peninsulaFlag)); +} + +uint32_t PeninsulaData::getDataChunkCount() const +{ + return chunkCount; +} + +float PeninsulaData::getDataAggregateMass() const +{ + return aggregateMass; +} + +const PxVec3 & PeninsulaData::getDataGeometricCenter() const +{ + return geometricCenter; +} + +uint32_t PeninsulaData::getRootLinkedChunkIndex() const +{ + PX_ASSERT(InvalidLinkedChunkIndex != rootLinkedChunkIndex); + return rootLinkedChunkIndex; +} + +SnapEvent * SnapEvent::instantiate(FractureEventProxy * fractureEventProxyBufferStart, uint32_t fractureEventProxyBufferCount, float tickSecondsToSnap) +{ + SnapEvent * snapEvent = NULL; + PX_ASSERT(NULL != fractureEventProxyBufferStart); + PX_ASSERT(0 != fractureEventProxyBufferCount); + PX_ASSERT(tickSecondsToSnap >= 0.0f); + snapEvent = PX_NEW(SnapEvent)(fractureEventProxyBufferStart, fractureEventProxyBufferCount, tickSecondsToSnap); + return snapEvent; +} + +void SnapEvent::onDestroy() +{ + PX_ASSERT(NULL != fractureEventProxyBufferStart); + PX_DELETE([]fractureEventProxyBufferStart); // derived from UserAllocated, don't have to use PX_FREE(x) + fractureEventProxyBufferStart = NULL; + PX_DELETE(this); +} + +bool SnapEvent::isRipeAfterUpdatingTime(float deltaTime) +{ + bool isRipeAfterUpdatingTime = false; + PX_ASSERT(deltaTime >= 0.0f); + if(tickSecondsRemainingToSnap >= 0.0f) + { + PX_ASSERT(deltaTime > FLT_EPSILON); + tickSecondsRemainingToSnap -= deltaTime; + if(tickSecondsRemainingToSnap < 0.0f) + { + isRipeAfterUpdatingTime = true; + } + } + return isRipeAfterUpdatingTime; +} + +bool SnapEvent::isExpired() const +{ + return (tickSecondsRemainingToSnap < 0.0f); +} + +uint32_t SnapEvent::getFractureEventProxyCount() const +{ + return fractureEventProxyBufferCount; +} + +const FractureEventProxy & SnapEvent::getFractureEventProxy(uint32_t index) const +{ + PX_ASSERT(index < fractureEventProxyBufferCount); + PX_ASSERT(NULL != fractureEventProxyBufferStart); + return fractureEventProxyBufferStart[index]; +} + +SnapEvent::SnapEvent(FractureEventProxy * fractureEventProxyBufferStart_, uint32_t fractureEventProxyBufferCount_, float tickSecondsToSnap_) + :fractureEventProxyBufferStart(fractureEventProxyBufferStart_) + ,fractureEventProxyBufferCount(fractureEventProxyBufferCount_) + ,tickSecondsRemainingToSnap(tickSecondsToSnap_) +{ + PX_ASSERT(NULL != fractureEventProxyBufferStart); + PX_ASSERT(0 != fractureEventProxyBufferCount); + PX_ASSERT(tickSecondsRemainingToSnap >= 0.0f); +} + +SnapEvent::~SnapEvent() +{ + PX_ASSERT(NULL == fractureEventProxyBufferStart); +} +DestructibleStructureStressSolver::DestructibleStructureStressSolver(const DestructibleStructure & bindedStructureAlias_ , float strength_) + :bindedStructureAlias(bindedStructureAlias_) + ,structureLinkCount(0) + ,structureLinkCondition(NULL) + ,scratchBuffer(NULL) + ,scratchBufferLocked(false) + ,userTimeDelay(PX_MAX_F32) + ,userMassThreshold(PX_MAX_F32) +{ + PX_ASSERT(NULL != &bindedStructureAlias); + + // initialize internal members + structureLinkCount = bindedStructureAlias.chunks.size(); + structureLinkCondition = PX_NEW(uint8_t)[structureLinkCount]; + ::memset(static_cast<void*>(structureLinkCondition), 0x00, structureLinkCount * sizeof(uint8_t)); + for(uint32_t index = 0; index < bindedStructureAlias.supportDepthChunks.size(); ++index) + { + structureLinkCondition[bindedStructureAlias.supportDepthChunks[index]] = DestructibleStructureStressSolver::LinkedChunkExist; + } + scratchBuffer = PX_NEW(uint8_t)[structureLinkCount]; + ::memset(static_cast<void*>(scratchBuffer), 0x00, structureLinkCount * sizeof(uint8_t)); + PX_ASSERT(structureLinkCount > 0 && NULL != structureLinkCondition && NULL != scratchBuffer); + + // get user's parameters + for(physx::Array<DestructibleActorImpl*>::ConstIterator kIter = bindedStructureAlias.destructibles.begin(); kIter != bindedStructureAlias.destructibles.end(); ++kIter) + { + const DestructibleActorImpl & currentDestructibleActor = *(*kIter); + PX_ASSERT(NULL != ¤tDestructibleActor); + const float currentUserTimeDelay = currentDestructibleActor.getStressSolverTimeDelay(); + PX_ASSERT(currentUserTimeDelay >= 0.0f); + const float currentUserMassThreshold = currentDestructibleActor.getStressSolverMassThreshold(); + PX_ASSERT(currentUserMassThreshold >= 0.0f); + if(currentUserTimeDelay < userTimeDelay) + { + userTimeDelay = currentUserTimeDelay; + } + if(currentUserMassThreshold < userMassThreshold) + { + userMassThreshold = currentUserMassThreshold; + } + } + PX_ASSERT(userTimeDelay < PX_MAX_F32); + PX_ASSERT(userMassThreshold < PX_MAX_F32); + //Define the real joint for the chunks within the Actors + isPhysxBasedSim = false; + isSimulating = false; + if(strength_ > 0) + { + createShadowScene(MaxWarmingFrame,MaxActiveCycle,strength_); + } +} + +DestructibleStructureStressSolver::~DestructibleStructureStressSolver() +{ + if(isPhysxBasedSim) + { + removePhysStressSolver(); + } + while(!snapEventContainer.empty()) + { + snapEventContainer.popBack()->onDestroy(); + } + if(NULL != scratchBuffer) + { + PX_ASSERT(!scratchBufferLocked); + PX_FREE(scratchBuffer); // use PX_FREE(x) instead of PX_DELETE([]x) + scratchBuffer = NULL; + } + if(NULL != structureLinkCondition) + { + PX_FREE(structureLinkCondition); // use PX_FREE(x) instead of PX_DELETE([]x) + structureLinkCondition = NULL; + } +} + +void DestructibleStructureStressSolver::onTick(float deltaTime) +{ + PX_ASSERT(deltaTime >= 0.0f); + if(!snapEventContainer.empty()) + { + uint32_t expiredSnapEventCount = 0; + + // update and fracture ripe linked chunk(s) + for(physx::Array<SnapEvent*>::ConstIterator kIter = snapEventContainer.begin(); kIter != snapEventContainer.end(); ++kIter) + { + SnapEvent & currentSnapEvent = *(*kIter); + PX_ASSERT(NULL != ¤tSnapEvent); + const bool snapEventJustRipe = currentSnapEvent.isRipeAfterUpdatingTime(deltaTime); + if(snapEventJustRipe) + { + for(uint32_t index = 0; index < currentSnapEvent.getFractureEventProxyCount(); ++index) + { + // skip fracturing linked chunks that were fractured in the meantime + const FractureEventProxy & currentFractureEventProxy = currentSnapEvent.getFractureEventProxy(index); + PX_ASSERT(NULL != ¤tFractureEventProxy); + const uint32_t currentLinkedChunkIndex = currentFractureEventProxy.rootLinkedChunkIndex; + PX_ASSERT(assertLinkedChunkIndexOk(currentLinkedChunkIndex)); + if(!isLinkedChunkBroken(currentLinkedChunkIndex)) + { + setLinkedChunkBroken(currentLinkedChunkIndex); + const FractureEvent & currentFractureEvent = interpret(currentFractureEventProxy); + PX_ASSERT(NULL != ¤tFractureEvent); + getBindedStructureMutable().fractureChunk(currentFractureEvent); + } + } + continue; + } + else + { + if(currentSnapEvent.isExpired()) + { + ++expiredSnapEventCount; + continue; + } + } + } + + // clear the container if it no longer contain any pending snap events + PX_ASSERT(expiredSnapEventCount <= snapEventContainer.size()); + if(snapEventContainer.size() == expiredSnapEventCount) + { + while(!snapEventContainer.empty()) + { + snapEventContainer.popBack()->onDestroy(); + } + } + } +} + +void DestructibleStructureStressSolver::physcsBasedStressSolverTick() +{ + PX_PROFILE_ZONE("DestructiblePhysBasedStressSolver", GetInternalApexSDK()->getContextId()); + + if(currentWarmingFrame < initialWarmFrames) + { + currentWarmingFrame++; + } + else + { + initializingMaxForce = false; + } + if(continuousNoUpdationCount > MaxLeaveInAdvaceWarmingWindow) + { + initializingMaxForce = false; + } + uint32_t breakChunk = 0xFFFFFFFF; + + if(initializingMaxForce || !isSleep) + { + breakChunk = predictBreakChunk(ShadowSceneDeltaTime,supportStrength); + } + if(currentActiveSimulationFrame < activeCycle) + { + if(isActiveWakedUp) + { + isSleep = false; + } + ++currentActiveSimulationFrame; + } + else + { + isSleep = true; + currentActiveSimulationFrame = 0; + } + isActiveWakedUp = false; + if(!initializingMaxForce) + { + for(uint32_t i = 0;i < this->initialWarmingKillList.size();i++) + { + removeChunkFromShadowScene(true,initialWarmingKillList[i]); + } + initialWarmingKillList.clear(); + for(uint32_t i = 0;i < islandKillList.size();i++) + { + isActiveWakedUp = true; + if(!initializingMaxForce) + { + removeChunkFromShadowScene(false,islandKillList[i]); + } + } + islandKillList.clear(); + } + + + if(breakChunk == 0xFFFFFFFF) + { + return; + } + else + { + breakChunks(breakChunk); + } +} + +void DestructibleStructureStressSolver::removeChunkFromIsland(uint32_t index) +{ + islandKillList.pushBack(index); +} + +void DestructibleStructureStressSolver::breakChunks(uint32_t breakChunk) +{ + removeChunkFromShadowScene(false, breakChunk); + DestructibleStructure::Chunk &chunk = getBindedStructureMutable().chunks[breakChunk]; + if(!chunk.isDestroyed()) + { + FractureEvent e2; + e2.position= getBindedStructureMutable().getChunkWorldCentroid(chunk); + e2.chunkIndexInAsset = chunk.indexInAsset; + e2.impulse= PxVec3(0.0f); + e2.destructibleID = chunk.destructibleID; + e2.flags= chunk.flags; + e2.hitDirection = PxVec3(0.0f); + getBindedStructureMutable().fractureChunk(e2); + } +} + +void DestructibleStructureStressSolver::calculateMaxForce(uint32_t& index, float supportStrength_) +{ + PX_PROFILE_ZONE("DestructiblePhysBasedStressSolverCalculateForce", GetInternalApexSDK()->getContextId()); + float maximumForce = 0; + uint32_t maximumIndex = 0xFFFFFFFF; + PxVec3 linearForce(0),angularForce(0); + uint32_t updateCount = 0; + for(uint32_t i = 0;i < linkedJoint.size();i++) + { + if(!linkedJoint[i].isDestroyed) + { + linkedJoint[i].joint->getConstraint()->getForce(linearForce,angularForce); + forces[linkedJoint[i].actor1Index] += angularForce.magnitude(); + } + } + for(uint32_t i = 0;i<forces.size();i++) + { + if(!shadowActors[i].isDestroyed) + { + shadowActors[i].currentForce = forces[i]; + if(initializingMaxForce) + { + if(forces[i] > shadowActors[i].maxInitialForce) + { + updateCount++; + } + shadowActors[i].maxInitialForce = PxMax( shadowActors[i].maxInitialForce,forces[i]); + } + if(forces[i] > maximumForce) + { + maximumForce = forces[i]; + maximumIndex = i; + } + } + } + for(uint32_t i = 0; i<forces.size();i++) + { + forces[i] = 0; + } + + if(updateCount <= (supportChunkSize/((MaxLeaveInAdvaceWarmingWindow*2)))) + { + if(isNoChunkWarmingUpdate) + { + continuousNoUpdationCount++; + } + isNoChunkWarmingUpdate = true; + } + else + { + isNoChunkWarmingUpdate = false; + continuousNoUpdationCount = 0; + } + if(initializingMaxForce) + { + index = 0xFFFFFFFF; + return; + } + if(maximumIndex < shadowActors.size() && shadowActors[maximumIndex].currentForce >= shadowActors[maximumIndex].maxInitialForce* (1+supportStrength_)) + { + index = bindedStructureAlias.supportDepthChunks[maximumIndex]; + return; + } + else + { + index = 0xFFFFFFFF; + return; + } + return; +} + +void DestructibleStructureStressSolver::removeChunkFromShadowScene(bool localIndex, uint32_t index) +{ + PX_PROFILE_ZONE("DestructiblePhysBasedStressSolverRemoveChunk", GetInternalApexSDK()->getContextId()); + if(!localIndex) + { + index = globalHashedtoSupportChunks[index]; + } + if(index == 0xFFFFFFFF) + { + return; + } + if(initializingMaxForce) + { + initialWarmingKillList.pushBack(index); + return; + } + if(!shadowActors[index].isDestroyed) + { + shadowScene->removeActor(*shadowActors[index].actor); + isActiveWakedUp = true; + shadowActors[index].isDestroyed = true; + } +} + +uint32_t DestructibleStructureStressSolver::predictBreakChunk(float deltaTime, float supportStrength_) +{ + // Simulate shadowScene for prediction + uint32_t maximumIndex = 0xFFFFFFFF; + //if(shadowScene->checkResults()) + { + if(isSimulating) + { + shadowScene->fetchResults(true); + } + } + + shadowScene->simulate(deltaTime); + isSimulating = true; + + calculateMaxForce(maximumIndex,supportStrength_); + return maximumIndex; +} + +void DestructibleStructureStressSolver::resetActiveCycle(uint32_t actCycle) +{ + activeCycle = actCycle; +} + +void DestructibleStructureStressSolver::resetInitialWarmFrames(uint32_t iniWarmFrames) +{ + initialWarmFrames = iniWarmFrames; +} + +void DestructibleStructureStressSolver::resetSupportStrength(float supStrength) +{ + supportStrength = supStrength; +} + +void DestructibleStructureStressSolver::createShadowScene(uint32_t initialWarmFrames_,uint32_t actCycle, float supStrength) +{ + + PX_PROFILE_ZONE("DestructiblePhysBasedStressSolverInitial", GetInternalApexSDK()->getContextId()); + //Initialize Parameters + initializingMaxForce = true; + isSimulating = false; + initialWarmFrames = initialWarmFrames_; + currentWarmingFrame = 0; + supportChunkSize = bindedStructureAlias.supportDepthChunks.size(); + isSleep = true; + isActiveWakedUp = false; + currentActiveSimulationFrame = 0; + continuousNoUpdationCount = 0; + activeCycle = actCycle; + isPhysxBasedSim = true; + activeCycle = actCycle; + supportStrength = supStrength; + isCustomEnablesSimulating = true; + isNoChunkWarmingUpdate = false; + + //Initialize the shadow scene + + bindedStructureAlias.dscene->getApexScene()->getPhysXScene()->lockRead(); + + newSceneSDK = &bindedStructureAlias.dscene->getApexScene()->getPhysXScene()->getPhysics(); + PxSceneDesc sceneDesc(newSceneSDK->getTolerancesScale()); + sceneDesc.gravity = bindedStructureAlias.dscene->getApexScene()->getGravity(); + sceneDesc.cpuDispatcher = PxDefaultCpuDispatcherCreate(4); + sceneDesc.filterCallback = NULL; + sceneDesc.filterShader = bindedStructureAlias.dscene->getApexScene()->getPhysXScene()->getFilterShader(); + shadowScene = newSceneSDK->createScene(sceneDesc); + shadowScene->setSimulationEventCallback(NULL); + + bindedStructureAlias.dscene->getApexScene()->getPhysXScene()->unlockRead(); + + + //Initialize arrays + globalHashedtoSupportChunks.resize(bindedStructureAlias.chunks.size()); + shadowActors.resize(supportChunkSize); + for(uint32_t i = 0;i < supportChunkSize; ++i) + { + globalHashedtoSupportChunks[i] = 0xFFFFFFFF; + } + for(uint32_t i = 0 ;i < supportChunkSize; ++i) + { + globalHashedtoSupportChunks[bindedStructureAlias.supportDepthChunks[i]] = i; + } + PxBounds3 bound; + bound.setEmpty(); + for(uint32_t i = 0; i < supportChunkSize; ++i) + { + if(!bindedStructureAlias.chunks[bindedStructureAlias.supportDepthChunks[i]].isDestroyed()) + { + bound.include(bindedStructureAlias.getChunkWorldCentroid(bindedStructureAlias.chunks[bindedStructureAlias.supportDepthChunks[i]])); + } + } + PxVec3 translate = bound.getCenter(); + for(uint32_t i = 0; i< supportChunkSize; ++i) + { + forces.pushBack(0); + } + //Initialize shadow actors + for(uint32_t i = 0;i < supportChunkSize;++i) + { + const nvidia::destructible::DestructibleStructure::Chunk* chunk = &bindedStructureAlias.chunks[bindedStructureAlias.supportDepthChunks[i]]; + if(!chunk->isDestroyed()/*&&!(chunk->flags&ChunkRemoved)*/) // BRG - reclaimed ChunkRemoved bit. This should not have been used here anyhow - it had function-limited scope + { + shadowActors[i].actor = newSceneSDK->createRigidDynamic(PxTransform(bindedStructureAlias.getChunkWorldCentroid(bindedStructureAlias.chunks[bindedStructureAlias.supportDepthChunks[i]])-translate)); + DestructibleActorImpl* dactor = bindedStructureAlias.dscene->mDestructibles.direct(chunk->destructibleID); + shadowActors[i].actor->setMass(dactor->getChunkMass(chunk->indexInAsset)); + shadowScene->addActor(*shadowActors[i].actor); + shadowActors[i].actor->wakeUp(); + shadowActors[i].isDestroyed = false; + shadowActors[i].currentForce = 0.0; + shadowActors[i].maxInitialForce = 0.0; + //Add the static joint objects to the externally supported chunks + if(chunk->flags& ChunkExternallySupported) + { + PxFixedJointCreate(*newSceneSDK,shadowActors[i].actor,PxTransform(PxVec3(0.0f, 0.0, 0.0f), PxQuat(PxIdentity)),NULL,shadowActors[i].actor->getGlobalPose()); + } + } + else + { + shadowActors[i].isDestroyed=true; + } + } + //Create the joints using a local hash array.. .after that we clear it. + Array<Array<bool> > linkedHash; + linkedHash.resize(supportChunkSize); + for(uint32_t i = 0;i < supportChunkSize;++i) + { + linkedHash[i].resize(supportChunkSize); + for(uint32_t j = 0;j < supportChunkSize; ++j) + { + linkedHash[i][j]=false; + } + } + //Link all the chunks which are overlapping. + for(uint32_t i = 0; i < supportChunkSize;++i) + { + const uint32_t firstOverlapIndex = bindedStructureAlias.firstOverlapIndices[bindedStructureAlias.supportDepthChunks[i]]; + const uint32_t stopOverlapIndex = bindedStructureAlias.firstOverlapIndices[bindedStructureAlias.supportDepthChunks[i]+1]; + for(uint32_t index = firstOverlapIndex; index < stopOverlapIndex; ++index) + { + const uint32_t currentLinkedChunkIndex = bindedStructureAlias.overlaps[index]; + linkedHash[globalHashedtoSupportChunks[currentLinkedChunkIndex]][i]=true; + linkedHash[i][globalHashedtoSupportChunks[currentLinkedChunkIndex]]=true; + } + } + //We use hash since we don't know if there is redundant overlapping info, for example A-B and B-A.So we should gurantee that only one joint is linked between two rigid bodies. + //The overhead to initial hash is not so big since it is in the initializing stage, not affect the frame rate when simulating. + for(uint32_t i = 0; i < supportChunkSize; ++i ) + { + for(uint32_t j = 0; j < i; ++j) + { + if(linkedHash[i][j]) + { + //Create the joints for actor1 and actor2 + if(!shadowActors[i].isDestroyed&&!shadowActors[j].isDestroyed) + { + PxFixedJoint* createdJoint = PxFixedJointCreate(*newSceneSDK,shadowActors[i].actor,shadowActors[j].actor->getGlobalPose(),shadowActors[j].actor,shadowActors[i].actor->getGlobalPose()); + if(createdJoint) + { + LinkedJoint joint; + joint.actor1Index = i; + joint.actor2Index = j; + joint.isDestroyed = false; + joint.joint = createdJoint; + linkedJoint.pushBack(joint); + } + } + } + } + } + for(uint32_t i = 0;i < linkedHash.size(); ++i) + { + linkedHash[i].clear(); + } + linkedHash.clear(); +} + +void DestructibleStructureStressSolver::enablePhyStressSolver(float strength) +{ + PX_ASSERT(strength > 0); + isCustomEnablesSimulating = true; + if(!isPhysxBasedSim) + { + createShadowScene(MaxWarmingFrame,MaxActiveCycle,strength); + } + bindedStructureAlias.dscene->setStructureUpdate(&getBindedStructureMutable(), true); // Get a tick to update this +} + +void DestructibleStructureStressSolver::removePhysStressSolver() +{ + if(isPhysxBasedSim) + { + for(uint32_t i=0;i<shadowActors.size();i++) + { + if(!shadowActors[i].isDestroyed) + { + shadowScene->removeActor(*shadowActors[i].actor); + } + } + shadowActors.clear(); + for(uint32_t i=0;i<linkedJoint.size();i++) + { + if(!linkedJoint[i].isDestroyed) + { + if(linkedJoint[i].joint) + { + linkedJoint[i].joint->release(); + linkedJoint[i].joint=NULL; + } + } + } + linkedJoint.clear(); + + if (isSimulating) + { + shadowScene->fetchResults(true); + isSimulating = false; + } + + if(shadowScene) + { + shadowScene->release(); + } + + globalHashedtoSupportChunks.clear(); + initialWarmingKillList.clear(); + islandKillList.clear(); + forces.clear(); + } +} + +void DestructibleStructureStressSolver::disablePhyStressSolver() +{ + isCustomEnablesSimulating = false; +} + +void DestructibleStructureStressSolver::onUpdate(uint32_t linkedChunkIndex) +{ + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + if(!isLinkedChunkBroken(linkedChunkIndex)) + { + setLinkedChunkBroken(linkedChunkIndex); + recentlyBrokenLinkedChunkIndices.pushBack(linkedChunkIndex); + } +} + +void DestructibleStructureStressSolver::onResolve() +{ + physx::Array<uint32_t> linkedChunkIndicesForEvaluation; + processLinkedChunkIndicesForEvaluation(linkedChunkIndicesForEvaluation); + if(!linkedChunkIndicesForEvaluation.empty()) + { + evaluateForPotentialIslands(linkedChunkIndicesForEvaluation); + } +} + +void DestructibleStructureStressSolver::processLinkedChunkIndicesForEvaluation(physx::Array<uint32_t> & linkedChunkIndicesForEvaluation) +{ + PX_ASSERT(NULL != &linkedChunkIndicesForEvaluation); + PX_ASSERT(linkedChunkIndicesForEvaluation.empty()); + + StructureScratchBuffer evaluationRecord = acquireScratchBuffer(); + + // avoid getting snap events' links because they either pending fracture or are already broken (the snap event container only clear out when all snap events have been executed) + for(physx::Array<SnapEvent*>::ConstIterator kIter = snapEventContainer.begin(); kIter != snapEventContainer.end(); ++kIter) + { + SnapEvent & currentSnapEvent = *(*kIter); + PX_ASSERT(NULL != ¤tSnapEvent); + for(uint32_t index = 0; index < currentSnapEvent.getFractureEventProxyCount(); ++index) + { + const uint32_t currentLinkedChunkIndex = currentSnapEvent.getFractureEventProxy(index).rootLinkedChunkIndex; + PX_ASSERT(assertLinkedChunkIndexOk(currentLinkedChunkIndex)); + if(!evaluationRecord.isOccupied(currentLinkedChunkIndex)) + { + evaluationRecord.setOccupied(currentLinkedChunkIndex); + } + } + } + + // push unique adjacent unbroken links of recently broken links + while(!recentlyBrokenLinkedChunkIndices.empty()) + { + const uint32_t currentLinkedChunkIndex = recentlyBrokenLinkedChunkIndices.popBack(); + PX_ASSERT(assertLinkedChunkIndexOk(currentLinkedChunkIndex)); + physx::Array<uint32_t> unbrokenAdjacentLinkedChunkIndices; + getUnbrokenAdjacentLinkedChunkIndices(currentLinkedChunkIndex, unbrokenAdjacentLinkedChunkIndices); + for(physx::Array<uint32_t>::ConstIterator kIter = unbrokenAdjacentLinkedChunkIndices.begin(); kIter != unbrokenAdjacentLinkedChunkIndices.end(); ++kIter) + { + const uint32_t currentUnbrokenAdjacentLinkedChunkIndex = *kIter; + PX_ASSERT(assertLinkedChunkIndexOk(currentUnbrokenAdjacentLinkedChunkIndex)); + if(!evaluationRecord.isOccupied(currentUnbrokenAdjacentLinkedChunkIndex)) + { + evaluationRecord.setOccupied(currentUnbrokenAdjacentLinkedChunkIndex); + linkedChunkIndicesForEvaluation.pushBack(currentUnbrokenAdjacentLinkedChunkIndex); + } + } + } + + // push unique previously-identified strained links + if(!strainedLinkedChunkIndices.empty()) + { + bool containerRequireRefresh = false; + + // we also take this chance to mark links that may already be broken off + for(physx::Array<uint32_t>::Iterator iter = strainedLinkedChunkIndices.begin(); iter != strainedLinkedChunkIndices.end(); ++iter) + { + const uint32_t currentLinkedChunkIndex = *iter; + PX_ASSERT(assertLinkedChunkIndexOk(currentLinkedChunkIndex)); + PX_ASSERT(InvalidLinkedChunkIndex != *iter); + if(isLinkedChunkBroken(currentLinkedChunkIndex)) + { + *iter = InvalidLinkedChunkIndex; + containerRequireRefresh = true; + } + else + { + PX_ASSERT(isLinkedChunkStrained(currentLinkedChunkIndex)); + if(!evaluationRecord.isOccupied(currentLinkedChunkIndex)) + { + evaluationRecord.setOccupied(currentLinkedChunkIndex); + linkedChunkIndicesForEvaluation.pushBack(currentLinkedChunkIndex); + } + } + } + + // update the container to hold only unbroken links + if(containerRequireRefresh) + { + physx::Array<uint32_t> updatedContainer; + for(physx::Array<uint32_t>::ConstIterator kIter = strainedLinkedChunkIndices.begin(); kIter != strainedLinkedChunkIndices.end(); ++kIter) + { + if(InvalidLinkedChunkIndex != *kIter) + { + updatedContainer.pushBack(*kIter); + } + } + strainedLinkedChunkIndices = updatedContainer; + } + } + + relinquishScratchBuffer(); + PX_ASSERT(assertLinkedChunkIndicesForEvaluationOk(linkedChunkIndicesForEvaluation)); + PX_ASSERT(recentlyBrokenLinkedChunkIndices.empty()); +} + +void DestructibleStructureStressSolver::evaluateForPotentialIslands(const physx::Array<uint32_t> & linkedChunkIndicesForEvaluation) +{ + PX_COMPILE_TIME_ASSERT(2 == DestructibleStructureStressSolver::PathTraversalCount); + PX_ASSERT(NULL != &linkedChunkIndicesForEvaluation); + PX_ASSERT(!linkedChunkIndicesForEvaluation.empty()); + for(physx::Array<uint32_t>::ConstIterator kIter = linkedChunkIndicesForEvaluation.begin(); kIter != linkedChunkIndicesForEvaluation.end(); ++kIter) + { + const uint32_t currentLinkedChunkIndex = *kIter; + PX_ASSERT(assertLinkedChunkIndexOk(currentLinkedChunkIndex)); + physx::Array<uint32_t> unbrokenAdjacentLinkedChunkIndices; + if(passLinkCountTest(currentLinkedChunkIndex, unbrokenAdjacentLinkedChunkIndices)) + { + PX_ASSERT(!unbrokenAdjacentLinkedChunkIndices.empty()); + uint32_t linkedChunkIndicesForTraversal[2] = {InvalidLinkedChunkIndex, InvalidLinkedChunkIndex}; + if(passLinkAdjacencyTest(unbrokenAdjacentLinkedChunkIndices, linkedChunkIndicesForTraversal)) + { + PX_ASSERT(InvalidLinkedChunkIndex != linkedChunkIndicesForTraversal[0] && InvalidLinkedChunkIndex != linkedChunkIndicesForTraversal[1]); + evaluateForPotentialPeninsulas(currentLinkedChunkIndex, linkedChunkIndicesForTraversal); + } + } + } +} + +bool DestructibleStructureStressSolver::passLinkCountTest(uint32_t linkedChunkIndex, physx::Array<uint32_t> & unbrokenAdjacentLinkedChunkIndices) const +{ + PX_COMPILE_TIME_ASSERT(2 == DestructibleStructureStressSolver::LowerLimitActivationCount && 3 == DestructibleStructureStressSolver::UpperLimitActivationCount); + bool passLinkCountTest = false; + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + PX_ASSERT(NULL != &unbrokenAdjacentLinkedChunkIndices); + PX_ASSERT(unbrokenAdjacentLinkedChunkIndices.empty()); + + // check that the candidate linked chunk has 2 or 3 remaining unbroken links, and that initially it had more + const uint32_t firstOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndex]; + const uint32_t stopOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndex + 1]; + const uint32_t initialLinkCount = stopOverlapIndex - firstOverlapIndex; + if(initialLinkCount > 2) + { + uint32_t unbrokenLinkCount = 0; + for(uint32_t index = firstOverlapIndex; index < stopOverlapIndex; ++index) + { + const uint32_t currentLinkedChunkIndex = bindedStructureAlias.overlaps[index]; + if(!isLinkedChunkBroken(currentLinkedChunkIndex)) + { + ++unbrokenLinkCount; + if(unbrokenLinkCount > 3) + { + break; + } + } + } + switch(unbrokenLinkCount) + { + case 0: + // ignore + break; + case 1: + // ignore + break; + case 2: + { + PX_ASSERT(initialLinkCount > 2); + getUnbrokenAdjacentLinkedChunkIndices(linkedChunkIndex, unbrokenAdjacentLinkedChunkIndices); + passLinkCountTest = true; + } + break; + case 3: + { + if(initialLinkCount > 3) + { + getUnbrokenAdjacentLinkedChunkIndices(linkedChunkIndex, unbrokenAdjacentLinkedChunkIndices); + passLinkCountTest = true; + } + } + break; + case 4: + // ignore + break; + default: + PX_ASSERT(!"!"); + } + } + PX_ASSERT(passLinkCountTest ? (2 == unbrokenAdjacentLinkedChunkIndices.size() || 3 == unbrokenAdjacentLinkedChunkIndices.size()) : unbrokenAdjacentLinkedChunkIndices.empty()); + return passLinkCountTest; +} + +bool DestructibleStructureStressSolver::passLinkAdjacencyTest(const physx::Array<uint32_t> & unbrokenAdjacentLinkedChunkIndices, uint32_t (&linkedChunkIndicesForTraversal)[2]) const +{ + PX_COMPILE_TIME_ASSERT(2 == DestructibleStructureStressSolver::LowerLimitActivationCount && 3 == DestructibleStructureStressSolver::UpperLimitActivationCount); + PX_COMPILE_TIME_ASSERT(2 == DestructibleStructureStressSolver::PathTraversalCount); + bool passLinkAdjacencyTest = false; + PX_ASSERT(NULL != &unbrokenAdjacentLinkedChunkIndices); + PX_ASSERT(2 == unbrokenAdjacentLinkedChunkIndices.size() || 3 == unbrokenAdjacentLinkedChunkIndices.size()); + PX_ASSERT(NULL != linkedChunkIndicesForTraversal); + linkedChunkIndicesForTraversal[0] = InvalidLinkedChunkIndex; + linkedChunkIndicesForTraversal[1] = InvalidLinkedChunkIndex; + + // check that the candidate linked chunk has 2 traversal paths which are not immediately adjacent to each other, and that only 1 traversal path can optionally include 1 different starting point + const uint32_t unbrokenLinkCount = unbrokenAdjacentLinkedChunkIndices.size(); + switch(unbrokenLinkCount) + { + case 2: + { + // the 2 linked chunks must not be adjacent to each other + if(!areUnbrokenLinkedChunksAdjacent(unbrokenAdjacentLinkedChunkIndices[0], unbrokenAdjacentLinkedChunkIndices[1])) + { + linkedChunkIndicesForTraversal[0] = unbrokenAdjacentLinkedChunkIndices[0]; + linkedChunkIndicesForTraversal[1] = unbrokenAdjacentLinkedChunkIndices[1]; + passLinkAdjacencyTest = true; + } + } + break; + case 3: + { + // if 2 linked chunks are adjacent, the 3rd linked chunk cannot be adjacent to either one + if(areUnbrokenLinkedChunksAdjacent(unbrokenAdjacentLinkedChunkIndices[0], unbrokenAdjacentLinkedChunkIndices[1])) + { + if(!areUnbrokenLinkedChunksAdjacent(unbrokenAdjacentLinkedChunkIndices[0], unbrokenAdjacentLinkedChunkIndices[2]) && + !areUnbrokenLinkedChunksAdjacent(unbrokenAdjacentLinkedChunkIndices[1], unbrokenAdjacentLinkedChunkIndices[2]) ) + { + linkedChunkIndicesForTraversal[0] = unbrokenAdjacentLinkedChunkIndices[0]; + linkedChunkIndicesForTraversal[1] = unbrokenAdjacentLinkedChunkIndices[2]; + passLinkAdjacencyTest = true; + } + } + // if 2 linked chunks are not adjacent, the 3rd linked chunk must be adjacent to only one other linked chunk + else + { + if( areUnbrokenLinkedChunksAdjacent(unbrokenAdjacentLinkedChunkIndices[0], unbrokenAdjacentLinkedChunkIndices[2]) ? + !areUnbrokenLinkedChunksAdjacent(unbrokenAdjacentLinkedChunkIndices[1], unbrokenAdjacentLinkedChunkIndices[2]) : + areUnbrokenLinkedChunksAdjacent(unbrokenAdjacentLinkedChunkIndices[1], unbrokenAdjacentLinkedChunkIndices[2]) ) + { + linkedChunkIndicesForTraversal[0] = unbrokenAdjacentLinkedChunkIndices[0]; + linkedChunkIndicesForTraversal[1] = unbrokenAdjacentLinkedChunkIndices[1]; + passLinkAdjacencyTest = true; + } + } + } + break; + default: + PX_ASSERT(!"!"); + } + PX_ASSERT(passLinkAdjacencyTest ? (InvalidLinkedChunkIndex != linkedChunkIndicesForTraversal[0] && InvalidLinkedChunkIndex != linkedChunkIndicesForTraversal[1]) : (InvalidLinkedChunkIndex == linkedChunkIndicesForTraversal[0] && InvalidLinkedChunkIndex == linkedChunkIndicesForTraversal[1])); + return passLinkAdjacencyTest; +} + +void DestructibleStructureStressSolver::evaluateForPotentialPeninsulas(uint32_t rootLinkedChunkIndex, const uint32_t (&linkedChunkIndicesForTraversal)[2]) +{ + PX_COMPILE_TIME_ASSERT(2 == DestructibleStructureStressSolver::PathTraversalCount); + PX_ASSERT(assertLinkedChunkIndexOk(rootLinkedChunkIndex)); + PX_ASSERT(NULL != linkedChunkIndicesForTraversal); + + // collect both peninsulas' data + PeninsulaData peninsulaData[2]; + for(uint32_t index = 0; index < 2; ++index) + { + StructureScratchBuffer traverseRecord = acquireScratchBuffer(); + traverseRecord.setOccupied(rootLinkedChunkIndex); + peninsulaData[index].resetData(); + peninsulaData[index] = traverseLink(linkedChunkIndicesForTraversal[index], traverseRecord); + peninsulaData[index].setRootLinkedChunkIndex(rootLinkedChunkIndex); + relinquishScratchBuffer(); + } + + evaluatePeninsulas(peninsulaData); +} + +PeninsulaData DestructibleStructureStressSolver::traverseLink(uint32_t linkedChunkIndex, StructureScratchBuffer & traverseRecord) const +{ + PeninsulaData peninsulaData; + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + + // this will not count as a valid peninsula if it contains any chunk that is being externally supported + traverseRecord.setOccupied(linkedChunkIndex); + if(0 != (ChunkExternallySupported & bindedStructureAlias.chunks[linkedChunkIndex].flags)) + { + peninsulaData.setFlag(PeninsulaData::PeninsulaEncounteredExternalSupport); + } + if(isLinkedChunkStrained(linkedChunkIndex)) + { + peninsulaData.setFlag(PeninsulaData::PeninsulaEncounteredAnotherWeakLink); + } + + // gather data for remaining unbroken links + if(peninsulaData.isValid()) + { + peninsulaData.setLinkedChunkData(getActorChunkPair(linkedChunkIndex), Int2Type<StressEvaluationEnum>()); + const uint32_t firstOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndex]; + const uint32_t stopOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndex + 1]; + for(uint32_t index = firstOverlapIndex; index < stopOverlapIndex; ++index) + { + const uint32_t currentLinkedChunkIndex = bindedStructureAlias.overlaps[index]; + if(!isLinkedChunkBroken(currentLinkedChunkIndex)) + { + if(!traverseRecord.isOccupied(currentLinkedChunkIndex)) + { + peninsulaData.assimilate(traverseLink(currentLinkedChunkIndex, traverseRecord), Int2Type<StressEvaluationEnum>()); + if(!peninsulaData.isValid()) + { + peninsulaData.resetData(); + break; + } + } + } + } + } + + return peninsulaData; +} + +void DestructibleStructureStressSolver::evaluatePeninsulas(const PeninsulaData (&peninsulasForEvaluation)[2]) +{ + PX_COMPILE_TIME_ASSERT(2 == DestructibleStructureStressSolver::PathTraversalCount); + PX_ASSERT(NULL != peninsulasForEvaluation); + + // determine type of operation + const bool trySnapOffWithinFreeIsland = !peninsulasForEvaluation[0].hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport) && !peninsulasForEvaluation[1].hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport); + const bool trySnapOffFromSupportedPeninsula = peninsulasForEvaluation[0].hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport) ^ peninsulasForEvaluation[1].hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport); + const bool trackLinkForFutureEvaluation = peninsulasForEvaluation[0].hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport) && peninsulasForEvaluation[1].hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport); + PX_ASSERT(trySnapOffWithinFreeIsland ? !trySnapOffFromSupportedPeninsula && !trackLinkForFutureEvaluation : trySnapOffFromSupportedPeninsula ? !trackLinkForFutureEvaluation : trackLinkForFutureEvaluation); + + // try snapping off based on data of the peninsula with more mass + if(trySnapOffWithinFreeIsland) + { + const PeninsulaData & subjectPeninsulaData = peninsulasForEvaluation[0].getDataAggregateMass() > peninsulasForEvaluation[1].getDataAggregateMass() ? peninsulasForEvaluation[0] : peninsulasForEvaluation[1]; + SnapEvent * snapEvent = NULL; + snapEvent = interpret(subjectPeninsulaData, Int2Type<StressEvaluationEnum>()); + if(NULL != snapEvent) + { + snapEventContainer.pushBack(snapEvent); + snapEvent = NULL; + } + } + // try snapping off based on data of the peninsula that is not being externally supported + else if(trySnapOffFromSupportedPeninsula) + { + const PeninsulaData & subjectPeninsulaData = peninsulasForEvaluation[0].hasFlag(PeninsulaData::PeninsulaEncounteredExternalSupport) ? peninsulasForEvaluation[1] : peninsulasForEvaluation[0]; + SnapEvent * snapEvent = NULL; + snapEvent = interpret(subjectPeninsulaData, Int2Type<StressEvaluationEnum>()); + if(NULL != snapEvent) + { + snapEventContainer.pushBack(snapEvent); + snapEvent = NULL; + } + } + // track this link for re-evaluation because it is susceptible to snapping off + else if(trackLinkForFutureEvaluation) + { + PX_ASSERT(peninsulasForEvaluation[0].getRootLinkedChunkIndex() == peninsulasForEvaluation[1].getRootLinkedChunkIndex()); + const uint32_t linkedChunkIndex = peninsulasForEvaluation[0].getRootLinkedChunkIndex(); + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + if(!isLinkedChunkStrained(linkedChunkIndex)) + { + setLinkedChunkStrained(linkedChunkIndex); + strainedLinkedChunkIndices.pushBack(linkedChunkIndex); + } + } +} + +SnapEvent * DestructibleStructureStressSolver::interpret(const PeninsulaData & peninsulaData, Int2Type<StressEvaluationType::EvaluateByCount>) const +{ + SnapEvent * snapEvent= NULL; + PX_ASSERT(NULL != &peninsulaData); + const bool stressConditionPassed = (peninsulaData.getDataChunkCount() > 20); + if(stressConditionPassed) + { + const bool breakAdjacentLinkedChunks = true; + + // set up data for proxy fracture events + physx::Array<uint32_t> unbrokenAdjacentLinkedChunkIndices; + const uint32_t linkedChunkIndex = peninsulaData.getRootLinkedChunkIndex(); + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + if(breakAdjacentLinkedChunks) + { + getUnbrokenAdjacentLinkedChunkIndices(linkedChunkIndex, unbrokenAdjacentLinkedChunkIndices); + } + FractureEventProxy * fractureEventProxyBufferStart = NULL; + const uint32_t fractureEventProxyBufferCount = 1 + unbrokenAdjacentLinkedChunkIndices.size(); + fractureEventProxyBufferStart = PX_NEW(FractureEventProxy)[fractureEventProxyBufferCount]; + ::memset(static_cast<void*>(fractureEventProxyBufferStart), 0x00, fractureEventProxyBufferCount * sizeof(FractureEventProxy)); + + // set up data for primary weak link + ActorChunkPair actorChunkPair = getActorChunkPair(linkedChunkIndex); + FractureEventProxy & fractureEventProxy = fractureEventProxyBufferStart[0]; + fractureEventProxy.rootLinkedChunkIndex = linkedChunkIndex; + fractureEventProxy.chunkIndexInAsset = actorChunkPair.chunkAlias->indexInAsset; + fractureEventProxy.destructibleId = actorChunkPair.actorAlias->getID(); + fractureEventProxy.fractureEventProxyFlags = 0; + fractureEventProxy.fractureEventProxyFlags |= FractureEvent::Snap; + fractureEventProxy.rootLinkedChunkPosition = PxVec3(0.0f); + fractureEventProxy.impulse = PxVec3(0.0f); + + // set up data for secondary weak links + if(breakAdjacentLinkedChunks) + { + for(uint32_t index = 0; index < unbrokenAdjacentLinkedChunkIndices.size(); ++index) + { + ActorChunkPair currentActorChunkPair = getActorChunkPair(unbrokenAdjacentLinkedChunkIndices[index]); + FractureEventProxy & currentFractureEventProxy = fractureEventProxyBufferStart[1 + index]; + currentFractureEventProxy.rootLinkedChunkIndex = unbrokenAdjacentLinkedChunkIndices[index]; + currentFractureEventProxy.chunkIndexInAsset = currentActorChunkPair.chunkAlias->indexInAsset; + currentFractureEventProxy.destructibleId = currentActorChunkPair.actorAlias->getID(); + currentFractureEventProxy.fractureEventProxyFlags = 0; + currentFractureEventProxy.fractureEventProxyFlags |= FractureEvent::Snap; + currentFractureEventProxy.rootLinkedChunkPosition = PxVec3(0.0f); + currentFractureEventProxy.impulse = PxVec3(0.0f); + } + } + + // store them in a snap event + const float tickSecondsToSnap = peninsulaData.getDataChunkCount() > 40 ? 2.5f : 5.0f; + PX_ASSERT(NULL != fractureEventProxyBufferStart && 0 != fractureEventProxyBufferCount); + snapEvent = SnapEvent::instantiate(fractureEventProxyBufferStart, fractureEventProxyBufferCount, tickSecondsToSnap); + PX_ASSERT(NULL != snapEvent); + fractureEventProxyBufferStart = NULL; + } + return snapEvent; +} + +SnapEvent * DestructibleStructureStressSolver::interpret(const PeninsulaData & peninsulaData, Int2Type<StressEvaluationType::EvaluateByMoment>) const +{ + SnapEvent * snapEvent= NULL; + PX_ASSERT(NULL != &peninsulaData); + const bool stressConditionPassed = peninsulaData.getDataAggregateMass() > userMassThreshold; + if(stressConditionPassed) + { + // set up data for proxy fracture events + const uint32_t linkedChunkIndex = peninsulaData.getRootLinkedChunkIndex(); + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + FractureEventProxy * fractureEventProxyBufferStart = NULL; + const uint32_t fractureEventProxyBufferCount = 1; + fractureEventProxyBufferStart = PX_NEW(FractureEventProxy)[fractureEventProxyBufferCount]; + ::memset(static_cast<void*>(fractureEventProxyBufferStart), 0x00, fractureEventProxyBufferCount * sizeof(FractureEventProxy)); + + // set up data for primary weak link + ActorChunkPair actorChunkPair = getActorChunkPair(linkedChunkIndex); + FractureEventProxy & fractureEventProxy = fractureEventProxyBufferStart[0]; + fractureEventProxy.rootLinkedChunkIndex = linkedChunkIndex; + fractureEventProxy.chunkIndexInAsset = actorChunkPair.chunkAlias->indexInAsset; + fractureEventProxy.destructibleId = actorChunkPair.actorAlias->getID(); + fractureEventProxy.fractureEventProxyFlags = 0; + fractureEventProxy.fractureEventProxyFlags |= FractureEvent::Snap; + fractureEventProxy.rootLinkedChunkPosition = actorChunkPair.actorAlias->getStructure()->getChunkWorldCentroid(*(actorChunkPair.chunkAlias)); + fractureEventProxy.impulse = -1 * (peninsulaData.getDataGeometricCenter() - fractureEventProxy.rootLinkedChunkPosition).getNormalized(); + + // store them in a snap event + const float tickSecondsToSnap = userTimeDelay; + PX_ASSERT(NULL != fractureEventProxyBufferStart && 0 != fractureEventProxyBufferCount); + snapEvent = SnapEvent::instantiate(fractureEventProxyBufferStart, fractureEventProxyBufferCount, tickSecondsToSnap); + PX_ASSERT(NULL != snapEvent); + fractureEventProxyBufferStart = NULL; + } + return snapEvent; +} + +const FractureEvent & DestructibleStructureStressSolver::interpret(const FractureEventProxy & fractureEventProxy) const +{ + static FractureEvent staticFractureEvent; + PX_ASSERT(NULL != &fractureEventProxy); + ::memset(static_cast<void*>(&staticFractureEvent), 0x00, 1 * sizeof(FractureEvent)); + staticFractureEvent.position = fractureEventProxy.rootLinkedChunkPosition; + staticFractureEvent.chunkIndexInAsset = fractureEventProxy.chunkIndexInAsset; + staticFractureEvent.impulse = fractureEventProxy.impulse; + staticFractureEvent.destructibleID = fractureEventProxy.destructibleId; + staticFractureEvent.flags = fractureEventProxy.fractureEventProxyFlags; + staticFractureEvent.hitDirection = PxVec3(0.0f); + return staticFractureEvent; +} + +bool DestructibleStructureStressSolver::isLinkedChunkBroken(uint32_t linkedChunkIndex) const +{ + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + PX_ASSERT(NULL != structureLinkCondition); + PX_ASSERT(structureLinkCondition[linkedChunkIndex] < DestructibleStructureStressSolver::LinkedChunkInvalidMaxFlag); + PX_ASSERT(0 != (DestructibleStructureStressSolver::LinkedChunkExist & structureLinkCondition[linkedChunkIndex])); + return (0 != (DestructibleStructureStressSolver::LinkedChunkBroken & structureLinkCondition[linkedChunkIndex])); +} + +void DestructibleStructureStressSolver::setLinkedChunkBroken(uint32_t linkedChunkIndex) +{ + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + PX_ASSERT(NULL != structureLinkCondition); + PX_ASSERT(0 != (DestructibleStructureStressSolver::LinkedChunkExist & structureLinkCondition[linkedChunkIndex])); + PX_ASSERT(0 == (DestructibleStructureStressSolver::LinkedChunkBroken & structureLinkCondition[linkedChunkIndex]) && "usage error!"); + structureLinkCondition[linkedChunkIndex] |= DestructibleStructureStressSolver::LinkedChunkBroken; + PX_ASSERT(structureLinkCondition[linkedChunkIndex] < DestructibleStructureStressSolver::LinkedChunkInvalidMaxFlag); +} + +bool DestructibleStructureStressSolver::isLinkedChunkStrained(uint32_t linkedChunkIndex) const +{ + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + PX_ASSERT(NULL != structureLinkCondition); + PX_ASSERT(structureLinkCondition[linkedChunkIndex] < DestructibleStructureStressSolver::LinkedChunkInvalidMaxFlag); + PX_ASSERT(0 != (DestructibleStructureStressSolver::LinkedChunkExist & structureLinkCondition[linkedChunkIndex])); + PX_ASSERT(!isLinkedChunkBroken(linkedChunkIndex) && "usage error!"); + return (0 != (DestructibleStructureStressSolver::LinkedChunkStrained & structureLinkCondition[linkedChunkIndex])); +} + +void DestructibleStructureStressSolver::setLinkedChunkStrained(uint32_t linkedChunkIndex) +{ + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + PX_ASSERT(NULL != structureLinkCondition); + PX_ASSERT(0 != (DestructibleStructureStressSolver::LinkedChunkExist & structureLinkCondition[linkedChunkIndex])); + PX_ASSERT(0 == (DestructibleStructureStressSolver::LinkedChunkStrained & structureLinkCondition[linkedChunkIndex]) && "usage error!"); + PX_ASSERT(!isLinkedChunkBroken(linkedChunkIndex) && "usage error!"); + structureLinkCondition[linkedChunkIndex] |= DestructibleStructureStressSolver::LinkedChunkStrained; + PX_ASSERT(structureLinkCondition[linkedChunkIndex] < DestructibleStructureStressSolver::LinkedChunkInvalidMaxFlag); +} + +void DestructibleStructureStressSolver::getUnbrokenAdjacentLinkedChunkIndices(uint32_t linkedChunkIndex, physx::Array<uint32_t> & unbrokenAdjacentLinkedChunkIndices) const +{ + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndex)); + PX_ASSERT(NULL != &unbrokenAdjacentLinkedChunkIndices); + PX_ASSERT(unbrokenAdjacentLinkedChunkIndices.empty()); + const uint32_t firstOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndex]; + const uint32_t stopOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndex + 1]; + for(uint32_t index = firstOverlapIndex; index < stopOverlapIndex; ++index) + { + const uint32_t currentLinkedChunkIndex = bindedStructureAlias.overlaps[index]; + if(!isLinkedChunkBroken(currentLinkedChunkIndex)) + { + unbrokenAdjacentLinkedChunkIndices.pushBack(currentLinkedChunkIndex); + } + } +} + +bool DestructibleStructureStressSolver::areUnbrokenLinkedChunksAdjacent(uint32_t linkedChunkIndexReference, uint32_t linkedChunkIndexSubject) const +{ + bool areUnbrokenLinkedChunksAdjacent = false; + PX_ASSERT(assertLinkedChunkIndexOk(linkedChunkIndexReference) && assertLinkedChunkIndexOk(linkedChunkIndexSubject)); + PX_ASSERT(!isLinkedChunkBroken(linkedChunkIndexReference) && !isLinkedChunkBroken(linkedChunkIndexSubject)); + const uint32_t firstOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndexReference]; + const uint32_t stopOverlapIndex = bindedStructureAlias.firstOverlapIndices[linkedChunkIndexReference + 1]; + for(uint32_t index = firstOverlapIndex; index < stopOverlapIndex; ++index) + { + const uint32_t currentLinkedChunkIndex = bindedStructureAlias.overlaps[index]; + if(currentLinkedChunkIndex == linkedChunkIndexSubject) + { + PX_ASSERT(!isLinkedChunkBroken(currentLinkedChunkIndex)); + areUnbrokenLinkedChunksAdjacent = true; + break; + } + } + return areUnbrokenLinkedChunksAdjacent; +} + +ActorChunkPair DestructibleStructureStressSolver::getActorChunkPair(uint32_t chunkIndexInStructure) const +{ + const DestructibleActorImpl * actor = NULL; + const DestructibleStructure::Chunk * chunk = NULL; + PX_ASSERT(chunkIndexInStructure < bindedStructureAlias.chunks.size()); + for(physx::Array<DestructibleActorImpl*>::ConstIterator kIter = bindedStructureAlias.destructibles.begin(); kIter != bindedStructureAlias.destructibles.end(); ++kIter) + { + const DestructibleActorImpl * currentDestructibleActor = *kIter; + PX_ASSERT(NULL != currentDestructibleActor); + if(chunkIndexInStructure >= currentDestructibleActor->getFirstChunkIndex() && chunkIndexInStructure < (currentDestructibleActor->getFirstChunkIndex() + currentDestructibleActor->getDestructibleAsset()->getChunkCount())) + { + actor = currentDestructibleActor; + chunk = &(bindedStructureAlias.chunks[chunkIndexInStructure]); + PX_ASSERT((actor->getFirstChunkIndex() + chunk->indexInAsset) == chunkIndexInStructure); + break; + } + } + PX_ASSERT(NULL != actor && NULL != chunk); + return ActorChunkPair(actor, chunk); +} + +StructureScratchBuffer DestructibleStructureStressSolver::acquireScratchBuffer() const +{ + // bitwise const qualifier only - so as to allow const methods to use this method too + PX_ASSERT(!scratchBufferLocked); + scratchBufferLocked = true; + return StructureScratchBuffer(scratchBuffer, structureLinkCount); +} + +void DestructibleStructureStressSolver::relinquishScratchBuffer() const +{ + // bitwise const qualifier only - so as to allow const methods to use this method too + PX_ASSERT(scratchBufferLocked); + scratchBufferLocked = false; +} + +DestructibleStructure & DestructibleStructureStressSolver::getBindedStructureMutable() +{ + return const_cast<DestructibleStructure&>(bindedStructureAlias); +} + +bool DestructibleStructureStressSolver::assertLinkedChunkIndexOk(uint32_t linkedChunkIndex) const +{ + PX_ASSERT(bindedStructureAlias.chunks.size() == structureLinkCount ? linkedChunkIndex < structureLinkCount : false); + PX_UNUSED(linkedChunkIndex); + return true; +} + +bool DestructibleStructureStressSolver::assertLinkedChunkIndicesForEvaluationOk(const physx::Array<uint32_t> & linkedChunkIndicesForEvaluation) const +{ + for(physx::Array<uint32_t>::ConstIterator kIter = linkedChunkIndicesForEvaluation.begin(); kIter != linkedChunkIndicesForEvaluation.end(); ++kIter) + { + const uint32_t currentLinkedChunkIndex = *kIter; + PX_ASSERT(assertLinkedChunkIndexOk(currentLinkedChunkIndex)); + PX_ASSERT(!isLinkedChunkBroken(currentLinkedChunkIndex)); + PX_UNUSED(currentLinkedChunkIndex); + } + for(physx::Array<uint32_t>::ConstIterator kIter = linkedChunkIndicesForEvaluation.begin(); kIter != linkedChunkIndicesForEvaluation.end(); ++kIter) + { + const uint32_t referenceLinkedChunkIndex = *kIter; + for(physx::Array<uint32_t>::ConstIterator kJter = kIter + 1; kJter != linkedChunkIndicesForEvaluation.end(); ++kJter) + { + const uint32_t subjectLinkedChunkIndex = *kJter; + PX_ASSERT(referenceLinkedChunkIndex != subjectLinkedChunkIndex); + PX_UNUSED(referenceLinkedChunkIndex); + PX_UNUSED(subjectLinkedChunkIndex); + } + } + return true; +} + +} // namespace destructible +} // namespace nvidia
\ No newline at end of file |