aboutsummaryrefslogtreecommitdiff
path: root/sdk/lowlevel/source/NvBlastActor.cpp
diff options
context:
space:
mode:
authorBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
committerBryan Galdrikian <[email protected]>2018-05-31 11:36:08 -0700
commit7115f60b91b5717d90f643fd692010905c7004db (patch)
treeeffd68c6978751c517d54c2f2bb5bb6e7dc93e18 /sdk/lowlevel/source/NvBlastActor.cpp
parentUpdating BlastTool zip (diff)
downloadblast-1.1.3_rc1.tar.xz
blast-1.1.3_rc1.zip
Blast 1.1.3. See docs/release_notes.txt.v1.1.3_rc1
Diffstat (limited to 'sdk/lowlevel/source/NvBlastActor.cpp')
-rwxr-xr-x[-rw-r--r--]sdk/lowlevel/source/NvBlastActor.cpp2052
1 files changed, 1026 insertions, 1026 deletions
diff --git a/sdk/lowlevel/source/NvBlastActor.cpp b/sdk/lowlevel/source/NvBlastActor.cpp
index d93f2e3..bdcd4f8 100644..100755
--- a/sdk/lowlevel/source/NvBlastActor.cpp
+++ b/sdk/lowlevel/source/NvBlastActor.cpp
@@ -1,1026 +1,1026 @@
-// This code contains NVIDIA Confidential Information and is disclosed to you
-// under a form of NVIDIA software license agreement provided separately to you.
-//
-// Notice
-// NVIDIA Corporation and its licensors retain all intellectual property and
-// proprietary rights in and to this software and 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.
-//
-// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
-// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
-// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
-// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// Information and code furnished is believed to be accurate and reliable.
-// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
-// information or for any infringement of patents or other rights of third parties that may
-// result from its use. No license is granted by implication or otherwise under any patent
-// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
-// This code supersedes and replaces all information previously supplied.
-// NVIDIA Corporation products are not authorized for use as critical
-// components in life support devices or systems without express written approval of
-// NVIDIA Corporation.
-//
-// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastActor.h"
-#include "NvBlastFamilyGraph.h"
-#include "NvBlastChunkHierarchy.h"
-#include "NvBlastIndexFns.h"
-#include "NvBlastDLink.h"
-#include "NvBlastGeometry.h"
-#include "NvBlastTime.h"
-#include <float.h>
-#include <algorithm>
-
-
-namespace Nv
-{
-namespace Blast
-{
-
-//////// Actor static methods ////////
-
-size_t Actor::createRequiredScratch(const NvBlastFamily* family)
-{
-#if NVBLASTLL_CHECK_PARAMS
- if (family == nullptr || reinterpret_cast<const FamilyHeader*>(family)->m_asset == nullptr)
- {
- NVBLAST_ALWAYS_ASSERT();
- return 0;
- }
-#endif
-
- const Asset& solverAsset = *reinterpret_cast<const FamilyHeader*>(family)->m_asset;
- return FamilyGraph::findIslandsRequiredScratch(solverAsset.m_graph.m_nodeCount);
-}
-
-
-Actor* Actor::create(NvBlastFamily* family, const NvBlastActorDesc* desc, void* scratch, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(family != nullptr, logFn, "Actor::create: NULL family pointer input.", return nullptr);
- NVBLASTLL_CHECK(reinterpret_cast<FamilyHeader*>(family)->m_asset != nullptr, logFn, "Actor::create: family has NULL asset.", return nullptr);
- NVBLASTLL_CHECK(reinterpret_cast<FamilyHeader*>(family)->m_asset->m_graph.m_nodeCount != 0, logFn, "Actor::create: family's asset has no support chunks.", return nullptr);
- NVBLASTLL_CHECK(desc != nullptr, logFn, "Actor::create: NULL desc pointer input.", return nullptr);
- NVBLASTLL_CHECK(scratch != nullptr, logFn, "Actor::create: NULL scratch input.", return nullptr);
-
- FamilyHeader* header = reinterpret_cast<FamilyHeader*>(family);
-
- if (header->m_actorCount > 0)
- {
- NVBLASTLL_LOG_ERROR(logFn, "Actor::create: input family is not empty.");
- return nullptr;
- }
-
- const Asset& solverAsset = *static_cast<const Asset*>(header->m_asset);
- const SupportGraph& graph = solverAsset.m_graph;
-
- // Lower support chunk healths - initialize
- float* lowerSupportChunkHealths = header->getLowerSupportChunkHealths();
- if (desc->initialSupportChunkHealths != nullptr) // Health array given
- {
- const uint32_t* supportChunkIndices = graph.getChunkIndices();
- for (uint32_t supportChunkNum = 0; supportChunkNum < graph.m_nodeCount; ++supportChunkNum)
- {
- const float initialHealth = desc->initialSupportChunkHealths[supportChunkNum];
- for (Asset::DepthFirstIt i(solverAsset, supportChunkIndices[supportChunkNum]); (bool)i; ++i)
- {
- lowerSupportChunkHealths[solverAsset.getContiguousLowerSupportIndex((uint32_t)i)] = initialHealth;
- }
- }
- }
- else // Use uniform initialization
- {
- const uint32_t lowerSupportChunkCount = solverAsset.getLowerSupportChunkCount();
- for (uint32_t i = 0; i < lowerSupportChunkCount; ++i)
- {
- lowerSupportChunkHealths[i] = desc->uniformInitialLowerSupportChunkHealth;
- }
- }
-
- // Bond healths - initialize
- const uint32_t bondCount = solverAsset.getBondCount();
- float* bondHealths = header->getBondHealths();
- if (desc->initialBondHealths != nullptr) // Health array given
- {
- memcpy(bondHealths, desc->initialBondHealths, bondCount * sizeof(float));
- }
- else // Use uniform initialization
- {
- for (uint32_t bondNum = 0; bondNum < bondCount; ++bondNum)
- {
- bondHealths[bondNum] = desc->uniformInitialBondHealth;
- }
- }
-
- // Get first actor - NOTE: we don't send an event for this! May need to do so for consistency.
- Actor* actor = header->borrowActor(0); // Using actor[0]
-
- // Fill in actor fields
- actor->m_firstGraphNodeIndex = 0;
- actor->m_graphNodeCount = graph.m_nodeCount;
- actor->m_leafChunkCount = solverAsset.m_leafChunkCount;
-
- // Graph node index links - initialize to chain
- uint32_t* graphNodeLinks = header->getGraphNodeIndexLinks();
- for (uint32_t i = 0; i < graph.m_nodeCount - 1; ++i)
- {
- graphNodeLinks[i] = i + 1;
- }
- graphNodeLinks[graph.m_nodeCount - 1] = invalidIndex<uint32_t>();
-
- // Update visible chunks (we assume that all chunks belong to one actor at the beginning)
- actor->updateVisibleChunksFromGraphNodes();
-
- // Initialize instance graph with this actor
- header->getFamilyGraph()->initialize(actor->getIndex(), &graph);
-
- // Call findIslands to set up the internal instance graph data
- header->getFamilyGraph()->findIslands(actor->getIndex(), scratch, &graph);
-
- return actor;
-}
-
-
-//////// Actor member methods ////////
-
-uint32_t Actor::damageBond(uint32_t nodeIndex0, uint32_t nodeIndex1, float healthDamage)
-{
- const uint32_t bondIndex = getGraph()->findBond(nodeIndex0, nodeIndex1);
- damageBond(nodeIndex0, nodeIndex1, bondIndex, healthDamage);
- return bondIndex;
-}
-
-
-void Actor::damageBond(uint32_t nodeIndex0, uint32_t nodeIndex1, uint32_t bondIndex, float healthDamage)
-{
- if (bondIndex == invalidIndex<uint32_t>())
- {
- NVBLAST_ALWAYS_ASSERT();
- return;
- }
-
- float* bondHealths = getBondHealths();
- if (bondHealths[bondIndex] > 0 && healthDamage > 0.0f)
- {
- // Subtract health
- bondHealths[bondIndex] -= healthDamage;
-
- // Was removed?
- if (bondHealths[bondIndex] <= 0)
- {
- // Notify graph that bond was removed
- getFamilyGraph()->notifyEdgeRemoved(getIndex(), nodeIndex0, nodeIndex1, bondIndex, getGraph());
- bondHealths[bondIndex] = 0; // Doing this for single-actor serialization consistency; should not actually be necessary
- }
- }
-}
-
-
-uint32_t Actor::damageBond(const NvBlastBondFractureData& cmd)
-{
- NVBLAST_ASSERT(!isInvalidIndex(cmd.nodeIndex1));
- return damageBond(cmd.nodeIndex0, cmd.nodeIndex1, cmd.health);
-}
-
-
-void Actor::generateFracture(NvBlastFractureBuffers* commandBuffers, const NvBlastDamageProgram& program, const void* programParams,
- NvBlastLog logFn, NvBlastTimers* timers) const
-{
- NVBLASTLL_CHECK(commandBuffers != nullptr, logFn, "Actor::generateFracture: NULL commandBuffers pointer input.", return);
- NVBLASTLL_CHECK(isValid(commandBuffers), logFn, "NvBlastActorGenerateFracture: commandBuffers memory is NULL but size is > 0.",
- commandBuffers->bondFractureCount = 0; commandBuffers->chunkFractureCount = 0; return);
-
-#if NVBLASTLL_CHECK_PARAMS
- if (commandBuffers->bondFractureCount == 0 && commandBuffers->chunkFractureCount == 0)
- {
- NVBLASTLL_LOG_WARNING(logFn, "NvBlastActorGenerateFracture: commandBuffers do not provide any space.");
- return;
- }
-#endif
-
-#if NV_PROFILE
- Time time;
-#else
- NV_UNUSED(timers);
-#endif
-
- const SupportGraph* graph = getGraph();
-
- const uint32_t graphNodeCount = getGraphNodeCount();
- if (graphNodeCount > 1 && program.graphShaderFunction != nullptr)
- {
- const NvBlastGraphShaderActor shaderActor = {
- getIndex(),
- getGraphNodeCount(),
- graph->m_nodeCount,
- getFirstGraphNodeIndex(),
- getGraphNodeIndexLinks(),
- graph->getChunkIndices(),
- graph->getAdjacencyPartition(),
- graph->getAdjacentNodeIndices(),
- graph->getAdjacentBondIndices(),
- getBonds(),
- getChunks(),
- getBondHealths(),
- getLowerSupportChunkHealths(),
- getFamilyHeader()->getFamilyGraph()->getIslandIds()
- };
-
- program.graphShaderFunction(commandBuffers, &shaderActor, programParams);
- }
- else if (graphNodeCount <= 1 && program.subgraphShaderFunction != nullptr)
- {
- const NvBlastSubgraphShaderActor shaderActor = {
- // The conditional (visible vs. support chunk) is needed because we allow single-child chunk chains
- // This makes it possible that an actor with a single support chunk will have a different visible chunk (ancestor of the support chunk)
- graphNodeCount == 1 ? graph->getChunkIndices()[getFirstGraphNodeIndex()] : getFirstVisibleChunkIndex(),
- getChunks()
- };
-
- program.subgraphShaderFunction(commandBuffers, &shaderActor, programParams);
- }
- else
- {
- commandBuffers->bondFractureCount = 0;
- commandBuffers->chunkFractureCount = 0;
- }
-
-#if NV_PROFILE
- if (timers != nullptr)
- {
- timers->material += time.getElapsedTicks();
- }
-#endif
-}
-
-
-
-
-size_t Actor::splitRequiredScratch() const
-{
- // Scratch is reused, just need the max of these two values
- return std::max(m_graphNodeCount * sizeof(uint32_t), static_cast<size_t>(FamilyGraph::findIslandsRequiredScratch(getGraph()->m_nodeCount)));
-}
-
-
-uint32_t Actor::split(NvBlastActorSplitEvent* result, uint32_t newActorsMaxCount, void* scratch, NvBlastLog logFn, NvBlastTimers* timers)
-{
- NVBLASTLL_CHECK(result != nullptr, logFn, "Actor::split: NULL result pointer input.", return 0);
- NVBLASTLL_CHECK(newActorsMaxCount > 0 && result->newActors != nullptr, logFn, "NvBlastActorSplit: no space for results provided.", return 0);
- NVBLASTLL_CHECK(scratch != nullptr, logFn, "Actor::split: NULL scratch pointer input.", return 0);
-
-#if NV_PROFILE
- Time time;
-#else
- NV_UNUSED(timers);
-#endif
-
- Actor** newActors = reinterpret_cast<Actor**>(result->newActors);
-
- uint32_t actorsCount = 0;
-
- if (getGraphNodeCount() <= 1)
- {
- uint32_t chunkHealthIndex = isSingleSupportChunk() ? getIndex() : getFirstVisibleChunkIndex() - getFirstSubsupportChunkIndex() + getGraph()->m_nodeCount;
-
- float* chunkHealths = getLowerSupportChunkHealths();
- if (chunkHealths[chunkHealthIndex] <= 0.0f)
- {
- actorsCount = partitionSingleLowerSupportChunk(newActors, newActorsMaxCount, logFn);
-
- for (uint32_t i = 0; i < actorsCount; ++i)
- {
- Actor* newActor = newActors[i];
- uint32_t firstVisible = newActor->getFirstVisibleChunkIndex();
- uint32_t firstSub = newActor->getFirstSubsupportChunkIndex();
- uint32_t nodeCount = newActor->getGraph()->m_nodeCount;
- uint32_t newActorIndex = newActor->getIndex();
- uint32_t healthIndex = newActor->isSubSupportChunk() ? firstVisible - firstSub + nodeCount : newActorIndex;
-
- if (chunkHealths[healthIndex] <= 0.0f)
- {
- uint32_t brittleActors = newActors[i]->partitionSingleLowerSupportChunk(&newActors[actorsCount], newActorsMaxCount - actorsCount, logFn);
- actorsCount += brittleActors;
-
- if (brittleActors > 0)
- {
- actorsCount--;
- newActors[i] = newActors[actorsCount];
- i--;
- }
- }
- }
- }
-
-
-#if NV_PROFILE
- if (timers != nullptr)
- {
- timers->partition += time.getElapsedTicks();
- }
-#endif
- }
- else
- {
- findIslands(scratch);
-
-#if NV_PROFILE
- if (timers != nullptr)
- {
- timers->island += time.getElapsedTicks();
- }
-#endif
-
- // Reuse scratch for node list
- uint32_t* graphNodeIndexList = reinterpret_cast<uint32_t*>(scratch);
-
- // Get the family header
- FamilyHeader* header = getFamilyHeader();
- NVBLAST_ASSERT(header != nullptr); // If m_actorEntryDataIndex is valid, this should be too
-
- // Record nodes in this actor before splitting
- const uint32_t* graphNodeIndexLinks = header->getGraphNodeIndexLinks(); // Get the links for the graph nodes
- uint32_t graphNodeIndexCount = 0;
- for (uint32_t graphNodeIndex = m_firstGraphNodeIndex; !isInvalidIndex(graphNodeIndex); graphNodeIndex = graphNodeIndexLinks[graphNodeIndex])
- {
- if (graphNodeIndexCount >= m_graphNodeCount)
- {
- // Safety, splitRequiredScratch() only guarantees m_graphNodeCount elements. In any case, this condition shouldn't happen.
- NVBLAST_ASSERT(graphNodeIndexCount < m_graphNodeCount);
- break;
- }
- graphNodeIndexList[graphNodeIndexCount++] = graphNodeIndex;
- }
-
- actorsCount = partitionMultipleGraphNodes(newActors, newActorsMaxCount, logFn);
-
- if (actorsCount > 1)
- {
-#if NV_PROFILE
- if (timers != nullptr)
- {
- timers->partition += time.getElapsedTicks();
- }
-#endif
-
- // Get various pointers and values to iterate
- const Asset* asset = getAsset();
- Actor* actors = header->getActors();
- IndexDLink<uint32_t>* visibleChunkIndexLinks = header->getVisibleChunkIndexLinks();
- uint32_t* chunkActorIndices = header->getChunkActorIndices();
- const SupportGraph& graph = asset->m_graph;
- const uint32_t* graphChunkIndices = graph.getChunkIndices();
- const NvBlastChunk* chunks = asset->getChunks();
- const uint32_t upperSupportChunkCount = asset->getUpperSupportChunkCount();
- const uint32_t* familyGraphIslandIDs = header->getFamilyGraph()->getIslandIds();
-
- // Iterate over all graph nodes and update visible chunk lists
- for (uint32_t graphNodeNum = 0; graphNodeNum < graphNodeIndexCount; ++graphNodeNum)
- {
- const uint32_t graphNodeIndex = graphNodeIndexList[graphNodeNum];
- const uint32_t supportChunkIndex = graphChunkIndices[graphNodeIndex];
- if (!isInvalidIndex(supportChunkIndex)) // Invalid if this is the world chunk
- {
- updateVisibleChunksFromSupportChunk<Actor>(actors, visibleChunkIndexLinks, chunkActorIndices, familyGraphIslandIDs[graphNodeIndex], graphChunkIndices[graphNodeIndex], chunks, upperSupportChunkCount);
- }
- }
-
- // Remove actors with no visible chunks - this can happen if we've split such that the world node is by itself
- uint32_t actualActorsCount = 0;
- for (uint32_t i = 0; i < actorsCount; ++i)
- {
- newActors[actualActorsCount] = newActors[i];
- if (newActors[actualActorsCount]->getVisibleChunkCount() > 0)
- {
- ++actualActorsCount;
- }
- else
- {
- header->returnActor(*newActors[actualActorsCount]);
- }
- }
- actorsCount = actualActorsCount;
-
-#if NV_PROFILE
- if (timers != nullptr)
- {
- timers->visibility += time.getElapsedTicks();
- }
-#endif
-
- for (uint32_t i = 0; i < actorsCount; ++i)
- {
- Actor* newActor = newActors[i];
- float* chunkHealths = newActor->getLowerSupportChunkHealths();
- uint32_t firstVisible = newActor->getFirstVisibleChunkIndex();
- uint32_t firstSub = newActor->getFirstSubsupportChunkIndex();
- uint32_t nodeCount = newActor->getGraph()->m_nodeCount;
- uint32_t newActorIndex = newActor->getIndex();
- uint32_t healthIndex = newActor->isSubSupportChunk() ? firstVisible - firstSub + nodeCount : newActorIndex;
-
- if (newActors[i]->getGraphNodeCount() <= 1)
- {
- // this relies on visibility updated, subsupport actors only have m_firstVisibleChunkIndex to identify the chunk
- if (chunkHealths[healthIndex] <= 0.0f)
- {
- uint32_t brittleActors = newActors[i]->partitionSingleLowerSupportChunk(&newActors[actorsCount], newActorsMaxCount - actorsCount, logFn);
- actorsCount += brittleActors;
-
- if (brittleActors > 0)
- {
- actorsCount--;
- newActors[i] = newActors[actorsCount];
- i--;
- }
- }
- }
- }
-
-#if NV_PROFILE
- if (timers != nullptr)
- {
- timers->partition += time.getElapsedTicks();
- }
-#endif
- }
- else
- {
- actorsCount = 0;
- }
- }
-
- result->deletedActor = actorsCount == 0 ? nullptr : this;
-
- return actorsCount;
-}
-
-
-uint32_t Actor::findIslands(void* scratch)
-{
- return getFamilyHeader()->getFamilyGraph()->findIslands(getIndex(), scratch, &getAsset()->m_graph);
-}
-
-
-uint32_t Actor::partitionMultipleGraphNodes(Actor** newActors, uint32_t newActorsSize, NvBlastLog logFn)
-{
- NVBLAST_ASSERT(newActorsSize == 0 || newActors != nullptr);
-
- // Check for single subsupport chunk, no partitioning
- if (m_graphNodeCount <= 1)
- {
- NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionMultipleGraphNodes: actor is a single lower-support chunk, and cannot be partitioned by this function.");
- return 0;
- }
-
- FamilyHeader* header = getFamilyHeader();
- NVBLAST_ASSERT(header != nullptr); // If m_actorEntryDataIndex is valid, this should be too
-
- // Get the links for the graph nodes
- uint32_t* graphNodeIndexLinks = header->getGraphNodeIndexLinks();
-
- // Get the graph chunk indices and leaf chunk counts
- const Asset* asset = getAsset();
- const uint32_t* graphChunkIndices = asset->m_graph.getChunkIndices();
- const uint32_t* subtreeLeafChunkCounts = asset->getSubtreeLeafChunkCounts();
-
- // Distribute graph nodes to new actors
- uint32_t newActorCount = 0;
- const uint32_t thisActorIndex = getIndex();
- m_leafChunkCount = 0;
- const uint32_t* islandIDs = header->getFamilyGraph()->getIslandIds();
- uint32_t lastGraphNodeIndex = invalidIndex<uint32_t>();
- uint32_t nextGraphNodeIndex = invalidIndex<uint32_t>();
- bool overflow = false;
- for (uint32_t graphNodeIndex = m_firstGraphNodeIndex; !isInvalidIndex(graphNodeIndex); graphNodeIndex = nextGraphNodeIndex)
- {
- nextGraphNodeIndex = graphNodeIndexLinks[graphNodeIndex];
- const uint32_t islandID = islandIDs[graphNodeIndex];
-
- if (islandID == thisActorIndex)
- {
- const uint32_t graphChunkIndex = graphChunkIndices[graphNodeIndex];
- if (!isInvalidIndex(graphChunkIndex)) // Invalid if this is the world chunk
- {
- m_leafChunkCount += subtreeLeafChunkCounts[graphChunkIndex];
- }
- lastGraphNodeIndex = graphNodeIndex;
- continue; // Leave the chunk in this actor
- }
-
- // Remove link from this actor
- if (isInvalidIndex(lastGraphNodeIndex))
- {
- m_firstGraphNodeIndex = nextGraphNodeIndex;
- }
- else
- {
- graphNodeIndexLinks[lastGraphNodeIndex] = nextGraphNodeIndex;
- }
- graphNodeIndexLinks[graphNodeIndex] = invalidIndex<uint32_t>();
- --m_graphNodeCount;
-
- // See if the chunk had been removed
- if (islandID == invalidIndex<uint32_t>())
- {
- continue;
- }
-
- // Get new actor if the islandID is valid
- Actor* newActor = header->borrowActor(islandID);
-
- // Check new actor to see if we're adding the first chunk
- if (isInvalidIndex(newActor->m_firstGraphNodeIndex))
- {
- // See if we can fit it in the output list
- if (newActorCount < newActorsSize)
- {
- newActors[newActorCount++] = newActor;
- }
- else
- {
- overflow = true;
- }
- }
-
- // Put link in new actor
- graphNodeIndexLinks[graphNodeIndex] = newActor->m_firstGraphNodeIndex;
- newActor->m_firstGraphNodeIndex = graphNodeIndex;
- ++newActor->m_graphNodeCount;
- // Add to the actor's leaf chunk count
- const uint32_t graphChunkIndex = graphChunkIndices[graphNodeIndex];
- if (!isInvalidIndex(graphChunkIndex)) // Invalid if this is the world chunk
- {
- newActor->m_leafChunkCount += subtreeLeafChunkCounts[graphChunkIndex];
- }
- }
-
- if (m_graphNodeCount > 0)
- {
- // There are still chunks in this actor. See if we can fit this in the output list.
- if (newActorCount < newActorsSize)
- {
- newActors[newActorCount++] = this;
- }
- else
- {
- overflow = true;
- }
- }
- else
- {
- // No more chunks; release this actor.
- release();
- }
-
- if (overflow)
- {
- NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionMultipleGraphNodes: input newActors array could not hold all actors generated.");
- }
-
- return newActorCount;
-}
-
-
-uint32_t Actor::partitionSingleLowerSupportChunk(Actor** newActors, uint32_t newActorsSize, NvBlastLog logFn)
-{
- NVBLAST_ASSERT(newActorsSize == 0 || newActors != nullptr);
-
- // Ensure this is a single subsupport chunk, no partitioning
- if (m_graphNodeCount > 1)
- {
- NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionSingleLowerSupportChunk: actor is not a single lower-support chunk, and cannot be partitioned by this function.");
- return 0;
- }
-
- FamilyHeader* header = getFamilyHeader();
-
- // The conditional (visible vs. support chunk) is needed because we allow single-child chunk chains
- // This makes it possible that an actor with a single support chunk will have a different visible chunk (ancestor of the support chunk)
- const uint32_t chunkIndex = m_graphNodeCount == 0 ? m_firstVisibleChunkIndex : getGraph()->getChunkIndices()[m_firstGraphNodeIndex];
-
- if (isInvalidIndex(chunkIndex))
- {
- return 0; // This actor has no chunks; only a graph node representing the world
- }
-
- NVBLAST_ASSERT(isInvalidIndex(header->getVisibleChunkIndexLinks()[chunkIndex].m_adj[1]));
-
- const NvBlastChunk& chunk = header->m_asset->getChunks()[chunkIndex];
- uint32_t childCount = chunk.childIndexStop - chunk.firstChildIndex;
-
- // Warn if we cannot fit all child chunks in the output list
- if (childCount > newActorsSize)
- {
- NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionSingleLowerSupportChunk: input newActors array will not hold all actors generated.");
- childCount = newActorsSize;
- }
-
- // Return if no chunks will be created.
- if (childCount == 0)
- {
- return 0;
- }
-
- // Activate a new actor for every child chunk
- const Asset* asset = getAsset();
- const NvBlastChunk* chunks = asset->getChunks();
- const uint32_t firstChildIndex = chunks[chunkIndex].firstChildIndex;
- for (uint32_t i = 0; i < childCount; ++i)
- {
- const uint32_t childIndex = firstChildIndex + i;
- NVBLAST_ASSERT(childIndex >= asset->m_firstSubsupportChunkIndex);
- const uint32_t actorIndex = asset->m_graph.m_nodeCount + (childIndex - asset->m_firstSubsupportChunkIndex);
- NVBLAST_ASSERT(!header->isActorActive(actorIndex));
- newActors[i] = header->borrowActor(actorIndex);
- newActors[i]->m_firstVisibleChunkIndex = childIndex;
- newActors[i]->m_visibleChunkCount = 1;
- newActors[i]->m_leafChunkCount = asset->getSubtreeLeafChunkCounts()[childIndex];
- }
-
- // Release this actor
- release();
-
- return childCount;
-}
-
-
-void Actor::updateVisibleChunksFromGraphNodes()
-{
- // Only apply this to upper-support chunk actors
- if (m_graphNodeCount == 0)
- {
- return;
- }
-
- const Asset* asset = getAsset();
-
- const uint32_t thisActorIndex = getIndex();
-
- // Get various arrays
- FamilyHeader* header = getFamilyHeader();
- Actor* actors = header->getActors();
- IndexDLink<uint32_t>* visibleChunkIndexLinks = header->getVisibleChunkIndexLinks();
- uint32_t* chunkActorIndices = header->getChunkActorIndices();
- const SupportGraph& graph = asset->m_graph;
- const uint32_t* graphChunkIndices = graph.getChunkIndices();
- const NvBlastChunk* chunks = asset->getChunks();
- const uint32_t upperSupportChunkCount = asset->getUpperSupportChunkCount();
-
- // Iterate over all graph nodes and update visible chunk list
- const uint32_t* graphNodeIndexLinks = header->getGraphNodeIndexLinks();
- for (uint32_t graphNodeIndex = m_firstGraphNodeIndex; !isInvalidIndex(graphNodeIndex); graphNodeIndex = graphNodeIndexLinks[graphNodeIndex])
- {
- const uint32_t supportChunkIndex = graphChunkIndices[graphNodeIndex];
- if (!isInvalidIndex(supportChunkIndex)) // Invalid if this is the world chunk
- {
- updateVisibleChunksFromSupportChunk<Actor>(actors, visibleChunkIndexLinks, chunkActorIndices, thisActorIndex, graphChunkIndices[graphNodeIndex], chunks, upperSupportChunkCount);
- }
- }
-}
-
-} // namespace Blast
-} // namespace Nv
-
-
-// API implementation
-
-extern "C"
-{
-
-NvBlastActor* NvBlastFamilyCreateFirstActor(NvBlastFamily* family, const NvBlastActorDesc* desc, void* scratch, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(family != nullptr, logFn, "NvBlastFamilyCreateFirstActor: NULL family input.", return nullptr);
- NVBLASTLL_CHECK(desc != nullptr, logFn, "NvBlastFamilyCreateFirstActor: NULL desc input.", return nullptr);
- NVBLASTLL_CHECK(scratch != nullptr, logFn, "NvBlastFamilyCreateFirstActor: NULL scratch input.", return nullptr);
-
- return Nv::Blast::Actor::create(family, desc, scratch, logFn);
-}
-
-
-size_t NvBlastFamilyGetRequiredScratchForCreateFirstActor(const NvBlastFamily* family, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(family != nullptr, logFn, "NvBlastFamilyGetRequiredScratchForCreateFirstActor: NULL family input.", return 0);
- NVBLASTLL_CHECK(reinterpret_cast<const Nv::Blast::FamilyHeader*>(family)->m_asset != nullptr,
- logFn, "NvBlastFamilyGetRequiredScratchForCreateFirstActor: family has NULL asset.", return 0);
-
- return Nv::Blast::Actor::createRequiredScratch(family);
-}
-
-
-bool NvBlastActorDeactivate(NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorDeactivate: NULL actor input.", return false);
-
- Nv::Blast::Actor& a = *static_cast<Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_WARNING(logFn, "NvBlastActorDeactivate: inactive actor input.");
- }
-
- return a.release();
-}
-
-
-uint32_t NvBlastActorGetVisibleChunkCount(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetVisibleChunkCount: NULL actor input.", return 0);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetVisibleChunkCount: inactive actor input.");
- return 0;
- }
-
- return a.getVisibleChunkCount();
-}
-
-
-uint32_t NvBlastActorGetVisibleChunkIndices(uint32_t* visibleChunkIndices, uint32_t visibleChunkIndicesSize, const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(visibleChunkIndices != nullptr, logFn, "NvBlastActorGetVisibleChunkIndices: NULL visibleChunkIndices pointer input.", return 0);
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetVisibleChunkIndices: NULL actor pointer input.", return 0);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetVisibleChunkIndices: inactive actor pointer input.");
- return 0;
- }
-
- // Iterate through visible chunk list and write to supplied array
- uint32_t indexCount = 0;
- for (Nv::Blast::Actor::VisibleChunkIt i = a; indexCount < visibleChunkIndicesSize && (bool)i; ++i)
- {
- visibleChunkIndices[indexCount++] = (uint32_t)i;
- }
-
- return indexCount;
-}
-
-
-uint32_t NvBlastActorGetGraphNodeCount(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetGraphNodeCount: NULL actor pointer input.", return 0);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetGraphNodeCount: inactive actor pointer input.");
- return 0;
- }
-
- return a.getGraphNodeCount();
-}
-
-
-uint32_t NvBlastActorGetGraphNodeIndices(uint32_t* graphNodeIndices, uint32_t graphNodeIndicesSize, const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(graphNodeIndices != nullptr, logFn, "NvBlastActorGetGraphNodeIndices: NULL graphNodeIndices pointer input.", return 0);
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetGraphNodeIndices: NULL actor pointer input.", return 0);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetGraphNodeIndices: inactive actor pointer input.");
- return 0;
- }
-
- // Iterate through graph node list and write to supplied array
- const uint32_t* graphChunkIndices = a.getAsset()->m_graph.getChunkIndices();
- uint32_t indexCount = 0;
- for (Nv::Blast::Actor::GraphNodeIt i = a; indexCount < graphNodeIndicesSize && (bool)i; ++i)
- {
- const uint32_t graphNodeIndex = (uint32_t)i;
- if (!Nv::Blast::isInvalidIndex(graphChunkIndices[graphNodeIndex]))
- {
- graphNodeIndices[indexCount++] = graphNodeIndex;
- }
- }
-
- return indexCount;
-}
-
-
-const float* NvBlastActorGetBondHealths(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetBondHealths: NULL actor pointer input.", return nullptr);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetBondHealths: inactive actor pointer input.");
- return nullptr;
- }
-
- return a.getFamilyHeader()->getBondHealths();
-}
-
-
-NvBlastFamily* NvBlastActorGetFamily(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetFamily: NULL actor pointer input.", return nullptr);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetFamily: inactive actor pointer input.");
- return nullptr;
- }
-
- return reinterpret_cast<NvBlastFamily*>(a.getFamilyHeader());
-}
-
-
-uint32_t NvBlastActorGetIndex(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetIndex: NULL actor pointer input.", return Nv::Blast::invalidIndex<uint32_t>());
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetIndex: actor is not active.");
- return Nv::Blast::invalidIndex<uint32_t>();
- }
-
- return a.getIndex();
-}
-
-
-void NvBlastActorGenerateFracture
-(
- NvBlastFractureBuffers* commandBuffers,
- const NvBlastActor* actor,
- const NvBlastDamageProgram program,
- const void* programParams,
- NvBlastLog logFn,
- NvBlastTimers* timers
-)
-{
- NVBLASTLL_CHECK(commandBuffers != nullptr, logFn, "NvBlastActorGenerateFracture: NULL commandBuffers pointer input.", return);
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGenerateFracture: NULL actor pointer input.", return);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGenerateFracture: actor is not active.");
- commandBuffers->bondFractureCount = 0;
- commandBuffers->chunkFractureCount = 0;
- return;
- }
-
- a.generateFracture(commandBuffers, program, programParams, logFn, timers);
-}
-
-
-void NvBlastActorApplyFracture
-(
- NvBlastFractureBuffers* eventBuffers,
- NvBlastActor* actor,
- const NvBlastFractureBuffers* commands,
- NvBlastLog logFn,
- NvBlastTimers* timers
-)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorApplyFracture: NULL actor pointer input.", return);
- NVBLASTLL_CHECK(commands != nullptr, logFn, "NvBlastActorApplyFracture: NULL commands pointer input.", return);
- NVBLASTLL_CHECK(Nv::Blast::isValid(commands), logFn, "NvBlastActorApplyFracture: commands memory is NULL but size is > 0.", return);
-
- Nv::Blast::Actor& a = *static_cast<Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorApplyFracture: actor is not active.");
- if (eventBuffers != nullptr)
- {
- eventBuffers->bondFractureCount = 0;
- eventBuffers->chunkFractureCount = 0;
- }
- return;
- }
-
- a.getFamilyHeader()->applyFracture(eventBuffers, commands, &a, logFn, timers);
-}
-
-
-size_t NvBlastActorGetRequiredScratchForSplit(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetRequiredScratchForSplit: NULL actor input.", return 0);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetRequiredScratchForSplit: actor is not active.");
- return 0;
- }
-
- return a.splitRequiredScratch();
-}
-
-
-uint32_t NvBlastActorGetMaxActorCountForSplit(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetMaxActorCountForSplit: NULL actor input.", return 0);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetMaxActorCountForSplit: actor is not active.");
- return 0;
- }
-
- return a.getLeafChunkCount() + 1; // GWD-167 workaround (+1)
-}
-
-
-uint32_t NvBlastActorSplit
-(
- NvBlastActorSplitEvent* result,
- NvBlastActor* actor,
- uint32_t newActorsMaxCount,
- void* scratch,
- NvBlastLog logFn,
- NvBlastTimers* timers
-)
-{
- NVBLASTLL_CHECK(result != nullptr, logFn, "NvBlastActorSplit: NULL result pointer input.", return 0);
- NVBLASTLL_CHECK(newActorsMaxCount > 0 && result->newActors != nullptr, logFn, "NvBlastActorSplit: no space for results provided.", return 0);
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorSplit: NULL actor pointer input.", return 0);
- NVBLASTLL_CHECK(scratch != nullptr, logFn, "NvBlastActorSplit: NULL scratch pointer input.", return 0);
-
- Nv::Blast::Actor& a = *static_cast<Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetIndex: actor is not active.");
- return 0;
- }
-
- return a.split(result, newActorsMaxCount, scratch, logFn, timers);
-}
-
-
-bool NvBlastActorCanFracture(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorCanFracture: NULL actor input.", return false);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
-
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorCanFracture: actor is not active.");
- return false;
- }
-
- bool canFracture = true;
-
- uint32_t graphNodeCount = a.getGraphNodeCount();
- if (graphNodeCount < 2)
- {
- uint32_t chunkHealthIndex = graphNodeCount == 0 ?
- a.getFirstVisibleChunkIndex() - a.getFirstSubsupportChunkIndex() + a.getGraph()->m_nodeCount :
- a.getFirstGraphNodeIndex();
- canFracture = (a.getLowerSupportChunkHealths()[chunkHealthIndex] > 0.0f);
- }
-
- return canFracture;
-}
-
-
-bool NvBlastActorIsBoundToWorld(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorIsBoundToWorld: NULL actor input.", return false);
-
- return static_cast<const Nv::Blast::Actor*>(actor)->isBoundToWorld();
-}
-
-
-bool NvBlastActorIsSplitRequired(const NvBlastActor* actor, NvBlastLog logFn)
-{
- NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorIsSplitRequired: NULL actor input.", return false);
-
- const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
- if (!a.isActive())
- {
- NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorIsSplitRequired: actor is not active.");
- return false;
- }
- return a.isSplitRequired();
-}
-
-} // extern "C"
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and 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.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastActor.h"
+#include "NvBlastFamilyGraph.h"
+#include "NvBlastChunkHierarchy.h"
+#include "NvBlastIndexFns.h"
+#include "NvBlastDLink.h"
+#include "NvBlastGeometry.h"
+#include "NvBlastTime.h"
+#include <float.h>
+#include <algorithm>
+
+
+namespace Nv
+{
+namespace Blast
+{
+
+//////// Actor static methods ////////
+
+size_t Actor::createRequiredScratch(const NvBlastFamily* family)
+{
+#if NVBLASTLL_CHECK_PARAMS
+ if (family == nullptr || reinterpret_cast<const FamilyHeader*>(family)->m_asset == nullptr)
+ {
+ NVBLAST_ALWAYS_ASSERT();
+ return 0;
+ }
+#endif
+
+ const Asset& solverAsset = *reinterpret_cast<const FamilyHeader*>(family)->m_asset;
+ return FamilyGraph::findIslandsRequiredScratch(solverAsset.m_graph.m_nodeCount);
+}
+
+
+Actor* Actor::create(NvBlastFamily* family, const NvBlastActorDesc* desc, void* scratch, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(family != nullptr, logFn, "Actor::create: NULL family pointer input.", return nullptr);
+ NVBLASTLL_CHECK(reinterpret_cast<FamilyHeader*>(family)->m_asset != nullptr, logFn, "Actor::create: family has NULL asset.", return nullptr);
+ NVBLASTLL_CHECK(reinterpret_cast<FamilyHeader*>(family)->m_asset->m_graph.m_nodeCount != 0, logFn, "Actor::create: family's asset has no support chunks.", return nullptr);
+ NVBLASTLL_CHECK(desc != nullptr, logFn, "Actor::create: NULL desc pointer input.", return nullptr);
+ NVBLASTLL_CHECK(scratch != nullptr, logFn, "Actor::create: NULL scratch input.", return nullptr);
+
+ FamilyHeader* header = reinterpret_cast<FamilyHeader*>(family);
+
+ if (header->m_actorCount > 0)
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "Actor::create: input family is not empty.");
+ return nullptr;
+ }
+
+ const Asset& solverAsset = *static_cast<const Asset*>(header->m_asset);
+ const SupportGraph& graph = solverAsset.m_graph;
+
+ // Lower support chunk healths - initialize
+ float* lowerSupportChunkHealths = header->getLowerSupportChunkHealths();
+ if (desc->initialSupportChunkHealths != nullptr) // Health array given
+ {
+ const uint32_t* supportChunkIndices = graph.getChunkIndices();
+ for (uint32_t supportChunkNum = 0; supportChunkNum < graph.m_nodeCount; ++supportChunkNum)
+ {
+ const float initialHealth = desc->initialSupportChunkHealths[supportChunkNum];
+ for (Asset::DepthFirstIt i(solverAsset, supportChunkIndices[supportChunkNum]); (bool)i; ++i)
+ {
+ lowerSupportChunkHealths[solverAsset.getContiguousLowerSupportIndex((uint32_t)i)] = initialHealth;
+ }
+ }
+ }
+ else // Use uniform initialization
+ {
+ const uint32_t lowerSupportChunkCount = solverAsset.getLowerSupportChunkCount();
+ for (uint32_t i = 0; i < lowerSupportChunkCount; ++i)
+ {
+ lowerSupportChunkHealths[i] = desc->uniformInitialLowerSupportChunkHealth;
+ }
+ }
+
+ // Bond healths - initialize
+ const uint32_t bondCount = solverAsset.getBondCount();
+ float* bondHealths = header->getBondHealths();
+ if (desc->initialBondHealths != nullptr) // Health array given
+ {
+ memcpy(bondHealths, desc->initialBondHealths, bondCount * sizeof(float));
+ }
+ else // Use uniform initialization
+ {
+ for (uint32_t bondNum = 0; bondNum < bondCount; ++bondNum)
+ {
+ bondHealths[bondNum] = desc->uniformInitialBondHealth;
+ }
+ }
+
+ // Get first actor - NOTE: we don't send an event for this! May need to do so for consistency.
+ Actor* actor = header->borrowActor(0); // Using actor[0]
+
+ // Fill in actor fields
+ actor->m_firstGraphNodeIndex = 0;
+ actor->m_graphNodeCount = graph.m_nodeCount;
+ actor->m_leafChunkCount = solverAsset.m_leafChunkCount;
+
+ // Graph node index links - initialize to chain
+ uint32_t* graphNodeLinks = header->getGraphNodeIndexLinks();
+ for (uint32_t i = 0; i < graph.m_nodeCount - 1; ++i)
+ {
+ graphNodeLinks[i] = i + 1;
+ }
+ graphNodeLinks[graph.m_nodeCount - 1] = invalidIndex<uint32_t>();
+
+ // Update visible chunks (we assume that all chunks belong to one actor at the beginning)
+ actor->updateVisibleChunksFromGraphNodes();
+
+ // Initialize instance graph with this actor
+ header->getFamilyGraph()->initialize(actor->getIndex(), &graph);
+
+ // Call findIslands to set up the internal instance graph data
+ header->getFamilyGraph()->findIslands(actor->getIndex(), scratch, &graph);
+
+ return actor;
+}
+
+
+//////// Actor member methods ////////
+
+uint32_t Actor::damageBond(uint32_t nodeIndex0, uint32_t nodeIndex1, float healthDamage)
+{
+ const uint32_t bondIndex = getGraph()->findBond(nodeIndex0, nodeIndex1);
+ damageBond(nodeIndex0, nodeIndex1, bondIndex, healthDamage);
+ return bondIndex;
+}
+
+
+void Actor::damageBond(uint32_t nodeIndex0, uint32_t nodeIndex1, uint32_t bondIndex, float healthDamage)
+{
+ if (bondIndex == invalidIndex<uint32_t>())
+ {
+ NVBLAST_ALWAYS_ASSERT();
+ return;
+ }
+
+ float* bondHealths = getBondHealths();
+ if (bondHealths[bondIndex] > 0 && healthDamage > 0.0f)
+ {
+ // Subtract health
+ bondHealths[bondIndex] -= healthDamage;
+
+ // Was removed?
+ if (bondHealths[bondIndex] <= 0)
+ {
+ // Notify graph that bond was removed
+ getFamilyGraph()->notifyEdgeRemoved(getIndex(), nodeIndex0, nodeIndex1, bondIndex, getGraph());
+ bondHealths[bondIndex] = 0; // Doing this for single-actor serialization consistency; should not actually be necessary
+ }
+ }
+}
+
+
+uint32_t Actor::damageBond(const NvBlastBondFractureData& cmd)
+{
+ NVBLAST_ASSERT(!isInvalidIndex(cmd.nodeIndex1));
+ return damageBond(cmd.nodeIndex0, cmd.nodeIndex1, cmd.health);
+}
+
+
+void Actor::generateFracture(NvBlastFractureBuffers* commandBuffers, const NvBlastDamageProgram& program, const void* programParams,
+ NvBlastLog logFn, NvBlastTimers* timers) const
+{
+ NVBLASTLL_CHECK(commandBuffers != nullptr, logFn, "Actor::generateFracture: NULL commandBuffers pointer input.", return);
+ NVBLASTLL_CHECK(isValid(commandBuffers), logFn, "NvBlastActorGenerateFracture: commandBuffers memory is NULL but size is > 0.",
+ commandBuffers->bondFractureCount = 0; commandBuffers->chunkFractureCount = 0; return);
+
+#if NVBLASTLL_CHECK_PARAMS
+ if (commandBuffers->bondFractureCount == 0 && commandBuffers->chunkFractureCount == 0)
+ {
+ NVBLASTLL_LOG_WARNING(logFn, "NvBlastActorGenerateFracture: commandBuffers do not provide any space.");
+ return;
+ }
+#endif
+
+#if NV_PROFILE
+ Time time;
+#else
+ NV_UNUSED(timers);
+#endif
+
+ const SupportGraph* graph = getGraph();
+
+ const uint32_t graphNodeCount = getGraphNodeCount();
+ if (graphNodeCount > 1 && program.graphShaderFunction != nullptr)
+ {
+ const NvBlastGraphShaderActor shaderActor = {
+ getIndex(),
+ getGraphNodeCount(),
+ graph->m_nodeCount,
+ getFirstGraphNodeIndex(),
+ getGraphNodeIndexLinks(),
+ graph->getChunkIndices(),
+ graph->getAdjacencyPartition(),
+ graph->getAdjacentNodeIndices(),
+ graph->getAdjacentBondIndices(),
+ getBonds(),
+ getChunks(),
+ getBondHealths(),
+ getLowerSupportChunkHealths(),
+ getFamilyHeader()->getFamilyGraph()->getIslandIds()
+ };
+
+ program.graphShaderFunction(commandBuffers, &shaderActor, programParams);
+ }
+ else if (graphNodeCount <= 1 && program.subgraphShaderFunction != nullptr)
+ {
+ const NvBlastSubgraphShaderActor shaderActor = {
+ // The conditional (visible vs. support chunk) is needed because we allow single-child chunk chains
+ // This makes it possible that an actor with a single support chunk will have a different visible chunk (ancestor of the support chunk)
+ graphNodeCount == 1 ? graph->getChunkIndices()[getFirstGraphNodeIndex()] : getFirstVisibleChunkIndex(),
+ getChunks()
+ };
+
+ program.subgraphShaderFunction(commandBuffers, &shaderActor, programParams);
+ }
+ else
+ {
+ commandBuffers->bondFractureCount = 0;
+ commandBuffers->chunkFractureCount = 0;
+ }
+
+#if NV_PROFILE
+ if (timers != nullptr)
+ {
+ timers->material += time.getElapsedTicks();
+ }
+#endif
+}
+
+
+
+
+size_t Actor::splitRequiredScratch() const
+{
+ // Scratch is reused, just need the max of these two values
+ return std::max(m_graphNodeCount * sizeof(uint32_t), static_cast<size_t>(FamilyGraph::findIslandsRequiredScratch(getGraph()->m_nodeCount)));
+}
+
+
+uint32_t Actor::split(NvBlastActorSplitEvent* result, uint32_t newActorsMaxCount, void* scratch, NvBlastLog logFn, NvBlastTimers* timers)
+{
+ NVBLASTLL_CHECK(result != nullptr, logFn, "Actor::split: NULL result pointer input.", return 0);
+ NVBLASTLL_CHECK(newActorsMaxCount > 0 && result->newActors != nullptr, logFn, "NvBlastActorSplit: no space for results provided.", return 0);
+ NVBLASTLL_CHECK(scratch != nullptr, logFn, "Actor::split: NULL scratch pointer input.", return 0);
+
+#if NV_PROFILE
+ Time time;
+#else
+ NV_UNUSED(timers);
+#endif
+
+ Actor** newActors = reinterpret_cast<Actor**>(result->newActors);
+
+ uint32_t actorsCount = 0;
+
+ if (getGraphNodeCount() <= 1)
+ {
+ uint32_t chunkHealthIndex = isSingleSupportChunk() ? getIndex() : getFirstVisibleChunkIndex() - getFirstSubsupportChunkIndex() + getGraph()->m_nodeCount;
+
+ float* chunkHealths = getLowerSupportChunkHealths();
+ if (chunkHealths[chunkHealthIndex] <= 0.0f)
+ {
+ actorsCount = partitionSingleLowerSupportChunk(newActors, newActorsMaxCount, logFn);
+
+ for (uint32_t i = 0; i < actorsCount; ++i)
+ {
+ Actor* newActor = newActors[i];
+ uint32_t firstVisible = newActor->getFirstVisibleChunkIndex();
+ uint32_t firstSub = newActor->getFirstSubsupportChunkIndex();
+ uint32_t nodeCount = newActor->getGraph()->m_nodeCount;
+ uint32_t newActorIndex = newActor->getIndex();
+ uint32_t healthIndex = newActor->isSubSupportChunk() ? firstVisible - firstSub + nodeCount : newActorIndex;
+
+ if (chunkHealths[healthIndex] <= 0.0f)
+ {
+ uint32_t brittleActors = newActors[i]->partitionSingleLowerSupportChunk(&newActors[actorsCount], newActorsMaxCount - actorsCount, logFn);
+ actorsCount += brittleActors;
+
+ if (brittleActors > 0)
+ {
+ actorsCount--;
+ newActors[i] = newActors[actorsCount];
+ i--;
+ }
+ }
+ }
+ }
+
+
+#if NV_PROFILE
+ if (timers != nullptr)
+ {
+ timers->partition += time.getElapsedTicks();
+ }
+#endif
+ }
+ else
+ {
+ findIslands(scratch);
+
+#if NV_PROFILE
+ if (timers != nullptr)
+ {
+ timers->island += time.getElapsedTicks();
+ }
+#endif
+
+ // Reuse scratch for node list
+ uint32_t* graphNodeIndexList = reinterpret_cast<uint32_t*>(scratch);
+
+ // Get the family header
+ FamilyHeader* header = getFamilyHeader();
+ NVBLAST_ASSERT(header != nullptr); // If m_actorEntryDataIndex is valid, this should be too
+
+ // Record nodes in this actor before splitting
+ const uint32_t* graphNodeIndexLinks = header->getGraphNodeIndexLinks(); // Get the links for the graph nodes
+ uint32_t graphNodeIndexCount = 0;
+ for (uint32_t graphNodeIndex = m_firstGraphNodeIndex; !isInvalidIndex(graphNodeIndex); graphNodeIndex = graphNodeIndexLinks[graphNodeIndex])
+ {
+ if (graphNodeIndexCount >= m_graphNodeCount)
+ {
+ // Safety, splitRequiredScratch() only guarantees m_graphNodeCount elements. In any case, this condition shouldn't happen.
+ NVBLAST_ASSERT(graphNodeIndexCount < m_graphNodeCount);
+ break;
+ }
+ graphNodeIndexList[graphNodeIndexCount++] = graphNodeIndex;
+ }
+
+ actorsCount = partitionMultipleGraphNodes(newActors, newActorsMaxCount, logFn);
+
+ if (actorsCount > 1)
+ {
+#if NV_PROFILE
+ if (timers != nullptr)
+ {
+ timers->partition += time.getElapsedTicks();
+ }
+#endif
+
+ // Get various pointers and values to iterate
+ const Asset* asset = getAsset();
+ Actor* actors = header->getActors();
+ IndexDLink<uint32_t>* visibleChunkIndexLinks = header->getVisibleChunkIndexLinks();
+ uint32_t* chunkActorIndices = header->getChunkActorIndices();
+ const SupportGraph& graph = asset->m_graph;
+ const uint32_t* graphChunkIndices = graph.getChunkIndices();
+ const NvBlastChunk* chunks = asset->getChunks();
+ const uint32_t upperSupportChunkCount = asset->getUpperSupportChunkCount();
+ const uint32_t* familyGraphIslandIDs = header->getFamilyGraph()->getIslandIds();
+
+ // Iterate over all graph nodes and update visible chunk lists
+ for (uint32_t graphNodeNum = 0; graphNodeNum < graphNodeIndexCount; ++graphNodeNum)
+ {
+ const uint32_t graphNodeIndex = graphNodeIndexList[graphNodeNum];
+ const uint32_t supportChunkIndex = graphChunkIndices[graphNodeIndex];
+ if (!isInvalidIndex(supportChunkIndex)) // Invalid if this is the world chunk
+ {
+ updateVisibleChunksFromSupportChunk<Actor>(actors, visibleChunkIndexLinks, chunkActorIndices, familyGraphIslandIDs[graphNodeIndex], graphChunkIndices[graphNodeIndex], chunks, upperSupportChunkCount);
+ }
+ }
+
+ // Remove actors with no visible chunks - this can happen if we've split such that the world node is by itself
+ uint32_t actualActorsCount = 0;
+ for (uint32_t i = 0; i < actorsCount; ++i)
+ {
+ newActors[actualActorsCount] = newActors[i];
+ if (newActors[actualActorsCount]->getVisibleChunkCount() > 0)
+ {
+ ++actualActorsCount;
+ }
+ else
+ {
+ header->returnActor(*newActors[actualActorsCount]);
+ }
+ }
+ actorsCount = actualActorsCount;
+
+#if NV_PROFILE
+ if (timers != nullptr)
+ {
+ timers->visibility += time.getElapsedTicks();
+ }
+#endif
+
+ for (uint32_t i = 0; i < actorsCount; ++i)
+ {
+ Actor* newActor = newActors[i];
+ float* chunkHealths = newActor->getLowerSupportChunkHealths();
+ uint32_t firstVisible = newActor->getFirstVisibleChunkIndex();
+ uint32_t firstSub = newActor->getFirstSubsupportChunkIndex();
+ uint32_t nodeCount = newActor->getGraph()->m_nodeCount;
+ uint32_t newActorIndex = newActor->getIndex();
+ uint32_t healthIndex = newActor->isSubSupportChunk() ? firstVisible - firstSub + nodeCount : newActorIndex;
+
+ if (newActors[i]->getGraphNodeCount() <= 1)
+ {
+ // this relies on visibility updated, subsupport actors only have m_firstVisibleChunkIndex to identify the chunk
+ if (chunkHealths[healthIndex] <= 0.0f)
+ {
+ uint32_t brittleActors = newActors[i]->partitionSingleLowerSupportChunk(&newActors[actorsCount], newActorsMaxCount - actorsCount, logFn);
+ actorsCount += brittleActors;
+
+ if (brittleActors > 0)
+ {
+ actorsCount--;
+ newActors[i] = newActors[actorsCount];
+ i--;
+ }
+ }
+ }
+ }
+
+#if NV_PROFILE
+ if (timers != nullptr)
+ {
+ timers->partition += time.getElapsedTicks();
+ }
+#endif
+ }
+ else
+ {
+ actorsCount = 0;
+ }
+ }
+
+ result->deletedActor = actorsCount == 0 ? nullptr : this;
+
+ return actorsCount;
+}
+
+
+uint32_t Actor::findIslands(void* scratch)
+{
+ return getFamilyHeader()->getFamilyGraph()->findIslands(getIndex(), scratch, &getAsset()->m_graph);
+}
+
+
+uint32_t Actor::partitionMultipleGraphNodes(Actor** newActors, uint32_t newActorsSize, NvBlastLog logFn)
+{
+ NVBLAST_ASSERT(newActorsSize == 0 || newActors != nullptr);
+
+ // Check for single subsupport chunk, no partitioning
+ if (m_graphNodeCount <= 1)
+ {
+ NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionMultipleGraphNodes: actor is a single lower-support chunk, and cannot be partitioned by this function.");
+ return 0;
+ }
+
+ FamilyHeader* header = getFamilyHeader();
+ NVBLAST_ASSERT(header != nullptr); // If m_actorEntryDataIndex is valid, this should be too
+
+ // Get the links for the graph nodes
+ uint32_t* graphNodeIndexLinks = header->getGraphNodeIndexLinks();
+
+ // Get the graph chunk indices and leaf chunk counts
+ const Asset* asset = getAsset();
+ const uint32_t* graphChunkIndices = asset->m_graph.getChunkIndices();
+ const uint32_t* subtreeLeafChunkCounts = asset->getSubtreeLeafChunkCounts();
+
+ // Distribute graph nodes to new actors
+ uint32_t newActorCount = 0;
+ const uint32_t thisActorIndex = getIndex();
+ m_leafChunkCount = 0;
+ const uint32_t* islandIDs = header->getFamilyGraph()->getIslandIds();
+ uint32_t lastGraphNodeIndex = invalidIndex<uint32_t>();
+ uint32_t nextGraphNodeIndex = invalidIndex<uint32_t>();
+ bool overflow = false;
+ for (uint32_t graphNodeIndex = m_firstGraphNodeIndex; !isInvalidIndex(graphNodeIndex); graphNodeIndex = nextGraphNodeIndex)
+ {
+ nextGraphNodeIndex = graphNodeIndexLinks[graphNodeIndex];
+ const uint32_t islandID = islandIDs[graphNodeIndex];
+
+ if (islandID == thisActorIndex)
+ {
+ const uint32_t graphChunkIndex = graphChunkIndices[graphNodeIndex];
+ if (!isInvalidIndex(graphChunkIndex)) // Invalid if this is the world chunk
+ {
+ m_leafChunkCount += subtreeLeafChunkCounts[graphChunkIndex];
+ }
+ lastGraphNodeIndex = graphNodeIndex;
+ continue; // Leave the chunk in this actor
+ }
+
+ // Remove link from this actor
+ if (isInvalidIndex(lastGraphNodeIndex))
+ {
+ m_firstGraphNodeIndex = nextGraphNodeIndex;
+ }
+ else
+ {
+ graphNodeIndexLinks[lastGraphNodeIndex] = nextGraphNodeIndex;
+ }
+ graphNodeIndexLinks[graphNodeIndex] = invalidIndex<uint32_t>();
+ --m_graphNodeCount;
+
+ // See if the chunk had been removed
+ if (islandID == invalidIndex<uint32_t>())
+ {
+ continue;
+ }
+
+ // Get new actor if the islandID is valid
+ Actor* newActor = header->borrowActor(islandID);
+
+ // Check new actor to see if we're adding the first chunk
+ if (isInvalidIndex(newActor->m_firstGraphNodeIndex))
+ {
+ // See if we can fit it in the output list
+ if (newActorCount < newActorsSize)
+ {
+ newActors[newActorCount++] = newActor;
+ }
+ else
+ {
+ overflow = true;
+ }
+ }
+
+ // Put link in new actor
+ graphNodeIndexLinks[graphNodeIndex] = newActor->m_firstGraphNodeIndex;
+ newActor->m_firstGraphNodeIndex = graphNodeIndex;
+ ++newActor->m_graphNodeCount;
+ // Add to the actor's leaf chunk count
+ const uint32_t graphChunkIndex = graphChunkIndices[graphNodeIndex];
+ if (!isInvalidIndex(graphChunkIndex)) // Invalid if this is the world chunk
+ {
+ newActor->m_leafChunkCount += subtreeLeafChunkCounts[graphChunkIndex];
+ }
+ }
+
+ if (m_graphNodeCount > 0)
+ {
+ // There are still chunks in this actor. See if we can fit this in the output list.
+ if (newActorCount < newActorsSize)
+ {
+ newActors[newActorCount++] = this;
+ }
+ else
+ {
+ overflow = true;
+ }
+ }
+ else
+ {
+ // No more chunks; release this actor.
+ release();
+ }
+
+ if (overflow)
+ {
+ NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionMultipleGraphNodes: input newActors array could not hold all actors generated.");
+ }
+
+ return newActorCount;
+}
+
+
+uint32_t Actor::partitionSingleLowerSupportChunk(Actor** newActors, uint32_t newActorsSize, NvBlastLog logFn)
+{
+ NVBLAST_ASSERT(newActorsSize == 0 || newActors != nullptr);
+
+ // Ensure this is a single subsupport chunk, no partitioning
+ if (m_graphNodeCount > 1)
+ {
+ NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionSingleLowerSupportChunk: actor is not a single lower-support chunk, and cannot be partitioned by this function.");
+ return 0;
+ }
+
+ FamilyHeader* header = getFamilyHeader();
+
+ // The conditional (visible vs. support chunk) is needed because we allow single-child chunk chains
+ // This makes it possible that an actor with a single support chunk will have a different visible chunk (ancestor of the support chunk)
+ const uint32_t chunkIndex = m_graphNodeCount == 0 ? m_firstVisibleChunkIndex : getGraph()->getChunkIndices()[m_firstGraphNodeIndex];
+
+ if (isInvalidIndex(chunkIndex))
+ {
+ return 0; // This actor has no chunks; only a graph node representing the world
+ }
+
+ NVBLAST_ASSERT(isInvalidIndex(header->getVisibleChunkIndexLinks()[chunkIndex].m_adj[1]));
+
+ const NvBlastChunk& chunk = header->m_asset->getChunks()[chunkIndex];
+ uint32_t childCount = chunk.childIndexStop - chunk.firstChildIndex;
+
+ // Warn if we cannot fit all child chunks in the output list
+ if (childCount > newActorsSize)
+ {
+ NVBLASTLL_LOG_WARNING(logFn, "Nv::Blast::Actor::partitionSingleLowerSupportChunk: input newActors array will not hold all actors generated.");
+ childCount = newActorsSize;
+ }
+
+ // Return if no chunks will be created.
+ if (childCount == 0)
+ {
+ return 0;
+ }
+
+ // Activate a new actor for every child chunk
+ const Asset* asset = getAsset();
+ const NvBlastChunk* chunks = asset->getChunks();
+ const uint32_t firstChildIndex = chunks[chunkIndex].firstChildIndex;
+ for (uint32_t i = 0; i < childCount; ++i)
+ {
+ const uint32_t childIndex = firstChildIndex + i;
+ NVBLAST_ASSERT(childIndex >= asset->m_firstSubsupportChunkIndex);
+ const uint32_t actorIndex = asset->m_graph.m_nodeCount + (childIndex - asset->m_firstSubsupportChunkIndex);
+ NVBLAST_ASSERT(!header->isActorActive(actorIndex));
+ newActors[i] = header->borrowActor(actorIndex);
+ newActors[i]->m_firstVisibleChunkIndex = childIndex;
+ newActors[i]->m_visibleChunkCount = 1;
+ newActors[i]->m_leafChunkCount = asset->getSubtreeLeafChunkCounts()[childIndex];
+ }
+
+ // Release this actor
+ release();
+
+ return childCount;
+}
+
+
+void Actor::updateVisibleChunksFromGraphNodes()
+{
+ // Only apply this to upper-support chunk actors
+ if (m_graphNodeCount == 0)
+ {
+ return;
+ }
+
+ const Asset* asset = getAsset();
+
+ const uint32_t thisActorIndex = getIndex();
+
+ // Get various arrays
+ FamilyHeader* header = getFamilyHeader();
+ Actor* actors = header->getActors();
+ IndexDLink<uint32_t>* visibleChunkIndexLinks = header->getVisibleChunkIndexLinks();
+ uint32_t* chunkActorIndices = header->getChunkActorIndices();
+ const SupportGraph& graph = asset->m_graph;
+ const uint32_t* graphChunkIndices = graph.getChunkIndices();
+ const NvBlastChunk* chunks = asset->getChunks();
+ const uint32_t upperSupportChunkCount = asset->getUpperSupportChunkCount();
+
+ // Iterate over all graph nodes and update visible chunk list
+ const uint32_t* graphNodeIndexLinks = header->getGraphNodeIndexLinks();
+ for (uint32_t graphNodeIndex = m_firstGraphNodeIndex; !isInvalidIndex(graphNodeIndex); graphNodeIndex = graphNodeIndexLinks[graphNodeIndex])
+ {
+ const uint32_t supportChunkIndex = graphChunkIndices[graphNodeIndex];
+ if (!isInvalidIndex(supportChunkIndex)) // Invalid if this is the world chunk
+ {
+ updateVisibleChunksFromSupportChunk<Actor>(actors, visibleChunkIndexLinks, chunkActorIndices, thisActorIndex, graphChunkIndices[graphNodeIndex], chunks, upperSupportChunkCount);
+ }
+ }
+}
+
+} // namespace Blast
+} // namespace Nv
+
+
+// API implementation
+
+extern "C"
+{
+
+NvBlastActor* NvBlastFamilyCreateFirstActor(NvBlastFamily* family, const NvBlastActorDesc* desc, void* scratch, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(family != nullptr, logFn, "NvBlastFamilyCreateFirstActor: NULL family input.", return nullptr);
+ NVBLASTLL_CHECK(desc != nullptr, logFn, "NvBlastFamilyCreateFirstActor: NULL desc input.", return nullptr);
+ NVBLASTLL_CHECK(scratch != nullptr, logFn, "NvBlastFamilyCreateFirstActor: NULL scratch input.", return nullptr);
+
+ return Nv::Blast::Actor::create(family, desc, scratch, logFn);
+}
+
+
+size_t NvBlastFamilyGetRequiredScratchForCreateFirstActor(const NvBlastFamily* family, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(family != nullptr, logFn, "NvBlastFamilyGetRequiredScratchForCreateFirstActor: NULL family input.", return 0);
+ NVBLASTLL_CHECK(reinterpret_cast<const Nv::Blast::FamilyHeader*>(family)->m_asset != nullptr,
+ logFn, "NvBlastFamilyGetRequiredScratchForCreateFirstActor: family has NULL asset.", return 0);
+
+ return Nv::Blast::Actor::createRequiredScratch(family);
+}
+
+
+bool NvBlastActorDeactivate(NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorDeactivate: NULL actor input.", return false);
+
+ Nv::Blast::Actor& a = *static_cast<Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_WARNING(logFn, "NvBlastActorDeactivate: inactive actor input.");
+ }
+
+ return a.release();
+}
+
+
+uint32_t NvBlastActorGetVisibleChunkCount(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetVisibleChunkCount: NULL actor input.", return 0);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetVisibleChunkCount: inactive actor input.");
+ return 0;
+ }
+
+ return a.getVisibleChunkCount();
+}
+
+
+uint32_t NvBlastActorGetVisibleChunkIndices(uint32_t* visibleChunkIndices, uint32_t visibleChunkIndicesSize, const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(visibleChunkIndices != nullptr, logFn, "NvBlastActorGetVisibleChunkIndices: NULL visibleChunkIndices pointer input.", return 0);
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetVisibleChunkIndices: NULL actor pointer input.", return 0);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetVisibleChunkIndices: inactive actor pointer input.");
+ return 0;
+ }
+
+ // Iterate through visible chunk list and write to supplied array
+ uint32_t indexCount = 0;
+ for (Nv::Blast::Actor::VisibleChunkIt i = a; indexCount < visibleChunkIndicesSize && (bool)i; ++i)
+ {
+ visibleChunkIndices[indexCount++] = (uint32_t)i;
+ }
+
+ return indexCount;
+}
+
+
+uint32_t NvBlastActorGetGraphNodeCount(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetGraphNodeCount: NULL actor pointer input.", return 0);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetGraphNodeCount: inactive actor pointer input.");
+ return 0;
+ }
+
+ return a.getGraphNodeCount();
+}
+
+
+uint32_t NvBlastActorGetGraphNodeIndices(uint32_t* graphNodeIndices, uint32_t graphNodeIndicesSize, const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(graphNodeIndices != nullptr, logFn, "NvBlastActorGetGraphNodeIndices: NULL graphNodeIndices pointer input.", return 0);
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetGraphNodeIndices: NULL actor pointer input.", return 0);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetGraphNodeIndices: inactive actor pointer input.");
+ return 0;
+ }
+
+ // Iterate through graph node list and write to supplied array
+ const uint32_t* graphChunkIndices = a.getAsset()->m_graph.getChunkIndices();
+ uint32_t indexCount = 0;
+ for (Nv::Blast::Actor::GraphNodeIt i = a; indexCount < graphNodeIndicesSize && (bool)i; ++i)
+ {
+ const uint32_t graphNodeIndex = (uint32_t)i;
+ if (!Nv::Blast::isInvalidIndex(graphChunkIndices[graphNodeIndex]))
+ {
+ graphNodeIndices[indexCount++] = graphNodeIndex;
+ }
+ }
+
+ return indexCount;
+}
+
+
+const float* NvBlastActorGetBondHealths(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetBondHealths: NULL actor pointer input.", return nullptr);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetBondHealths: inactive actor pointer input.");
+ return nullptr;
+ }
+
+ return a.getFamilyHeader()->getBondHealths();
+}
+
+
+NvBlastFamily* NvBlastActorGetFamily(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetFamily: NULL actor pointer input.", return nullptr);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetFamily: inactive actor pointer input.");
+ return nullptr;
+ }
+
+ return reinterpret_cast<NvBlastFamily*>(a.getFamilyHeader());
+}
+
+
+uint32_t NvBlastActorGetIndex(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetIndex: NULL actor pointer input.", return Nv::Blast::invalidIndex<uint32_t>());
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetIndex: actor is not active.");
+ return Nv::Blast::invalidIndex<uint32_t>();
+ }
+
+ return a.getIndex();
+}
+
+
+void NvBlastActorGenerateFracture
+(
+ NvBlastFractureBuffers* commandBuffers,
+ const NvBlastActor* actor,
+ const NvBlastDamageProgram program,
+ const void* programParams,
+ NvBlastLog logFn,
+ NvBlastTimers* timers
+)
+{
+ NVBLASTLL_CHECK(commandBuffers != nullptr, logFn, "NvBlastActorGenerateFracture: NULL commandBuffers pointer input.", return);
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGenerateFracture: NULL actor pointer input.", return);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGenerateFracture: actor is not active.");
+ commandBuffers->bondFractureCount = 0;
+ commandBuffers->chunkFractureCount = 0;
+ return;
+ }
+
+ a.generateFracture(commandBuffers, program, programParams, logFn, timers);
+}
+
+
+void NvBlastActorApplyFracture
+(
+ NvBlastFractureBuffers* eventBuffers,
+ NvBlastActor* actor,
+ const NvBlastFractureBuffers* commands,
+ NvBlastLog logFn,
+ NvBlastTimers* timers
+)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorApplyFracture: NULL actor pointer input.", return);
+ NVBLASTLL_CHECK(commands != nullptr, logFn, "NvBlastActorApplyFracture: NULL commands pointer input.", return);
+ NVBLASTLL_CHECK(Nv::Blast::isValid(commands), logFn, "NvBlastActorApplyFracture: commands memory is NULL but size is > 0.", return);
+
+ Nv::Blast::Actor& a = *static_cast<Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorApplyFracture: actor is not active.");
+ if (eventBuffers != nullptr)
+ {
+ eventBuffers->bondFractureCount = 0;
+ eventBuffers->chunkFractureCount = 0;
+ }
+ return;
+ }
+
+ a.getFamilyHeader()->applyFracture(eventBuffers, commands, &a, logFn, timers);
+}
+
+
+size_t NvBlastActorGetRequiredScratchForSplit(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetRequiredScratchForSplit: NULL actor input.", return 0);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetRequiredScratchForSplit: actor is not active.");
+ return 0;
+ }
+
+ return a.splitRequiredScratch();
+}
+
+
+uint32_t NvBlastActorGetMaxActorCountForSplit(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorGetMaxActorCountForSplit: NULL actor input.", return 0);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetMaxActorCountForSplit: actor is not active.");
+ return 0;
+ }
+
+ return a.getLeafChunkCount() + 1; // GWD-167 workaround (+1)
+}
+
+
+uint32_t NvBlastActorSplit
+(
+ NvBlastActorSplitEvent* result,
+ NvBlastActor* actor,
+ uint32_t newActorsMaxCount,
+ void* scratch,
+ NvBlastLog logFn,
+ NvBlastTimers* timers
+)
+{
+ NVBLASTLL_CHECK(result != nullptr, logFn, "NvBlastActorSplit: NULL result pointer input.", return 0);
+ NVBLASTLL_CHECK(newActorsMaxCount > 0 && result->newActors != nullptr, logFn, "NvBlastActorSplit: no space for results provided.", return 0);
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorSplit: NULL actor pointer input.", return 0);
+ NVBLASTLL_CHECK(scratch != nullptr, logFn, "NvBlastActorSplit: NULL scratch pointer input.", return 0);
+
+ Nv::Blast::Actor& a = *static_cast<Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorGetIndex: actor is not active.");
+ return 0;
+ }
+
+ return a.split(result, newActorsMaxCount, scratch, logFn, timers);
+}
+
+
+bool NvBlastActorCanFracture(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorCanFracture: NULL actor input.", return false);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorCanFracture: actor is not active.");
+ return false;
+ }
+
+ bool canFracture = true;
+
+ uint32_t graphNodeCount = a.getGraphNodeCount();
+ if (graphNodeCount < 2)
+ {
+ uint32_t chunkHealthIndex = graphNodeCount == 0 ?
+ a.getFirstVisibleChunkIndex() - a.getFirstSubsupportChunkIndex() + a.getGraph()->m_nodeCount :
+ a.getFirstGraphNodeIndex();
+ canFracture = (a.getLowerSupportChunkHealths()[chunkHealthIndex] > 0.0f);
+ }
+
+ return canFracture;
+}
+
+
+bool NvBlastActorIsBoundToWorld(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorIsBoundToWorld: NULL actor input.", return false);
+
+ return static_cast<const Nv::Blast::Actor*>(actor)->isBoundToWorld();
+}
+
+
+bool NvBlastActorIsSplitRequired(const NvBlastActor* actor, NvBlastLog logFn)
+{
+ NVBLASTLL_CHECK(actor != nullptr, logFn, "NvBlastActorIsSplitRequired: NULL actor input.", return false);
+
+ const Nv::Blast::Actor& a = *static_cast<const Nv::Blast::Actor*>(actor);
+ if (!a.isActive())
+ {
+ NVBLASTLL_LOG_ERROR(logFn, "NvBlastActorIsSplitRequired: actor is not active.");
+ return false;
+ }
+ return a.isSplitRequired();
+}
+
+} // extern "C"