From 7115f60b91b5717d90f643fd692010905c7004db Mon Sep 17 00:00:00 2001 From: Bryan Galdrikian Date: Thu, 31 May 2018 11:36:08 -0700 Subject: Blast 1.1.3. See docs/release_notes.txt. --- .../assetutils/source/NvBlastExtAssetUtils.cpp | 966 ++++++++++----------- 1 file changed, 483 insertions(+), 483 deletions(-) mode change 100644 => 100755 sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp (limited to 'sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp') diff --git a/sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp b/sdk/extensions/assetutils/source/NvBlastExtAssetUtils.cpp old mode 100644 new mode 100755 index 072bb10..2c902d4 --- 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(NVBLAST_ALLOC(chunkCount * sizeof(NvBlastChunkDesc))); - NvBlastBondDesc* bondDescs = static_cast(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(); - 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(NVBLAST_ALLOC(totalChunkCount * sizeof(NvBlastChunkDesc))); - NvBlastBondDesc* bondDescs = static_cast(NVBLAST_ALLOC(totalBondCount * sizeof(NvBlastBondDesc))); - - // Create a list of chunk index offsets per component - uint32_t* offsetStackAlloc = static_cast(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(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(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(bond.centroid), S); - } - } - if (rotations != nullptr) - { - for (uint32_t i = 0; i < componentChunkCount; ++i) - { - rotate(reinterpret_cast(chunkDescs[chunkCount + i].centroid), rotations[c]); - } - for (uint32_t i = 0; i < componentBondCount; ++i) - { - NvBlastBond& bond = bondDescs[bondCount + i].bond; - rotate(reinterpret_cast(bond.normal), rotations[c]); // Normal can be transformed this way since we aren't scaling - rotate(reinterpret_cast(bond.centroid), rotations[c]); - } - } - if (translations != nullptr) - { - for (uint32_t i = 0; i < componentChunkCount; ++i) - { - translate(reinterpret_cast(chunkDescs[chunkCount + i].centroid), translations[c]); - } - for (uint32_t i = 0; i < componentBondCount; ++i) - { - translate(reinterpret_cast(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(); - bondDesc.chunkIndices[1] = !isInvalidIndex(newBondDesc.chunkIndices[1]) ? newBondDesc.chunkIndices[1] + chunkIndexOffsets[newBondDesc.componentIndices[1]] : invalidIndex(); - } - - // 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(NvBlastAssetGetChunks(asset, logLL)); - for (uint32_t i = 0; i < assetChunkCount; ++i, ++assetChunk) - { - transform(reinterpret_cast(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(NvBlastAssetGetBonds(asset, logLL)); - for (uint32_t i = 0; i < assetBondCount; ++i, ++assetBond) - { - transform(reinterpret_cast(assetBond->centroid), S, R, T); - NvcVec3& normal = reinterpret_cast(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(NVBLAST_ALLOC(chunkCount * sizeof(NvBlastChunkDesc))); + NvBlastBondDesc* bondDescs = static_cast(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(); + 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(NVBLAST_ALLOC(totalChunkCount * sizeof(NvBlastChunkDesc))); + NvBlastBondDesc* bondDescs = static_cast(NVBLAST_ALLOC(totalBondCount * sizeof(NvBlastBondDesc))); + + // Create a list of chunk index offsets per component + uint32_t* offsetStackAlloc = static_cast(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(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(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(bond.centroid), S); + } + } + if (rotations != nullptr) + { + for (uint32_t i = 0; i < componentChunkCount; ++i) + { + rotate(reinterpret_cast(chunkDescs[chunkCount + i].centroid), rotations[c]); + } + for (uint32_t i = 0; i < componentBondCount; ++i) + { + NvBlastBond& bond = bondDescs[bondCount + i].bond; + rotate(reinterpret_cast(bond.normal), rotations[c]); // Normal can be transformed this way since we aren't scaling + rotate(reinterpret_cast(bond.centroid), rotations[c]); + } + } + if (translations != nullptr) + { + for (uint32_t i = 0; i < componentChunkCount; ++i) + { + translate(reinterpret_cast(chunkDescs[chunkCount + i].centroid), translations[c]); + } + for (uint32_t i = 0; i < componentBondCount; ++i) + { + translate(reinterpret_cast(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(); + bondDesc.chunkIndices[1] = !isInvalidIndex(newBondDesc.chunkIndices[1]) ? newBondDesc.chunkIndices[1] + chunkIndexOffsets[newBondDesc.componentIndices[1]] : invalidIndex(); + } + + // 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(NvBlastAssetGetChunks(asset, logLL)); + for (uint32_t i = 0; i < assetChunkCount; ++i, ++assetChunk) + { + transform(reinterpret_cast(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(NvBlastAssetGetBonds(asset, logLL)); + for (uint32_t i = 0; i < assetBondCount; ++i, ++assetBond) + { + transform(reinterpret_cast(assetBond->centroid), S, R, T); + NvcVec3& normal = reinterpret_cast(assetBond->normal); + transform(normal, cofS, R); + const float l = length(normal); + assetBond->area *= l; + multiply(normal, l > 0.f ? sgnDetS / l : 1.f); + } +} -- cgit v1.2.3