/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "StdAfx.h" #include #include #include #include #include #include #include #include namespace Blast { BlastActor* BlastActorFactoryImpl::CreateActor(const BlastActorDesc& desc) { auto actor = aznew BlastActorImpl(desc); actor->Spawn(); return actor; } void BlastActorFactoryImpl::DestroyActor(BlastActor* actor) { delete actor; } AZStd::vector BlastActorFactoryImpl::CalculateVisibleChunks( const BlastFamily& blastFamily, const Nv::Blast::TkActor& tkActor) const { const Nv::Blast::TkAsset* tkAsset = tkActor.getAsset(); AZ_Assert(tkAsset, "Invalid TkAsset on TkActor."); if (!tkAsset) { return {}; } const Nv::Blast::ExtPxChunk* pxChunks = blastFamily.GetPxAsset().getChunks(); const NvBlastChunk* chunks = tkAsset->getChunks(); const uint32_t pxChunkCount = blastFamily.GetPxAsset().getChunkCount(); const uint32_t chunkCount = tkAsset->getChunkCount(); const uint32_t nodeCount = tkActor.getGraphNodeCount(); AZ_Assert(pxChunks, "ExtPxAsset asset has a null chunk array."); AZ_Assert(chunks, "TkActor's asset has a null chunk array."); if (!pxChunks || !chunks) { return {}; } AZStd::vector chunkIndicesScratch; chunkIndicesScratch.resize_no_construct(tkActor.getVisibleChunkCount()); tkActor.getVisibleChunkIndices(chunkIndicesScratch.data(), static_cast(chunkIndicesScratch.size())); AZStd::vector chunkIndices; // Filter the visible chunks to ensure they have subchunks chunkIndices.reserve(chunkIndicesScratch.size()); for (uint32_t chunkIndex : chunkIndicesScratch) { AZ_Assert(chunkIndex < pxChunkCount, "Out of bounds access to the ExtPxAsset's PxChunks."); if (chunkIndex < pxChunkCount) { const Nv::Blast::ExtPxChunk& chunk = pxChunks[chunkIndex]; if (chunk.subchunkCount > 0) { chunkIndices.push_back(chunkIndex); } } } return chunkIndices; } bool BlastActorFactoryImpl::CalculateIsLeafChunk( const Nv::Blast::TkActor& tkActor, const AZStd::vector& chunkIndices) const { const Nv::Blast::TkAsset* tkAsset = tkActor.getAsset(); AZ_Assert(tkAsset, "Invalid TkAsset on TkActor."); if (!tkAsset) { return false; } const uint32_t nodeCount = tkActor.getGraphNodeCount(); const uint32_t chunkCount = tkAsset->getChunkCount(); const NvBlastChunk* chunks = tkAsset->getChunks(); AZStd::vector chunkIndicesScratch; chunkIndicesScratch.resize_no_construct(tkActor.getVisibleChunkCount()); tkActor.getVisibleChunkIndices(chunkIndicesScratch.data(), static_cast(chunkIndicesScratch.size())); bool isLeafChunk = false; // Single lower-support chunk actors might be leaf actors - if so, set our leaf chunk flag for use in filter // data if (nodeCount <= 1 && !chunkIndicesScratch.empty() && !chunkIndices.empty()) { const uint32_t chunkIndex = chunkIndices[0]; AZ_Assert(chunkIndex < chunkCount, "Out of bounds access to the ExtPxAsset's PxChunks."); if (chunkIndex < chunkCount) { const NvBlastChunk& chunk = chunks[chunkIndex]; // Mark as a leaf chunk if it has no children isLeafChunk = chunk.firstChildIndex == chunk.childIndexStop; } } return isLeafChunk; } bool BlastActorFactoryImpl::CalculateIsStatic( const BlastFamily& blastFamily, const Nv::Blast::TkActor& tkActor, const AZStd::vector& chunkIndices) const { return tkActor.isBoundToWorld() || SupportGraphHasStaticActor(blastFamily, tkActor) || VisibleChunksHasStaticActor(blastFamily, chunkIndices); } AZStd::vector BlastActorFactoryImpl::CalculateComponents(bool isStatic) const { if (isStatic) { return {AZ::TransformComponentTypeId, PhysX::StaticRigidBodyComponentTypeId}; } return {AZ::TransformComponentTypeId, /* RigidBodyComponent */ AZ::TypeId("{D4E52A70-BDE1-4819-BD3C-93AB3F4F3BE3}")}; } bool BlastActorFactoryImpl::SupportGraphHasStaticActor( const BlastFamily& blastFamily, const Nv::Blast::TkActor& tkActor) const { const uint32_t nodeCount = tkActor.getGraphNodeCount(); const Nv::Blast::ExtPxChunk* pxChunks = blastFamily.GetPxAsset().getChunks(); const Nv::Blast::TkAsset* tkAsset = tkActor.getAsset(); if (nodeCount == 0 || !pxChunks || !tkAsset) { AZ_Assert(pxChunks, "BlastFamily's asset has a null chunk array."); AZ_Assert(tkAsset, "Invalid TkAsset on TkActor."); return false; } bool staticFound = false; AZStd::vector graphNodeIndices; graphNodeIndices.resize_no_construct(nodeCount); tkActor.getGraphNodeIndices(graphNodeIndices.data(), static_cast(graphNodeIndices.size())); const NvBlastSupportGraph graph = tkAsset->getGraph(); const uint32_t chunkCount = blastFamily.GetPxAsset().getChunkCount(); for (uint32_t graphNodeIndex : graphNodeIndices) { if (graphNodeIndex >= graph.nodeCount) { AZ_Assert(false, "Out of bounds access to NvBlastSupportGraph."); continue; } const uint32_t chunkIndex = graph.chunkIndices[graphNodeIndex]; if (chunkIndex >= chunkCount) { AZ_Assert(false, "Out of bounds access to BlastFamily asset's ExtPxChunks."); continue; } const Nv::Blast::ExtPxChunk& chunk = pxChunks[chunkIndex]; if (chunk.isStatic) { staticFound = true; break; } } return staticFound; } bool BlastActorFactoryImpl::VisibleChunksHasStaticActor( const BlastFamily& blastFamily, const AZStd::vector& chunkIndices) const { const uint32_t chunkCount = blastFamily.GetPxAsset().getChunkCount(); const Nv::Blast::ExtPxChunk* pxChunks = blastFamily.GetPxAsset().getChunks(); if (!pxChunks) { AZ_Assert(false, "ExtPxAsset has a null chunk array."); return false; } bool staticFound = false; for (const uint32_t chunkIndex : chunkIndices) { const Nv::Blast::ExtPxChunk& chunk = pxChunks[chunkIndex]; if (chunk.isStatic) { staticFound = true; break; } } return staticFound; } } // namespace Blast