/* * Copyright (c) 2016-2017, 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 "NvBlastExtPxFamilyImpl.h" #include "NvBlastExtPxActorImpl.h" #include "NvBlastExtPxAssetImpl.h" #include "NvBlastExtPxListener.h" #include "NvBlastExtPxManagerImpl.h" #include "NvBlastTkFamily.h" #include "NvBlastTkActor.h" #include "NvBlastTkJoint.h" #include "NvBlastAssert.h" #include "PxRigidDynamic.h" #include "PxScene.h" #include namespace Nv { namespace Blast { ExtPxFamilyImpl::ExtPxFamilyImpl(ExtPxManagerImpl& manager, TkFamily& tkFamily, const ExtPxAsset& pxAsset) : m_manager(manager), m_tkFamily(tkFamily), m_pxAsset(pxAsset), m_pxShapeDescTemplate(nullptr), m_pxActorDescTemplate(nullptr), m_isSpawned(false) { m_subchunkShapes.resize(static_cast(m_pxAsset.getSubchunkCount())); userData = nullptr; m_manager.registerFamily(*this); } ExtPxFamilyImpl::~ExtPxFamilyImpl() { m_manager.unregisterFamily(*this); if (m_isSpawned) { m_tkFamily.removeListener(*this); auto& actors = m_actorsBuffer; actors.resize(m_actors.size()); uint32_t i = 0; for (auto it = m_actors.getIterator(); !it.done(); ++it) { actors[i++] = *it; } destroyActors(actors.begin(), actors.size()); } m_tkFamily.release(); } void ExtPxFamilyImpl::release() { NVBLASTEXT_DELETE(this, ExtPxFamilyImpl); } bool ExtPxFamilyImpl::spawn(const physx::PxTransform& pose, const physx::PxVec3& scale, const ExtPxSpawnSettings& settings) { NVBLASTEXT_CHECK_ERROR(!m_isSpawned, "Family spawn: family already spawned. Was spawn() called twice?", return false); NVBLASTEXT_CHECK_ERROR(settings.scene != nullptr, "Family creation: desc.scene is nullptr", return false); NVBLASTEXT_CHECK_ERROR(settings.material != nullptr, "Family creation: desc.material is nullptr", return false); m_initialTransform = pose; m_spawnSettings = settings; // get current tkActors (usually it's only 1, but it can be already in split state) const uint32_t actorCount = (uint32_t)m_tkFamily.getActorCount(); m_newActorsBuffer.resize(actorCount); m_tkFamily.getActors(m_newActorsBuffer.begin(), actorCount); // calc max split count uint32_t splitMaxActorCount = 0; for (TkActor* actor : m_newActorsBuffer) { splitMaxActorCount = std::max(splitMaxActorCount, actor->getSplitMaxActorCount()); } // preallocate memory m_newActorsBuffer.resize(splitMaxActorCount); m_newActorCreateInfo.resize(splitMaxActorCount); m_physXActorsBuffer.resize(splitMaxActorCount); m_physXActorsBuffer.resize(splitMaxActorCount); m_indicesScratch.reserve(splitMaxActorCount); // fill initial actor create info for (uint32_t i = 0; i < actorCount; ++i) { PxActorCreateInfo& pxActorInfo = m_newActorCreateInfo[i]; pxActorInfo.m_angularVelocity = PxVec3(PxZero); pxActorInfo.m_linearVelocity = PxVec3(PxZero); pxActorInfo.m_transform = pose; pxActorInfo.m_scale = scale; } // create first actors in family createActors(m_newActorsBuffer.begin(), m_newActorCreateInfo.begin(), actorCount); // listen family for new actors m_tkFamily.addListener(*this); m_isSpawned = true; return true; } bool ExtPxFamilyImpl::despawn() { NVBLASTEXT_CHECK_ERROR(m_spawnSettings.scene != nullptr, "Family despawn: desc.scene is nullptr", return false); auto& actors = m_actorsBuffer; actors.resize(m_actors.size()); uint32_t i = 0; for (auto it = m_actors.getIterator(); !it.done(); ++it) { actors[i++] = *it; } destroyActors(actors.begin(), actors.size()); return true; } void ExtPxFamilyImpl::receive(const TkEvent* events, uint32_t eventCount) { auto& actorsToDelete = m_actorsBuffer; actorsToDelete.clear(); uint32_t totalNewActorsCount = 0; for (uint32_t i = 0; i < eventCount; ++i) { const TkEvent& e = events[i]; if (e.type == TkEvent::Split) { const TkSplitEvent* splitEvent = e.getPayload(); uint32_t newActorsCount = splitEvent->numChildren; ExtPxActorImpl* parentActor = nullptr; PxRigidDynamic* parentPxActor = nullptr; if (splitEvent->parentData.userData) { parentActor = reinterpret_cast(splitEvent->parentData.userData); parentPxActor = &parentActor->getPhysXActor(); } for (uint32_t j = totalNewActorsCount; j < totalNewActorsCount + newActorsCount; ++j) { m_newActorCreateInfo[j].m_transform = parentPxActor ? parentPxActor->getGlobalPose() : m_initialTransform; //TODO: Get the current scale of the actor! m_newActorCreateInfo[j].m_scale = m_initialScale; m_newActorCreateInfo[j].m_linearVelocity = parentPxActor ? parentPxActor->getLinearVelocity() : PxVec3(PxZero); m_newActorCreateInfo[j].m_angularVelocity = parentPxActor ? parentPxActor->getAngularVelocity() : PxVec3(PxZero); m_newActorsBuffer[j] = splitEvent->children[j - totalNewActorsCount]; } totalNewActorsCount += newActorsCount; if (parentActor) { actorsToDelete.pushBack(parentActor); } } } destroyActors(actorsToDelete.begin(), actorsToDelete.size()); if (totalNewActorsCount > 0) { uint32_t cappedNewActorsCount = totalNewActorsCount; const uint32_t actorCountLimit = m_manager.getActorCountLimit(); const uint32_t totalActorCount = m_manager.getPxActorCount(); if (actorCountLimit > 0 && cappedNewActorsCount + totalActorCount > actorCountLimit) { cappedNewActorsCount = actorCountLimit > totalActorCount ? actorCountLimit - totalActorCount : 0; } createActors(m_newActorsBuffer.begin(), m_newActorCreateInfo.begin(), cappedNewActorsCount); m_culledActors.reserve(m_culledActors.size() + totalNewActorsCount - cappedNewActorsCount); for (uint32_t i = cappedNewActorsCount; i < totalNewActorsCount; ++i) { m_culledActors.pushBack(m_newActorsBuffer[i]); } totalNewActorsCount = cappedNewActorsCount; // In case it's used below } for (uint32_t i = 0; i < eventCount; ++i) { const TkEvent& e = events[i]; if (e.type == TkEvent::JointUpdate) { const TkJointUpdateEvent* jointEvent = e.getPayload(); NVBLAST_ASSERT(jointEvent->joint); TkJoint& joint = *jointEvent->joint; switch (jointEvent->subtype) { case TkJointUpdateEvent::External: m_manager.createJoint(joint); break; case TkJointUpdateEvent::Changed: m_manager.updateJoint(joint); break; case TkJointUpdateEvent::Unreferenced: m_manager.destroyJoint(joint); joint.release(); break; } } } } void ExtPxFamilyImpl::createActors(TkActor** tkActors, const PxActorCreateInfo* pxActorInfos, uint32_t count) { auto actorsToAdd = m_physXActorsBuffer.begin(); for (uint32_t i = 0; i < count; ++i) { ExtPxActorImpl* actor = NVBLASTEXT_NEW(ExtPxActorImpl)(this, tkActors[i], pxActorInfos[i]); m_actors.insert(actor); actorsToAdd[i] = &actor->getPhysXActor(); dispatchActorCreated(*actor); // Handle incomplete joints auto e = m_manager.m_incompleteJointMultiMap.find(tkActors[i]); if (e != nullptr) { ExtArray::type joints = e->second; // Copying the array m_manager.m_incompleteJointMultiMap.erase(tkActors[i]); for (uint32_t j = 0; j < joints.size(); ++j) { m_manager.updateJoint(*joints[j]); } } } m_spawnSettings.scene->addActors(actorsToAdd, static_cast(count)); } void ExtPxFamilyImpl::destroyActors(ExtPxActor** actors, uint32_t count) { auto pxActorsToRemove = m_physXActorsBuffer.begin(); for (uint32_t i = 0; i < count; ++i) { pxActorsToRemove[i] = &actors[i]->getPhysXActor(); } m_spawnSettings.scene->removeActors(pxActorsToRemove, static_cast(count)); for (uint32_t i = 0; i < count; ++i) { ExtPxActorImpl* actor = (ExtPxActorImpl*)actors[i]; m_actors.erase(actor); dispatchActorDestroyed(*actor); NVBLASTEXT_DELETE(actor, ExtPxActorImpl); } } void ExtPxFamilyImpl::dispatchActorCreated(ExtPxActor& actor) { for (ExtPxListener* listener : m_listeners) listener->onActorCreated(*this, actor); m_manager.dispatchActorCreated(*this, actor); } void ExtPxFamilyImpl::dispatchActorDestroyed(ExtPxActor& actor) { for (ExtPxListener* listener : m_listeners) listener->onActorDestroyed(*this, actor); m_manager.dispatchActorDestroyed(*this, actor); } void ExtPxFamilyImpl::postSplitUpdate() { for (auto actor : m_culledActors) { actor->release(); } m_culledActors.resize(0); } } // namespace Blast } // namespace Nv