#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 = alloc(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 = alloc(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 } // linear falloff }; NvBlastBondFractureData outFracture[12]; /*num lower-support chunks + bonds?*/ NvBlastFractureBuffers events; events.bondFractureCount = 12; events.bondFractures = outFracture; events.chunkFractureCount = 0; events.chunkFractures = nullptr; NvBlastProgramParams programParams; programParams.damageDescCount = 1; programParams.damageDescBuffer = &damage; NvBlastDamageProgram program = { NvBlastExtFalloffGraphShader, nullptr }; NvBlastActorGenerateFracture(&events, actor, program, &programParams, messageLog, nullptr); NvBlastActorApplyFracture(&events, actor, &events, messageLog, nullptr); 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); } free(family); free(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, 2 }, { { -1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 2.0f, 0.0f }, 0 } }, { { 2, 3 }, { { -1.0f, 0.0f, 0.0f }, 1.0f, { -1.0f, 2.0f, 0.0f }, 0 } }, { { 3, 4 }, { { 0.0f, -1.0f, 0.0f }, 1.0f, { -2.0f, 1.0f, 0.0f }, 0 } }, { { 4, 5 }, { { 0.0f, -1.0f, 0.0f }, 1.0f, { -2.0f, -1.0f, 0.0f }, 0 } }, { { 5, 6 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { -1.0f, -2.0f, 0.0f }, 0 } }, { { 6, 7 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, -2.0f, 0.0f }, 0 } } }; // create asset const NvBlastAssetDesc assetDesc = { 8, c_chunks, bondsCount, c_bonds }; std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, messageLog)); void* amem = alloc(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 = alloc(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 }; NvBlastProgramParams programParams; programParams.damageDescCount = 1; programParams.damageDescBuffer = &damage; 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); free(family); free(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, 2 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, +1.0f, 0.0f }, 0 } }, { { 3, 4 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, -1.0f, 0.0f }, 0 } }, { { 1, 3 }, { { 0.0f, -1.0f, 0.0f }, 1.0f, { -1.0f, 0.0f, 0.0f }, 0 } }, { { 2, 4 }, { { 0.0f, -1.0f, 0.0f }, 1.0f, { +1.0f, 0.0f, 0.0f }, 0 } }, }; 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 = alloc(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 = alloc(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_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); } free(family); free(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, 2 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, +1.0f, 0.0f }, 0 } }, { { 3, 4 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 0.0f, -1.0f, 0.0f }, 0 } }, { { 1, 3 }, { { 0.0f, -1.0f, 0.0f }, 1.0f, { -1.0f, 0.0f, 0.0f }, 0 } }, { { 2, 4 }, { { 0.0f, -1.0f, 0.0f }, 1.0f, { +1.0f, 0.0f, 0.0f }, 0 } }, }; 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 = alloc(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 = alloc(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_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); } free(family); free(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 = alloc(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 = alloc(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); 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); 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); 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); } free(family); free(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] = { // chunks, normal, area, centroid, userdata { { 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, { 2.0f, 0.0f, 0.0f }, 0 } }, { { 3, 4 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 } }, }; NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; // create asset with chunk map std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); void* amem = alloc(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 = alloc(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_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); } free(family); free(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] = { // chunks, normal, area, centroid, userdata { { 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, { 2.0f, 0.0f, 0.0f }, 0 } }, { { 3, 4 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 } }, }; NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; { // create asset with chunk map std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); void* amem = alloc(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 = alloc(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)); free(family); } { // create actor NvBlastActorDesc actorDesc; actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; void* fmem = alloc(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_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); } free(family); } free(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] = { // chunks, normal, area, centroid, userdata { { 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, { 2.0f, 0.0f, 0.0f }, 0 } }, { { 3, 4 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f, 0.0f }, 0 } }, }; NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 3, c_bonds }; { // create asset with chunk map std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); void* amem = alloc(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 = alloc(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_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)); free(family); } { // create actor NvBlastActorDesc actorDesc; actorDesc.initialBondHealths = actorDesc.initialSupportChunkHealths = nullptr; actorDesc.uniformInitialBondHealth = actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; void* fmem = alloc(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_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); } free(family); } free(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 = alloc(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 = alloc(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 } // linear falloff }; NvBlastBondFractureData outBondFracture[2]; NvBlastChunkFractureData outChunkFracture[2]; NvBlastFractureBuffers events; events.bondFractureCount = 2; events.bondFractures = outBondFracture; events.chunkFractureCount = 2; events.chunkFractures = outChunkFracture; NvBlastProgramParams programParams; programParams.damageDescCount = 1; programParams.damageDescBuffer = &damage; NvBlastDamageProgram program = { NvBlastExtFalloffGraphShader, NvBlastExtFalloffSubgraphShader }; NvBlastActorGenerateFracture(&events, actor, program, &programParams, messageLog, nullptr); NvBlastActorApplyFracture(&events, actor, &events, messageLog, nullptr); 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); } free(family); free(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] = { // chunks, normal, area, centroid, userdata { { 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 }, { { 1.0f, 0.0f, 0.0f }, 1.0f, { 1.0f, 0.0f, 0.0f }, 0 } } }; NvBlastAssetDesc assetDesc = { chunksCount, c_chunks, 4, c_bonds }; // create asset with chunk map std::vector scratch((size_t)NvBlastGetRequiredScratchForCreateAsset(&assetDesc, myLog)); void* amem = alloc(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 = alloc(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); 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); 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); 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); 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); } free(family); free(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 = alloc(assetGetMemorySize(&assetDesc)); asset = assetCreate(mem, &assetDesc, scratch.data(), myLog); ASSERT_TRUE(asset != nullptr); } void* fmem = alloc(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)); } free(family); free(asset); EXPECT_NO_WARNING; } #endif