aboutsummaryrefslogtreecommitdiff
path: root/test/src/unit/TkCompositeTests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/src/unit/TkCompositeTests.cpp')
-rwxr-xr-x[-rw-r--r--]test/src/unit/TkCompositeTests.cpp1550
1 files changed, 775 insertions, 775 deletions
diff --git a/test/src/unit/TkCompositeTests.cpp b/test/src/unit/TkCompositeTests.cpp
index 8f55612..96fcc75 100644..100755
--- a/test/src/unit/TkCompositeTests.cpp
+++ b/test/src/unit/TkCompositeTests.cpp
@@ -1,775 +1,775 @@
-// 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 "TkBaseTest.h"
-
-#include <map>
-#include <random>
-#include <algorithm>
-
-#include "PsMemoryBuffer.h"
-
-#include "NvBlastTime.h"
-
-
-/*
-Composite and joint tests:
-
-0) Test serialization of composites and assemblies
-
-1) Create assembly, actors and joints should be created automatically
-
-2) Create an actor with internal joints. Splitting the actor should cause joint create events to be dispatched
-
-3) Joint update events should be fired when attached actors change
-
-4) Joint delete events should be fired when at least one attached actor is deleted
-
-5) Creating a composite from assets with internal joints should have expected behaviors (1-4) above
-*/
-
-
-struct Composite
-{
- std::vector<TkActorDesc> m_actorDescs;
- std::vector<physx::PxTransform> m_relTMs;
- std::vector<TkJointDesc> m_jointDescs;
-};
-
-
-template<int FailLevel, int Verbosity>
-class TkCompositeTest : public TkBaseTest<FailLevel, Verbosity>
-{
-public:
-
- // Composite/joint tests
- void createAssembly(std::vector<TkActor*>& actors, std::vector<TkJoint*>& joints, bool createNRFJoints)
- {
- TkFramework* fw = NvBlastTkFrameworkGet();
-
- actors.resize(4, nullptr);
- actors[0] = fw->createActor(TkActorDesc(testAssets[0]));
- actors[1] = fw->createActor(TkActorDesc(testAssets[0]));
- actors[2] = fw->createActor(TkActorDesc(testAssets[1]));
- actors[3] = fw->createActor(TkActorDesc(testAssets[1]));
-
- std::vector<TkFamily*> families(4);
- families[0] = &actors[0]->getFamily();
- families[1] = &actors[1]->getFamily();
- families[2] = &actors[2]->getFamily();
- families[3] = &actors[3]->getFamily();
-
- EXPECT_FALSE(actors[0] == nullptr);
- EXPECT_FALSE(actors[1] == nullptr);
- EXPECT_FALSE(actors[2] == nullptr);
- EXPECT_FALSE(actors[3] == nullptr);
-
- const TkJointDesc jointDescsNoNRF[8] =
- {
- // Actor indices, chunk indices, attach position in the composite frame
- { { families[0], families[1] }, { 6, 5 }, { PxVec3(0.0f, -1.5f, 0.5f), PxVec3(0.0f, -1.5f, 0.5f) } },
- { { families[0], families[1] }, { 4, 3 }, { PxVec3(0.0f, -0.5f, -0.5f), PxVec3(0.0f, -0.5f, -0.5f) } },
-
- { { families[0], families[2] }, { 8, 6 }, { PxVec3(-0.5f, 0.0f, 0.5f), PxVec3(-0.5f, 0.0f, 0.5f) } },
- { { families[0], families[2] }, { 3, 1 }, { PxVec3(-1.5f, 0.0f, -0.5f), PxVec3(-1.5f, 0.0f, -0.5f) } },
-
- { { families[1], families[3] }, { 7, 5 }, { PxVec3(0.5f, 0.0f, 0.5f), PxVec3(0.5f, 0.0f, 0.5f) } },
- { { families[1], families[3] }, { 4, 2 }, { PxVec3(1.0f, 0.0f, -0.5f), PxVec3(1.0f, 0.0f, -0.5f) } },
-
- { { families[2], families[3] }, { 8, 7 }, { PxVec3(0.0f, 1.5f, 0.5f), PxVec3(0.0f, 1.5f, 0.5f) } },
- { { families[2], families[3] }, { 2, 1 }, { PxVec3(0.0f, 0.5f, -0.5f), PxVec3(0.0f, 0.5f, -0.5f) } }
- };
-
- const TkJointDesc jointDescsWithNRF[12] =
- {
- // Actor indices, chunk indices, attach position in the composite frame
- { { families[0], families[1] }, { 6, 5 }, { PxVec3(0.0f, -1.5f, 0.5f), PxVec3(0.0f, -1.5f, 0.5f) } },
- { { families[0], families[1] }, { 4, 3 }, { PxVec3(0.0f, -0.5f, -0.5f), PxVec3(0.0f, -0.5f, -0.5f) } },
-
- { { families[0], nullptr }, { 8, 0xFFFFFFFF }, { PxVec3(-0.5f, 0.0f, 0.5f), PxVec3(-0.5f, 0.0f, 0.5f) } },
- { { families[0], nullptr }, { 3, 0xFFFFFFFF }, { PxVec3(-1.5f, 0.0f, -0.5f), PxVec3(-1.5f, 0.0f, -0.5f) } },
-
- { { nullptr, families[2] }, { 0xFFFFFFFF, 6 }, { PxVec3(-0.5f, 0.0f, 0.5f), PxVec3(-0.5f, 0.0f, 0.5f) } },
- { { nullptr, families[2] }, { 0xFFFFFFFF, 1 }, { PxVec3(-1.5f, 0.0f, -0.5f), PxVec3(-1.5f, 0.0f, -0.5f) } },
-
- { { families[1], nullptr }, { 7, 0xFFFFFFFF }, { PxVec3(0.5f, 0.0f, 0.5f), PxVec3(0.5f, 0.0f, 0.5f) } },
- { { families[1], nullptr }, { 4, 0xFFFFFFFF }, { PxVec3(1.0f, 0.0f, -0.5f), PxVec3(1.0f, 0.0f, -0.5f) } },
-
- { { nullptr, families[3] }, { 0xFFFFFFFF, 5 }, { PxVec3(0.5f, 0.0f, 0.5f), PxVec3(0.5f, 0.0f, 0.5f) } },
- { { nullptr, families[3] }, { 0xFFFFFFFF, 2 }, { PxVec3(1.0f, 0.0f, -0.5f), PxVec3(1.0f, 0.0f, -0.5f) } },
-
- { { families[2], families[3] }, { 8, 7 }, { PxVec3(0.0f, 1.5f, 0.5f), PxVec3(0.0f, 1.5f, 0.5f) } },
- { { families[2], families[3] }, { 2, 1 }, { PxVec3(0.0f, 0.5f, -0.5f), PxVec3(0.0f, 0.5f, -0.5f), } }
- };
-
- const TkJointDesc* jointDescs = createNRFJoints ? jointDescsWithNRF : jointDescsNoNRF;
- const int jointCount = createNRFJoints ? 12 : 8;
-
- joints.resize(jointCount, nullptr);
- for (int i = 0; i < jointCount; ++i)
- {
- joints[i] = fw->createJoint(jointDescs[i]);
- EXPECT_FALSE(joints[i] == nullptr);
- }
- }
-
- void familySerialization(std::vector<TkFamily*>& families, TestFamilyTracker& tracker)
- {
-#if 1
- NV_UNUSED(families);
- NV_UNUSED(tracker);
-#else
- TkFramework* fw = NvBlastTkFrameworkGet();
-
- PsMemoryBuffer* membuf = PX_NEW(PsMemoryBuffer);
- EXPECT_TRUE(membuf != nullptr);
- if (membuf == nullptr)
- {
- return;
- }
-
- std::vector<TkFamily*> oldFamilies = families;
-
- for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
- {
- GTEST_FATAL_FAILURE_("Serialization of families needs to be put into extensions.");
-// families[familyNum]->serialize(*membuf);
- }
-
- for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
- {
- TkFamily* f = families[familyNum];
-
- std::vector<TkActor*> actors(f->getActorCount());
- f->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
- for (auto a : actors)
- {
- tracker.eraseActor(a);
- }
-
- f->release();
- families[familyNum] = nullptr;
- }
-
- for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
- {
- GTEST_FATAL_FAILURE_("Deserialization of families needs to be put into extensions.");
-// TkFamily* f = reinterpret_cast<TkFamily*>(fw->deserialize(*membuf));
-// f->addListener(tracker);
-// families[familyNum] = f;
- }
-
- for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
- {
- TkFamily* f = families[familyNum];
-
- std::vector<TkActor*> actors(f->getActorCount());
- f->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
- for (auto a : actors)
- {
- tracker.insertActor(a);
-
- std::vector<TkJoint*> joints(a->getJointCount());
- a->getJoints(joints.data(), (uint32_t)joints.size());
-
- for (auto j : joints)
- {
- const TkJointData jd = j->getData();
- if (jd.actors[0] != jd.actors[1])
- {
- tracker.joints.insert(j);
- }
- }
- }
- }
-
- membuf->release();
-#endif
- }
-
- void recollectActors(std::vector<TkFamily*>& families, std::vector<TkActor*>& actors)
- {
- uint32_t totalActorCount = 0;
- for (auto family : families)
- {
- EXPECT_LE(family->getActorCount() + totalActorCount, actors.size());
- totalActorCount += family->getActors(actors.data() + totalActorCount, static_cast<uint32_t>(actors.size()) - totalActorCount);
- }
- }
-
- void assemblyCreateAndRelease(bool createNRFJoints, bool serializationTest)
- {
- createFramework();
- createTestAssets();
-
- TkFramework* fw = NvBlastTkFrameworkGet();
-
- const TkType* familyType = fw->getType(TkTypeIndex::Family);
- EXPECT_TRUE(familyType != nullptr);
-
- TestFamilyTracker tracker;
-
- std::vector<TkFamily*> families1;
- std::vector<TkFamily*> families2;
-
- // Create one assembly
- std::vector<TkActor*> actors1;
- std::vector<TkJoint*> joints1;
- createAssembly(actors1, joints1, createNRFJoints);
- tracker.joints.insert(joints1.begin(), joints1.end());
-
- // Create another assembly
- std::vector<TkActor*> actors2;
- std::vector<TkJoint*> joints2;
- createAssembly(actors2, joints2, createNRFJoints);
- tracker.joints.insert(joints2.begin(), joints2.end());
-
- // Store families and fill group
- for (size_t actorNum = 0; actorNum < actors1.size(); ++actorNum)
- {
- TkFamily& family = actors1[actorNum]->getFamily();
- families1.push_back(&family);
- family.addListener(tracker);
- }
- for (size_t actorNum = 0; actorNum < actors2.size(); ++actorNum)
- {
- TkFamily& family = actors2[actorNum]->getFamily();
- families2.push_back(&family);
- family.addListener(tracker);
- }
-
- if (serializationTest)
- {
- familySerialization(families1, tracker);
- recollectActors(families1, actors1);
- familySerialization(families2, tracker);
- recollectActors(families2, actors2);
- }
-
- EXPECT_EQ(joints1.size() + joints2.size(), tracker.joints.size());
-
- // Release 1st assembly's actors
- for (size_t actorNum = 0; actorNum < actors1.size(); ++actorNum)
- {
- actors1[actorNum]->release();
- }
-
- if (serializationTest)
- {
- familySerialization(families2, tracker);
- recollectActors(families2, actors2);
- }
-
- EXPECT_EQ(joints2.size(), tracker.joints.size());
-
- // Release 2nd assembly's actors
- for (size_t actorNum = 0; actorNum < actors1.size(); ++actorNum)
- {
- actors2[actorNum]->release();
- }
-
- EXPECT_EQ(0, tracker.joints.size());
-
- releaseTestAssets();
- releaseFramework();
- }
-
- void assemblyInternalJoints(bool testAssemblySerialization)
- {
- createFramework();
- createTestAssets(true); // Create assets with internal joints
-
- TkFramework* fw = NvBlastTkFrameworkGet();
-
- TestFamilyTracker tracker;
-
- TkGroupDesc gdesc;
- gdesc.workerCount = m_taskman->getCpuDispatcher()->getWorkerCount();
- TkGroup* group = fw->createGroup(gdesc);
- EXPECT_TRUE(group != nullptr);
-
- m_groupTM->setGroup(group);
-
- TkActorDesc adesc(testAssets[0]);
-
- TkActor* actor1 = fw->createActor(adesc);
- EXPECT_TRUE(actor1 != nullptr);
- tracker.insertActor(actor1);
-
- actor1->getFamily().addListener(tracker);
-
- TkFamily* family = &actor1->getFamily();
-
- group->addActor(*actor1);
-
- CSParams cs2(2, 0.0f);
- NvBlastExtProgramParams csParams2 = { &cs2, nullptr };
- actor1->damage(getCubeSlicerProgram(), &csParams2);
-
- EXPECT_EQ((size_t)0, tracker.joints.size());
-
- m_groupTM->process();
- m_groupTM->wait();
-
- if (testAssemblySerialization)
- {
- std::vector<TkFamily*> families;
- families.push_back(family);
- familySerialization(families, tracker);
- family = families[0];
- std::vector<TkActor*> actors(family->getActorCount());
- family->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
- for (TkActor* actor : actors)
- {
- group->addActor(*actor);
- }
- }
-
- EXPECT_EQ((size_t)2, family->getActorCount());
- EXPECT_EQ((size_t)4, tracker.joints.size()); // 2) Create an actor with internal joints. Splitting the actor should cause joint create events to be dispatched
-
- std::vector<TkActor*> actors(family->getActorCount());
- family->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
-
- for (TkJoint* joint : tracker.joints)
- {
- TkJointData jd = joint->getData();
- EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[0]));
- EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[1]));
- }
-
- NvBlastExtRadialDamageDesc radialDamage = getRadialDamageDesc(0, 0, 0);
- NvBlastExtProgramParams radialParams = { &radialDamage, nullptr };
- for (TkActor* actor : actors)
- {
- actor->damage(getFalloffProgram(), &radialParams);
- }
-
- m_groupTM->process();
- m_groupTM->wait();
-
- if (testAssemblySerialization)
- {
- std::vector<TkFamily*> families;
- families.push_back(family);
- familySerialization(families, tracker);
- family = families[0];
- }
-
- EXPECT_EQ((size_t)8, family->getActorCount());
- EXPECT_EQ((size_t)4, tracker.joints.size());
-
- // 3) Joint update events should be fired when attached actors change
-
- actors.resize(family->getActorCount());
- family->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
-
- for (TkJoint* joint : tracker.joints)
- {
- TkJointData jd = joint->getData();
- EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[0]));
- EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[1]));
- }
-
- for (TkActor* actor : actors)
- {
- actor->release();
- }
-
- EXPECT_EQ((size_t)0, tracker.joints.size()); // 4) Joint delete events should be fired when at least one attached actor is deleted
-
- group->release();
-
- releaseTestAssets();
- releaseFramework();
- }
-
- void assemblyCompositeWithInternalJoints(bool createNRFJoints, bool serializationTest)
- {
- createFramework();
- createTestAssets(true); // Create assets with internal joints
-
- TkFramework* fw = NvBlastTkFrameworkGet();
-
- const TkType* familyType = fw->getType(TkTypeIndex::Family);
- EXPECT_TRUE(familyType != nullptr);
-
- if (familyType == nullptr)
- {
- return;
- }
-
- TestFamilyTracker tracker;
-
- std::vector<TkFamily*> families;
-
- // Create assembly
- std::vector<TkActor*> actors;
- std::vector<TkJoint*> joints;
- createAssembly(actors, joints, createNRFJoints);
- tracker.joints.insert(joints.begin(), joints.end());
-
- TkGroupDesc gdesc;
- gdesc.workerCount = m_taskman->getCpuDispatcher()->getWorkerCount();
- TkGroup* group = fw->createGroup(gdesc);
- EXPECT_TRUE(group != nullptr);
-
- m_groupTM->setGroup(group);
-
- for (size_t i = 0; i < actors.size(); ++i)
- {
- TkFamily& family = actors[i]->getFamily();
- families.push_back(&family);
- family.addListener(tracker);
- tracker.insertActor(actors[i]);
- group->addActor(*actors[i]);
- }
-
- if (serializationTest)
- {
- familySerialization(families, tracker);
- recollectActors(families, actors);
- for (auto actor : actors)
- {
- group->addActor(*actor);
- }
- }
-
- EXPECT_EQ((size_t)4, actors.size());
-
- const size_t compJointCount = createNRFJoints ? (size_t)12 : (size_t)8;
-
- EXPECT_EQ(compJointCount, tracker.joints.size());
-
- CSParams cs2(2, 0.0f);
- NvBlastExtProgramParams csParams2 = { &cs2, nullptr };
-
- size_t totalActorCount = 0;
- for (uint32_t i = 0; i < 4; ++i)
- {
- actors[i]->damage(getCubeSlicerProgram(), &csParams2);
-
- m_groupTM->process();
- m_groupTM->wait();
-
- if (serializationTest)
- {
- familySerialization(families, tracker);
- for (size_t j = 0; j < families.size(); ++j)
- {
- TkFamily* family = families[j];
- std::vector<TkActor*> a(family->getActorCount());
- family->getActors(a.data(), static_cast<uint32_t>(a.size()));
- for (auto actor : a)
- {
- group->addActor(*actor);
- }
- EXPECT_TRUE(j <= i || a.size() == 1);
- if (j > i && a.size() == 1)
- {
- actors[j] = a[0];
- }
- }
- }
-
- EXPECT_EQ((size_t)2, families[i]->getActorCount());
- EXPECT_EQ((size_t)(compJointCount + 4 * (i + 1)), tracker.joints.size()); // Four joints created per actor
-
- totalActorCount += families[i]->getActorCount();
- }
-
- actors.resize(totalActorCount);
- totalActorCount = 0;
- for (int i = 0; i < 4; ++i)
- {
- families[i]->getActors(actors.data() + totalActorCount, families[i]->getActorCount());
- totalActorCount += families[i]->getActorCount();
- }
-
- for (TkJoint* joint : tracker.joints)
- {
- TkJointData jd = joint->getData();
- EXPECT_TRUE(jd.actors[0] == nullptr || actors.end() != std::find(actors.begin(), actors.end(), jd.actors[0]));
- EXPECT_TRUE(jd.actors[1] == nullptr || actors.end() != std::find(actors.begin(), actors.end(), jd.actors[1]));
- }
-
- NvBlastExtRadialDamageDesc radialDamage = getRadialDamageDesc(0, 0, 0);
- NvBlastExtProgramParams radialParams = { &radialDamage, nullptr };
- for (TkActor* actor : actors)
- {
- actor->damage(getFalloffProgram(), &radialParams);
- }
-
- m_groupTM->process();
- m_groupTM->wait();
-
- totalActorCount = 0;
- for (int i = 0; i < 4; ++i)
- {
- totalActorCount += families[i]->getActorCount();
- }
-
- if (serializationTest)
- {
- familySerialization(families, tracker);
- }
-
- EXPECT_EQ((size_t)32, totalActorCount);
- EXPECT_EQ(compJointCount + (size_t)16, tracker.joints.size());
-
- actors.resize(totalActorCount);
- totalActorCount = 0;
- for (int i = 0; i < 4; ++i)
- {
- families[i]->getActors(actors.data() + totalActorCount, families[i]->getActorCount());
- totalActorCount += families[i]->getActorCount();
- }
-
- // 3) Joint update events should be fired when attached actors change
-
- for (TkActor* actor : actors)
- {
- actor->release();
- }
-
- EXPECT_EQ((size_t)0, tracker.joints.size()); // 4) Joint delete events should be fired when at least one attached actor is deleted
-
- group->release();
-
- releaseTestAssets();
- releaseFramework();
- }
-
- void assemblyExternalJoints_MultiFamilyDamage(bool explicitJointRelease = true)
- {
- createFramework();
-
- const NvBlastChunkDesc chunkDescs[3] =
- {
-// centroid volume parent idx flags ID
- { { 0.0f, 0.0f, 0.0f }, 4.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 },
- { { 0.0f,-1.0f, 0.0f }, 2.0f, 0, NvBlastChunkDesc::SupportFlag, 1 },
- { { 0.0f, 1.0f, 0.0f }, 2.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }
- };
-
- const NvBlastBondDesc bondDesc =
-// normal area centroid userData chunks
- { { { 0.0f, 1.0f, 0.0f }, 1.0f, { 0.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } };
-
- TkFramework* framework = NvBlastTkFrameworkGet();
-
- TestFamilyTracker tracker;
-
- TkAssetDesc desc;
- desc.chunkCount = 3;
- desc.chunkDescs = chunkDescs;
- desc.bondCount = 1;
- desc.bondDescs = &bondDesc;
- desc.bondFlags = nullptr;
- TkAsset* asset = framework->createAsset(desc);
- EXPECT_TRUE(asset != nullptr);
-
- TkGroupDesc gdesc;
- gdesc.workerCount = m_taskman->getCpuDispatcher()->getWorkerCount();
- TkGroup* group = framework->createGroup(gdesc);
- EXPECT_TRUE(group != nullptr);
-
- m_groupTM->setGroup(group);
-
- TkActorDesc adesc(asset);
- TkActor* actor1 = framework->createActor(adesc);
- EXPECT_TRUE(actor1 != nullptr);
- TkActor* actor2 = framework->createActor(adesc);
- EXPECT_TRUE(actor2 != nullptr);
-
- group->addActor(*actor1);
- group->addActor(*actor2);
-
- TkFamily* family1 = &actor1->getFamily();
- TkFamily* family2 = &actor2->getFamily();
-
- family1->addListener(tracker);
- family2->addListener(tracker);
- tracker.insertActor(actor1);
- tracker.insertActor(actor2);
-
- TkJointDesc jdesc;
- jdesc.families[0] = family1;
- jdesc.families[1] = family2;
- jdesc.chunkIndices[0] = 2;
- jdesc.chunkIndices[1] = 1;
- jdesc.attachPositions[0] = PxVec3(0.0f, 1.0f, 0.0f);
- jdesc.attachPositions[1] = PxVec3(0.0f, -1.0f, 0.0f);
- TkJoint* joint = framework->createJoint(jdesc);
- EXPECT_TRUE(joint != nullptr);
- tracker.joints.insert(joint);
-
- NvBlastExtRadialDamageDesc radialDamage1 = getRadialDamageDesc(0, 1, 0, 2, 2);
- NvBlastExtProgramParams radialParams1 = { &radialDamage1, nullptr };
- actor1->damage(getFalloffProgram(), &radialParams1);
- NvBlastExtRadialDamageDesc radialDamage2 = getRadialDamageDesc(0, -1, 0, 2, 2);
- NvBlastExtProgramParams radialParams2 = { &radialDamage2, nullptr };
- actor2->damage(getFalloffProgram(), &radialParams2);
-
- m_groupTM->process();
- m_groupTM->wait();
-
- TkActor* actors1[2];
- TkActor* actors2[2];
- EXPECT_EQ(2, family1->getActors(actors1, 2));
- EXPECT_EQ(2, family2->getActors(actors2, 2));
-
- const TkJointData jdata = joint->getData();
- EXPECT_TRUE(jdata.actors[0] != nullptr);
- EXPECT_TRUE(jdata.actors[1] != nullptr);
- EXPECT_TRUE(&jdata.actors[0]->getFamily() == family1);
- EXPECT_TRUE(&jdata.actors[1]->getFamily() == family2);
-
- // Clean up
- if (explicitJointRelease)
- {
- joint->release();
- family2->release();
- family1->release();
- asset->release();
- releaseFramework();
- }
- else
- {
- EXPECT_EQ(1, tracker.joints.size());
- releaseFramework();
- // Commenting these out - but shouldn't we be sending delete events when we release the framework?
-// EXPECT_EQ(0, tracker.joints.size());
-// EXPECT_EQ(0, tracker.actors.size());
- }
- }
-
-protected:
- // http://clang.llvm.org/compatibility.html#dep_lookup_bases
- // http://stackoverflow.com/questions/6592512/templates-parent-class-member-variables-not-visible-in-inherited-class
-
- using TkBaseTest<FailLevel, Verbosity>::testAssets;
- using TkBaseTest<FailLevel, Verbosity>::m_taskman;
- using TkBaseTest<FailLevel, Verbosity>::m_groupTM;
- using TkBaseTest<FailLevel, Verbosity>::createFramework;
- using TkBaseTest<FailLevel, Verbosity>::releaseFramework;
- using TkBaseTest<FailLevel, Verbosity>::createTestAssets;
- using TkBaseTest<FailLevel, Verbosity>::releaseTestAssets;
- using TkBaseTest<FailLevel, Verbosity>::getCubeSlicerProgram;
- using TkBaseTest<FailLevel, Verbosity>::getDefaultMaterial;
- using TkBaseTest<FailLevel, Verbosity>::getRadialDamageDesc;
- using TkBaseTest<FailLevel, Verbosity>::getFalloffProgram;
-};
-
-
-typedef TkCompositeTest<NvBlastMessage::Error, 1> TkCompositeTestAllowWarnings;
-typedef TkCompositeTest<NvBlastMessage::Error, 1> TkCompositeTestStrict;
-
-
-/*
-1) Create assembly, actors and joints should be created automatically
-*/
-
-TEST_F(TkCompositeTestStrict, AssemblyCreateAndRelease_NoNRFJoints_NoSerialization)
-{
- assemblyCreateAndRelease(false, false);
-}
-
-TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCreateAndRelease_NoNRFJoints_AssemblySerialization)
-{
- assemblyCreateAndRelease(false, true);
-}
-
-TEST_F(TkCompositeTestStrict, AssemblyCreateAndRelease_WithNRFJoints_NoSerialization)
-{
- assemblyCreateAndRelease(true, false);
-}
-
-TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCreateAndRelease_WithNRFJoints_AssemblySerialization)
-{
- assemblyCreateAndRelease(true, true);
-}
-
-
-/**
-2) Create an actor with internal joints. Splitting the actor should cause joint create events to be dispatched
-
-3) Joint update events should be fired when attached actors change
-
-4) Joint delete events should be fired when at least one attached actor is deleted
-*/
-
-TEST_F(TkCompositeTestStrict, AssemblyInternalJoints_NoSerialization)
-{
- assemblyInternalJoints(false);
-}
-
-TEST_F(TkCompositeTestStrict, DISABLED_AssemblyInternalJoints_AssemblySerialization)
-{
- assemblyInternalJoints(true);
-}
-
-
-/**
-5) Creating a composite from assets with internal joints should have expected behaviors (1-4) above
-*/
-
-TEST_F(TkCompositeTestStrict, AssemblyCompositeWithInternalJoints_NoNRFJoints_NoSerialization)
-{
- assemblyCompositeWithInternalJoints(false, false);
-}
-
-TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCompositeWithInternalJoints_NoNRFJoints_AssemblySerialization)
-{
- assemblyCompositeWithInternalJoints(false, true);
-}
-
-TEST_F(TkCompositeTestStrict, AssemblyCompositeWithInternalJoints_WithNRFJoints_NoSerialization)
-{
- assemblyCompositeWithInternalJoints(true, false);
-}
-
-TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCompositeWithInternalJoints_WithNRFJoints_AssemblySerialization)
-{
- assemblyCompositeWithInternalJoints(true, true);
-}
-
-
-/*
-More tests
-*/
-
-TEST_F(TkCompositeTestStrict, AssemblyExternalJoints_MultiFamilyDamage)
-{
- assemblyExternalJoints_MultiFamilyDamage(true);
-}
-
-TEST_F(TkCompositeTestStrict, AssemblyExternalJoints_MultiFamilyDamage_AutoJointRelease)
-{
- assemblyExternalJoints_MultiFamilyDamage(false);
-}
+// 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 "TkBaseTest.h"
+
+#include <map>
+#include <random>
+#include <algorithm>
+
+#include "PsMemoryBuffer.h"
+
+#include "NvBlastTime.h"
+
+
+/*
+Composite and joint tests:
+
+0) Test serialization of composites and assemblies
+
+1) Create assembly, actors and joints should be created automatically
+
+2) Create an actor with internal joints. Splitting the actor should cause joint create events to be dispatched
+
+3) Joint update events should be fired when attached actors change
+
+4) Joint delete events should be fired when at least one attached actor is deleted
+
+5) Creating a composite from assets with internal joints should have expected behaviors (1-4) above
+*/
+
+
+struct Composite
+{
+ std::vector<TkActorDesc> m_actorDescs;
+ std::vector<physx::PxTransform> m_relTMs;
+ std::vector<TkJointDesc> m_jointDescs;
+};
+
+
+template<int FailLevel, int Verbosity>
+class TkCompositeTest : public TkBaseTest<FailLevel, Verbosity>
+{
+public:
+
+ // Composite/joint tests
+ void createAssembly(std::vector<TkActor*>& actors, std::vector<TkJoint*>& joints, bool createNRFJoints)
+ {
+ TkFramework* fw = NvBlastTkFrameworkGet();
+
+ actors.resize(4, nullptr);
+ actors[0] = fw->createActor(TkActorDesc(testAssets[0]));
+ actors[1] = fw->createActor(TkActorDesc(testAssets[0]));
+ actors[2] = fw->createActor(TkActorDesc(testAssets[1]));
+ actors[3] = fw->createActor(TkActorDesc(testAssets[1]));
+
+ std::vector<TkFamily*> families(4);
+ families[0] = &actors[0]->getFamily();
+ families[1] = &actors[1]->getFamily();
+ families[2] = &actors[2]->getFamily();
+ families[3] = &actors[3]->getFamily();
+
+ EXPECT_FALSE(actors[0] == nullptr);
+ EXPECT_FALSE(actors[1] == nullptr);
+ EXPECT_FALSE(actors[2] == nullptr);
+ EXPECT_FALSE(actors[3] == nullptr);
+
+ const TkJointDesc jointDescsNoNRF[8] =
+ {
+ // Actor indices, chunk indices, attach position in the composite frame
+ { { families[0], families[1] }, { 6, 5 }, { PxVec3(0.0f, -1.5f, 0.5f), PxVec3(0.0f, -1.5f, 0.5f) } },
+ { { families[0], families[1] }, { 4, 3 }, { PxVec3(0.0f, -0.5f, -0.5f), PxVec3(0.0f, -0.5f, -0.5f) } },
+
+ { { families[0], families[2] }, { 8, 6 }, { PxVec3(-0.5f, 0.0f, 0.5f), PxVec3(-0.5f, 0.0f, 0.5f) } },
+ { { families[0], families[2] }, { 3, 1 }, { PxVec3(-1.5f, 0.0f, -0.5f), PxVec3(-1.5f, 0.0f, -0.5f) } },
+
+ { { families[1], families[3] }, { 7, 5 }, { PxVec3(0.5f, 0.0f, 0.5f), PxVec3(0.5f, 0.0f, 0.5f) } },
+ { { families[1], families[3] }, { 4, 2 }, { PxVec3(1.0f, 0.0f, -0.5f), PxVec3(1.0f, 0.0f, -0.5f) } },
+
+ { { families[2], families[3] }, { 8, 7 }, { PxVec3(0.0f, 1.5f, 0.5f), PxVec3(0.0f, 1.5f, 0.5f) } },
+ { { families[2], families[3] }, { 2, 1 }, { PxVec3(0.0f, 0.5f, -0.5f), PxVec3(0.0f, 0.5f, -0.5f) } }
+ };
+
+ const TkJointDesc jointDescsWithNRF[12] =
+ {
+ // Actor indices, chunk indices, attach position in the composite frame
+ { { families[0], families[1] }, { 6, 5 }, { PxVec3(0.0f, -1.5f, 0.5f), PxVec3(0.0f, -1.5f, 0.5f) } },
+ { { families[0], families[1] }, { 4, 3 }, { PxVec3(0.0f, -0.5f, -0.5f), PxVec3(0.0f, -0.5f, -0.5f) } },
+
+ { { families[0], nullptr }, { 8, 0xFFFFFFFF }, { PxVec3(-0.5f, 0.0f, 0.5f), PxVec3(-0.5f, 0.0f, 0.5f) } },
+ { { families[0], nullptr }, { 3, 0xFFFFFFFF }, { PxVec3(-1.5f, 0.0f, -0.5f), PxVec3(-1.5f, 0.0f, -0.5f) } },
+
+ { { nullptr, families[2] }, { 0xFFFFFFFF, 6 }, { PxVec3(-0.5f, 0.0f, 0.5f), PxVec3(-0.5f, 0.0f, 0.5f) } },
+ { { nullptr, families[2] }, { 0xFFFFFFFF, 1 }, { PxVec3(-1.5f, 0.0f, -0.5f), PxVec3(-1.5f, 0.0f, -0.5f) } },
+
+ { { families[1], nullptr }, { 7, 0xFFFFFFFF }, { PxVec3(0.5f, 0.0f, 0.5f), PxVec3(0.5f, 0.0f, 0.5f) } },
+ { { families[1], nullptr }, { 4, 0xFFFFFFFF }, { PxVec3(1.0f, 0.0f, -0.5f), PxVec3(1.0f, 0.0f, -0.5f) } },
+
+ { { nullptr, families[3] }, { 0xFFFFFFFF, 5 }, { PxVec3(0.5f, 0.0f, 0.5f), PxVec3(0.5f, 0.0f, 0.5f) } },
+ { { nullptr, families[3] }, { 0xFFFFFFFF, 2 }, { PxVec3(1.0f, 0.0f, -0.5f), PxVec3(1.0f, 0.0f, -0.5f) } },
+
+ { { families[2], families[3] }, { 8, 7 }, { PxVec3(0.0f, 1.5f, 0.5f), PxVec3(0.0f, 1.5f, 0.5f) } },
+ { { families[2], families[3] }, { 2, 1 }, { PxVec3(0.0f, 0.5f, -0.5f), PxVec3(0.0f, 0.5f, -0.5f), } }
+ };
+
+ const TkJointDesc* jointDescs = createNRFJoints ? jointDescsWithNRF : jointDescsNoNRF;
+ const int jointCount = createNRFJoints ? 12 : 8;
+
+ joints.resize(jointCount, nullptr);
+ for (int i = 0; i < jointCount; ++i)
+ {
+ joints[i] = fw->createJoint(jointDescs[i]);
+ EXPECT_FALSE(joints[i] == nullptr);
+ }
+ }
+
+ void familySerialization(std::vector<TkFamily*>& families, TestFamilyTracker& tracker)
+ {
+#if 1
+ NV_UNUSED(families);
+ NV_UNUSED(tracker);
+#else
+ TkFramework* fw = NvBlastTkFrameworkGet();
+
+ PsMemoryBuffer* membuf = PX_NEW(PsMemoryBuffer);
+ EXPECT_TRUE(membuf != nullptr);
+ if (membuf == nullptr)
+ {
+ return;
+ }
+
+ std::vector<TkFamily*> oldFamilies = families;
+
+ for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
+ {
+ GTEST_FATAL_FAILURE_("Serialization of families needs to be put into extensions.");
+// families[familyNum]->serialize(*membuf);
+ }
+
+ for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
+ {
+ TkFamily* f = families[familyNum];
+
+ std::vector<TkActor*> actors(f->getActorCount());
+ f->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
+ for (auto a : actors)
+ {
+ tracker.eraseActor(a);
+ }
+
+ f->release();
+ families[familyNum] = nullptr;
+ }
+
+ for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
+ {
+ GTEST_FATAL_FAILURE_("Deserialization of families needs to be put into extensions.");
+// TkFamily* f = reinterpret_cast<TkFamily*>(fw->deserialize(*membuf));
+// f->addListener(tracker);
+// families[familyNum] = f;
+ }
+
+ for (size_t familyNum = 0; familyNum < families.size(); ++familyNum)
+ {
+ TkFamily* f = families[familyNum];
+
+ std::vector<TkActor*> actors(f->getActorCount());
+ f->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
+ for (auto a : actors)
+ {
+ tracker.insertActor(a);
+
+ std::vector<TkJoint*> joints(a->getJointCount());
+ a->getJoints(joints.data(), (uint32_t)joints.size());
+
+ for (auto j : joints)
+ {
+ const TkJointData jd = j->getData();
+ if (jd.actors[0] != jd.actors[1])
+ {
+ tracker.joints.insert(j);
+ }
+ }
+ }
+ }
+
+ membuf->release();
+#endif
+ }
+
+ void recollectActors(std::vector<TkFamily*>& families, std::vector<TkActor*>& actors)
+ {
+ uint32_t totalActorCount = 0;
+ for (auto family : families)
+ {
+ EXPECT_LE(family->getActorCount() + totalActorCount, actors.size());
+ totalActorCount += family->getActors(actors.data() + totalActorCount, static_cast<uint32_t>(actors.size()) - totalActorCount);
+ }
+ }
+
+ void assemblyCreateAndRelease(bool createNRFJoints, bool serializationTest)
+ {
+ createFramework();
+ createTestAssets();
+
+ TkFramework* fw = NvBlastTkFrameworkGet();
+
+ const TkType* familyType = fw->getType(TkTypeIndex::Family);
+ EXPECT_TRUE(familyType != nullptr);
+
+ TestFamilyTracker tracker;
+
+ std::vector<TkFamily*> families1;
+ std::vector<TkFamily*> families2;
+
+ // Create one assembly
+ std::vector<TkActor*> actors1;
+ std::vector<TkJoint*> joints1;
+ createAssembly(actors1, joints1, createNRFJoints);
+ tracker.joints.insert(joints1.begin(), joints1.end());
+
+ // Create another assembly
+ std::vector<TkActor*> actors2;
+ std::vector<TkJoint*> joints2;
+ createAssembly(actors2, joints2, createNRFJoints);
+ tracker.joints.insert(joints2.begin(), joints2.end());
+
+ // Store families and fill group
+ for (size_t actorNum = 0; actorNum < actors1.size(); ++actorNum)
+ {
+ TkFamily& family = actors1[actorNum]->getFamily();
+ families1.push_back(&family);
+ family.addListener(tracker);
+ }
+ for (size_t actorNum = 0; actorNum < actors2.size(); ++actorNum)
+ {
+ TkFamily& family = actors2[actorNum]->getFamily();
+ families2.push_back(&family);
+ family.addListener(tracker);
+ }
+
+ if (serializationTest)
+ {
+ familySerialization(families1, tracker);
+ recollectActors(families1, actors1);
+ familySerialization(families2, tracker);
+ recollectActors(families2, actors2);
+ }
+
+ EXPECT_EQ(joints1.size() + joints2.size(), tracker.joints.size());
+
+ // Release 1st assembly's actors
+ for (size_t actorNum = 0; actorNum < actors1.size(); ++actorNum)
+ {
+ actors1[actorNum]->release();
+ }
+
+ if (serializationTest)
+ {
+ familySerialization(families2, tracker);
+ recollectActors(families2, actors2);
+ }
+
+ EXPECT_EQ(joints2.size(), tracker.joints.size());
+
+ // Release 2nd assembly's actors
+ for (size_t actorNum = 0; actorNum < actors1.size(); ++actorNum)
+ {
+ actors2[actorNum]->release();
+ }
+
+ EXPECT_EQ(0, tracker.joints.size());
+
+ releaseTestAssets();
+ releaseFramework();
+ }
+
+ void assemblyInternalJoints(bool testAssemblySerialization)
+ {
+ createFramework();
+ createTestAssets(true); // Create assets with internal joints
+
+ TkFramework* fw = NvBlastTkFrameworkGet();
+
+ TestFamilyTracker tracker;
+
+ TkGroupDesc gdesc;
+ gdesc.workerCount = m_taskman->getCpuDispatcher()->getWorkerCount();
+ TkGroup* group = fw->createGroup(gdesc);
+ EXPECT_TRUE(group != nullptr);
+
+ m_groupTM->setGroup(group);
+
+ TkActorDesc adesc(testAssets[0]);
+
+ TkActor* actor1 = fw->createActor(adesc);
+ EXPECT_TRUE(actor1 != nullptr);
+ tracker.insertActor(actor1);
+
+ actor1->getFamily().addListener(tracker);
+
+ TkFamily* family = &actor1->getFamily();
+
+ group->addActor(*actor1);
+
+ CSParams cs2(2, 0.0f);
+ NvBlastExtProgramParams csParams2 = { &cs2, nullptr };
+ actor1->damage(getCubeSlicerProgram(), &csParams2);
+
+ EXPECT_EQ((size_t)0, tracker.joints.size());
+
+ m_groupTM->process();
+ m_groupTM->wait();
+
+ if (testAssemblySerialization)
+ {
+ std::vector<TkFamily*> families;
+ families.push_back(family);
+ familySerialization(families, tracker);
+ family = families[0];
+ std::vector<TkActor*> actors(family->getActorCount());
+ family->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
+ for (TkActor* actor : actors)
+ {
+ group->addActor(*actor);
+ }
+ }
+
+ EXPECT_EQ((size_t)2, family->getActorCount());
+ EXPECT_EQ((size_t)4, tracker.joints.size()); // 2) Create an actor with internal joints. Splitting the actor should cause joint create events to be dispatched
+
+ std::vector<TkActor*> actors(family->getActorCount());
+ family->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
+
+ for (TkJoint* joint : tracker.joints)
+ {
+ TkJointData jd = joint->getData();
+ EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[0]));
+ EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[1]));
+ }
+
+ NvBlastExtRadialDamageDesc radialDamage = getRadialDamageDesc(0, 0, 0);
+ NvBlastExtProgramParams radialParams = { &radialDamage, nullptr };
+ for (TkActor* actor : actors)
+ {
+ actor->damage(getFalloffProgram(), &radialParams);
+ }
+
+ m_groupTM->process();
+ m_groupTM->wait();
+
+ if (testAssemblySerialization)
+ {
+ std::vector<TkFamily*> families;
+ families.push_back(family);
+ familySerialization(families, tracker);
+ family = families[0];
+ }
+
+ EXPECT_EQ((size_t)8, family->getActorCount());
+ EXPECT_EQ((size_t)4, tracker.joints.size());
+
+ // 3) Joint update events should be fired when attached actors change
+
+ actors.resize(family->getActorCount());
+ family->getActors(actors.data(), static_cast<uint32_t>(actors.size()));
+
+ for (TkJoint* joint : tracker.joints)
+ {
+ TkJointData jd = joint->getData();
+ EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[0]));
+ EXPECT_FALSE(actors.end() == std::find(actors.begin(), actors.end(), jd.actors[1]));
+ }
+
+ for (TkActor* actor : actors)
+ {
+ actor->release();
+ }
+
+ EXPECT_EQ((size_t)0, tracker.joints.size()); // 4) Joint delete events should be fired when at least one attached actor is deleted
+
+ group->release();
+
+ releaseTestAssets();
+ releaseFramework();
+ }
+
+ void assemblyCompositeWithInternalJoints(bool createNRFJoints, bool serializationTest)
+ {
+ createFramework();
+ createTestAssets(true); // Create assets with internal joints
+
+ TkFramework* fw = NvBlastTkFrameworkGet();
+
+ const TkType* familyType = fw->getType(TkTypeIndex::Family);
+ EXPECT_TRUE(familyType != nullptr);
+
+ if (familyType == nullptr)
+ {
+ return;
+ }
+
+ TestFamilyTracker tracker;
+
+ std::vector<TkFamily*> families;
+
+ // Create assembly
+ std::vector<TkActor*> actors;
+ std::vector<TkJoint*> joints;
+ createAssembly(actors, joints, createNRFJoints);
+ tracker.joints.insert(joints.begin(), joints.end());
+
+ TkGroupDesc gdesc;
+ gdesc.workerCount = m_taskman->getCpuDispatcher()->getWorkerCount();
+ TkGroup* group = fw->createGroup(gdesc);
+ EXPECT_TRUE(group != nullptr);
+
+ m_groupTM->setGroup(group);
+
+ for (size_t i = 0; i < actors.size(); ++i)
+ {
+ TkFamily& family = actors[i]->getFamily();
+ families.push_back(&family);
+ family.addListener(tracker);
+ tracker.insertActor(actors[i]);
+ group->addActor(*actors[i]);
+ }
+
+ if (serializationTest)
+ {
+ familySerialization(families, tracker);
+ recollectActors(families, actors);
+ for (auto actor : actors)
+ {
+ group->addActor(*actor);
+ }
+ }
+
+ EXPECT_EQ((size_t)4, actors.size());
+
+ const size_t compJointCount = createNRFJoints ? (size_t)12 : (size_t)8;
+
+ EXPECT_EQ(compJointCount, tracker.joints.size());
+
+ CSParams cs2(2, 0.0f);
+ NvBlastExtProgramParams csParams2 = { &cs2, nullptr };
+
+ size_t totalActorCount = 0;
+ for (uint32_t i = 0; i < 4; ++i)
+ {
+ actors[i]->damage(getCubeSlicerProgram(), &csParams2);
+
+ m_groupTM->process();
+ m_groupTM->wait();
+
+ if (serializationTest)
+ {
+ familySerialization(families, tracker);
+ for (size_t j = 0; j < families.size(); ++j)
+ {
+ TkFamily* family = families[j];
+ std::vector<TkActor*> a(family->getActorCount());
+ family->getActors(a.data(), static_cast<uint32_t>(a.size()));
+ for (auto actor : a)
+ {
+ group->addActor(*actor);
+ }
+ EXPECT_TRUE(j <= i || a.size() == 1);
+ if (j > i && a.size() == 1)
+ {
+ actors[j] = a[0];
+ }
+ }
+ }
+
+ EXPECT_EQ((size_t)2, families[i]->getActorCount());
+ EXPECT_EQ((size_t)(compJointCount + 4 * (i + 1)), tracker.joints.size()); // Four joints created per actor
+
+ totalActorCount += families[i]->getActorCount();
+ }
+
+ actors.resize(totalActorCount);
+ totalActorCount = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ families[i]->getActors(actors.data() + totalActorCount, families[i]->getActorCount());
+ totalActorCount += families[i]->getActorCount();
+ }
+
+ for (TkJoint* joint : tracker.joints)
+ {
+ TkJointData jd = joint->getData();
+ EXPECT_TRUE(jd.actors[0] == nullptr || actors.end() != std::find(actors.begin(), actors.end(), jd.actors[0]));
+ EXPECT_TRUE(jd.actors[1] == nullptr || actors.end() != std::find(actors.begin(), actors.end(), jd.actors[1]));
+ }
+
+ NvBlastExtRadialDamageDesc radialDamage = getRadialDamageDesc(0, 0, 0);
+ NvBlastExtProgramParams radialParams = { &radialDamage, nullptr };
+ for (TkActor* actor : actors)
+ {
+ actor->damage(getFalloffProgram(), &radialParams);
+ }
+
+ m_groupTM->process();
+ m_groupTM->wait();
+
+ totalActorCount = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ totalActorCount += families[i]->getActorCount();
+ }
+
+ if (serializationTest)
+ {
+ familySerialization(families, tracker);
+ }
+
+ EXPECT_EQ((size_t)32, totalActorCount);
+ EXPECT_EQ(compJointCount + (size_t)16, tracker.joints.size());
+
+ actors.resize(totalActorCount);
+ totalActorCount = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ families[i]->getActors(actors.data() + totalActorCount, families[i]->getActorCount());
+ totalActorCount += families[i]->getActorCount();
+ }
+
+ // 3) Joint update events should be fired when attached actors change
+
+ for (TkActor* actor : actors)
+ {
+ actor->release();
+ }
+
+ EXPECT_EQ((size_t)0, tracker.joints.size()); // 4) Joint delete events should be fired when at least one attached actor is deleted
+
+ group->release();
+
+ releaseTestAssets();
+ releaseFramework();
+ }
+
+ void assemblyExternalJoints_MultiFamilyDamage(bool explicitJointRelease = true)
+ {
+ createFramework();
+
+ const NvBlastChunkDesc chunkDescs[3] =
+ {
+// centroid volume parent idx flags ID
+ { { 0.0f, 0.0f, 0.0f }, 4.0f, UINT32_MAX, NvBlastChunkDesc::NoFlags, 0 },
+ { { 0.0f,-1.0f, 0.0f }, 2.0f, 0, NvBlastChunkDesc::SupportFlag, 1 },
+ { { 0.0f, 1.0f, 0.0f }, 2.0f, 0, NvBlastChunkDesc::SupportFlag, 2 }
+ };
+
+ const NvBlastBondDesc bondDesc =
+// normal area centroid userData chunks
+ { { { 0.0f, 1.0f, 0.0f }, 1.0f, { 0.0f, 0.0f, 0.0f }, 0 }, { 1, 2 } };
+
+ TkFramework* framework = NvBlastTkFrameworkGet();
+
+ TestFamilyTracker tracker;
+
+ TkAssetDesc desc;
+ desc.chunkCount = 3;
+ desc.chunkDescs = chunkDescs;
+ desc.bondCount = 1;
+ desc.bondDescs = &bondDesc;
+ desc.bondFlags = nullptr;
+ TkAsset* asset = framework->createAsset(desc);
+ EXPECT_TRUE(asset != nullptr);
+
+ TkGroupDesc gdesc;
+ gdesc.workerCount = m_taskman->getCpuDispatcher()->getWorkerCount();
+ TkGroup* group = framework->createGroup(gdesc);
+ EXPECT_TRUE(group != nullptr);
+
+ m_groupTM->setGroup(group);
+
+ TkActorDesc adesc(asset);
+ TkActor* actor1 = framework->createActor(adesc);
+ EXPECT_TRUE(actor1 != nullptr);
+ TkActor* actor2 = framework->createActor(adesc);
+ EXPECT_TRUE(actor2 != nullptr);
+
+ group->addActor(*actor1);
+ group->addActor(*actor2);
+
+ TkFamily* family1 = &actor1->getFamily();
+ TkFamily* family2 = &actor2->getFamily();
+
+ family1->addListener(tracker);
+ family2->addListener(tracker);
+ tracker.insertActor(actor1);
+ tracker.insertActor(actor2);
+
+ TkJointDesc jdesc;
+ jdesc.families[0] = family1;
+ jdesc.families[1] = family2;
+ jdesc.chunkIndices[0] = 2;
+ jdesc.chunkIndices[1] = 1;
+ jdesc.attachPositions[0] = PxVec3(0.0f, 1.0f, 0.0f);
+ jdesc.attachPositions[1] = PxVec3(0.0f, -1.0f, 0.0f);
+ TkJoint* joint = framework->createJoint(jdesc);
+ EXPECT_TRUE(joint != nullptr);
+ tracker.joints.insert(joint);
+
+ NvBlastExtRadialDamageDesc radialDamage1 = getRadialDamageDesc(0, 1, 0, 2, 2);
+ NvBlastExtProgramParams radialParams1 = { &radialDamage1, nullptr };
+ actor1->damage(getFalloffProgram(), &radialParams1);
+ NvBlastExtRadialDamageDesc radialDamage2 = getRadialDamageDesc(0, -1, 0, 2, 2);
+ NvBlastExtProgramParams radialParams2 = { &radialDamage2, nullptr };
+ actor2->damage(getFalloffProgram(), &radialParams2);
+
+ m_groupTM->process();
+ m_groupTM->wait();
+
+ TkActor* actors1[2];
+ TkActor* actors2[2];
+ EXPECT_EQ(2, family1->getActors(actors1, 2));
+ EXPECT_EQ(2, family2->getActors(actors2, 2));
+
+ const TkJointData jdata = joint->getData();
+ EXPECT_TRUE(jdata.actors[0] != nullptr);
+ EXPECT_TRUE(jdata.actors[1] != nullptr);
+ EXPECT_TRUE(&jdata.actors[0]->getFamily() == family1);
+ EXPECT_TRUE(&jdata.actors[1]->getFamily() == family2);
+
+ // Clean up
+ if (explicitJointRelease)
+ {
+ joint->release();
+ family2->release();
+ family1->release();
+ asset->release();
+ releaseFramework();
+ }
+ else
+ {
+ EXPECT_EQ(1, tracker.joints.size());
+ releaseFramework();
+ // Commenting these out - but shouldn't we be sending delete events when we release the framework?
+// EXPECT_EQ(0, tracker.joints.size());
+// EXPECT_EQ(0, tracker.actors.size());
+ }
+ }
+
+protected:
+ // http://clang.llvm.org/compatibility.html#dep_lookup_bases
+ // http://stackoverflow.com/questions/6592512/templates-parent-class-member-variables-not-visible-in-inherited-class
+
+ using TkBaseTest<FailLevel, Verbosity>::testAssets;
+ using TkBaseTest<FailLevel, Verbosity>::m_taskman;
+ using TkBaseTest<FailLevel, Verbosity>::m_groupTM;
+ using TkBaseTest<FailLevel, Verbosity>::createFramework;
+ using TkBaseTest<FailLevel, Verbosity>::releaseFramework;
+ using TkBaseTest<FailLevel, Verbosity>::createTestAssets;
+ using TkBaseTest<FailLevel, Verbosity>::releaseTestAssets;
+ using TkBaseTest<FailLevel, Verbosity>::getCubeSlicerProgram;
+ using TkBaseTest<FailLevel, Verbosity>::getDefaultMaterial;
+ using TkBaseTest<FailLevel, Verbosity>::getRadialDamageDesc;
+ using TkBaseTest<FailLevel, Verbosity>::getFalloffProgram;
+};
+
+
+typedef TkCompositeTest<NvBlastMessage::Error, 1> TkCompositeTestAllowWarnings;
+typedef TkCompositeTest<NvBlastMessage::Error, 1> TkCompositeTestStrict;
+
+
+/*
+1) Create assembly, actors and joints should be created automatically
+*/
+
+TEST_F(TkCompositeTestStrict, AssemblyCreateAndRelease_NoNRFJoints_NoSerialization)
+{
+ assemblyCreateAndRelease(false, false);
+}
+
+TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCreateAndRelease_NoNRFJoints_AssemblySerialization)
+{
+ assemblyCreateAndRelease(false, true);
+}
+
+TEST_F(TkCompositeTestStrict, AssemblyCreateAndRelease_WithNRFJoints_NoSerialization)
+{
+ assemblyCreateAndRelease(true, false);
+}
+
+TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCreateAndRelease_WithNRFJoints_AssemblySerialization)
+{
+ assemblyCreateAndRelease(true, true);
+}
+
+
+/**
+2) Create an actor with internal joints. Splitting the actor should cause joint create events to be dispatched
+
+3) Joint update events should be fired when attached actors change
+
+4) Joint delete events should be fired when at least one attached actor is deleted
+*/
+
+TEST_F(TkCompositeTestStrict, AssemblyInternalJoints_NoSerialization)
+{
+ assemblyInternalJoints(false);
+}
+
+TEST_F(TkCompositeTestStrict, DISABLED_AssemblyInternalJoints_AssemblySerialization)
+{
+ assemblyInternalJoints(true);
+}
+
+
+/**
+5) Creating a composite from assets with internal joints should have expected behaviors (1-4) above
+*/
+
+TEST_F(TkCompositeTestStrict, AssemblyCompositeWithInternalJoints_NoNRFJoints_NoSerialization)
+{
+ assemblyCompositeWithInternalJoints(false, false);
+}
+
+TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCompositeWithInternalJoints_NoNRFJoints_AssemblySerialization)
+{
+ assemblyCompositeWithInternalJoints(false, true);
+}
+
+TEST_F(TkCompositeTestStrict, AssemblyCompositeWithInternalJoints_WithNRFJoints_NoSerialization)
+{
+ assemblyCompositeWithInternalJoints(true, false);
+}
+
+TEST_F(TkCompositeTestStrict, DISABLED_AssemblyCompositeWithInternalJoints_WithNRFJoints_AssemblySerialization)
+{
+ assemblyCompositeWithInternalJoints(true, true);
+}
+
+
+/*
+More tests
+*/
+
+TEST_F(TkCompositeTestStrict, AssemblyExternalJoints_MultiFamilyDamage)
+{
+ assemblyExternalJoints_MultiFamilyDamage(true);
+}
+
+TEST_F(TkCompositeTestStrict, AssemblyExternalJoints_MultiFamilyDamage_AutoJointRelease)
+{
+ assemblyExternalJoints_MultiFamilyDamage(false);
+}