aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/assetutils/source/NvBlastExtAssetUtils.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/extensions/assetutils/source/NvBlastExtAssetUtils.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/extensions/assetutils/source/NvBlastExtAssetUtils.cpp')
-rwxr-xr-x[-rw-r--r--]sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp966
1 files changed, 483 insertions, 483 deletions
diff --git a/sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp b/sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp
index 072bb10..2c902d4 100644..100755
--- a/sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp
+++ b/sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp
@@ -1,483 +1,483 @@
-// 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) 2018 NVIDIA Corporation. All rights reserved.
-
-
-#include "NvBlastExtAssetUtils.h"
-#include "NvBlast.h"
-#include "NvBlastIndexFns.h"
-#include "NvBlastMemory.h"
-#include "NvBlastGlobals.h"
-#include "math.h"
-
-using namespace Nv::Blast;
-
-
-/**
-Fill the chunk and bond descriptors from an asset.
-
-\param[out] chunkDescsWritten the number of chunk descriptors written to chunkDescs
-\param[out] bondDescsWritten the number of bond descriptors written to bondDescs
-\param[out] chunkDescs user-supplied buffer of NvBlastChunkDesc. Size must be at least NvBlastAssetGetChunkCount(asset, logFn)
-\param[out] bondDescs user-supplied buffer of NvBlastBondDesc. Size must be at least NvBlastAssetGetBondCount(asset, logFn)
-\param[in] asset asset from which to extract descriptors
-*/
-static void fillChunkAndBondDescriptorsFromAsset
-(
- uint32_t& chunkDescsWritten,
- uint32_t& bondDescsWritten,
- NvBlastChunkDesc* chunkDescs,
- NvBlastBondDesc* bondDescs,
- const NvBlastAsset* asset
-)
-{
- chunkDescsWritten = 0;
- bondDescsWritten = 0;
-
- // Chunk descs
- const uint32_t assetChunkCount = NvBlastAssetGetChunkCount(asset, logLL);
- const NvBlastChunk* assetChunk = NvBlastAssetGetChunks(asset, logLL);
- for (uint32_t i = 0; i < assetChunkCount; ++i, ++assetChunk)
- {
- NvBlastChunkDesc& chunkDesc = chunkDescs[chunkDescsWritten++];
- memcpy(chunkDesc.centroid, assetChunk->centroid, sizeof(float) * 3);
- chunkDesc.volume = assetChunk->volume;
- chunkDesc.parentChunkIndex = assetChunk->parentChunkIndex;
- chunkDesc.flags = 0; // To be filled in below
- chunkDesc.userData = assetChunk->userData;
- }
-
- // Bond descs
- const uint32_t assetBondCount = NvBlastAssetGetBondCount(asset, logLL);
- const NvBlastBond* assetBond = NvBlastAssetGetBonds(asset, logLL);
- for (uint32_t i = 0; i < assetBondCount; ++i, ++assetBond)
- {
- NvBlastBondDesc& bondDesc = bondDescs[bondDescsWritten++];
- memcpy(&bondDesc.bond, assetBond, sizeof(NvBlastBond));
- }
-
- // Walk the graph and restore connection descriptors
- const NvBlastSupportGraph graph = NvBlastAssetGetSupportGraph(asset, logLL);
- for (uint32_t i = 0; i < graph.nodeCount; ++i)
- {
- const int32_t currentChunk = graph.chunkIndices[i];
- if (isInvalidIndex(currentChunk))
- {
- continue;
- }
-
- chunkDescs[currentChunk].flags |= NvBlastChunkDesc::SupportFlag; // Filling in chunk flags here
-
- for (uint32_t j = graph.adjacencyPartition[i]; j < graph.adjacencyPartition[i + 1]; ++j)
- {
- NvBlastBondDesc& bondDesc = bondDescs[graph.adjacentBondIndices[j]];
- bondDesc.chunkIndices[0] = currentChunk;
- const uint32_t adjacentChunkIndex = graph.chunkIndices[graph.adjacentNodeIndices[j]];
- bondDesc.chunkIndices[1] = adjacentChunkIndex;
- }
- }
-}
-
-
-/**
-Scale a 3-vector v in-place.
-
-\param[in,out] v The vector to scale.
-\param[in] s The scale. Represents the diagonal elements of a diagonal matrix.
-
-The result will be v <- s*v.
-*/
-static inline void scale(NvcVec3& v, const NvcVec3& s)
-{
- v.x *= s.x;
- v.y *= s.y;
- v.z *= s.z;
-}
-
-
-/**
-Rotate a 3-vector v in-place using a rotation represented by a quaternion q.
-
-\param[in,out] v The vector to rotate.
-\param[in] q The quaternion representation the rotation.
-
-The format of q is { x, y, z, w } where (x,y,z) is the vector part and w is the scalar part.
-The quaternion q MUST be normalized.
-*/
-static inline void rotate(NvcVec3& v, const NvcQuat& q)
-{
- const float vx = 2.0f * v.x;
- const float vy = 2.0f * v.y;
- const float vz = 2.0f * v.z;
- const float w2 = q.w * q.w - 0.5f;
- const float dot2 = (q.x * vx + q.y * vy + q.z * vz);
- v.x = vx * w2 + (q.y * vz - q.z * vy) * q.w + q.x * dot2;
- v.y = vy * w2 + (q.z * vx - q.x * vz) * q.w + q.y * dot2;
- v.z = vz * w2 + (q.x * vy - q.y * vx) * q.w + q.z * dot2;
-}
-
-
-/**
-Translate a 3-vector v in-place.
-
-\param[in,out] v The vector to translate.
-\param[in] t The translation.
-
-The result will be v <- v+t.
-*/
-static inline void translate(NvcVec3& v, const NvcVec3& t)
-{
- v.x += t.x;
- v.y += t.y;
- v.z += t.z;
-}
-
-
-NvBlastAsset* NvBlastExtAssetUtilsAddWorldBonds
-(
- const NvBlastAsset* asset,
- const uint32_t* worldBoundChunks,
- uint32_t worldBoundChunkCount,
- const NvcVec3* bondDirections,
- const uint32_t* bondUserData
-)
-{
- const uint32_t chunkCount = NvBlastAssetGetChunkCount(asset, logLL);
- const uint32_t oldBondCount = NvBlastAssetGetBondCount(asset, logLL);
- const uint32_t newBondCount = oldBondCount + worldBoundChunkCount;
-
- NvBlastChunkDesc* chunkDescs = static_cast<NvBlastChunkDesc*>(NVBLAST_ALLOC(chunkCount * sizeof(NvBlastChunkDesc)));
- NvBlastBondDesc* bondDescs = static_cast<NvBlastBondDesc*>(NVBLAST_ALLOC(newBondCount * sizeof(NvBlastBondDesc)));
-
- // Create chunk descs
- uint32_t chunkDescsWritten;
- uint32_t bondDescsWritten;
- fillChunkAndBondDescriptorsFromAsset(chunkDescsWritten, bondDescsWritten, chunkDescs, bondDescs, asset);
-
- // Add world bonds
- uint32_t bondCount = oldBondCount;
- for (uint32_t i = 0; i < worldBoundChunkCount; i++)
- {
- NvBlastBondDesc& bondDesc = bondDescs[bondCount++];
- const uint32_t chunkIndex = worldBoundChunks[i];
- bondDesc.chunkIndices[0] = chunkIndex;
- bondDesc.chunkIndices[1] = invalidIndex<uint32_t>();
- memcpy(&bondDesc.bond.normal, bondDirections + i, sizeof(float) * 3);
- bondDesc.bond.area = 1.0f; // Should be set by user
- memcpy(&bondDesc.bond.centroid, chunkDescs[chunkIndex].centroid, sizeof(float) * 3);
- bondDesc.bond.userData = bondUserData != nullptr ? bondUserData[i] : 0;
- }
-
- // Create new asset
- NvBlastAssetDesc assetDesc;
- assetDesc.chunkCount = chunkCount;
- assetDesc.chunkDescs = chunkDescs;
- assetDesc.bondCount = bondCount;
- assetDesc.bondDescs = bondDescs;
- void* scratch = NVBLAST_ALLOC(NvBlastGetRequiredScratchForCreateAsset(&assetDesc, logLL));
- NvBlastAsset* newAsset = NvBlastCreateAsset(NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&assetDesc, logLL)), &assetDesc, scratch, logLL);
-
- // Free buffers
- NVBLAST_FREE(scratch);
- NVBLAST_FREE(bondDescs);
- NVBLAST_FREE(chunkDescs);
-
- return newAsset;
-}
-
-
-NvBlastAssetDesc NvBlastExtAssetUtilsMergeAssets
-(
- const NvBlastAsset** components,
- const NvcVec3* scales,
- const NvcQuat* rotations,
- const NvcVec3* translations,
- uint32_t componentCount,
- const NvBlastExtAssetUtilsBondDesc* newBondDescs,
- uint32_t newBondCount,
- uint32_t* chunkIndexOffsets,
- uint32_t* chunkReorderMap,
- uint32_t chunkReorderMapSize
-)
-{
- // Count the total number of chunks and bonds in the new asset
- uint32_t totalChunkCount = 0;
- uint32_t totalBondCount = newBondCount;
- for (uint32_t c = 0; c < componentCount; ++c)
- {
- totalChunkCount += NvBlastAssetGetChunkCount(components[c], logLL);
- totalBondCount += NvBlastAssetGetBondCount(components[c], logLL);
- }
-
- // Allocate space for chunk and bond descriptors
- NvBlastChunkDesc* chunkDescs = static_cast<NvBlastChunkDesc*>(NVBLAST_ALLOC(totalChunkCount * sizeof(NvBlastChunkDesc)));
- NvBlastBondDesc* bondDescs = static_cast<NvBlastBondDesc*>(NVBLAST_ALLOC(totalBondCount * sizeof(NvBlastBondDesc)));
-
- // Create a list of chunk index offsets per component
- uint32_t* offsetStackAlloc = static_cast<uint32_t*>(NvBlastAlloca(componentCount * sizeof(uint32_t)));
- if (chunkIndexOffsets == nullptr)
- {
- chunkIndexOffsets = offsetStackAlloc; // Use local stack alloc if no array is provided
- }
-
- // Fill the chunk and bond descriptors from the components
- uint32_t chunkCount = 0;
- uint32_t bondCount = 0;
- for (uint32_t c = 0; c < componentCount; ++c)
- {
- chunkIndexOffsets[c] = chunkCount;
- uint32_t componentChunkCount;
- uint32_t componentBondCount;
- fillChunkAndBondDescriptorsFromAsset(componentChunkCount, componentBondCount, chunkDescs + chunkCount, bondDescs + bondCount, components[c]);
- // Fix chunks' parent indices
- for (uint32_t i = 0; i < componentChunkCount; ++i)
- {
- if (!isInvalidIndex(chunkDescs[chunkCount + i].parentChunkIndex))
- {
- chunkDescs[chunkCount + i].parentChunkIndex += chunkCount;
- }
- }
- // Fix bonds' chunk indices
- for (uint32_t i = 0; i < componentBondCount; ++i)
- {
- NvBlastBondDesc& bondDesc = bondDescs[bondCount + i];
- for (int j = 0; j < 2; ++j)
- {
- if (!isInvalidIndex(bondDesc.chunkIndices[j]))
- {
- bondDesc.chunkIndices[j] += chunkCount;
- }
- }
- }
- // Transform geometric data
- if (scales != nullptr)
- {
- const NvcVec3& S = scales[c];
- NvcVec3 cofS = { S.y * S.z, S.z * S.x, S.x * S.y };
- float absDetS = S.x * S.y * S.z;
- const float sgnDetS = absDetS < 0.0f ? -1.0f : 1.0f;
- absDetS *= sgnDetS;
- for (uint32_t i = 0; i < componentChunkCount; ++i)
- {
- scale(reinterpret_cast<NvcVec3&>(chunkDescs[chunkCount + i].centroid), S);
- chunkDescs[chunkCount + i].volume *= absDetS;
- }
- for (uint32_t i = 0; i < componentBondCount; ++i)
- {
- NvBlastBond& bond = bondDescs[bondCount + i].bond;
- scale(reinterpret_cast<NvcVec3&>(bond.normal), cofS);
- float renorm = sqrtf(bond.normal[0] * bond.normal[0] + bond.normal[1] * bond.normal[1] + bond.normal[2] * bond.normal[2]);
- bond.area *= renorm;
- if (renorm != 0)
- {
- renorm = sgnDetS / renorm;
- bond.normal[0] *= renorm;
- bond.normal[1] *= renorm;
- bond.normal[2] *= renorm;
- }
- scale(reinterpret_cast<NvcVec3&>(bond.centroid), S);
- }
- }
- if (rotations != nullptr)
- {
- for (uint32_t i = 0; i < componentChunkCount; ++i)
- {
- rotate(reinterpret_cast<NvcVec3&>(chunkDescs[chunkCount + i].centroid), rotations[c]);
- }
- for (uint32_t i = 0; i < componentBondCount; ++i)
- {
- NvBlastBond& bond = bondDescs[bondCount + i].bond;
- rotate(reinterpret_cast<NvcVec3&>(bond.normal), rotations[c]); // Normal can be transformed this way since we aren't scaling
- rotate(reinterpret_cast<NvcVec3&>(bond.centroid), rotations[c]);
- }
- }
- if (translations != nullptr)
- {
- for (uint32_t i = 0; i < componentChunkCount; ++i)
- {
- translate(reinterpret_cast<NvcVec3&>(chunkDescs[chunkCount + i].centroid), translations[c]);
- }
- for (uint32_t i = 0; i < componentBondCount; ++i)
- {
- translate(reinterpret_cast<NvcVec3&>(bondDescs[bondCount + i].bond.centroid), translations[c]);
- }
- }
- chunkCount += componentChunkCount;
- bondCount += componentBondCount;
- }
-
- // Fill the bond descriptors from the new bond descs
- for (uint32_t b = 0; b < newBondCount; ++b)
- {
- const NvBlastExtAssetUtilsBondDesc& newBondDesc = newBondDescs[b];
- NvBlastBondDesc& bondDesc = bondDescs[bondCount++];
- memcpy(&bondDesc.bond, &newBondDesc.bond, sizeof(NvBlastBond));
- bondDesc.chunkIndices[0] = !isInvalidIndex(newBondDesc.chunkIndices[0]) ? newBondDesc.chunkIndices[0] + chunkIndexOffsets[newBondDesc.componentIndices[0]] : invalidIndex<uint32_t>();
- bondDesc.chunkIndices[1] = !isInvalidIndex(newBondDesc.chunkIndices[1]) ? newBondDesc.chunkIndices[1] + chunkIndexOffsets[newBondDesc.componentIndices[1]] : invalidIndex<uint32_t>();
- }
-
- // Create new asset desriptor
- NvBlastAssetDesc assetDesc;
- assetDesc.chunkCount = chunkCount;
- assetDesc.chunkDescs = chunkDescs;
- assetDesc.bondCount = bondCount;
- assetDesc.bondDescs = bondDescs;
-
- // Massage the descriptors so that they are valid for scratch creation
- void* scratch = NVBLAST_ALLOC(chunkCount * sizeof(NvBlastChunkDesc)); // Enough for NvBlastEnsureAssetExactSupportCoverage and NvBlastReorderAssetDescChunks
-
- NvBlastEnsureAssetExactSupportCoverage(chunkDescs, chunkCount, scratch, logLL);
-
- if (chunkReorderMapSize < chunkCount)
- {
- if (chunkReorderMap != nullptr)
- {
- // Chunk reorder map is not large enough. Fill it with invalid indices and don't use it.
- memset(chunkReorderMap, 0xFF, chunkReorderMapSize * sizeof(uint32_t));
- NVBLAST_LOG_WARNING("NvBlastExtAssetUtilsMergeAssets: insufficient chunkReorderMap array passed in. NvBlastReorderAssetDescChunks will not be used.");
- }
- chunkReorderMap = nullptr; // Don't use
- }
-
- if (chunkReorderMap != nullptr)
- {
- NvBlastReorderAssetDescChunks(chunkDescs, chunkCount, bondDescs, bondCount, chunkReorderMap, true, scratch, logLL);
- }
-
- NVBLAST_FREE(scratch);
-
- return assetDesc;
-}
-
-
-/**
-Multiply a 3-vector v in-place by value.
-
-\param[in,out] v The vector to multiply.
-\param[in] m The 3x3 matrix.
-*/
-static inline void multiply(NvcVec3& v, float value)
-{
- v.x *= value;
- v.y *= value;
- v.z *= value;
-}
-
-
-/**
-Get Vec3 length
-*/
-static inline float length(const NvcVec3& p)
-{
- return sqrtf(p.x * p.x + p.y * p.y + p.z * p.z);
-}
-
-
-/**
-Transform a point in-place: scale, rotate, then translate
-
-\param[in,out] p The point to transform.
-\param[in] S The diagonal elements of a diagonal scale matrix.
-\param[in] R A quaternion representing the rotation. Must be normalized.
-\param[in] T The translation vector.
-*/
-static inline void transform(NvcVec3& p, const NvcVec3& S, const NvcQuat& R, const NvcVec3& T)
-{
- scale(p, S);
- rotate(p, R);
- translate(p, T);
-}
-
-
-/**
-Transform a vector in-place: scale, then rotate
-
-\param[in,out] v The vector to transform.
-\param[in] S The diagonal elements of a diagonal scale matrix.
-\param[in] R A quaternion representing the rotation. Must be normalized.
-*/
-static inline void transform(NvcVec3& v, const NvcVec3& S, const NvcQuat& R)
-{
- scale(v, S);
- rotate(v, R);
-}
-
-
-void NvBlastExtAssetTransformInPlace(NvBlastAsset* asset, const NvcVec3* scaling, const NvcQuat* rotation, const NvcVec3* translation)
-{
- // Local copies of scaling (S), rotation (R), and translation (T)
- NvcVec3 S = { 1, 1, 1 };
- NvcQuat R = { 0, 0, 0, 1 };
- NvcVec3 T = { 0, 0, 0 };
- NvcVec3 cofS = { 1, 1, 1 };
- float absDetS = 1;
- float sgnDetS = 1;
-
- {
- if (rotation)
- {
- R = *rotation;
- }
-
- if (scaling)
- {
- S = *scaling;
- cofS.x = S.y * S.z;
- cofS.y = S.z * S.x;
- cofS.z = S.x * S.y;
- absDetS = S.x * S.y * S.z;
- sgnDetS = absDetS < 0.0f ? -1.0f : 1.0f;
- absDetS *= sgnDetS;
- }
-
- if (translation)
- {
- T = *translation;
- }
- }
-
- // Chunk descs
- const uint32_t assetChunkCount = NvBlastAssetGetChunkCount(asset, logLL);
- NvBlastChunk* assetChunk = const_cast<NvBlastChunk*>(NvBlastAssetGetChunks(asset, logLL));
- for (uint32_t i = 0; i < assetChunkCount; ++i, ++assetChunk)
- {
- transform(reinterpret_cast<NvcVec3&>(assetChunk->centroid), S, R, T);
- assetChunk->volume *= absDetS; // Use |detS| to keep the volume positive
- }
-
- // Bond descs
- const uint32_t assetBondCount = NvBlastAssetGetBondCount(asset, logLL);
- NvBlastBond* assetBond = const_cast<NvBlastBond*>(NvBlastAssetGetBonds(asset, logLL));
- for (uint32_t i = 0; i < assetBondCount; ++i, ++assetBond)
- {
- transform(reinterpret_cast<NvcVec3&>(assetBond->centroid), S, R, T);
- NvcVec3& normal = reinterpret_cast<NvcVec3&>(assetBond->normal);
- transform(normal, cofS, R);
- const float l = length(normal);
- assetBond->area *= l;
- multiply(normal, l > 0.f ? sgnDetS / l : 1.f);
- }
-}
+// 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) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtAssetUtils.h"
+#include "NvBlast.h"
+#include "NvBlastIndexFns.h"
+#include "NvBlastMemory.h"
+#include "NvBlastGlobals.h"
+#include "math.h"
+
+using namespace Nv::Blast;
+
+
+/**
+Fill the chunk and bond descriptors from an asset.
+
+\param[out] chunkDescsWritten the number of chunk descriptors written to chunkDescs
+\param[out] bondDescsWritten the number of bond descriptors written to bondDescs
+\param[out] chunkDescs user-supplied buffer of NvBlastChunkDesc. Size must be at least NvBlastAssetGetChunkCount(asset, logFn)
+\param[out] bondDescs user-supplied buffer of NvBlastBondDesc. Size must be at least NvBlastAssetGetBondCount(asset, logFn)
+\param[in] asset asset from which to extract descriptors
+*/
+static void fillChunkAndBondDescriptorsFromAsset
+(
+ uint32_t& chunkDescsWritten,
+ uint32_t& bondDescsWritten,
+ NvBlastChunkDesc* chunkDescs,
+ NvBlastBondDesc* bondDescs,
+ const NvBlastAsset* asset
+)
+{
+ chunkDescsWritten = 0;
+ bondDescsWritten = 0;
+
+ // Chunk descs
+ const uint32_t assetChunkCount = NvBlastAssetGetChunkCount(asset, logLL);
+ const NvBlastChunk* assetChunk = NvBlastAssetGetChunks(asset, logLL);
+ for (uint32_t i = 0; i < assetChunkCount; ++i, ++assetChunk)
+ {
+ NvBlastChunkDesc& chunkDesc = chunkDescs[chunkDescsWritten++];
+ memcpy(chunkDesc.centroid, assetChunk->centroid, sizeof(float) * 3);
+ chunkDesc.volume = assetChunk->volume;
+ chunkDesc.parentChunkIndex = assetChunk->parentChunkIndex;
+ chunkDesc.flags = 0; // To be filled in below
+ chunkDesc.userData = assetChunk->userData;
+ }
+
+ // Bond descs
+ const uint32_t assetBondCount = NvBlastAssetGetBondCount(asset, logLL);
+ const NvBlastBond* assetBond = NvBlastAssetGetBonds(asset, logLL);
+ for (uint32_t i = 0; i < assetBondCount; ++i, ++assetBond)
+ {
+ NvBlastBondDesc& bondDesc = bondDescs[bondDescsWritten++];
+ memcpy(&bondDesc.bond, assetBond, sizeof(NvBlastBond));
+ }
+
+ // Walk the graph and restore connection descriptors
+ const NvBlastSupportGraph graph = NvBlastAssetGetSupportGraph(asset, logLL);
+ for (uint32_t i = 0; i < graph.nodeCount; ++i)
+ {
+ const int32_t currentChunk = graph.chunkIndices[i];
+ if (isInvalidIndex(currentChunk))
+ {
+ continue;
+ }
+
+ chunkDescs[currentChunk].flags |= NvBlastChunkDesc::SupportFlag; // Filling in chunk flags here
+
+ for (uint32_t j = graph.adjacencyPartition[i]; j < graph.adjacencyPartition[i + 1]; ++j)
+ {
+ NvBlastBondDesc& bondDesc = bondDescs[graph.adjacentBondIndices[j]];
+ bondDesc.chunkIndices[0] = currentChunk;
+ const uint32_t adjacentChunkIndex = graph.chunkIndices[graph.adjacentNodeIndices[j]];
+ bondDesc.chunkIndices[1] = adjacentChunkIndex;
+ }
+ }
+}
+
+
+/**
+Scale a 3-vector v in-place.
+
+\param[in,out] v The vector to scale.
+\param[in] s The scale. Represents the diagonal elements of a diagonal matrix.
+
+The result will be v <- s*v.
+*/
+static inline void scale(NvcVec3& v, const NvcVec3& s)
+{
+ v.x *= s.x;
+ v.y *= s.y;
+ v.z *= s.z;
+}
+
+
+/**
+Rotate a 3-vector v in-place using a rotation represented by a quaternion q.
+
+\param[in,out] v The vector to rotate.
+\param[in] q The quaternion representation the rotation.
+
+The format of q is { x, y, z, w } where (x,y,z) is the vector part and w is the scalar part.
+The quaternion q MUST be normalized.
+*/
+static inline void rotate(NvcVec3& v, const NvcQuat& q)
+{
+ const float vx = 2.0f * v.x;
+ const float vy = 2.0f * v.y;
+ const float vz = 2.0f * v.z;
+ const float w2 = q.w * q.w - 0.5f;
+ const float dot2 = (q.x * vx + q.y * vy + q.z * vz);
+ v.x = vx * w2 + (q.y * vz - q.z * vy) * q.w + q.x * dot2;
+ v.y = vy * w2 + (q.z * vx - q.x * vz) * q.w + q.y * dot2;
+ v.z = vz * w2 + (q.x * vy - q.y * vx) * q.w + q.z * dot2;
+}
+
+
+/**
+Translate a 3-vector v in-place.
+
+\param[in,out] v The vector to translate.
+\param[in] t The translation.
+
+The result will be v <- v+t.
+*/
+static inline void translate(NvcVec3& v, const NvcVec3& t)
+{
+ v.x += t.x;
+ v.y += t.y;
+ v.z += t.z;
+}
+
+
+NvBlastAsset* NvBlastExtAssetUtilsAddWorldBonds
+(
+ const NvBlastAsset* asset,
+ const uint32_t* worldBoundChunks,
+ uint32_t worldBoundChunkCount,
+ const NvcVec3* bondDirections,
+ const uint32_t* bondUserData
+)
+{
+ const uint32_t chunkCount = NvBlastAssetGetChunkCount(asset, logLL);
+ const uint32_t oldBondCount = NvBlastAssetGetBondCount(asset, logLL);
+ const uint32_t newBondCount = oldBondCount + worldBoundChunkCount;
+
+ NvBlastChunkDesc* chunkDescs = static_cast<NvBlastChunkDesc*>(NVBLAST_ALLOC(chunkCount * sizeof(NvBlastChunkDesc)));
+ NvBlastBondDesc* bondDescs = static_cast<NvBlastBondDesc*>(NVBLAST_ALLOC(newBondCount * sizeof(NvBlastBondDesc)));
+
+ // Create chunk descs
+ uint32_t chunkDescsWritten;
+ uint32_t bondDescsWritten;
+ fillChunkAndBondDescriptorsFromAsset(chunkDescsWritten, bondDescsWritten, chunkDescs, bondDescs, asset);
+
+ // Add world bonds
+ uint32_t bondCount = oldBondCount;
+ for (uint32_t i = 0; i < worldBoundChunkCount; i++)
+ {
+ NvBlastBondDesc& bondDesc = bondDescs[bondCount++];
+ const uint32_t chunkIndex = worldBoundChunks[i];
+ bondDesc.chunkIndices[0] = chunkIndex;
+ bondDesc.chunkIndices[1] = invalidIndex<uint32_t>();
+ memcpy(&bondDesc.bond.normal, bondDirections + i, sizeof(float) * 3);
+ bondDesc.bond.area = 1.0f; // Should be set by user
+ memcpy(&bondDesc.bond.centroid, chunkDescs[chunkIndex].centroid, sizeof(float) * 3);
+ bondDesc.bond.userData = bondUserData != nullptr ? bondUserData[i] : 0;
+ }
+
+ // Create new asset
+ NvBlastAssetDesc assetDesc;
+ assetDesc.chunkCount = chunkCount;
+ assetDesc.chunkDescs = chunkDescs;
+ assetDesc.bondCount = bondCount;
+ assetDesc.bondDescs = bondDescs;
+ void* scratch = NVBLAST_ALLOC(NvBlastGetRequiredScratchForCreateAsset(&assetDesc, logLL));
+ NvBlastAsset* newAsset = NvBlastCreateAsset(NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&assetDesc, logLL)), &assetDesc, scratch, logLL);
+
+ // Free buffers
+ NVBLAST_FREE(scratch);
+ NVBLAST_FREE(bondDescs);
+ NVBLAST_FREE(chunkDescs);
+
+ return newAsset;
+}
+
+
+NvBlastAssetDesc NvBlastExtAssetUtilsMergeAssets
+(
+ const NvBlastAsset** components,
+ const NvcVec3* scales,
+ const NvcQuat* rotations,
+ const NvcVec3* translations,
+ uint32_t componentCount,
+ const NvBlastExtAssetUtilsBondDesc* newBondDescs,
+ uint32_t newBondCount,
+ uint32_t* chunkIndexOffsets,
+ uint32_t* chunkReorderMap,
+ uint32_t chunkReorderMapSize
+)
+{
+ // Count the total number of chunks and bonds in the new asset
+ uint32_t totalChunkCount = 0;
+ uint32_t totalBondCount = newBondCount;
+ for (uint32_t c = 0; c < componentCount; ++c)
+ {
+ totalChunkCount += NvBlastAssetGetChunkCount(components[c], logLL);
+ totalBondCount += NvBlastAssetGetBondCount(components[c], logLL);
+ }
+
+ // Allocate space for chunk and bond descriptors
+ NvBlastChunkDesc* chunkDescs = static_cast<NvBlastChunkDesc*>(NVBLAST_ALLOC(totalChunkCount * sizeof(NvBlastChunkDesc)));
+ NvBlastBondDesc* bondDescs = static_cast<NvBlastBondDesc*>(NVBLAST_ALLOC(totalBondCount * sizeof(NvBlastBondDesc)));
+
+ // Create a list of chunk index offsets per component
+ uint32_t* offsetStackAlloc = static_cast<uint32_t*>(NvBlastAlloca(componentCount * sizeof(uint32_t)));
+ if (chunkIndexOffsets == nullptr)
+ {
+ chunkIndexOffsets = offsetStackAlloc; // Use local stack alloc if no array is provided
+ }
+
+ // Fill the chunk and bond descriptors from the components
+ uint32_t chunkCount = 0;
+ uint32_t bondCount = 0;
+ for (uint32_t c = 0; c < componentCount; ++c)
+ {
+ chunkIndexOffsets[c] = chunkCount;
+ uint32_t componentChunkCount;
+ uint32_t componentBondCount;
+ fillChunkAndBondDescriptorsFromAsset(componentChunkCount, componentBondCount, chunkDescs + chunkCount, bondDescs + bondCount, components[c]);
+ // Fix chunks' parent indices
+ for (uint32_t i = 0; i < componentChunkCount; ++i)
+ {
+ if (!isInvalidIndex(chunkDescs[chunkCount + i].parentChunkIndex))
+ {
+ chunkDescs[chunkCount + i].parentChunkIndex += chunkCount;
+ }
+ }
+ // Fix bonds' chunk indices
+ for (uint32_t i = 0; i < componentBondCount; ++i)
+ {
+ NvBlastBondDesc& bondDesc = bondDescs[bondCount + i];
+ for (int j = 0; j < 2; ++j)
+ {
+ if (!isInvalidIndex(bondDesc.chunkIndices[j]))
+ {
+ bondDesc.chunkIndices[j] += chunkCount;
+ }
+ }
+ }
+ // Transform geometric data
+ if (scales != nullptr)
+ {
+ const NvcVec3& S = scales[c];
+ NvcVec3 cofS = { S.y * S.z, S.z * S.x, S.x * S.y };
+ float absDetS = S.x * S.y * S.z;
+ const float sgnDetS = absDetS < 0.0f ? -1.0f : 1.0f;
+ absDetS *= sgnDetS;
+ for (uint32_t i = 0; i < componentChunkCount; ++i)
+ {
+ scale(reinterpret_cast<NvcVec3&>(chunkDescs[chunkCount + i].centroid), S);
+ chunkDescs[chunkCount + i].volume *= absDetS;
+ }
+ for (uint32_t i = 0; i < componentBondCount; ++i)
+ {
+ NvBlastBond& bond = bondDescs[bondCount + i].bond;
+ scale(reinterpret_cast<NvcVec3&>(bond.normal), cofS);
+ float renorm = sqrtf(bond.normal[0] * bond.normal[0] + bond.normal[1] * bond.normal[1] + bond.normal[2] * bond.normal[2]);
+ bond.area *= renorm;
+ if (renorm != 0)
+ {
+ renorm = sgnDetS / renorm;
+ bond.normal[0] *= renorm;
+ bond.normal[1] *= renorm;
+ bond.normal[2] *= renorm;
+ }
+ scale(reinterpret_cast<NvcVec3&>(bond.centroid), S);
+ }
+ }
+ if (rotations != nullptr)
+ {
+ for (uint32_t i = 0; i < componentChunkCount; ++i)
+ {
+ rotate(reinterpret_cast<NvcVec3&>(chunkDescs[chunkCount + i].centroid), rotations[c]);
+ }
+ for (uint32_t i = 0; i < componentBondCount; ++i)
+ {
+ NvBlastBond& bond = bondDescs[bondCount + i].bond;
+ rotate(reinterpret_cast<NvcVec3&>(bond.normal), rotations[c]); // Normal can be transformed this way since we aren't scaling
+ rotate(reinterpret_cast<NvcVec3&>(bond.centroid), rotations[c]);
+ }
+ }
+ if (translations != nullptr)
+ {
+ for (uint32_t i = 0; i < componentChunkCount; ++i)
+ {
+ translate(reinterpret_cast<NvcVec3&>(chunkDescs[chunkCount + i].centroid), translations[c]);
+ }
+ for (uint32_t i = 0; i < componentBondCount; ++i)
+ {
+ translate(reinterpret_cast<NvcVec3&>(bondDescs[bondCount + i].bond.centroid), translations[c]);
+ }
+ }
+ chunkCount += componentChunkCount;
+ bondCount += componentBondCount;
+ }
+
+ // Fill the bond descriptors from the new bond descs
+ for (uint32_t b = 0; b < newBondCount; ++b)
+ {
+ const NvBlastExtAssetUtilsBondDesc& newBondDesc = newBondDescs[b];
+ NvBlastBondDesc& bondDesc = bondDescs[bondCount++];
+ memcpy(&bondDesc.bond, &newBondDesc.bond, sizeof(NvBlastBond));
+ bondDesc.chunkIndices[0] = !isInvalidIndex(newBondDesc.chunkIndices[0]) ? newBondDesc.chunkIndices[0] + chunkIndexOffsets[newBondDesc.componentIndices[0]] : invalidIndex<uint32_t>();
+ bondDesc.chunkIndices[1] = !isInvalidIndex(newBondDesc.chunkIndices[1]) ? newBondDesc.chunkIndices[1] + chunkIndexOffsets[newBondDesc.componentIndices[1]] : invalidIndex<uint32_t>();
+ }
+
+ // Create new asset desriptor
+ NvBlastAssetDesc assetDesc;
+ assetDesc.chunkCount = chunkCount;
+ assetDesc.chunkDescs = chunkDescs;
+ assetDesc.bondCount = bondCount;
+ assetDesc.bondDescs = bondDescs;
+
+ // Massage the descriptors so that they are valid for scratch creation
+ void* scratch = NVBLAST_ALLOC(chunkCount * sizeof(NvBlastChunkDesc)); // Enough for NvBlastEnsureAssetExactSupportCoverage and NvBlastReorderAssetDescChunks
+
+ NvBlastEnsureAssetExactSupportCoverage(chunkDescs, chunkCount, scratch, logLL);
+
+ if (chunkReorderMapSize < chunkCount)
+ {
+ if (chunkReorderMap != nullptr)
+ {
+ // Chunk reorder map is not large enough. Fill it with invalid indices and don't use it.
+ memset(chunkReorderMap, 0xFF, chunkReorderMapSize * sizeof(uint32_t));
+ NVBLAST_LOG_WARNING("NvBlastExtAssetUtilsMergeAssets: insufficient chunkReorderMap array passed in. NvBlastReorderAssetDescChunks will not be used.");
+ }
+ chunkReorderMap = nullptr; // Don't use
+ }
+
+ if (chunkReorderMap != nullptr)
+ {
+ NvBlastReorderAssetDescChunks(chunkDescs, chunkCount, bondDescs, bondCount, chunkReorderMap, true, scratch, logLL);
+ }
+
+ NVBLAST_FREE(scratch);
+
+ return assetDesc;
+}
+
+
+/**
+Multiply a 3-vector v in-place by value.
+
+\param[in,out] v The vector to multiply.
+\param[in] m The 3x3 matrix.
+*/
+static inline void multiply(NvcVec3& v, float value)
+{
+ v.x *= value;
+ v.y *= value;
+ v.z *= value;
+}
+
+
+/**
+Get Vec3 length
+*/
+static inline float length(const NvcVec3& p)
+{
+ return sqrtf(p.x * p.x + p.y * p.y + p.z * p.z);
+}
+
+
+/**
+Transform a point in-place: scale, rotate, then translate
+
+\param[in,out] p The point to transform.
+\param[in] S The diagonal elements of a diagonal scale matrix.
+\param[in] R A quaternion representing the rotation. Must be normalized.
+\param[in] T The translation vector.
+*/
+static inline void transform(NvcVec3& p, const NvcVec3& S, const NvcQuat& R, const NvcVec3& T)
+{
+ scale(p, S);
+ rotate(p, R);
+ translate(p, T);
+}
+
+
+/**
+Transform a vector in-place: scale, then rotate
+
+\param[in,out] v The vector to transform.
+\param[in] S The diagonal elements of a diagonal scale matrix.
+\param[in] R A quaternion representing the rotation. Must be normalized.
+*/
+static inline void transform(NvcVec3& v, const NvcVec3& S, const NvcQuat& R)
+{
+ scale(v, S);
+ rotate(v, R);
+}
+
+
+void NvBlastExtAssetTransformInPlace(NvBlastAsset* asset, const NvcVec3* scaling, const NvcQuat* rotation, const NvcVec3* translation)
+{
+ // Local copies of scaling (S), rotation (R), and translation (T)
+ NvcVec3 S = { 1, 1, 1 };
+ NvcQuat R = { 0, 0, 0, 1 };
+ NvcVec3 T = { 0, 0, 0 };
+ NvcVec3 cofS = { 1, 1, 1 };
+ float absDetS = 1;
+ float sgnDetS = 1;
+
+ {
+ if (rotation)
+ {
+ R = *rotation;
+ }
+
+ if (scaling)
+ {
+ S = *scaling;
+ cofS.x = S.y * S.z;
+ cofS.y = S.z * S.x;
+ cofS.z = S.x * S.y;
+ absDetS = S.x * S.y * S.z;
+ sgnDetS = absDetS < 0.0f ? -1.0f : 1.0f;
+ absDetS *= sgnDetS;
+ }
+
+ if (translation)
+ {
+ T = *translation;
+ }
+ }
+
+ // Chunk descs
+ const uint32_t assetChunkCount = NvBlastAssetGetChunkCount(asset, logLL);
+ NvBlastChunk* assetChunk = const_cast<NvBlastChunk*>(NvBlastAssetGetChunks(asset, logLL));
+ for (uint32_t i = 0; i < assetChunkCount; ++i, ++assetChunk)
+ {
+ transform(reinterpret_cast<NvcVec3&>(assetChunk->centroid), S, R, T);
+ assetChunk->volume *= absDetS; // Use |detS| to keep the volume positive
+ }
+
+ // Bond descs
+ const uint32_t assetBondCount = NvBlastAssetGetBondCount(asset, logLL);
+ NvBlastBond* assetBond = const_cast<NvBlastBond*>(NvBlastAssetGetBonds(asset, logLL));
+ for (uint32_t i = 0; i < assetBondCount; ++i, ++assetBond)
+ {
+ transform(reinterpret_cast<NvcVec3&>(assetBond->centroid), S, R, T);
+ NvcVec3& normal = reinterpret_cast<NvcVec3&>(assetBond->normal);
+ transform(normal, cofS, R);
+ const float l = length(normal);
+ assetBond->area *= l;
+ multiply(normal, l > 0.f ? sgnDetS / l : 1.f);
+ }
+}