Changeset View
Changeset View
Standalone View
Standalone View
tests/gtests/usd/abstract_hierarchy_iterator_test.cc
| Show All 24 Lines | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| } | } | ||||
| #include <map> | #include <map> | ||||
| #include <set> | #include <set> | ||||
| /* Mapping from ID.name to set of export hierarchy path. Duplicated objects can be exported | /* Mapping from ID.name to set of export hierarchy path. Duplicated objects can be exported | ||||
| * multiple times with different export paths, hence the set. */ | * multiple times with different export paths, hence the set. */ | ||||
| typedef std::map<std::string, std::set<std::string>> created_writers; | typedef std::map<std::string, std::set<std::string>> used_writers; | ||||
| using namespace blender::io; | using namespace blender::io; | ||||
| class TestHierarchyWriter : public AbstractHierarchyWriter { | class TestHierarchyWriter : public AbstractHierarchyWriter { | ||||
| public: | public: | ||||
| std::string writer_type; | std::string writer_type; | ||||
| created_writers &writers_map; | used_writers &writers_map; | ||||
| TestHierarchyWriter(const std::string &writer_type, created_writers &writers_map) | TestHierarchyWriter(const std::string &writer_type, used_writers &writers_map) | ||||
| : writer_type(writer_type), writers_map(writers_map) | : writer_type(writer_type), writers_map(writers_map) | ||||
| { | { | ||||
| } | } | ||||
| void write(HierarchyContext &context) override | void write(HierarchyContext &context) override | ||||
| { | { | ||||
| const char *id_name = context.object->id.name; | const char *id_name = context.object->id.name; | ||||
| created_writers::mapped_type &writers = writers_map[id_name]; | used_writers::mapped_type &writers = writers_map[id_name]; | ||||
| if (writers.find(context.export_path) != writers.end()) { | if (writers.find(context.export_path) != writers.end()) { | ||||
| ADD_FAILURE() << "Unexpectedly found another " << writer_type << " writer for " << id_name | ADD_FAILURE() << "Unexpectedly found another " << writer_type << " writer for " << id_name | ||||
| << " to export to " << context.export_path; | << " to export to " << context.export_path; | ||||
| } | } | ||||
| writers.insert(context.export_path); | writers.insert(context.export_path); | ||||
| } | } | ||||
| }; | }; | ||||
| void debug_print_writers(const char *label, const created_writers &writers_map) | void debug_print_writers(const char *label, const used_writers &writers_map) | ||||
| { | { | ||||
| printf("%s:\n", label); | printf("%s:\n", label); | ||||
| for (auto idname_writers : writers_map) { | for (auto idname_writers : writers_map) { | ||||
| printf(" %s:\n", idname_writers.first.c_str()); | printf(" %s:\n", idname_writers.first.c_str()); | ||||
| for (const std::string &export_path : idname_writers.second) { | for (const std::string &export_path : idname_writers.second) { | ||||
| printf(" - %s\n", export_path.c_str()); | printf(" - %s\n", export_path.c_str()); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| class TestingHierarchyIterator : public AbstractHierarchyIterator { | class TestingHierarchyIterator : public AbstractHierarchyIterator { | ||||
| public: /* Public so that the test cases can directly inspect the created writers. */ | public: /* Public so that the test cases can directly inspect the created writers. */ | ||||
| created_writers transform_writers; | used_writers transform_writers; | ||||
| created_writers data_writers; | used_writers data_writers; | ||||
| created_writers hair_writers; | used_writers hair_writers; | ||||
| created_writers particle_writers; | used_writers particle_writers; | ||||
| public: | public: | ||||
| explicit TestingHierarchyIterator(Depsgraph *depsgraph) : AbstractHierarchyIterator(depsgraph) | explicit TestingHierarchyIterator(Depsgraph *depsgraph) : AbstractHierarchyIterator(depsgraph) | ||||
| { | { | ||||
| } | } | ||||
| virtual ~TestingHierarchyIterator() | virtual ~TestingHierarchyIterator() | ||||
| { | { | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | if (!blendfile_load("usd/usd_hierarchy_export_test.blend")) { | ||||
| return; | return; | ||||
| } | } | ||||
| depsgraph_create(DAG_EVAL_RENDER); | depsgraph_create(DAG_EVAL_RENDER); | ||||
| iterator_create(); | iterator_create(); | ||||
| iterator->iterate_and_write(); | iterator->iterate_and_write(); | ||||
| // Mapping from object name to set of export paths. | // Mapping from object name to set of export paths. | ||||
| created_writers expected_transforms = { | used_writers expected_transforms = { | ||||
| {"OBCamera", {"/Camera"}}, | {"OBCamera", {"/Camera"}}, | ||||
| {"OBDupli1", {"/Dupli1"}}, | {"OBDupli1", {"/Dupli1"}}, | ||||
| {"OBDupli2", {"/ParentOfDupli2/Dupli2"}}, | {"OBDupli2", {"/ParentOfDupli2/Dupli2"}}, | ||||
| {"OBGEO_Ear_L", | {"OBGEO_Ear_L", | ||||
| {"/Dupli1/GEO_Head-0/GEO_Ear_L-1", | {"/Dupli1/GEO_Head-0/GEO_Ear_L-1", | ||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L", | "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L", | ||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1"}}, | "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1"}}, | ||||
| {"OBGEO_Ear_R", | {"OBGEO_Ear_R", | ||||
| Show All 9 Lines | used_writers expected_transforms = { | ||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose", | "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose", | ||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3"}}, | "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3"}}, | ||||
| {"OBGround plane", {"/Ground plane"}}, | {"OBGround plane", {"/Ground plane"}}, | ||||
| {"OBOutsideDupliGrandParent", {"/Ground plane/OutsideDupliGrandParent"}}, | {"OBOutsideDupliGrandParent", {"/Ground plane/OutsideDupliGrandParent"}}, | ||||
| {"OBOutsideDupliParent", {"/Ground plane/OutsideDupliGrandParent/OutsideDupliParent"}}, | {"OBOutsideDupliParent", {"/Ground plane/OutsideDupliGrandParent/OutsideDupliParent"}}, | ||||
| {"OBParentOfDupli2", {"/ParentOfDupli2"}}}; | {"OBParentOfDupli2", {"/ParentOfDupli2"}}}; | ||||
| EXPECT_EQ(expected_transforms, iterator->transform_writers); | EXPECT_EQ(expected_transforms, iterator->transform_writers); | ||||
| created_writers expected_data = { | used_writers expected_data = { | ||||
| {"OBCamera", {"/Camera/Camera"}}, | {"OBCamera", {"/Camera/Camera"}}, | ||||
| {"OBGEO_Ear_L", | {"OBGEO_Ear_L", | ||||
| {"/Dupli1/GEO_Head-0/GEO_Ear_L-1/Ear", | {"/Dupli1/GEO_Head-0/GEO_Ear_L-1/Ear", | ||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L/Ear", | "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L/Ear", | ||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1/Ear"}}, | "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1/Ear"}}, | ||||
| {"OBGEO_Ear_R", | {"OBGEO_Ear_R", | ||||
| {"/Dupli1/GEO_Head-0/GEO_Ear_R-2/Ear", | {"/Dupli1/GEO_Head-0/GEO_Ear_R-2/Ear", | ||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R/Ear", | "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R/Ear", | ||||
| Show All 10 Lines | used_writers expected_data = { | ||||
| {"OBParentOfDupli2", {"/ParentOfDupli2/Icosphere"}}, | {"OBParentOfDupli2", {"/ParentOfDupli2/Icosphere"}}, | ||||
| }; | }; | ||||
| EXPECT_EQ(expected_data, iterator->data_writers); | EXPECT_EQ(expected_data, iterator->data_writers); | ||||
| // The scene has no hair or particle systems. | // The scene has no hair or particle systems. | ||||
| EXPECT_EQ(0, iterator->hair_writers.size()); | EXPECT_EQ(0, iterator->hair_writers.size()); | ||||
| EXPECT_EQ(0, iterator->particle_writers.size()); | EXPECT_EQ(0, iterator->particle_writers.size()); | ||||
| // On the second iteration, everything should be written as well. | |||||
| // This tests the default value of iterator->export_subset_. | |||||
| iterator->transform_writers.clear(); | |||||
| iterator->data_writers.clear(); | |||||
| iterator->iterate_and_write(); | |||||
| EXPECT_EQ(expected_transforms, iterator->transform_writers); | |||||
| EXPECT_EQ(expected_data, iterator->data_writers); | |||||
| } | |||||
| TEST_F(USDHierarchyIteratorTest, ExportSubsetTest) | |||||
| { | |||||
| // The scene has no hair or particle systems, and this is already covered by ExportHierarchyTest, | |||||
| // so not included here. Update this test when hair & particle systems are included. | |||||
| /* Load the test blend file. */ | |||||
| if (!blendfile_load("usd/usd_hierarchy_export_test.blend")) { | |||||
| return; | |||||
| } | |||||
| depsgraph_create(DAG_EVAL_RENDER); | |||||
| iterator_create(); | |||||
| // Mapping from object name to set of export paths. | |||||
| used_writers expected_transforms = { | |||||
| {"OBCamera", {"/Camera"}}, | |||||
| {"OBDupli1", {"/Dupli1"}}, | |||||
| {"OBDupli2", {"/ParentOfDupli2/Dupli2"}}, | |||||
| {"OBGEO_Ear_L", | |||||
| {"/Dupli1/GEO_Head-0/GEO_Ear_L-1", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1"}}, | |||||
| {"OBGEO_Ear_R", | |||||
| {"/Dupli1/GEO_Head-0/GEO_Ear_R-2", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_R-2"}}, | |||||
| {"OBGEO_Head", | |||||
| {"/Dupli1/GEO_Head-0", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0"}}, | |||||
| {"OBGEO_Nose", | |||||
| {"/Dupli1/GEO_Head-0/GEO_Nose-3", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3"}}, | |||||
| {"OBGround plane", {"/Ground plane"}}, | |||||
| {"OBOutsideDupliGrandParent", {"/Ground plane/OutsideDupliGrandParent"}}, | |||||
| {"OBOutsideDupliParent", {"/Ground plane/OutsideDupliGrandParent/OutsideDupliParent"}}, | |||||
| {"OBParentOfDupli2", {"/ParentOfDupli2"}}}; | |||||
| used_writers expected_data = { | |||||
| {"OBCamera", {"/Camera/Camera"}}, | |||||
| {"OBGEO_Ear_L", | |||||
| {"/Dupli1/GEO_Head-0/GEO_Ear_L-1/Ear", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_L/Ear", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_L-1/Ear"}}, | |||||
| {"OBGEO_Ear_R", | |||||
| {"/Dupli1/GEO_Head-0/GEO_Ear_R-2/Ear", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Ear_R/Ear", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Ear_R-2/Ear"}}, | |||||
| {"OBGEO_Head", | |||||
| {"/Dupli1/GEO_Head-0/Face", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/Face", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/Face"}}, | |||||
| {"OBGEO_Nose", | |||||
| {"/Dupli1/GEO_Head-0/GEO_Nose-3/Nose", | |||||
| "/Ground plane/OutsideDupliGrandParent/OutsideDupliParent/GEO_Head/GEO_Nose/Nose", | |||||
| "/ParentOfDupli2/Dupli2/GEO_Head-0/GEO_Nose-3/Nose"}}, | |||||
| {"OBGround plane", {"/Ground plane/Plane"}}, | |||||
| {"OBParentOfDupli2", {"/ParentOfDupli2/Icosphere"}}, | |||||
| }; | |||||
| // Even when only asking an export of transforms, on the first frame everything should be | |||||
| // exported. | |||||
| iterator->set_export_subset({ | |||||
| .transforms = true, | |||||
| .shapes = false, | |||||
| }); | |||||
| iterator->iterate_and_write(); | |||||
| EXPECT_EQ(expected_transforms, iterator->transform_writers); | |||||
| EXPECT_EQ(expected_data, iterator->data_writers); | |||||
| // Clear data to prepare for the next iteration. | |||||
| iterator->transform_writers.clear(); | |||||
| iterator->data_writers.clear(); | |||||
| // Second iteration, should only write transforms now. | |||||
| iterator->iterate_and_write(); | |||||
| EXPECT_EQ(expected_transforms, iterator->transform_writers); | |||||
| EXPECT_EQ(0, iterator->data_writers.size()); | |||||
| // Clear data to prepare for the next iteration. | |||||
| iterator->transform_writers.clear(); | |||||
| iterator->data_writers.clear(); | |||||
| // Third iteration, should only write data now. | |||||
| iterator->set_export_subset({ | |||||
| .transforms = false, | |||||
| .shapes = true, | |||||
| }); | |||||
| iterator->iterate_and_write(); | |||||
| EXPECT_EQ(0, iterator->transform_writers.size()); | |||||
| EXPECT_EQ(expected_data, iterator->data_writers); | |||||
| // Clear data to prepare for the next iteration. | |||||
| iterator->transform_writers.clear(); | |||||
| iterator->data_writers.clear(); | |||||
| // Fourth iteration, should export everything now. | |||||
| iterator->set_export_subset({ | |||||
| .transforms = true, | |||||
| .shapes = true, | |||||
| }); | |||||
| iterator->iterate_and_write(); | |||||
| EXPECT_EQ(expected_transforms, iterator->transform_writers); | |||||
| EXPECT_EQ(expected_data, iterator->data_writers); | |||||
| } | } | ||||