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. --- test/src/unit/APITests.cpp | 3446 ++++++++++++++++++++++---------------------- 1 file changed, 1723 insertions(+), 1723 deletions(-) mode change 100644 => 100755 test/src/unit/APITests.cpp (limited to 'test/src/unit/APITests.cpp') diff --git a/test/src/unit/APITests.cpp b/test/src/unit/APITests.cpp old mode 100644 new mode 100755 index 655a65c..d1ff4cd --- a/test/src/unit/APITests.cpp +++ b/test/src/unit/APITests.cpp @@ -1,1723 +1,1723 @@ -// 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 "BlastBaseTest.h" -#include "NvBlastIndexFns.h" -#include "NvBlastExtDamageShaders.h" - -#include - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Utils / Tests Common -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -using namespace Nv::Blast; - -class APITest : public BlastBaseTest < NvBlastMessage::Error, 1 > -{ -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Tests -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -TEST_F(APITest, Basic) -{ - // create asset - const NvBlastAssetDesc& assetDesc = g_assetDescs[0]; - - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); - EXPECT_TRUE(actor != nullptr); - - NvBlastExtRadialDamageDesc damage = { - 10.0f, // compressive - { 0.0f, 0.0f, 0.0f }, // position - 4.0f, // min radius - maximum damage - 6.0f // max radius - zero damage - }; - - NvBlastBondFractureData outFracture[12]; /*num lower-support chunks + bonds?*/ - - NvBlastFractureBuffers events; - events.bondFractureCount = 12; - events.bondFractures = outFracture; - events.chunkFractureCount = 0; - events.chunkFractures = nullptr; - - NvBlastExtProgramParams programParams = { &damage, nullptr }; - - NvBlastDamageProgram program = { - NvBlastExtFalloffGraphShader, - nullptr - }; - - NvBlastActorGenerateFracture(&events, actor, program, &programParams, messageLog, nullptr); - NvBlastActorApplyFracture(&events, actor, &events, messageLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - EXPECT_EQ(12, events.bondFractureCount); - - NvBlastActor* newActors[8]; /* num lower-support chunks? plus space for deletedActor */ - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors; - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); - size_t newActorsCount = NvBlastActorSplit(&result, actor, 8, scratch.data(), messageLog, nullptr); - EXPECT_EQ(8, newActorsCount); - EXPECT_EQ(true, result.deletedActor == actor); - - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); - EXPECT_TRUE(actorReleaseResult); - } - alignedFree(family); - alignedFree(asset); -} - -TEST_F(APITest, DamageBondsCompressive) -{ - const size_t bondsCount = 6; - - const NvBlastChunkDesc c_chunks[8] = - { - // centroid volume parent idx flags ID - { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 5 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 6 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 7 } - }; - - const NvBlastBondDesc c_bonds[bondsCount] = - { - { { {-1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 2.0f, 0.0f }, 0 }, { 1, 2 } }, - { { {-1.0f, 0.0f, 0.0f }, 1.0f, {-1.0f, 2.0f, 0.0f }, 0 }, { 2, 3 } }, - { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-2.0f, 1.0f, 0.0f }, 0 }, { 3, 4 } }, - { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-2.0f,-1.0f, 0.0f }, 0 }, { 4, 5 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, {-1.0f,-2.0f, 0.0f }, 0 }, { 5, 6 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f,-2.0f, 0.0f }, 0 }, { 6, 7 } } - }; - - // create asset - const NvBlastAssetDesc assetDesc = { 8, c_chunks, bondsCount, c_bonds }; - - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); - EXPECT_TRUE(actor != nullptr); - - // get graph nodes check - std::vector graphNodeIndices; - graphNodeIndices.resize(NvBlastActorGetGraphNodeCount(actor, nullptr)); - uint32_t graphNodesCount = NvBlastActorGetGraphNodeIndices(graphNodeIndices.data(), (uint32_t)graphNodeIndices.size(), actor, nullptr); - EXPECT_EQ(graphNodesCount, 7); - - NvBlastExtRadialDamageDesc damage = { - 1.0f, // compressive - { 4.0f, 2.0f, 0.0f }, // position - 4.0f, // min radius - maximum damage - 6.0f // max radius - zero damage - }; // linear falloff - - NvBlastBondFractureData outCommands[bondsCount] = { - { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, - { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, - { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, - { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, - { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, - { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, - }; - - NvBlastFractureBuffers commands = { - 6, 0, outCommands, nullptr - }; - - NvBlastExtProgramParams programParams = { &damage, nullptr }; - - NvBlastDamageProgram program = { - NvBlastExtFalloffGraphShader, - nullptr - }; - - NvBlastActorGenerateFracture(&commands, actor, program, &programParams, messageLog, nullptr); - - ASSERT_EQ(3, commands.bondFractureCount); - ASSERT_EQ(0, commands.chunkFractureCount); - - // node indices in _graph_ chunks - NvBlastBondFractureData expectedCommand[] = { - { 0, 0, 1, 1.0f }, - { 0, 1, 2, 0.5f }, - { 0, 5, 6, 0.5f } - }; - - for (int i = 0; i < 3; i++) - { - EXPECT_EQ(expectedCommand[i].nodeIndex0, outCommands[i].nodeIndex0); - EXPECT_EQ(expectedCommand[i].nodeIndex1, outCommands[i].nodeIndex1); - EXPECT_EQ(expectedCommand[i].health, outCommands[i].health); - } - - const bool actorReleaseResult = NvBlastActorDeactivate(actor, messageLog); - EXPECT_TRUE(actorReleaseResult); - alignedFree(family); - alignedFree(asset); -} - -TEST_F(APITest, DirectFractureKillsChunk) -{ - // 1--2 - // | | - // 3--4 <-- kill 4 - - const NvBlastChunkDesc c_chunks[9] = - { - // centroid volume parent idx flags ID - { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 5 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 6 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 7 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 8 }, - }; - - const NvBlastBondDesc c_bonds[4] = - { - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, 1.0f, 0.0f }, 0 }, { 1, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f,-1.0f, 0.0f }, 0 }, { 3, 4 } }, - { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } }, - { { { 0.0f,-1.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 2, 4 } }, - }; - - NvBlastAssetDesc assetDesc; - assetDesc.chunkCount = 9; - assetDesc.chunkDescs = c_chunks; - assetDesc.bondCount = 4; - assetDesc.bondDescs = c_bonds; - - // create asset - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); - EXPECT_TRUE(actor != nullptr); - - NvBlastChunkFractureData fractureCmd; - fractureCmd.chunkIndex = 4; - fractureCmd.health = 1.0f; - - NvBlastFractureBuffers commands = { 0, 1, nullptr, &fractureCmd }; - - NvBlastChunkFractureData fractureEvt; - NvBlastFractureBuffers events = { 0, 1, nullptr, &fractureEvt }; - - NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - EXPECT_EQ(1, events.chunkFractureCount); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, messageLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), messageLog, nullptr); - newActors.resize(newActorsCount); - - EXPECT_EQ(5, newActorsCount); - EXPECT_EQ(actor, result.deletedActor); - // check newActors contain original actor - EXPECT_TRUE(std::any_of(newActors.begin(), newActors.end(), [&](const NvBlastActor* a) { return actor == a; })); - - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); - EXPECT_TRUE(actorReleaseResult); - } - alignedFree(family); - alignedFree(asset); -} - -TEST_F(APITest, DirectFractureKillsIslandRootChunk) -{ - // 1--2 <-- kill 1 - // | | - // 3--4 - - const NvBlastChunkDesc c_chunks[9] = - { - // centroid volume parent idx flags ID - { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 7 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 8 }, - }; - - const NvBlastBondDesc c_bonds[4] = - { - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, 1.0f, 0.0f }, 0 }, { 1, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f,-1.0f, 0.0f }, 0 }, { 3, 4 } }, - { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } }, - { { { 0.0f,-1.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 2, 4 } }, - }; - - NvBlastAssetDesc assetDesc; - assetDesc.chunkCount = 9; - assetDesc.chunkDescs = c_chunks; - assetDesc.bondCount = 4; - assetDesc.bondDescs = c_bonds; - - // create asset - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); - EXPECT_TRUE(actor != nullptr); - - NvBlastChunkFractureData fractureCmd; - fractureCmd.chunkIndex = 1; - fractureCmd.health = 1.0f; - - NvBlastFractureBuffers commands = { 0, 1, nullptr, &fractureCmd }; - - NvBlastChunkFractureData fractureEvt; - NvBlastFractureBuffers events = { 0, 1, nullptr, &fractureEvt }; - - NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - EXPECT_EQ(1, events.chunkFractureCount); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, messageLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), messageLog, nullptr); - newActors.resize(newActorsCount); - - EXPECT_EQ(5, newActorsCount); - EXPECT_EQ(actor, result.deletedActor); - // check if newActors don't contain original actor - EXPECT_TRUE(!std::any_of(newActors.begin(), newActors.end(), [&](const NvBlastActor* a) { return actor == a; })); - - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); - EXPECT_TRUE(actorReleaseResult); - } - alignedFree(family); - alignedFree(asset); -} - -TEST_F(APITest, SubsupportFracture) -{ - const NvBlastAssetDesc& assetDesc = g_assetDescs[1]; // cube with subsupport - - // create asset with chunk map - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); - EXPECT_TRUE(actor != nullptr); - - // first set of fracture commands - NvBlastChunkFractureData f1 = { 0, 1, 2.0f }; - NvBlastChunkFractureData f3 = { 0, 3, 0.5f }; - NvBlastChunkFractureData f5 = { 0, 5, 1.0f }; - NvBlastChunkFractureData f7 = { 0, 7, 1.0f }; - - std::vector chunkFractureData; - chunkFractureData.reserve(assetDesc.chunkCount); - chunkFractureData.push_back(f1); - chunkFractureData.push_back(f3); - chunkFractureData.push_back(f5); - chunkFractureData.push_back(f7); - ASSERT_EQ(assetDesc.chunkCount, chunkFractureData.capacity()); - ASSERT_EQ(4, chunkFractureData.size()); - - NvBlastFractureBuffers target = { 0, static_cast(chunkFractureData.capacity()), nullptr, chunkFractureData.data() }; - { - NvBlastFractureBuffers events = target; - NvBlastFractureBuffers commands = { 0, static_cast(chunkFractureData.size()), nullptr, chunkFractureData.data() }; - NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - ASSERT_EQ(4 + 8, events.chunkFractureCount); // all requested chunks take damage, and the children of one of them - } - - // re-apply same set of commands - chunkFractureData.clear(); - chunkFractureData.reserve(assetDesc.chunkCount); - chunkFractureData.push_back(f1); - chunkFractureData.push_back(f3); - chunkFractureData.push_back(f5); - chunkFractureData.push_back(f7); - ASSERT_EQ(assetDesc.chunkCount, chunkFractureData.capacity()); - ASSERT_EQ(4, chunkFractureData.size()); - - { - NvBlastFractureBuffers events = target; - NvBlastFractureBuffers commands = { 0, static_cast(chunkFractureData.size()), nullptr, chunkFractureData.data() }; - NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - ASSERT_EQ(1, events.chunkFractureCount); // f3 has broken the chunk - } - - // fracture all support chunks - // the chunks from the previous fractures must not be reported again (since they are all broken already) - NvBlastChunkFractureData f2 = { 0, 2, 2.0f }; // will damage chunk and children - NvBlastChunkFractureData f4 = { 0, 4, 0.5f }; // will damage chunk without creating children on split - NvBlastChunkFractureData f6 = { 0, 6, 2.0f }; // will damage chunk and children - NvBlastChunkFractureData f8 = { 0, 8, 1.0f }; // will damage chunk - - chunkFractureData.clear(); - chunkFractureData.reserve(assetDesc.chunkCount); - chunkFractureData.push_back(f1); - chunkFractureData.push_back(f2); - chunkFractureData.push_back(f3); - chunkFractureData.push_back(f4); - chunkFractureData.push_back(f5); - chunkFractureData.push_back(f6); - chunkFractureData.push_back(f7); - chunkFractureData.push_back(f8); - ASSERT_EQ(assetDesc.chunkCount, chunkFractureData.capacity()); - ASSERT_EQ(8, chunkFractureData.size()); - - NvBlastFractureBuffers events = target; - { - NvBlastFractureBuffers commands = { 0, static_cast(chunkFractureData.size()), nullptr, chunkFractureData.data() }; - NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - ASSERT_EQ(4 + 8 + 8, events.chunkFractureCount); // the new fracture commands all apply, plus two of them damage their children too - } - - for (size_t i = 0; i < events.chunkFractureCount; i++) - { - const uint32_t chunkIndex = events.chunkFractures[i].chunkIndex; - - ASSERT_TRUE(chunkIndex != 1); - ASSERT_TRUE(chunkIndex != 3); - ASSERT_TRUE(chunkIndex != 5); - ASSERT_TRUE(chunkIndex != 7); - - // literal values come from g_cube2ChunkDescs - bool isInSupportRange = chunkIndex <= 8 && chunkIndex >= 1; - bool isChildOfTwo = chunkIndex <= 24 && chunkIndex >= 17; - bool isChildOfSix = chunkIndex <= 56 && chunkIndex >= 49; - - ASSERT_TRUE(isInSupportRange || isChildOfTwo || isChildOfSix); - } - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, messageLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), messageLog, nullptr); - newActors.resize(newActorsCount); - - EXPECT_EQ(64 - 8 + 1, newActorsCount); - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); - EXPECT_TRUE(actorReleaseResult); - } - alignedFree(family); - alignedFree(asset); -} - -static bool hasWarned = false; -static void myLog(int type, const char* msg, const char* file, int line) -{ - BlastBaseTest<-1, 0>::messageLog(type, msg, file, line); - hasWarned = true; -} -#define EXPECT_WARNING EXPECT_TRUE(hasWarned); hasWarned=false; -#define EXPECT_NO_WARNING EXPECT_FALSE(hasWarned); hasWarned=false; - -TEST_F(APITest, FractureNoEvents) -{ - static const uint32_t GUARD = 0xb1a57; - - const uint32_t chunksCount = 17; - const NvBlastChunkDesc c_chunks[chunksCount] = - { - // centroid volume parent idx flags ID - { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, - }; - - const NvBlastBondDesc c_bonds[3] = - { - // normal, area, centroid, userdata, chunks - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 2.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, - }; - - NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; - - // create asset with chunk map - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - std::vector cfData; - cfData.resize(0 + 1); - cfData[cfData.size() - 1].userdata = GUARD; - std::vector bfData; - - NvBlastChunkFractureData command[] = - { - { 0, 1, 10.0f }, - { 0, 2, 10.0f }, - }; - - NvBlastFractureBuffers commands = { 0, 2, nullptr, command }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - EXPECT_NO_WARNING; // events can be null - EXPECT_EQ(GUARD, cfData[cfData.size() - 1].userdata); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - newActors.resize(newActorsCount); - - EXPECT_EQ(9, newActorsCount); - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], myLog); - EXPECT_TRUE(actorReleaseResult); - } - - alignedFree(family); - alignedFree(asset); - - EXPECT_NO_WARNING; -} - -TEST_F(APITest, FractureBufferLimits) -{ - static const uint32_t GUARD = 0xb1a57; - - const uint32_t chunksCount = 17; - const NvBlastChunkDesc c_chunks[chunksCount] = - { - // centroid volume parent idx flags ID - { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, - }; - - const NvBlastBondDesc c_bonds[3] = - { - // normal, area, centroid, userdata, chunks - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 2.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, - }; - - NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; - { - // create asset with chunk map - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); - EXPECT_TRUE(asset != nullptr); - - for (uint32_t i = 0; i < 14; i++) - { - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - std::vector cfData; - cfData.resize(i + 1); - cfData[cfData.size() - 1].userdata = GUARD; - std::vector bfData; - - NvBlastChunkFractureData command[] = - { - { 0, 1, 10.0f }, - { 0, 2, 10.0f }, - }; - - NvBlastFractureBuffers commands = { 0, 2, nullptr, command }; - NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; - - NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); - - EXPECT_WARNING; - EXPECT_EQ(GUARD, cfData[cfData.size() - 1].userdata); - EXPECT_EQ(i, events.chunkFractureCount); - for (uint32_t i = 0; i < events.chunkFractureCount; i++) - { - EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); - } - - EXPECT_TRUE(NvBlastActorDeactivate(actor, myLog)); - alignedFree(family); - } - - { - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - std::vector cfData; - cfData.resize(14 + 1); - cfData[cfData.size() - 1].userdata = GUARD; - std::vector bfData; - - NvBlastChunkFractureData command[] = - { - { 0, 1, 10.0f }, - { 0, 2, 10.0f }, - }; - - NvBlastFractureBuffers commands = { 0, 2, nullptr, command }; - NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; - - NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - EXPECT_NO_WARNING; - EXPECT_EQ(14, events.chunkFractureCount); - for (uint32_t i = 0; i < events.chunkFractureCount; i++) - { - EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); - } - ASSERT_EQ(GUARD, cfData[cfData.size() - 1].userdata); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - newActors.resize(newActorsCount); - - EXPECT_EQ(9, newActorsCount); - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], myLog); - EXPECT_TRUE(actorReleaseResult); - } - - alignedFree(family); - } - - alignedFree(asset); - } - EXPECT_NO_WARNING; -} - -TEST_F(APITest, FractureBufferLimitsInSitu) -{ - static const uint32_t GUARD = 0xb1a57; - - const uint32_t chunksCount = 17; - const NvBlastChunkDesc c_chunks[chunksCount] = - { - // cenroid volume parent idx flags ID - { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, - - { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, - }; - - const NvBlastBondDesc c_bonds[3] = - { - // normal, area, centroid, userdata, chunks - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 2.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, - }; - - NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; - { - // create asset with chunk map - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); - EXPECT_TRUE(asset != nullptr); - - for (uint32_t i = 0; i < 14 - 2; i++) - { - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - std::vector cfData; - cfData.resize(2 + i + 1); - - std::vector bfData; - - cfData[0].userdata = 0; - cfData[0].chunkIndex = 1; - cfData[0].health = 10.0f; - - cfData[1].userdata = 0; - cfData[1].chunkIndex = 2; - cfData[1].health = 10.0f; - - cfData[2 + i].userdata = GUARD; - - NvBlastFractureBuffers commands = { 0, 2, nullptr, cfData.data() }; - NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; - - NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - EXPECT_WARNING; - EXPECT_EQ(GUARD, cfData[cfData.size() - 1].userdata); - EXPECT_EQ(2 + i, events.chunkFractureCount); - for (uint32_t i = 0; i < events.chunkFractureCount; i++) - { - EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); - } - - EXPECT_TRUE(NvBlastActorDeactivate(actor, myLog)); - - alignedFree(family); - } - - { - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - std::vector cfData; - cfData.resize(14 + 1); - cfData[cfData.size() - 1].userdata = GUARD; - std::vector bfData; - - cfData[0].userdata = 0; - cfData[0].chunkIndex = 1; - cfData[0].health = 10.0f; - - cfData[1].userdata = 0; - cfData[1].chunkIndex = 2; - cfData[1].health = 10.0f; - - cfData[14].userdata = GUARD; - - NvBlastFractureBuffers commands = { 0, 2, nullptr, cfData.data() }; - NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; - - NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - EXPECT_NO_WARNING; - EXPECT_EQ(14, events.chunkFractureCount); - for (uint32_t i = 0; i < events.chunkFractureCount; i++) - { - EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); - } - ASSERT_EQ(GUARD, cfData[cfData.size() - 1].userdata); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - newActors.resize(newActorsCount); - - EXPECT_EQ(9, newActorsCount); - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], myLog); - EXPECT_TRUE(actorReleaseResult); - } - alignedFree(family); - } - - alignedFree(asset); - } - EXPECT_NO_WARNING; -} - -/* -This test checks if bond or chunk fracture commands passed to NvBlastActorApplyFracture do not correspond to -the actor passed in they (commands) will be ignored and warning message will be fired. -*/ -TEST_F(APITest, FractureWarnAndFilterOtherActorCommands) -{ - const uint32_t chunksCount = 17; - const NvBlastChunkDesc c_chunks[chunksCount] = - { - // centroid volume parent idx flags ID - { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, - }; - - const NvBlastBondDesc c_bonds[4] = - { - // normal, area, centroid, userdata, chunks - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } } - }; - - NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 4, c_bonds }; - - // create asset with chunk map - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - // split in 2 - std::vector actors; - { - NvBlastBondFractureData command[] = - { - { 0, 0, 2, 10.0f }, - { 0, 1, 2, 10.0f } - }; - - NvBlastFractureBuffers commands = { 2, 0, command, nullptr }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(2, newActorsCount); - EXPECT_EQ(actor, result.deletedActor); - - actors.insert(actors.begin(), result.newActors, result.newActors + newActorsCount); - } - - // damage bonds belonging to other actors, nothing expected to be broken - { - for (uint32_t i = 0; i < actors.size(); ++i) - { - NvBlastActor* actor = actors[i]; - NvBlastActor* otherActor = actors[(i + 1) % 2]; - - // get graph nodes check - std::vector graphNodeIndices; - graphNodeIndices.resize(NvBlastActorGetGraphNodeCount(otherActor, nullptr)); - uint32_t graphNodesCount = NvBlastActorGetGraphNodeIndices(graphNodeIndices.data(), (uint32_t)graphNodeIndices.size(), otherActor, nullptr); - EXPECT_EQ(graphNodesCount, 2); - - NvBlastBondFractureData command[] = - { - { 0, graphNodeIndices[0], graphNodeIndices[1], 10.0f } - }; - - NvBlastFractureBuffers commands = { 1, 0, command, nullptr }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_WARNING; - EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(0, newActorsCount); - EXPECT_EQ(nullptr, result.deletedActor); - } - } - - // damage bonds, split actors in 2 each - std::vector actors2; - { - for (uint32_t i = 0; i < 2; ++i) - { - NvBlastActor* actor = actors[i]; - - // get graph nodes check - std::vector graphNodeIndices; - graphNodeIndices.resize(NvBlastActorGetGraphNodeCount(actor, nullptr)); - uint32_t graphNodesCount = NvBlastActorGetGraphNodeIndices(graphNodeIndices.data(), (uint32_t)graphNodeIndices.size(), actor, nullptr); - EXPECT_EQ(graphNodesCount, 2); - - NvBlastBondFractureData command[] = - { - { 0, graphNodeIndices[0], graphNodeIndices[1], 10.0f } - }; - - NvBlastFractureBuffers commands = { 1, 0, command, nullptr }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(2, newActorsCount); - EXPECT_EQ(actor, result.deletedActor); - - actors2.insert(actors2.begin(), result.newActors, result.newActors + newActorsCount); - } - } - - // damage chunk belonging to other actor (expect no split or damage taken) - { - for (uint32_t i = 0; i < actors.size(); ++i) - { - NvBlastActor* actor = actors[i]; - NvBlastActor* otherActor = actors[(i + 1) % 2]; - - uint32_t chunkToDamage; - NvBlastActorGetVisibleChunkIndices(&chunkToDamage, 1, otherActor, myLog); - - NvBlastChunkFractureData command[] = - { - { 0, chunkToDamage, 0.9f }, - }; - - NvBlastFractureBuffers commands = { 0, 1, nullptr, command }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_WARNING; - EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(0, newActorsCount); - EXPECT_EQ(nullptr, result.deletedActor); - - EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); - uint32_t chunkIndex; - NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); - EXPECT_NE(chunkToDamage, chunkIndex); - } - } - - for (NvBlastActor* actor : actors2) - { - NvBlastActorDeactivate(actor, myLog); - } - - alignedFree(family); - alignedFree(asset); - - EXPECT_NO_WARNING; -} - -/** -If duplicate bonds are passed asset create routine will ignore them (but fire warning) -We pass duplicated bonds to world chunk and fully fracture actor once. -*/ -TEST_F(APITest, FractureWithBondDuplicates) -{ - const uint32_t chunksCount = 17; - const NvBlastChunkDesc c_chunks[chunksCount] = - { - // centroid volume parent idx flags ID - { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 5 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 6 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 7 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 8 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, - }; - - const uint32_t bondCount = 20; - const uint32_t world = ~(uint32_t)0; // world chunk => invalid index - const NvBlastBondDesc c_bonds[bondCount] = - { - // normal, area, centroid, userdata, chunks - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 1, world } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 2, 1 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 2, world } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 2, world } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 3, 1 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 4, 3 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 4, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 4, world } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 5, 1 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 5, world } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, 5 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, world } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, world } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 7, 5 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 7, 3 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, 7 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, 6 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, 4 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, world } } - }; - - NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, bondCount, c_bonds }; - - // create asset - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); - EXPECT_WARNING; - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - // split in 2 - std::vector actors; - { - NvBlastExtRadialDamageDesc damage = { - 10.0f, // compressive - { 0.0f, 0.0f, 0.0f }, // position - 100.0f, // min radius - maximum damage - 100.0f // max radius - zero damage - }; - - NvBlastBondFractureData outBondFracture[bondCount]; - NvBlastChunkFractureData outChunkFracture[chunksCount]; - - NvBlastFractureBuffers events; - events.bondFractureCount = 2; - events.bondFractures = outBondFracture; - events.chunkFractureCount = 2; - events.chunkFractures = outChunkFracture; - - NvBlastExtProgramParams programParams = { &damage, nullptr }; - - NvBlastDamageProgram program = { - NvBlastExtFalloffGraphShader, - NvBlastExtFalloffSubgraphShader - }; - - NvBlastActorGenerateFracture(&events, actor, program, &programParams, myLog, nullptr); - NvBlastActorApplyFracture(nullptr, actor, &events, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(8, newActorsCount); - EXPECT_EQ(actor, result.deletedActor); - - actors.insert(actors.begin(), result.newActors, result.newActors + newActorsCount); - } - - for (NvBlastActor* actor : actors) - { - NvBlastActorDeactivate(actor, myLog); - } - - alignedFree(family); - alignedFree(asset); - - EXPECT_NO_WARNING; -} - -#if 0 -TEST(APITest, UserChunkMap) -{ - for (int i = 0; i < 2; ++i) - { - // Choose descriptor list - const NvBlastAssetDesc* descs = nullptr; - size_t size = 0; - switch (i) - { - case 0: - descs = g_assetDescs; - size = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); - break; - case 1: - descs = g_assetDescsMissingCoverage; - size = sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); - break; - default: - continue; - } - - // Iterate over list - for (size_t j = 0; j < size; ++j) - { - // Create asset - const NvBlastAssetDesc* desc = descs + j; - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(desc)); - std::vector chunkMap(desc->chunkCount); - NvBlastAsset* asset = NvBlastCreateAsset(&chunkMap[0], desc, alignedAlloc, scratch.data(), nullptr); - EXPECT_TRUE(asset); - - // Test map - Nv::Blast::Asset& a = static_cast(asset); - uint32_t supportChunkCount = 0; - uint32_t subsupportChunkCount = 0; - for (uint32_t i = 0; i < desc->chunkCount; ++i) - { - const uint32_t map = chunkMap[i]; - if (Nv::Blast::isInvalidIndex(map)) - { - continue; - } - else if (map < a.m_firstSubsupportChunkIndex) - { - EXPECT_LT(map, asset.m_graph.m_nodeCount); - ++supportChunkCount; - } - else - { - EXPECT_LT(map, asset.m_chunkCount); - EXPECT_GE(map, asset.m_graph.m_nodeCount); - ++subsupportChunkCount; - } - } - EXPECT_EQ(supportChunkCount, asset.m_graph.m_nodeCount); - EXPECT_EQ(subsupportChunkCount, a.getLowerSupportChunkCount() - asset.m_graph.m_nodeCount); - - // Release asset - NvBlastAssetRelease(asset, free, nullptr); - } - } -} -#endif - -TEST_F(APITest, NoBondsSausage) -{ - // create asset - const NvBlastChunkDesc c_chunks[4] = - { - // centroid volume parent idx flags ID - { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 2 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 3 } - }; - - NvBlastAssetDesc assetDesc; - assetDesc.chunkCount = 4; - assetDesc.chunkDescs = c_chunks; - assetDesc.bondCount = 0; - assetDesc.bondDescs = nullptr; - - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); - const NvBlastChunk* chunks = NvBlastAssetGetChunks(asset, messageLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); - EXPECT_TRUE(actor != nullptr); - - // check visible chunk - { - EXPECT_EQ(NvBlastActorGetVisibleChunkCount(actor, messageLog), 1); - uint32_t chunkIndex; - NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, messageLog); - EXPECT_EQ(chunks[chunkIndex].userData, 0); - } - - // damage - NvBlastExtRadialDamageDesc damage = { - 10.0f, // compressive - { 0.0f, 0.0f, 0.0f }, // position - 4.0f, // min radius - maximum damage - 6.0f // max radius - zero damage - }; - - NvBlastBondFractureData outBondFracture[2]; - NvBlastChunkFractureData outChunkFracture[2]; - - NvBlastFractureBuffers events; - events.bondFractureCount = 2; - events.bondFractures = outBondFracture; - events.chunkFractureCount = 2; - events.chunkFractures = outChunkFracture; - - NvBlastExtProgramParams programParams = { &damage, nullptr }; - - NvBlastDamageProgram program = { - NvBlastExtFalloffGraphShader, - NvBlastExtFalloffSubgraphShader - }; - - NvBlastActorGenerateFracture(&events, actor, program, &programParams, messageLog, nullptr); - NvBlastActorApplyFracture(&events, actor, &events, messageLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - EXPECT_EQ(0, events.bondFractureCount); - EXPECT_EQ(1, events.chunkFractureCount); - - // split - NvBlastActor* newActors[8]; /* num lower-support chunks? plus space for deletedActor */ - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors; - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); - size_t newActorsCount = NvBlastActorSplit(&result, actor, 8, scratch.data(), messageLog, nullptr); - EXPECT_EQ(1, newActorsCount); - EXPECT_EQ(true, result.deletedActor == actor); - - // check visible chunk - { - EXPECT_EQ(NvBlastActorGetVisibleChunkCount(result.newActors[0], messageLog), 1); - uint32_t chunkIndex; - NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, result.newActors[0], messageLog); - EXPECT_EQ(chunks[chunkIndex].userData, 3); - } - - // release all - for (uint32_t i = 0; i < newActorsCount; ++i) - { - const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); - EXPECT_TRUE(actorReleaseResult); - } - - alignedFree(family); - alignedFree(asset); -} - -TEST_F(APITest, SplitOnlyWhenNecessary) -{ - static const uint32_t GUARD = 0xb1a57; - - const uint32_t chunksCount = 17; - const NvBlastChunkDesc c_chunks[chunksCount] = - { - // centroid volume parent idx flags ID - { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, - - { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, - { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, - }; - - const NvBlastBondDesc c_bonds[4] = - { - // normal, area, centroid, userdata, chunks - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, - { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } } - }; - - NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 4, c_bonds }; - - // create asset with chunk map - std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); - void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); - NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); - EXPECT_TRUE(asset != nullptr); - - // create actor - NvBlastActorDesc actorDesc; - actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; - actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; - void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); - NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); - scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); - NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); - EXPECT_TRUE(actor != nullptr); - - - // damage health only (expect no split) - { - NvBlastBondFractureData command[] = - { - { 0, 0, 1, 0.99f }, - { 0, 1, 2, 0.50f }, - { 0, 2, 3, 0.01f } - }; - - NvBlastFractureBuffers commands = { 3, 0, command, nullptr }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(0, newActorsCount); - EXPECT_EQ(nullptr, result.deletedActor); - - EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); - uint32_t chunkIndex; - NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); - EXPECT_EQ(0, chunkIndex); - } - - // break 1 bond (expect no split) - { - NvBlastBondFractureData command[] = - { - { 0, 0, 2, 10.0f }, - }; - - NvBlastFractureBuffers commands = { 1, 0, command, nullptr }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(0, newActorsCount); - EXPECT_EQ(nullptr, result.deletedActor); - - EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); - uint32_t chunkIndex; - NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); - EXPECT_EQ(0, chunkIndex); - } - - // split in 4 - std::vector actors; - { - NvBlastBondFractureData command[] = - { - { 0, 0, 1, 10.0f }, - { 0, 1, 2, 10.0f }, - { 0, 2, 3, 10.0f } - }; - - NvBlastFractureBuffers commands = { 3, 0, command, nullptr }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(4, newActorsCount); - EXPECT_EQ(actor, result.deletedActor); - - actors.insert(actors.begin(), result.newActors, result.newActors + newActorsCount); - } - - // damage chunk's health only (expect no split) - { - for (NvBlastActor* actor : actors) - { - uint32_t chunkToDamage; - NvBlastActorGetVisibleChunkIndices(&chunkToDamage, 1, actor, myLog); - - NvBlastChunkFractureData command[] = - { - { 0, chunkToDamage, 0.9f }, - }; - - NvBlastFractureBuffers commands = { 0, 1, nullptr, command }; - NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); - EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); - - scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); - std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); - NvBlastActorSplitEvent result; - result.deletedActor = nullptr; - result.newActors = newActors.data(); - size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); - - EXPECT_EQ(0, newActorsCount); - EXPECT_EQ(nullptr, result.deletedActor); - - EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); - uint32_t chunkIndex; - NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); - EXPECT_EQ(chunkToDamage, chunkIndex); - } - } - - for (NvBlastActor* actor : actors) - { - NvBlastActorDeactivate(actor, myLog); - } - - alignedFree(family); - alignedFree(asset); - - EXPECT_NO_WARNING; -} - -#if NV_WINDOWS_FAMILY -#include -TEST_F(APITest,CExportsNoNameMangling) -{ - - // - // tests the lib-link-free approach using unmangled names (extern "C") - // - -#if NV_WIN32 -#if NV_DEBUG - const char* dllName = "NvBlastDebug_x86.dll"; -#elif NV_CHECKED - const char* dllName = "NvBlastChecked_x86.dll"; -#elif NV_PROFILE - const char* dllName = "NvBlastProfile_x86.dll"; -#else - const char* dllName = "NvBlast_x86.dll"; -#endif -#elif NV_WIN64 -#if NV_DEBUG - const char* dllName = "NvBlastDebug_x64.dll"; -#elif NV_CHECKED - const char* dllName = "NvBlastChecked_x64.dll"; -#elif NV_PROFILE - const char* dllName = "NvBlastProfile_x64.dll"; -#else - const char* dllName = "NvBlast_x64.dll"; -#endif -#endif - - HMODULE dllHandle = LoadLibrary(TEXT(dllName)); - DWORD error = GetLastError(); - ASSERT_TRUE(dllHandle != nullptr); - - - // Asset functions - typedef size_t(*NvBlastGetRequiredScratchForCreateAsset)(const NvBlastAssetDesc* desc); - typedef size_t(*NvBlastGetAssetMemorySize)(const NvBlastAssetDesc* desc); - typedef NvBlastAsset*(*NvBlastCreateAsset)(void* mem, const NvBlastAssetDesc* desc, void* scratch, NvBlastLog logFn); - - NvBlastGetRequiredScratchForCreateAsset assetCreateRequiredScratch = (NvBlastGetRequiredScratchForCreateAsset)GetProcAddress(dllHandle, TEXT("NvBlastGetRequiredScratchForCreateAsset")); - ASSERT_TRUE(assetCreateRequiredScratch != nullptr); - - NvBlastGetAssetMemorySize assetGetMemorySize = (NvBlastGetAssetMemorySize)GetProcAddress(dllHandle, TEXT("NvBlastGetAssetMemorySize")); - ASSERT_TRUE(assetGetMemorySize != nullptr); - - NvBlastCreateAsset assetCreate = (NvBlastCreateAsset)GetProcAddress(dllHandle, TEXT("NvBlastCreateAsset")); - ASSERT_TRUE(assetCreate != nullptr); - - // Family functions - typedef NvBlastFamily* (*NvBlastAssetCreateFamily)(void* mem, const NvBlastAsset* asset, NvBlastLog logFn); - typedef size_t(*NVBLASTASSETGETFAMILYMEMORYSIZE)(const NvBlastAsset* asset); - - NVBLASTASSETGETFAMILYMEMORYSIZE familyGetMemorySize = (NVBLASTASSETGETFAMILYMEMORYSIZE)GetProcAddress(dllHandle, TEXT("NvBlastAssetGetFamilyMemorySize")); - ASSERT_TRUE(familyGetMemorySize != nullptr); - - NvBlastAssetCreateFamily familyCreate = (NvBlastAssetCreateFamily)GetProcAddress(dllHandle, TEXT("NvBlastAssetCreateFamily")); - ASSERT_TRUE(familyCreate != nullptr); - - - // Actor functions - typedef size_t(*NvBlastFamilyGetRequiredScratchForCreateFirstActor)(const NvBlastFamily* family); - typedef NvBlastActor* (*NvBlastFamilyCreateFirstActor)(NvBlastFamily* family, const NvBlastActorDesc* desc, void* scratch, NvBlastLog logFn); - typedef bool(*NVBLASTACTORDEACTIVATE)(NvBlastActor* actor); - - NvBlastFamilyGetRequiredScratchForCreateFirstActor actorcreaterequiredscratch = (NvBlastFamilyGetRequiredScratchForCreateFirstActor)GetProcAddress(dllHandle, TEXT("NvBlastFamilyGetRequiredScratchForCreateFirstActor")); - ASSERT_TRUE(actorcreaterequiredscratch != nullptr); - - NvBlastFamilyCreateFirstActor actorCreate = (NvBlastFamilyCreateFirstActor)GetProcAddress(dllHandle, TEXT("NvBlastFamilyCreateFirstActor")); - ASSERT_TRUE(actorCreate != nullptr); - - NVBLASTACTORDEACTIVATE actorRelease = (NVBLASTACTORDEACTIVATE)GetProcAddress(dllHandle, TEXT("NvBlastActorDeactivate")); - ASSERT_TRUE(actorRelease != nullptr); - - - const NvBlastChunkDesc c_chunks[] = - { - // centroid volume parent idx flags ID - { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 0 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 0 }, - { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 0 }, - }; - - NvBlastAssetDesc assetDesc; - assetDesc.bondCount = 0; - assetDesc.bondDescs = nullptr; - assetDesc.chunkCount = 4; - assetDesc.chunkDescs = c_chunks; - - NvBlastAsset* asset; - { - size_t requiredsize = assetCreateRequiredScratch(&assetDesc); - std::vectorscratch(requiredsize); - void* mem = alignedZeroedAlloc(assetGetMemorySize(&assetDesc)); - asset = assetCreate(mem, &assetDesc, scratch.data(), myLog); - ASSERT_TRUE(asset != nullptr); - } - - void* fmem = alignedZeroedAlloc(familyGetMemorySize(asset)); - NvBlastFamily* family = familyCreate(fmem, asset, myLog); - - { - NvBlastActorDesc actorD; - actorD.initialBondHealths = actorD.initialSupportChunkHealths = nullptr; - actorD.uniformInitialBondHealth = actorD.uniformInitialLowerSupportChunkHealth = 1.0f; - - size_t requiredsize = actorcreaterequiredscratch(family); - std::vectorscratch(requiredsize); - NvBlastActor* actor = actorCreate(family, &actorD, scratch.data(), myLog); - ASSERT_TRUE(actor != nullptr); - - ASSERT_TRUE(actorRelease(actor)); - } - - alignedFree(family); - alignedFree(asset); - - EXPECT_NO_WARNING; -} -#endif +// 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 "BlastBaseTest.h" +#include "NvBlastIndexFns.h" +#include "NvBlastExtDamageShaders.h" + +#include + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Utils / Tests Common +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +using namespace Nv::Blast; + +class APITest : public BlastBaseTest < NvBlastMessage::Error, 1 > +{ +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tests +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TEST_F(APITest, Basic) +{ + // create asset + const NvBlastAssetDesc& assetDesc = g_assetDescs[0]; + + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); + EXPECT_TRUE(actor != nullptr); + + NvBlastExtRadialDamageDesc damage = { + 10.0f, // compressive + { 0.0f, 0.0f, 0.0f }, // position + 4.0f, // min radius - maximum damage + 6.0f // max radius - zero damage + }; + + NvBlastBondFractureData outFracture[12]; /*num lower-support chunks + bonds?*/ + + NvBlastFractureBuffers events; + events.bondFractureCount = 12; + events.bondFractures = outFracture; + events.chunkFractureCount = 0; + events.chunkFractures = nullptr; + + NvBlastExtProgramParams programParams = { &damage, nullptr }; + + NvBlastDamageProgram program = { + NvBlastExtFalloffGraphShader, + nullptr + }; + + NvBlastActorGenerateFracture(&events, actor, program, &programParams, messageLog, nullptr); + NvBlastActorApplyFracture(&events, actor, &events, messageLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + EXPECT_EQ(12, events.bondFractureCount); + + NvBlastActor* newActors[8]; /* num lower-support chunks? plus space for deletedActor */ + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors; + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); + size_t newActorsCount = NvBlastActorSplit(&result, actor, 8, scratch.data(), messageLog, nullptr); + EXPECT_EQ(8, newActorsCount); + EXPECT_EQ(true, result.deletedActor == actor); + + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); + EXPECT_TRUE(actorReleaseResult); + } + alignedFree(family); + alignedFree(asset); +} + +TEST_F(APITest, DamageBondsCompressive) +{ + const size_t bondsCount = 6; + + const NvBlastChunkDesc c_chunks[8] = + { + // centroid volume parent idx flags ID + { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 5 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 6 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 7 } + }; + + const NvBlastBondDesc c_bonds[bondsCount] = + { + { { {-1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 2.0f, 0.0f }, 0 }, { 1, 2 } }, + { { {-1.0f, 0.0f, 0.0f }, 1.0f, {-1.0f, 2.0f, 0.0f }, 0 }, { 2, 3 } }, + { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-2.0f, 1.0f, 0.0f }, 0 }, { 3, 4 } }, + { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-2.0f,-1.0f, 0.0f }, 0 }, { 4, 5 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, {-1.0f,-2.0f, 0.0f }, 0 }, { 5, 6 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f,-2.0f, 0.0f }, 0 }, { 6, 7 } } + }; + + // create asset + const NvBlastAssetDesc assetDesc = { 8, c_chunks, bondsCount, c_bonds }; + + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); + EXPECT_TRUE(actor != nullptr); + + // get graph nodes check + std::vector graphNodeIndices; + graphNodeIndices.resize(NvBlastActorGetGraphNodeCount(actor, nullptr)); + uint32_t graphNodesCount = NvBlastActorGetGraphNodeIndices(graphNodeIndices.data(), (uint32_t)graphNodeIndices.size(), actor, nullptr); + EXPECT_EQ(graphNodesCount, 7); + + NvBlastExtRadialDamageDesc damage = { + 1.0f, // compressive + { 4.0f, 2.0f, 0.0f }, // position + 4.0f, // min radius - maximum damage + 6.0f // max radius - zero damage + }; // linear falloff + + NvBlastBondFractureData outCommands[bondsCount] = { + { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, + { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, + { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, + { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, + { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, + { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 }, + }; + + NvBlastFractureBuffers commands = { + 6, 0, outCommands, nullptr + }; + + NvBlastExtProgramParams programParams = { &damage, nullptr }; + + NvBlastDamageProgram program = { + NvBlastExtFalloffGraphShader, + nullptr + }; + + NvBlastActorGenerateFracture(&commands, actor, program, &programParams, messageLog, nullptr); + + ASSERT_EQ(3, commands.bondFractureCount); + ASSERT_EQ(0, commands.chunkFractureCount); + + // node indices in _graph_ chunks + NvBlastBondFractureData expectedCommand[] = { + { 0, 0, 1, 1.0f }, + { 0, 1, 2, 0.5f }, + { 0, 5, 6, 0.5f } + }; + + for (int i = 0; i < 3; i++) + { + EXPECT_EQ(expectedCommand[i].nodeIndex0, outCommands[i].nodeIndex0); + EXPECT_EQ(expectedCommand[i].nodeIndex1, outCommands[i].nodeIndex1); + EXPECT_EQ(expectedCommand[i].health, outCommands[i].health); + } + + const bool actorReleaseResult = NvBlastActorDeactivate(actor, messageLog); + EXPECT_TRUE(actorReleaseResult); + alignedFree(family); + alignedFree(asset); +} + +TEST_F(APITest, DirectFractureKillsChunk) +{ + // 1--2 + // | | + // 3--4 <-- kill 4 + + const NvBlastChunkDesc c_chunks[9] = + { + // centroid volume parent idx flags ID + { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 5 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 6 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 7 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 4, NvBlastChunkDesc::NoFlags, 8 }, + }; + + const NvBlastBondDesc c_bonds[4] = + { + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, 1.0f, 0.0f }, 0 }, { 1, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f,-1.0f, 0.0f }, 0 }, { 3, 4 } }, + { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } }, + { { { 0.0f,-1.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 2, 4 } }, + }; + + NvBlastAssetDesc assetDesc; + assetDesc.chunkCount = 9; + assetDesc.chunkDescs = c_chunks; + assetDesc.bondCount = 4; + assetDesc.bondDescs = c_bonds; + + // create asset + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); + EXPECT_TRUE(actor != nullptr); + + NvBlastChunkFractureData fractureCmd; + fractureCmd.chunkIndex = 4; + fractureCmd.health = 1.0f; + + NvBlastFractureBuffers commands = { 0, 1, nullptr, &fractureCmd }; + + NvBlastChunkFractureData fractureEvt; + NvBlastFractureBuffers events = { 0, 1, nullptr, &fractureEvt }; + + NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + EXPECT_EQ(1, events.chunkFractureCount); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, messageLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), messageLog, nullptr); + newActors.resize(newActorsCount); + + EXPECT_EQ(5, newActorsCount); + EXPECT_EQ(actor, result.deletedActor); + // check newActors contain original actor + EXPECT_TRUE(std::any_of(newActors.begin(), newActors.end(), [&](const NvBlastActor* a) { return actor == a; })); + + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); + EXPECT_TRUE(actorReleaseResult); + } + alignedFree(family); + alignedFree(asset); +} + +TEST_F(APITest, DirectFractureKillsIslandRootChunk) +{ + // 1--2 <-- kill 1 + // | | + // 3--4 + + const NvBlastChunkDesc c_chunks[9] = + { + // centroid volume parent idx flags ID + { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 7 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 8 }, + }; + + const NvBlastBondDesc c_bonds[4] = + { + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, 1.0f, 0.0f }, 0 }, { 1, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f,-1.0f, 0.0f }, 0 }, { 3, 4 } }, + { { { 0.0f,-1.0f, 0.0f }, 1.0f, {-1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } }, + { { { 0.0f,-1.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 2, 4 } }, + }; + + NvBlastAssetDesc assetDesc; + assetDesc.chunkCount = 9; + assetDesc.chunkDescs = c_chunks; + assetDesc.bondCount = 4; + assetDesc.bondDescs = c_bonds; + + // create asset + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); + EXPECT_TRUE(actor != nullptr); + + NvBlastChunkFractureData fractureCmd; + fractureCmd.chunkIndex = 1; + fractureCmd.health = 1.0f; + + NvBlastFractureBuffers commands = { 0, 1, nullptr, &fractureCmd }; + + NvBlastChunkFractureData fractureEvt; + NvBlastFractureBuffers events = { 0, 1, nullptr, &fractureEvt }; + + NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + EXPECT_EQ(1, events.chunkFractureCount); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, messageLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), messageLog, nullptr); + newActors.resize(newActorsCount); + + EXPECT_EQ(5, newActorsCount); + EXPECT_EQ(actor, result.deletedActor); + // check if newActors don't contain original actor + EXPECT_TRUE(!std::any_of(newActors.begin(), newActors.end(), [&](const NvBlastActor* a) { return actor == a; })); + + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); + EXPECT_TRUE(actorReleaseResult); + } + alignedFree(family); + alignedFree(asset); +} + +TEST_F(APITest, SubsupportFracture) +{ + const NvBlastAssetDesc& assetDesc = g_assetDescs[1]; // cube with subsupport + + // create asset with chunk map + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); + EXPECT_TRUE(actor != nullptr); + + // first set of fracture commands + NvBlastChunkFractureData f1 = { 0, 1, 2.0f }; + NvBlastChunkFractureData f3 = { 0, 3, 0.5f }; + NvBlastChunkFractureData f5 = { 0, 5, 1.0f }; + NvBlastChunkFractureData f7 = { 0, 7, 1.0f }; + + std::vector chunkFractureData; + chunkFractureData.reserve(assetDesc.chunkCount); + chunkFractureData.push_back(f1); + chunkFractureData.push_back(f3); + chunkFractureData.push_back(f5); + chunkFractureData.push_back(f7); + ASSERT_EQ(assetDesc.chunkCount, chunkFractureData.capacity()); + ASSERT_EQ(4, chunkFractureData.size()); + + NvBlastFractureBuffers target = { 0, static_cast(chunkFractureData.capacity()), nullptr, chunkFractureData.data() }; + { + NvBlastFractureBuffers events = target; + NvBlastFractureBuffers commands = { 0, static_cast(chunkFractureData.size()), nullptr, chunkFractureData.data() }; + NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + ASSERT_EQ(4 + 8, events.chunkFractureCount); // all requested chunks take damage, and the children of one of them + } + + // re-apply same set of commands + chunkFractureData.clear(); + chunkFractureData.reserve(assetDesc.chunkCount); + chunkFractureData.push_back(f1); + chunkFractureData.push_back(f3); + chunkFractureData.push_back(f5); + chunkFractureData.push_back(f7); + ASSERT_EQ(assetDesc.chunkCount, chunkFractureData.capacity()); + ASSERT_EQ(4, chunkFractureData.size()); + + { + NvBlastFractureBuffers events = target; + NvBlastFractureBuffers commands = { 0, static_cast(chunkFractureData.size()), nullptr, chunkFractureData.data() }; + NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + ASSERT_EQ(1, events.chunkFractureCount); // f3 has broken the chunk + } + + // fracture all support chunks + // the chunks from the previous fractures must not be reported again (since they are all broken already) + NvBlastChunkFractureData f2 = { 0, 2, 2.0f }; // will damage chunk and children + NvBlastChunkFractureData f4 = { 0, 4, 0.5f }; // will damage chunk without creating children on split + NvBlastChunkFractureData f6 = { 0, 6, 2.0f }; // will damage chunk and children + NvBlastChunkFractureData f8 = { 0, 8, 1.0f }; // will damage chunk + + chunkFractureData.clear(); + chunkFractureData.reserve(assetDesc.chunkCount); + chunkFractureData.push_back(f1); + chunkFractureData.push_back(f2); + chunkFractureData.push_back(f3); + chunkFractureData.push_back(f4); + chunkFractureData.push_back(f5); + chunkFractureData.push_back(f6); + chunkFractureData.push_back(f7); + chunkFractureData.push_back(f8); + ASSERT_EQ(assetDesc.chunkCount, chunkFractureData.capacity()); + ASSERT_EQ(8, chunkFractureData.size()); + + NvBlastFractureBuffers events = target; + { + NvBlastFractureBuffers commands = { 0, static_cast(chunkFractureData.size()), nullptr, chunkFractureData.data() }; + NvBlastActorApplyFracture(&events, actor, &commands, messageLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + ASSERT_EQ(4 + 8 + 8, events.chunkFractureCount); // the new fracture commands all apply, plus two of them damage their children too + } + + for (size_t i = 0; i < events.chunkFractureCount; i++) + { + const uint32_t chunkIndex = events.chunkFractures[i].chunkIndex; + + ASSERT_TRUE(chunkIndex != 1); + ASSERT_TRUE(chunkIndex != 3); + ASSERT_TRUE(chunkIndex != 5); + ASSERT_TRUE(chunkIndex != 7); + + // literal values come from g_cube2ChunkDescs + bool isInSupportRange = chunkIndex <= 8 && chunkIndex >= 1; + bool isChildOfTwo = chunkIndex <= 24 && chunkIndex >= 17; + bool isChildOfSix = chunkIndex <= 56 && chunkIndex >= 49; + + ASSERT_TRUE(isInSupportRange || isChildOfTwo || isChildOfSix); + } + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, messageLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), messageLog, nullptr); + newActors.resize(newActorsCount); + + EXPECT_EQ(64 - 8 + 1, newActorsCount); + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); + EXPECT_TRUE(actorReleaseResult); + } + alignedFree(family); + alignedFree(asset); +} + +static bool hasWarned = false; +static void myLog(int type, const char* msg, const char* file, int line) +{ + BlastBaseTest<-1, 0>::messageLog(type, msg, file, line); + hasWarned = true; +} +#define EXPECT_WARNING EXPECT_TRUE(hasWarned); hasWarned=false; +#define EXPECT_NO_WARNING EXPECT_FALSE(hasWarned); hasWarned=false; + +TEST_F(APITest, FractureNoEvents) +{ + static const uint32_t GUARD = 0xb1a57; + + const uint32_t chunksCount = 17; + const NvBlastChunkDesc c_chunks[chunksCount] = + { + // centroid volume parent idx flags ID + { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, + }; + + const NvBlastBondDesc c_bonds[3] = + { + // normal, area, centroid, userdata, chunks + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 2.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, + }; + + NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; + + // create asset with chunk map + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + std::vector cfData; + cfData.resize(0 + 1); + cfData[cfData.size() - 1].userdata = GUARD; + std::vector bfData; + + NvBlastChunkFractureData command[] = + { + { 0, 1, 10.0f }, + { 0, 2, 10.0f }, + }; + + NvBlastFractureBuffers commands = { 0, 2, nullptr, command }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + EXPECT_NO_WARNING; // events can be null + EXPECT_EQ(GUARD, cfData[cfData.size() - 1].userdata); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + newActors.resize(newActorsCount); + + EXPECT_EQ(9, newActorsCount); + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], myLog); + EXPECT_TRUE(actorReleaseResult); + } + + alignedFree(family); + alignedFree(asset); + + EXPECT_NO_WARNING; +} + +TEST_F(APITest, FractureBufferLimits) +{ + static const uint32_t GUARD = 0xb1a57; + + const uint32_t chunksCount = 17; + const NvBlastChunkDesc c_chunks[chunksCount] = + { + // centroid volume parent idx flags ID + { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, + }; + + const NvBlastBondDesc c_bonds[3] = + { + // normal, area, centroid, userdata, chunks + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 2.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, + }; + + NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; + { + // create asset with chunk map + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); + EXPECT_TRUE(asset != nullptr); + + for (uint32_t i = 0; i < 14; i++) + { + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + std::vector cfData; + cfData.resize(i + 1); + cfData[cfData.size() - 1].userdata = GUARD; + std::vector bfData; + + NvBlastChunkFractureData command[] = + { + { 0, 1, 10.0f }, + { 0, 2, 10.0f }, + }; + + NvBlastFractureBuffers commands = { 0, 2, nullptr, command }; + NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; + + NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); + + EXPECT_WARNING; + EXPECT_EQ(GUARD, cfData[cfData.size() - 1].userdata); + EXPECT_EQ(i, events.chunkFractureCount); + for (uint32_t i = 0; i < events.chunkFractureCount; i++) + { + EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); + } + + EXPECT_TRUE(NvBlastActorDeactivate(actor, myLog)); + alignedFree(family); + } + + { + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + std::vector cfData; + cfData.resize(14 + 1); + cfData[cfData.size() - 1].userdata = GUARD; + std::vector bfData; + + NvBlastChunkFractureData command[] = + { + { 0, 1, 10.0f }, + { 0, 2, 10.0f }, + }; + + NvBlastFractureBuffers commands = { 0, 2, nullptr, command }; + NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; + + NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + EXPECT_NO_WARNING; + EXPECT_EQ(14, events.chunkFractureCount); + for (uint32_t i = 0; i < events.chunkFractureCount; i++) + { + EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); + } + ASSERT_EQ(GUARD, cfData[cfData.size() - 1].userdata); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + newActors.resize(newActorsCount); + + EXPECT_EQ(9, newActorsCount); + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], myLog); + EXPECT_TRUE(actorReleaseResult); + } + + alignedFree(family); + } + + alignedFree(asset); + } + EXPECT_NO_WARNING; +} + +TEST_F(APITest, FractureBufferLimitsInSitu) +{ + static const uint32_t GUARD = 0xb1a57; + + const uint32_t chunksCount = 17; + const NvBlastChunkDesc c_chunks[chunksCount] = + { + // cenroid volume parent idx flags ID + { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, + + { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, + }; + + const NvBlastBondDesc c_bonds[3] = + { + // normal, area, centroid, userdata, chunks + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 2.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, + }; + + NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; + { + // create asset with chunk map + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); + EXPECT_TRUE(asset != nullptr); + + for (uint32_t i = 0; i < 14 - 2; i++) + { + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + std::vector cfData; + cfData.resize(2 + i + 1); + + std::vector bfData; + + cfData[0].userdata = 0; + cfData[0].chunkIndex = 1; + cfData[0].health = 10.0f; + + cfData[1].userdata = 0; + cfData[1].chunkIndex = 2; + cfData[1].health = 10.0f; + + cfData[2 + i].userdata = GUARD; + + NvBlastFractureBuffers commands = { 0, 2, nullptr, cfData.data() }; + NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; + + NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + EXPECT_WARNING; + EXPECT_EQ(GUARD, cfData[cfData.size() - 1].userdata); + EXPECT_EQ(2 + i, events.chunkFractureCount); + for (uint32_t i = 0; i < events.chunkFractureCount; i++) + { + EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); + } + + EXPECT_TRUE(NvBlastActorDeactivate(actor, myLog)); + + alignedFree(family); + } + + { + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + std::vector cfData; + cfData.resize(14 + 1); + cfData[cfData.size() - 1].userdata = GUARD; + std::vector bfData; + + cfData[0].userdata = 0; + cfData[0].chunkIndex = 1; + cfData[0].health = 10.0f; + + cfData[1].userdata = 0; + cfData[1].chunkIndex = 2; + cfData[1].health = 10.0f; + + cfData[14].userdata = GUARD; + + NvBlastFractureBuffers commands = { 0, 2, nullptr, cfData.data() }; + NvBlastFractureBuffers events = { static_cast(bfData.size()), static_cast(cfData.size()) - 1, bfData.data(), cfData.data() }; + + NvBlastActorApplyFracture(&events, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + EXPECT_NO_WARNING; + EXPECT_EQ(14, events.chunkFractureCount); + for (uint32_t i = 0; i < events.chunkFractureCount; i++) + { + EXPECT_EQ(events.chunkFractures[i].chunkIndex, events.chunkFractures[i].userdata); + } + ASSERT_EQ(GUARD, cfData[cfData.size() - 1].userdata); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + newActors.resize(newActorsCount); + + EXPECT_EQ(9, newActorsCount); + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], myLog); + EXPECT_TRUE(actorReleaseResult); + } + alignedFree(family); + } + + alignedFree(asset); + } + EXPECT_NO_WARNING; +} + +/* +This test checks if bond or chunk fracture commands passed to NvBlastActorApplyFracture do not correspond to +the actor passed in they (commands) will be ignored and warning message will be fired. +*/ +TEST_F(APITest, FractureWarnAndFilterOtherActorCommands) +{ + const uint32_t chunksCount = 17; + const NvBlastChunkDesc c_chunks[chunksCount] = + { + // centroid volume parent idx flags ID + { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, + }; + + const NvBlastBondDesc c_bonds[4] = + { + // normal, area, centroid, userdata, chunks + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } } + }; + + NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 4, c_bonds }; + + // create asset with chunk map + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + // split in 2 + std::vector actors; + { + NvBlastBondFractureData command[] = + { + { 0, 0, 2, 10.0f }, + { 0, 1, 2, 10.0f } + }; + + NvBlastFractureBuffers commands = { 2, 0, command, nullptr }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(2, newActorsCount); + EXPECT_EQ(actor, result.deletedActor); + + actors.insert(actors.begin(), result.newActors, result.newActors + newActorsCount); + } + + // damage bonds belonging to other actors, nothing expected to be broken + { + for (uint32_t i = 0; i < actors.size(); ++i) + { + NvBlastActor* actor = actors[i]; + NvBlastActor* otherActor = actors[(i + 1) % 2]; + + // get graph nodes check + std::vector graphNodeIndices; + graphNodeIndices.resize(NvBlastActorGetGraphNodeCount(otherActor, nullptr)); + uint32_t graphNodesCount = NvBlastActorGetGraphNodeIndices(graphNodeIndices.data(), (uint32_t)graphNodeIndices.size(), otherActor, nullptr); + EXPECT_EQ(graphNodesCount, 2); + + NvBlastBondFractureData command[] = + { + { 0, graphNodeIndices[0], graphNodeIndices[1], 10.0f } + }; + + NvBlastFractureBuffers commands = { 1, 0, command, nullptr }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_WARNING; + EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(0, newActorsCount); + EXPECT_EQ(nullptr, result.deletedActor); + } + } + + // damage bonds, split actors in 2 each + std::vector actors2; + { + for (uint32_t i = 0; i < 2; ++i) + { + NvBlastActor* actor = actors[i]; + + // get graph nodes check + std::vector graphNodeIndices; + graphNodeIndices.resize(NvBlastActorGetGraphNodeCount(actor, nullptr)); + uint32_t graphNodesCount = NvBlastActorGetGraphNodeIndices(graphNodeIndices.data(), (uint32_t)graphNodeIndices.size(), actor, nullptr); + EXPECT_EQ(graphNodesCount, 2); + + NvBlastBondFractureData command[] = + { + { 0, graphNodeIndices[0], graphNodeIndices[1], 10.0f } + }; + + NvBlastFractureBuffers commands = { 1, 0, command, nullptr }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(2, newActorsCount); + EXPECT_EQ(actor, result.deletedActor); + + actors2.insert(actors2.begin(), result.newActors, result.newActors + newActorsCount); + } + } + + // damage chunk belonging to other actor (expect no split or damage taken) + { + for (uint32_t i = 0; i < actors.size(); ++i) + { + NvBlastActor* actor = actors[i]; + NvBlastActor* otherActor = actors[(i + 1) % 2]; + + uint32_t chunkToDamage; + NvBlastActorGetVisibleChunkIndices(&chunkToDamage, 1, otherActor, myLog); + + NvBlastChunkFractureData command[] = + { + { 0, chunkToDamage, 0.9f }, + }; + + NvBlastFractureBuffers commands = { 0, 1, nullptr, command }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_WARNING; + EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(0, newActorsCount); + EXPECT_EQ(nullptr, result.deletedActor); + + EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); + uint32_t chunkIndex; + NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); + EXPECT_NE(chunkToDamage, chunkIndex); + } + } + + for (NvBlastActor* actor : actors2) + { + NvBlastActorDeactivate(actor, myLog); + } + + alignedFree(family); + alignedFree(asset); + + EXPECT_NO_WARNING; +} + +/** +If duplicate bonds are passed asset create routine will ignore them (but fire warning) +We pass duplicated bonds to world chunk and fully fracture actor once. +*/ +TEST_F(APITest, FractureWithBondDuplicates) +{ + const uint32_t chunksCount = 17; + const NvBlastChunkDesc c_chunks[chunksCount] = + { + // centroid volume parent idx flags ID + { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 5 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 6 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 7 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 8 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, + }; + + const uint32_t bondCount = 20; + const uint32_t world = ~(uint32_t)0; // world chunk => invalid index + const NvBlastBondDesc c_bonds[bondCount] = + { + // normal, area, centroid, userdata, chunks + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 1, world } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 2, 1 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 2, world } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 2, world } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 3, 1 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 4, 3 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 4, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 4, world } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 5, 1 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 5, world } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, 5 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, world } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 6, world } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 7, 5 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 7, 3 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, 7 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, 6 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, 4 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f,{ 1.0f, 0.0f, 0.0f }, 0 },{ 8, world } } + }; + + NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, bondCount, c_bonds }; + + // create asset + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); + EXPECT_WARNING; + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + // split in 2 + std::vector actors; + { + NvBlastExtRadialDamageDesc damage = { + 10.0f, // compressive + { 0.0f, 0.0f, 0.0f }, // position + 100.0f, // min radius - maximum damage + 100.0f // max radius - zero damage + }; + + NvBlastBondFractureData outBondFracture[bondCount]; + NvBlastChunkFractureData outChunkFracture[chunksCount]; + + NvBlastFractureBuffers events; + events.bondFractureCount = 2; + events.bondFractures = outBondFracture; + events.chunkFractureCount = 2; + events.chunkFractures = outChunkFracture; + + NvBlastExtProgramParams programParams = { &damage, nullptr }; + + NvBlastDamageProgram program = { + NvBlastExtFalloffGraphShader, + NvBlastExtFalloffSubgraphShader + }; + + NvBlastActorGenerateFracture(&events, actor, program, &programParams, myLog, nullptr); + NvBlastActorApplyFracture(nullptr, actor, &events, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(8, newActorsCount); + EXPECT_EQ(actor, result.deletedActor); + + actors.insert(actors.begin(), result.newActors, result.newActors + newActorsCount); + } + + for (NvBlastActor* actor : actors) + { + NvBlastActorDeactivate(actor, myLog); + } + + alignedFree(family); + alignedFree(asset); + + EXPECT_NO_WARNING; +} + +#if 0 +TEST(APITest, UserChunkMap) +{ + for (int i = 0; i < 2; ++i) + { + // Choose descriptor list + const NvBlastAssetDesc* descs = nullptr; + size_t size = 0; + switch (i) + { + case 0: + descs = g_assetDescs; + size = sizeof(g_assetDescs) / sizeof(g_assetDescs[0]); + break; + case 1: + descs = g_assetDescsMissingCoverage; + size = sizeof(g_assetDescsMissingCoverage) / sizeof(g_assetDescsMissingCoverage[0]); + break; + default: + continue; + } + + // Iterate over list + for (size_t j = 0; j < size; ++j) + { + // Create asset + const NvBlastAssetDesc* desc = descs + j; + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(desc)); + std::vector chunkMap(desc->chunkCount); + NvBlastAsset* asset = NvBlastCreateAsset(&chunkMap[0], desc, alignedAlloc, scratch.data(), nullptr); + EXPECT_TRUE(asset); + + // Test map + Nv::Blast::Asset& a = static_cast(asset); + uint32_t supportChunkCount = 0; + uint32_t subsupportChunkCount = 0; + for (uint32_t i = 0; i < desc->chunkCount; ++i) + { + const uint32_t map = chunkMap[i]; + if (Nv::Blast::isInvalidIndex(map)) + { + continue; + } + else if (map < a.m_firstSubsupportChunkIndex) + { + EXPECT_LT(map, asset.m_graph.m_nodeCount); + ++supportChunkCount; + } + else + { + EXPECT_LT(map, asset.m_chunkCount); + EXPECT_GE(map, asset.m_graph.m_nodeCount); + ++subsupportChunkCount; + } + } + EXPECT_EQ(supportChunkCount, asset.m_graph.m_nodeCount); + EXPECT_EQ(subsupportChunkCount, a.getLowerSupportChunkCount() - asset.m_graph.m_nodeCount); + + // Release asset + NvBlastAssetRelease(asset, free, nullptr); + } + } +} +#endif + +TEST_F(APITest, NoBondsSausage) +{ + // create asset + const NvBlastChunkDesc c_chunks[4] = + { + // centroid volume parent idx flags ID + { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 2 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 3 } + }; + + NvBlastAssetDesc assetDesc; + assetDesc.chunkCount = 4; + assetDesc.chunkDescs = c_chunks; + assetDesc.bondCount = 0; + assetDesc.bondDescs = nullptr; + + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, messageLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), messageLog); + const NvBlastChunk* chunks = NvBlastAssetGetChunks(asset, messageLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, messageLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, messageLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, messageLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), messageLog); + EXPECT_TRUE(actor != nullptr); + + // check visible chunk + { + EXPECT_EQ(NvBlastActorGetVisibleChunkCount(actor, messageLog), 1); + uint32_t chunkIndex; + NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, messageLog); + EXPECT_EQ(chunks[chunkIndex].userData, 0); + } + + // damage + NvBlastExtRadialDamageDesc damage = { + 10.0f, // compressive + { 0.0f, 0.0f, 0.0f }, // position + 4.0f, // min radius - maximum damage + 6.0f // max radius - zero damage + }; + + NvBlastBondFractureData outBondFracture[2]; + NvBlastChunkFractureData outChunkFracture[2]; + + NvBlastFractureBuffers events; + events.bondFractureCount = 2; + events.bondFractures = outBondFracture; + events.chunkFractureCount = 2; + events.chunkFractures = outChunkFracture; + + NvBlastExtProgramParams programParams = { &damage, nullptr }; + + NvBlastDamageProgram program = { + NvBlastExtFalloffGraphShader, + NvBlastExtFalloffSubgraphShader + }; + + NvBlastActorGenerateFracture(&events, actor, program, &programParams, messageLog, nullptr); + NvBlastActorApplyFracture(&events, actor, &events, messageLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + EXPECT_EQ(0, events.bondFractureCount); + EXPECT_EQ(1, events.chunkFractureCount); + + // split + NvBlastActor* newActors[8]; /* num lower-support chunks? plus space for deletedActor */ + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors; + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, messageLog)); + size_t newActorsCount = NvBlastActorSplit(&result, actor, 8, scratch.data(), messageLog, nullptr); + EXPECT_EQ(1, newActorsCount); + EXPECT_EQ(true, result.deletedActor == actor); + + // check visible chunk + { + EXPECT_EQ(NvBlastActorGetVisibleChunkCount(result.newActors[0], messageLog), 1); + uint32_t chunkIndex; + NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, result.newActors[0], messageLog); + EXPECT_EQ(chunks[chunkIndex].userData, 3); + } + + // release all + for (uint32_t i = 0; i < newActorsCount; ++i) + { + const bool actorReleaseResult = NvBlastActorDeactivate(result.newActors[i], messageLog); + EXPECT_TRUE(actorReleaseResult); + } + + alignedFree(family); + alignedFree(asset); +} + +TEST_F(APITest, SplitOnlyWhenNecessary) +{ + static const uint32_t GUARD = 0xb1a57; + + const uint32_t chunksCount = 17; + const NvBlastChunkDesc c_chunks[chunksCount] = + { + // centroid volume parent idx flags ID + { { 0.0f, 0.0f, 0.0f }, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 1 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 3 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 4 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 5 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 1, NvBlastChunkDesc::NoFlags, 6 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 7 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 2, NvBlastChunkDesc::NoFlags, 8 }, + + { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 9 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 5, NvBlastChunkDesc::NoFlags, 10 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 11 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 6, NvBlastChunkDesc::NoFlags, 12 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 13 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 7, NvBlastChunkDesc::NoFlags, 14 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 15 }, + { { 0.0f, 0.0f, 0.0f }, 0.0f, 8, NvBlastChunkDesc::NoFlags, 16 }, + }; + + const NvBlastBondDesc c_bonds[4] = + { + // normal, area, centroid, userdata, chunks + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 2, 3 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 3, 4 } }, + { { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 }, { 1, 3 } } + }; + + NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 4, c_bonds }; + + // create asset with chunk map + std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); + void* amem = alignedZeroedAlloc(NvBlastGetAssetMemorySize(&assetDesc, myLog)); + NvBlastAsset* asset = NvBlastCreateAsset(amem, &assetDesc, scratch.data(), myLog); + EXPECT_TRUE(asset != nullptr); + + // create actor + NvBlastActorDesc actorDesc; + actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; + actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; + void* fmem = alignedZeroedAlloc(NvBlastAssetGetFamilyMemorySize(asset, myLog)); + NvBlastFamily* family = NvBlastAssetCreateFamily(fmem, asset, myLog); + scratch.resize((size_t)NvBlastFamilyGetRequiredScratchForCreateFirstActor(family, myLog)); + NvBlastActor* actor = NvBlastFamilyCreateFirstActor(family, &actorDesc, scratch.data(), myLog); + EXPECT_TRUE(actor != nullptr); + + + // damage health only (expect no split) + { + NvBlastBondFractureData command[] = + { + { 0, 0, 1, 0.99f }, + { 0, 1, 2, 0.50f }, + { 0, 2, 3, 0.01f } + }; + + NvBlastFractureBuffers commands = { 3, 0, command, nullptr }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(0, newActorsCount); + EXPECT_EQ(nullptr, result.deletedActor); + + EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); + uint32_t chunkIndex; + NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); + EXPECT_EQ(0, chunkIndex); + } + + // break 1 bond (expect no split) + { + NvBlastBondFractureData command[] = + { + { 0, 0, 2, 10.0f }, + }; + + NvBlastFractureBuffers commands = { 1, 0, command, nullptr }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(0, newActorsCount); + EXPECT_EQ(nullptr, result.deletedActor); + + EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); + uint32_t chunkIndex; + NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); + EXPECT_EQ(0, chunkIndex); + } + + // split in 4 + std::vector actors; + { + NvBlastBondFractureData command[] = + { + { 0, 0, 1, 10.0f }, + { 0, 1, 2, 10.0f }, + { 0, 2, 3, 10.0f } + }; + + NvBlastFractureBuffers commands = { 3, 0, command, nullptr }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_TRUE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(4, newActorsCount); + EXPECT_EQ(actor, result.deletedActor); + + actors.insert(actors.begin(), result.newActors, result.newActors + newActorsCount); + } + + // damage chunk's health only (expect no split) + { + for (NvBlastActor* actor : actors) + { + uint32_t chunkToDamage; + NvBlastActorGetVisibleChunkIndices(&chunkToDamage, 1, actor, myLog); + + NvBlastChunkFractureData command[] = + { + { 0, chunkToDamage, 0.9f }, + }; + + NvBlastFractureBuffers commands = { 0, 1, nullptr, command }; + NvBlastActorApplyFracture(nullptr, actor, &commands, myLog, nullptr); + EXPECT_FALSE(NvBlastActorIsSplitRequired(actor, messageLog)); + + scratch.resize((size_t)NvBlastActorGetRequiredScratchForSplit(actor, myLog)); + std::vector newActors(NvBlastActorGetMaxActorCountForSplit(actor, myLog)); + NvBlastActorSplitEvent result; + result.deletedActor = nullptr; + result.newActors = newActors.data(); + size_t newActorsCount = NvBlastActorSplit(&result, actor, static_cast(newActors.size()), scratch.data(), myLog, nullptr); + + EXPECT_EQ(0, newActorsCount); + EXPECT_EQ(nullptr, result.deletedActor); + + EXPECT_EQ(1, NvBlastActorGetVisibleChunkCount(actor, myLog)); + uint32_t chunkIndex; + NvBlastActorGetVisibleChunkIndices(&chunkIndex, 1, actor, myLog); + EXPECT_EQ(chunkToDamage, chunkIndex); + } + } + + for (NvBlastActor* actor : actors) + { + NvBlastActorDeactivate(actor, myLog); + } + + alignedFree(family); + alignedFree(asset); + + EXPECT_NO_WARNING; +} + +#if NV_WINDOWS_FAMILY +#include +TEST_F(APITest,CExportsNoNameMangling) +{ + + // + // tests the lib-link-free approach using unmangled names (extern "C") + // + +#if NV_WIN32 +#if NV_DEBUG + const char* dllName = "NvBlastDebug_x86.dll"; +#elif NV_CHECKED + const char* dllName = "NvBlastChecked_x86.dll"; +#elif NV_PROFILE + const char* dllName = "NvBlastProfile_x86.dll"; +#else + const char* dllName = "NvBlast_x86.dll"; +#endif +#elif NV_WIN64 +#if NV_DEBUG + const char* dllName = "NvBlastDebug_x64.dll"; +#elif NV_CHECKED + const char* dllName = "NvBlastChecked_x64.dll"; +#elif NV_PROFILE + const char* dllName = "NvBlastProfile_x64.dll"; +#else + const char* dllName = "NvBlast_x64.dll"; +#endif +#endif + + HMODULE dllHandle = LoadLibrary(TEXT(dllName)); + DWORD error = GetLastError(); + ASSERT_TRUE(dllHandle != nullptr); + + + // Asset functions + typedef size_t(*NvBlastGetRequiredScratchForCreateAsset)(const NvBlastAssetDesc* desc); + typedef size_t(*NvBlastGetAssetMemorySize)(const NvBlastAssetDesc* desc); + typedef NvBlastAsset*(*NvBlastCreateAsset)(void* mem, const NvBlastAssetDesc* desc, void* scratch, NvBlastLog logFn); + + NvBlastGetRequiredScratchForCreateAsset assetCreateRequiredScratch = (NvBlastGetRequiredScratchForCreateAsset)GetProcAddress(dllHandle, TEXT("NvBlastGetRequiredScratchForCreateAsset")); + ASSERT_TRUE(assetCreateRequiredScratch != nullptr); + + NvBlastGetAssetMemorySize assetGetMemorySize = (NvBlastGetAssetMemorySize)GetProcAddress(dllHandle, TEXT("NvBlastGetAssetMemorySize")); + ASSERT_TRUE(assetGetMemorySize != nullptr); + + NvBlastCreateAsset assetCreate = (NvBlastCreateAsset)GetProcAddress(dllHandle, TEXT("NvBlastCreateAsset")); + ASSERT_TRUE(assetCreate != nullptr); + + // Family functions + typedef NvBlastFamily* (*NvBlastAssetCreateFamily)(void* mem, const NvBlastAsset* asset, NvBlastLog logFn); + typedef size_t(*NVBLASTASSETGETFAMILYMEMORYSIZE)(const NvBlastAsset* asset); + + NVBLASTASSETGETFAMILYMEMORYSIZE familyGetMemorySize = (NVBLASTASSETGETFAMILYMEMORYSIZE)GetProcAddress(dllHandle, TEXT("NvBlastAssetGetFamilyMemorySize")); + ASSERT_TRUE(familyGetMemorySize != nullptr); + + NvBlastAssetCreateFamily familyCreate = (NvBlastAssetCreateFamily)GetProcAddress(dllHandle, TEXT("NvBlastAssetCreateFamily")); + ASSERT_TRUE(familyCreate != nullptr); + + + // Actor functions + typedef size_t(*NvBlastFamilyGetRequiredScratchForCreateFirstActor)(const NvBlastFamily* family); + typedef NvBlastActor* (*NvBlastFamilyCreateFirstActor)(NvBlastFamily* family, const NvBlastActorDesc* desc, void* scratch, NvBlastLog logFn); + typedef bool(*NVBLASTACTORDEACTIVATE)(NvBlastActor* actor); + + NvBlastFamilyGetRequiredScratchForCreateFirstActor actorcreaterequiredscratch = (NvBlastFamilyGetRequiredScratchForCreateFirstActor)GetProcAddress(dllHandle, TEXT("NvBlastFamilyGetRequiredScratchForCreateFirstActor")); + ASSERT_TRUE(actorcreaterequiredscratch != nullptr); + + NvBlastFamilyCreateFirstActor actorCreate = (NvBlastFamilyCreateFirstActor)GetProcAddress(dllHandle, TEXT("NvBlastFamilyCreateFirstActor")); + ASSERT_TRUE(actorCreate != nullptr); + + NVBLASTACTORDEACTIVATE actorRelease = (NVBLASTACTORDEACTIVATE)GetProcAddress(dllHandle, TEXT("NvBlastActorDeactivate")); + ASSERT_TRUE(actorRelease != nullptr); + + + const NvBlastChunkDesc c_chunks[] = + { + // centroid volume parent idx flags ID + { {0.0f, 0.0f, 0.0f}, 0.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 0 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 0 }, + { {0.0f, 0.0f, 0.0f}, 0.0f, 0, NvBlastChunkDesc::SupportFlag, 0 }, + }; + + NvBlastAssetDesc assetDesc; + assetDesc.bondCount = 0; + assetDesc.bondDescs = nullptr; + assetDesc.chunkCount = 4; + assetDesc.chunkDescs = c_chunks; + + NvBlastAsset* asset; + { + size_t requiredsize = assetCreateRequiredScratch(&assetDesc); + std::vectorscratch(requiredsize); + void* mem = alignedZeroedAlloc(assetGetMemorySize(&assetDesc)); + asset = assetCreate(mem, &assetDesc, scratch.data(), myLog); + ASSERT_TRUE(asset != nullptr); + } + + void* fmem = alignedZeroedAlloc(familyGetMemorySize(asset)); + NvBlastFamily* family = familyCreate(fmem, asset, myLog); + + { + NvBlastActorDesc actorD; + actorD.initialBondHealths = actorD.initialSupportChunkHealths = nullptr; + actorD.uniformInitialBondHealth = actorD.uniformInitialLowerSupportChunkHealth = 1.0f; + + size_t requiredsize = actorcreaterequiredscratch(family); + std::vectorscratch(requiredsize); + NvBlastActor* actor = actorCreate(family, &actorD, scratch.data(), myLog); + ASSERT_TRUE(actor != nullptr); + + ASSERT_TRUE(actorRelease(actor)); + } + + alignedFree(family); + alignedFree(asset); + + EXPECT_NO_WARNING; +} +#endif -- cgit v1.2.3