mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 07:56:38 +00:00 
			
		
		
		
	Merge pull request #1864 from elsid/nifbullet_tests
Add unit tests for BulletNifLoader
This commit is contained in:
		
						commit
						953e3a4eba
					
				
					 14 changed files with 1615 additions and 48 deletions
				
			
		|  | @ -24,8 +24,6 @@ addons: | |||
|     packages: [ | ||||
|       # Dev | ||||
|       cmake, clang-3.6, libunshield-dev, libtinyxml-dev, | ||||
|       # Tests | ||||
|       libgtest-dev, google-mock, | ||||
|       # Boost | ||||
|       libboost-filesystem-dev, libboost-program-options-dev, libboost-system-dev, | ||||
|       # FFmpeg | ||||
|  |  | |||
|  | @ -1,11 +1,3 @@ | |||
| #!/bin/sh | ||||
| sudo ln -s /usr/bin/clang-3.6 /usr/local/bin/clang | ||||
| sudo ln -s /usr/bin/clang++-3.6 /usr/local/bin/clang++ | ||||
| 
 | ||||
| # build libgtest & libgtest_main | ||||
| sudo mkdir /usr/src/gtest/build | ||||
| cd /usr/src/gtest/build | ||||
| sudo cmake .. -DBUILD_SHARED_LIBS=1 | ||||
| sudo make -j4 | ||||
| sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so | ||||
| sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so | ||||
|  |  | |||
|  | @ -1,8 +1,21 @@ | |||
| #!/bin/sh | ||||
| #!/bin/sh -e | ||||
| 
 | ||||
| free -m | ||||
| 
 | ||||
| env GENERATOR='Unix Makefiles' CONFIGURATION=Release CI/build_googletest.sh | ||||
| GOOGLETEST_DIR="$(pwd)/googletest/build" | ||||
| 
 | ||||
| mkdir build | ||||
| cd build | ||||
| export CODE_COVERAGE=1 | ||||
| if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi | ||||
| ${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games  -DCMAKE_BUILD_TYPE="None" -DUSE_SYSTEM_TINYXML=TRUE | ||||
| ${ANALYZE}cmake \ | ||||
|     -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} \ | ||||
|     -DBUILD_UNITTESTS=1 \ | ||||
|     -DCMAKE_INSTALL_PREFIX=/usr \ | ||||
|     -DBINDIR=/usr/games \ | ||||
|     -DCMAKE_BUILD_TYPE="None" \ | ||||
|     -DUSE_SYSTEM_TINYXML=TRUE \ | ||||
|     -DGTEST_ROOT="${GOOGLETEST_DIR}" \ | ||||
|     -DGMOCK_ROOT="${GOOGLETEST_DIR}" \ | ||||
|     .. | ||||
|  |  | |||
							
								
								
									
										13
									
								
								CI/build_googletest.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										13
									
								
								CI/build_googletest.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,13 @@ | |||
| #!/bin/sh -e | ||||
| 
 | ||||
| git clone https://github.com/google/googletest.git | ||||
| cd googletest | ||||
| mkdir build | ||||
| cd build | ||||
| cmake \ | ||||
|     -D CMAKE_BUILD_TYPE="${CONFIGURATION}" \ | ||||
|     -D CMAKE_INSTALL_PREFIX=. \ | ||||
|     -G "${GENERATOR}" \ | ||||
|     .. | ||||
| cmake --build . --config "${CONFIGURATION}" | ||||
| cmake --build . --target install --config "${CONFIGURATION}" | ||||
|  | @ -1,7 +1,9 @@ | |||
| find_package(GTest REQUIRED) | ||||
| find_package(GMock REQUIRED) | ||||
| 
 | ||||
| if (GTEST_FOUND) | ||||
| if (GTEST_FOUND AND GMOCK_FOUND) | ||||
|     include_directories(SYSTEM ${GTEST_INCLUDE_DIRS}) | ||||
|     include_directories(SYSTEM ${GMOCK_INCLUDE_DIRS}) | ||||
| 
 | ||||
|     file(GLOB UNITTEST_SRC_FILES | ||||
|         ../openmw/mwworld/store.cpp | ||||
|  | @ -13,17 +15,22 @@ if (GTEST_FOUND) | |||
|         esm/test_fixed_string.cpp | ||||
| 
 | ||||
|         misc/test_stringops.cpp | ||||
| 
 | ||||
|         nifloader/testbulletnifloader.cpp | ||||
|     ) | ||||
| 
 | ||||
|     source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) | ||||
| 
 | ||||
|     openmw_add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) | ||||
| 
 | ||||
|     target_link_libraries(openmw_test_suite ${GTEST_BOTH_LIBRARIES} components) | ||||
|     target_link_libraries(openmw_test_suite ${GMOCK_LIBRARIES} components) | ||||
|     # Fix for not visible pthreads functions for linker with glibc 2.15 | ||||
|     if (UNIX AND NOT APPLE) | ||||
|         target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) | ||||
|     endif() | ||||
| 
 | ||||
|     if (BUILD_WITH_CODE_COVERAGE) | ||||
|         add_definitions(--coverage) | ||||
|         target_link_libraries(openmw_test_suite gcov) | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										951
									
								
								apps/openmw_test_suite/nifloader/testbulletnifloader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										951
									
								
								apps/openmw_test_suite/nifloader/testbulletnifloader.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,951 @@ | |||
| #include <components/nifbullet/bulletnifloader.hpp> | ||||
| #include <components/bullethelpers/processtrianglecallback.hpp> | ||||
| #include <components/nif/node.hpp> | ||||
| 
 | ||||
| #include <BulletCollision/CollisionShapes/btBoxShape.h> | ||||
| #include <BulletCollision/CollisionShapes/btCompoundShape.h> | ||||
| #include <BulletCollision/CollisionShapes/btTriangleMesh.h> | ||||
| 
 | ||||
| #include <gtest/gtest.h> | ||||
| #include <gmock/gmock.h> | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|     template <class T> | ||||
|     bool compareObjects(const T* lhs, const T* rhs) | ||||
|     { | ||||
|         return (!lhs && !rhs) || (lhs && rhs && *lhs == *rhs); | ||||
|     } | ||||
| 
 | ||||
|     std::vector<btVector3> getTriangles(const btBvhTriangleMeshShape& shape) | ||||
|     { | ||||
|         std::vector<btVector3> result; | ||||
|         auto callback = BulletHelpers::makeProcessTriangleCallback([&] (btVector3* triangle, int, int) { | ||||
|             for (std::size_t i = 0; i < 3; ++i) | ||||
|                 result.push_back(triangle[i]); | ||||
|         }); | ||||
|         btVector3 aabbMin; | ||||
|         btVector3 aabbMax; | ||||
|         shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax); | ||||
|         shape.processAllTriangles(&callback, aabbMin, aabbMax); | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btVector3& value) | ||||
| { | ||||
|     return stream << "btVector3 {" | ||||
|         << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getX() << ", " | ||||
|         << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getY() << ", " | ||||
|         << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getZ() << "}"; | ||||
| } | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btMatrix3x3& value) | ||||
| { | ||||
|     stream << "btMatrix3x3 {"; | ||||
|     for (int i = 0; i < 3; ++i) | ||||
|          stream << value.getRow(i) << ", "; | ||||
|     return stream << "}"; | ||||
| } | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btTransform& value) | ||||
| { | ||||
|     return stream << "btTransform {" << value.getBasis() << ", " << value.getOrigin() << "}"; | ||||
| } | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btCollisionShape* value); | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btCompoundShape& value) | ||||
| { | ||||
|     stream << "btCompoundShape {" << value.getLocalScaling() << ", "; | ||||
|     stream << "{"; | ||||
|     for (int i = 0; i < value.getNumChildShapes(); ++i) | ||||
|         stream << value.getChildShape(i) << ", "; | ||||
|     stream << "},"; | ||||
|     stream << "{"; | ||||
|     for (int i = 0; i < value.getNumChildShapes(); ++i) | ||||
|         stream << value.getChildTransform(i) << ", "; | ||||
|     stream << "}"; | ||||
|     return stream << "}"; | ||||
| } | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btBoxShape& value) | ||||
| { | ||||
|     return stream << "btBoxShape {" << value.getLocalScaling() << ", " << value.getHalfExtentsWithoutMargin() << "}"; | ||||
| } | ||||
| 
 | ||||
| namespace Resource | ||||
| { | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const TriangleMeshShape& value) | ||||
| { | ||||
|     stream << "Resource::TriangleMeshShape {" << value.getLocalScaling() << ", " | ||||
|         << value.usesQuantizedAabbCompression() << ", " << value.getOwnsBvh() << ", {"; | ||||
|     auto callback = BulletHelpers::makeProcessTriangleCallback([&] (btVector3* triangle, int, int) { | ||||
|         for (std::size_t i = 0; i < 3; ++i) | ||||
|             stream << triangle[i] << ", "; | ||||
|     }); | ||||
|     btVector3 aabbMin; | ||||
|     btVector3 aabbMax; | ||||
|     value.getAabb(btTransform::getIdentity(), aabbMin, aabbMax); | ||||
|     value.processAllTriangles(&callback, aabbMin, aabbMax); | ||||
|     return stream << "}}"; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btCollisionShape& value) | ||||
| { | ||||
|     switch (value.getShapeType()) | ||||
|     { | ||||
|         case COMPOUND_SHAPE_PROXYTYPE: | ||||
|             return stream << static_cast<const btCompoundShape&>(value); | ||||
|         case BOX_SHAPE_PROXYTYPE: | ||||
|             return stream << static_cast<const btBoxShape&>(value); | ||||
|         case TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||||
|             if (const auto casted = dynamic_cast<const Resource::TriangleMeshShape*>(&value)) | ||||
|                 return stream << *casted; | ||||
|             break; | ||||
|     } | ||||
|     return stream << "btCollisionShape {" << value.getShapeType() << "}"; | ||||
| } | ||||
| 
 | ||||
| static std::ostream& operator <<(std::ostream& stream, const btCollisionShape* value) | ||||
| { | ||||
|     return value ? stream << "&" << *value : stream << "nullptr"; | ||||
| } | ||||
| 
 | ||||
| namespace osg | ||||
| { | ||||
|     static std::ostream& operator <<(std::ostream& stream, const Vec3f& value) | ||||
|     { | ||||
|         return stream << "osg::Vec3f {" | ||||
|             << value.x() << ", " | ||||
|             << value.y() << ", " | ||||
|             << value.z() << "}"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace std | ||||
| { | ||||
|     static std::ostream& operator <<(std::ostream& stream, const map<int, int>& value) | ||||
|     { | ||||
|         stream << "std::map<int, int> {"; | ||||
|         for (const auto& v : value) | ||||
|             stream << "{" << v.first << ", " << v.second << "},"; | ||||
|         return stream << "}"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace Resource | ||||
| { | ||||
|     static bool operator ==(const Resource::BulletShape& lhs, const Resource::BulletShape& rhs) | ||||
|     { | ||||
|         return compareObjects(lhs.mCollisionShape, rhs.mCollisionShape) | ||||
|             && lhs.mCollisionBoxHalfExtents == rhs.mCollisionBoxHalfExtents | ||||
|             && lhs.mCollisionBoxTranslate == rhs.mCollisionBoxTranslate | ||||
|             && lhs.mAnimatedShapes == rhs.mAnimatedShapes; | ||||
|     } | ||||
| 
 | ||||
|     static std::ostream& operator <<(std::ostream& stream, const Resource::BulletShape& value) | ||||
|     { | ||||
|         return stream << "Resource::BulletShape {" | ||||
|             << value.mCollisionShape << ", " | ||||
|             << value.mCollisionBoxHalfExtents << ", " | ||||
|             << value.mAnimatedShapes | ||||
|             << "}"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static bool operator ==(const btCollisionShape& lhs, const btCollisionShape& rhs); | ||||
| 
 | ||||
| static bool operator ==(const btCompoundShape& lhs, const btCompoundShape& rhs) | ||||
| { | ||||
|     if (lhs.getNumChildShapes() != rhs.getNumChildShapes() || lhs.getLocalScaling() != rhs.getLocalScaling()) | ||||
|         return false; | ||||
|     for (int i = 0; i < lhs.getNumChildShapes(); ++i) | ||||
|     { | ||||
|         if (!compareObjects(lhs.getChildShape(i), rhs.getChildShape(i)) | ||||
|                 || !(lhs.getChildTransform(i) == rhs.getChildTransform(i))) | ||||
|             return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool operator ==(const btBoxShape& lhs, const btBoxShape& rhs) | ||||
| { | ||||
|     return lhs.getLocalScaling() == rhs.getLocalScaling() | ||||
|         && lhs.getHalfExtentsWithoutMargin() == rhs.getHalfExtentsWithoutMargin(); | ||||
| } | ||||
| 
 | ||||
| static bool operator ==(const btBvhTriangleMeshShape& lhs, const btBvhTriangleMeshShape& rhs) | ||||
| { | ||||
|     return lhs.getLocalScaling() == rhs.getLocalScaling() | ||||
|         && lhs.usesQuantizedAabbCompression() == rhs.usesQuantizedAabbCompression() | ||||
|         && lhs.getOwnsBvh() == rhs.getOwnsBvh() | ||||
|         && getTriangles(lhs) == getTriangles(rhs); | ||||
| } | ||||
| 
 | ||||
| static bool operator ==(const btCollisionShape& lhs, const btCollisionShape& rhs) | ||||
| { | ||||
|     if (lhs.getShapeType() != rhs.getShapeType()) | ||||
|         return false; | ||||
|     switch (lhs.getShapeType()) | ||||
|     { | ||||
|         case COMPOUND_SHAPE_PROXYTYPE: | ||||
|             return static_cast<const btCompoundShape&>(lhs) == static_cast<const btCompoundShape&>(rhs); | ||||
|         case BOX_SHAPE_PROXYTYPE: | ||||
|             return static_cast<const btBoxShape&>(lhs) == static_cast<const btBoxShape&>(rhs); | ||||
|         case TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||||
|             if (const auto lhsCasted = dynamic_cast<const Resource::TriangleMeshShape*>(&lhs)) | ||||
|                 if (const auto rhsCasted = dynamic_cast<const Resource::TriangleMeshShape*>(&rhs)) | ||||
|                     return *lhsCasted == *rhsCasted; | ||||
|             return false; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|     using namespace testing; | ||||
|     using NifBullet::BulletNifLoader; | ||||
| 
 | ||||
|     void init(Nif::Transformation& value) | ||||
|     { | ||||
|         value = Nif::Transformation::getIdentity(); | ||||
|     } | ||||
| 
 | ||||
|     void init(Nif::Extra& value) | ||||
|     { | ||||
|         value.extra = Nif::ExtraPtr(nullptr); | ||||
|     } | ||||
| 
 | ||||
|     void init(Nif::Controlled& value) | ||||
|     { | ||||
|         init(static_cast<Nif::Extra&>(value)); | ||||
|         value.controller = Nif::ControllerPtr(nullptr); | ||||
|     } | ||||
| 
 | ||||
|     void init(Nif::Named& value) | ||||
|     { | ||||
|         init(static_cast<Nif::Controlled&>(value)); | ||||
|     } | ||||
| 
 | ||||
|     void init(Nif::Node& value) | ||||
|     { | ||||
|         init(static_cast<Nif::Named&>(value)); | ||||
|         value.flags = 0; | ||||
|         init(value.trafo); | ||||
|         value.hasBounds = false; | ||||
|         value.parent = nullptr; | ||||
|         value.isBone = false; | ||||
|     } | ||||
| 
 | ||||
|     void init(Nif::NiTriShape& value) | ||||
|     { | ||||
|         init(static_cast<Nif::Node&>(value)); | ||||
|         value.recType = Nif::RC_NiTriShape; | ||||
|         value.data = Nif::NiTriShapeDataPtr(nullptr); | ||||
|         value.skin = Nif::NiSkinInstancePtr(nullptr); | ||||
|     } | ||||
| 
 | ||||
|     void init(Nif::NiSkinInstance& value) | ||||
|     { | ||||
|         value.data = Nif::NiSkinDataPtr(nullptr); | ||||
|         value.root = Nif::NodePtr(nullptr); | ||||
|     } | ||||
| 
 | ||||
|     void init(Nif::Controller& value) | ||||
|     { | ||||
|         value.next = Nif::ControllerPtr(nullptr); | ||||
|         value.flags = 0; | ||||
|         value.frequency = 0; | ||||
|         value.phase = 0; | ||||
|         value.timeStart = 0; | ||||
|         value.timeStop = 0; | ||||
|         value.target = Nif::ControlledPtr(nullptr); | ||||
|     } | ||||
| 
 | ||||
|     void copy(const btTransform& src, Nif::Transformation& dst) { | ||||
|         dst.pos = osg::Vec3f(src.getOrigin().x(), src.getOrigin().y(), src.getOrigin().z()); | ||||
|         for (int row = 0; row < 3; ++row) | ||||
|             for (int column = 0; column < 3; ++column) | ||||
|                 dst.rotation.mValues[column][row] = src.getBasis().getRow(row)[column]; | ||||
|     } | ||||
| 
 | ||||
|     struct NifFileMock : Nif::File | ||||
|     { | ||||
|         MOCK_CONST_METHOD1(fail, void (const std::string&)); | ||||
|         MOCK_CONST_METHOD1(warn, void (const std::string&)); | ||||
|         MOCK_CONST_METHOD1(getRecord, Nif::Record* (std::size_t)); | ||||
|         MOCK_CONST_METHOD0(numRecords, std::size_t ()); | ||||
|         MOCK_CONST_METHOD1(getRoot, Nif::Record* (std::size_t)); | ||||
|         MOCK_CONST_METHOD0(numRoots, std::size_t ()); | ||||
|         MOCK_METHOD1(setUseSkinning, void (bool)); | ||||
|         MOCK_CONST_METHOD0(getUseSkinning, bool ()); | ||||
|         MOCK_CONST_METHOD0(getFilename, std::string ()); | ||||
|     }; | ||||
| 
 | ||||
|     struct RecordMock : Nif::Record | ||||
|     { | ||||
|         MOCK_METHOD1(read, void (Nif::NIFStream *nif)); | ||||
|     }; | ||||
| 
 | ||||
|     struct TestBulletNifLoader : Test | ||||
|     { | ||||
|         BulletNifLoader mLoader; | ||||
|         const StrictMock<const NifFileMock> mNifFile; | ||||
|         Nif::Node mNode; | ||||
|         Nif::Node mNode2; | ||||
|         Nif::NiNode mNiNode; | ||||
|         Nif::NiNode mNiNode2; | ||||
|         Nif::NiNode mNiNode3; | ||||
|         Nif::NiTriShapeData mNiTriShapeData; | ||||
|         Nif::NiTriShape mNiTriShape; | ||||
|         Nif::NiTriShapeData mNiTriShapeData2; | ||||
|         Nif::NiTriShape mNiTriShape2; | ||||
|         Nif::NiSkinInstance mNiSkinInstance; | ||||
|         Nif::NiStringExtraData mNiStringExtraData; | ||||
|         Nif::NiStringExtraData mNiStringExtraData2; | ||||
|         Nif::Controller mController; | ||||
|         btTransform mTransform {btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(1, 2, 3)}; | ||||
|         btTransform mResultTransform { | ||||
|             btMatrix3x3( | ||||
|                 1, 0, 0, | ||||
|                 0, 0.82417738437652587890625, 0.56633174419403076171875, | ||||
|                 0, -0.56633174419403076171875, 0.82417738437652587890625 | ||||
|             ), | ||||
|             btVector3(1, 2, 3) | ||||
|         }; | ||||
|         btTransform mResultTransform2 { | ||||
|             btMatrix3x3( | ||||
|                 1, 0, 0, | ||||
|                 0, 0.7951543331146240234375, 0.606407105922698974609375, | ||||
|                 0, -0.606407105922698974609375, 0.7951543331146240234375 | ||||
|             ), | ||||
|             btVector3(4, 8, 12) | ||||
|         }; | ||||
| 
 | ||||
|         TestBulletNifLoader() | ||||
|         { | ||||
|             init(mNode); | ||||
|             init(mNode2); | ||||
|             init(mNiNode); | ||||
|             init(mNiNode2); | ||||
|             init(mNiNode3); | ||||
|             init(mNiTriShape); | ||||
|             init(mNiTriShape2); | ||||
|             init(mNiSkinInstance); | ||||
|             init(mNiStringExtraData); | ||||
|             init(mNiStringExtraData2); | ||||
|             init(mController); | ||||
| 
 | ||||
|             mNiTriShapeData.vertices = {osg::Vec3f(0, 0, 0), osg::Vec3f(1, 0, 0), osg::Vec3f(1, 1, 0)}; | ||||
|             mNiTriShapeData.triangles = {0, 1, 2}; | ||||
|             mNiTriShape.data = Nif::NiTriShapeDataPtr(&mNiTriShapeData); | ||||
| 
 | ||||
|             mNiTriShapeData2.vertices = {osg::Vec3f(0, 0, 1), osg::Vec3f(1, 0, 1), osg::Vec3f(1, 1, 1)}; | ||||
|             mNiTriShapeData2.triangles = {0, 1, 2}; | ||||
|             mNiTriShape2.data = Nif::NiTriShapeDataPtr(&mNiTriShapeData2); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_zero_num_roots_should_return_default) | ||||
|     { | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(0)); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_root_not_nif_node_should_return_default) | ||||
|     { | ||||
|         StrictMock<RecordMock> record; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&record)); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_default_root_nif_node_should_return_default) | ||||
|     { | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_default_root_collision_node_nif_node_should_return_default) | ||||
|     { | ||||
|         mNode.recType = Nif::RC_RootCollisionNode; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_default_root_nif_node_and_filename_starting_with_x_should_return_default) | ||||
|     { | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_root_nif_node_with_bounding_box_should_return_shape_with_compound_shape_and_box_inside) | ||||
|     { | ||||
|         mNode.hasBounds = true; | ||||
|         mNode.flags |= Nif::NiNode::Flag_BBoxCollision; | ||||
|         mNode.boundXYZ = osg::Vec3f(1, 2, 3); | ||||
|         mNode.boundPos = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode)); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3); | ||||
|         expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3); | ||||
|         std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3))); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release()); | ||||
|         expected.mCollisionShape = shape.release(); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_child_nif_node_with_bounding_box) | ||||
|     { | ||||
|         mNode.hasBounds = true; | ||||
|         mNode.flags |= Nif::NiNode::Flag_BBoxCollision; | ||||
|         mNode.boundXYZ = osg::Vec3f(1, 2, 3); | ||||
|         mNode.boundPos = osg::Vec3f(-1, -2, -3); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3); | ||||
|         expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3); | ||||
|         std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3))); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release()); | ||||
|         expected.mCollisionShape = shape.release(); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_root_and_child_nif_node_with_bounding_box_but_root_without_flag_should_use_child_bounds) | ||||
|     { | ||||
|         mNode.hasBounds = true; | ||||
|         mNode.flags |= Nif::NiNode::Flag_BBoxCollision; | ||||
|         mNode.boundXYZ = osg::Vec3f(1, 2, 3); | ||||
|         mNode.boundPos = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         mNiNode.hasBounds = true; | ||||
|         mNiNode.boundXYZ = osg::Vec3f(4, 5, 6); | ||||
|         mNiNode.boundPos = osg::Vec3f(-4, -5, -6); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3); | ||||
|         expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3); | ||||
|         std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3))); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release()); | ||||
|         expected.mCollisionShape = shape.release(); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_root_and_two_children_where_both_with_bounds_but_only_first_with_flag_should_use_first_bounds) | ||||
|     { | ||||
|         mNode.hasBounds = true; | ||||
|         mNode.flags |= Nif::NiNode::Flag_BBoxCollision; | ||||
|         mNode.boundXYZ = osg::Vec3f(1, 2, 3); | ||||
|         mNode.boundPos = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         mNode2.hasBounds = true; | ||||
|         mNode2.boundXYZ = osg::Vec3f(4, 5, 6); | ||||
|         mNode2.boundPos = osg::Vec3f(-4, -5, -6); | ||||
| 
 | ||||
|         mNiNode.hasBounds = true; | ||||
|         mNiNode.boundXYZ = osg::Vec3f(7, 8, 9); | ||||
|         mNiNode.boundPos = osg::Vec3f(-7, -8, -9); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3); | ||||
|         expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3); | ||||
|         std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3))); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release()); | ||||
|         expected.mCollisionShape = shape.release(); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_root_and_two_children_where_both_with_bounds_but_only_second_with_flag_should_use_second_bounds) | ||||
|     { | ||||
|         mNode.hasBounds = true; | ||||
|         mNode.boundXYZ = osg::Vec3f(1, 2, 3); | ||||
|         mNode.boundPos = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         mNode2.hasBounds = true; | ||||
|         mNode2.flags |= Nif::NiNode::Flag_BBoxCollision; | ||||
|         mNode2.boundXYZ = osg::Vec3f(4, 5, 6); | ||||
|         mNode2.boundPos = osg::Vec3f(-4, -5, -6); | ||||
| 
 | ||||
|         mNiNode.hasBounds = true; | ||||
|         mNiNode.boundXYZ = osg::Vec3f(7, 8, 9); | ||||
|         mNiNode.boundPos = osg::Vec3f(-7, -8, -9); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionBoxHalfExtents = osg::Vec3f(4, 5, 6); | ||||
|         expected.mCollisionBoxTranslate = osg::Vec3f(-4, -5, -6); | ||||
|         std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(4, 5, 6))); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-4, -5, -6)), box.release()); | ||||
|         expected.mCollisionShape = shape.release(); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_root_nif_node_with_bounds_but_without_flag_should_return_shape_with_bounds_but_with_null_collision_shape) | ||||
|     { | ||||
|         mNode.hasBounds = true; | ||||
|         mNode.boundXYZ = osg::Vec3f(1, 2, 3); | ||||
|         mNode.boundPos = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3); | ||||
|         expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_root_node_should_return_shape_with_triangle_mesh_shape) | ||||
|     { | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_root_node_with_bounds_should_return_shape_with_bounds_but_with_null_collision_shape) | ||||
|     { | ||||
|         mNiTriShape.hasBounds = true; | ||||
|         mNiTriShape.boundXYZ = osg::Vec3f(1, 2, 3); | ||||
|         mNiTriShape.boundPos = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionBoxHalfExtents = osg::Vec3f(1, 2, 3); | ||||
|         expected.mCollisionBoxTranslate = osg::Vec3f(-1, -2, -3); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_should_return_shape_with_triangle_mesh_shape) | ||||
|     { | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_nested_tri_shape_child_should_return_shape_with_triangle_mesh_shape) | ||||
|     { | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiNode2)})); | ||||
|         mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_two_tri_shape_children_should_return_shape_with_triangle_mesh_shape_with_all_meshes) | ||||
|     { | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ | ||||
|             Nif::NodePtr(&mNiTriShape), | ||||
|             Nif::NodePtr(&mNiTriShape2) | ||||
|         })); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_shape_with_triangle_mesh_shape) | ||||
|     { | ||||
|         mNiTriShape.skin = Nif::NiSkinInstancePtr(&mNiSkinInstance); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_root_node_and_filename_starting_with_x_should_return_shape_with_compound_shape) | ||||
|     { | ||||
|         copy(mTransform, mNiTriShape.trafo); | ||||
|         mNiTriShape.trafo.scale = 3; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true)); | ||||
|         mesh->setLocalScaling(btVector3(3, 3, 3)); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(mResultTransform, mesh.release()); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = shape.release(); | ||||
|         expected.mAnimatedShapes = {{-1, 0}}; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_should_return_shape_with_compound_shape) | ||||
|     { | ||||
|         copy(mTransform, mNiTriShape.trafo); | ||||
|         mNiTriShape.trafo.scale = 3; | ||||
|         mNiTriShape.parent = &mNiNode; | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
|         mNiNode.trafo.scale = 4; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true)); | ||||
|         mesh->setLocalScaling(btVector3(12, 12, 12)); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(mResultTransform2, mesh.release()); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = shape.release(); | ||||
|         expected.mAnimatedShapes = {{-1, 0}}; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_and_filename_starting_with_x_should_return_shape_with_compound_shape) | ||||
|     { | ||||
|         copy(mTransform, mNiTriShape.trafo); | ||||
|         mNiTriShape.trafo.scale = 3; | ||||
| 
 | ||||
|         copy(mTransform, mNiTriShape2.trafo); | ||||
|         mNiTriShape2.trafo.scale = 3; | ||||
| 
 | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ | ||||
|             Nif::NodePtr(&mNiTriShape), | ||||
|             Nif::NodePtr(&mNiTriShape2), | ||||
|         })); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true)); | ||||
|         mesh->setLocalScaling(btVector3(3, 3, 3)); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false)); | ||||
|         triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1)); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> mesh2(new Resource::TriangleMeshShape(triangles2.release(), true)); | ||||
|         mesh2->setLocalScaling(btVector3(3, 3, 3)); | ||||
| 
 | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(mResultTransform, mesh.release()); | ||||
|         shape->addChildShape(mResultTransform, mesh2.release()); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = shape.release(); | ||||
|         expected.mAnimatedShapes = {{-1, 0}}; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_controller_should_return_shape_with_compound_shape) | ||||
|     { | ||||
|         mController.recType = Nif::RC_NiKeyframeController; | ||||
|         mController.flags |= Nif::NiNode::ControllerFlag_Active; | ||||
|         copy(mTransform, mNiTriShape.trafo); | ||||
|         mNiTriShape.trafo.scale = 3; | ||||
|         mNiTriShape.parent = &mNiNode; | ||||
|         mNiTriShape.controller = Nif::ControllerPtr(&mController); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
|         mNiNode.trafo.scale = 4; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true)); | ||||
|         mesh->setLocalScaling(btVector3(12, 12, 12)); | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(mResultTransform2, mesh.release()); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = shape.release(); | ||||
|         expected.mAnimatedShapes = {{-1, 0}}; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_where_one_with_controller_should_return_shape_with_compound_shape) | ||||
|     { | ||||
|         mController.recType = Nif::RC_NiKeyframeController; | ||||
|         mController.flags |= Nif::NiNode::ControllerFlag_Active; | ||||
|         copy(mTransform, mNiTriShape.trafo); | ||||
|         mNiTriShape.trafo.scale = 3; | ||||
|         copy(mTransform, mNiTriShape2.trafo); | ||||
|         mNiTriShape2.trafo.scale = 3; | ||||
|         mNiTriShape2.parent = &mNiNode; | ||||
|         mNiTriShape2.controller = Nif::ControllerPtr(&mController); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ | ||||
|             Nif::NodePtr(&mNiTriShape), | ||||
|             Nif::NodePtr(&mNiTriShape2), | ||||
|         })); | ||||
|         mNiNode.trafo.scale = 4; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(1, 2, 3), btVector3(4, 2, 3), btVector3(4, 4.632747650146484375, 1.56172335147857666015625)); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true)); | ||||
|         mesh->setLocalScaling(btVector3(1, 1, 1)); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false)); | ||||
|         triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1)); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> mesh2(new Resource::TriangleMeshShape(triangles2.release(), true)); | ||||
|         mesh2->setLocalScaling(btVector3(12, 12, 12)); | ||||
| 
 | ||||
|         std::unique_ptr<btCompoundShape> shape(new btCompoundShape); | ||||
|         shape->addChildShape(mResultTransform2, mesh2.release()); | ||||
|         shape->addChildShape(btTransform::getIdentity(), mesh.release()); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = shape.release(); | ||||
|         expected.mAnimatedShapes = {{-1, 0}}; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_root_avoid_node_and_tri_shape_child_node_should_return_shape_with_null_collision_shape) | ||||
|     { | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
|         mNiNode.recType = Nif::RC_AvoidNode; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_should_return_shape_with_null_collision_shape) | ||||
|     { | ||||
|         mNiTriShape.data = Nif::NiTriShapeDataPtr(nullptr); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_triangles_should_return_shape_with_null_collision_shape) | ||||
|     { | ||||
|         mNiTriShape.data->triangles.clear(); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape) | ||||
|     { | ||||
|         mNiStringExtraData.string = "NC___"; | ||||
|         mNiStringExtraData.recType = Nif::RC_NiStringExtraData; | ||||
|         mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape) | ||||
|     { | ||||
|         mNiStringExtraData.extra = Nif::ExtraPtr(&mNiStringExtraData2); | ||||
|         mNiStringExtraData2.string = "NC___"; | ||||
|         mNiStringExtraData2.recType = Nif::RC_NiStringExtraData; | ||||
|         mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_mrk_should_return_shape_with_null_collision_shape) | ||||
|     { | ||||
|         mNiStringExtraData.string = "MRK"; | ||||
|         mNiStringExtraData.recType = Nif::RC_NiStringExtraData; | ||||
|         mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData); | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         Resource::BulletShape expected; | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| 
 | ||||
|     TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_mrk_and_other_collision_node_should_return_shape_with_triangle_mesh_shape_with_all_meshes) | ||||
|     { | ||||
|         mNiStringExtraData.string = "MRK"; | ||||
|         mNiStringExtraData.recType = Nif::RC_NiStringExtraData; | ||||
|         mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData); | ||||
|         mNiNode3.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)})); | ||||
|         mNiNode3.recType = Nif::RC_RootCollisionNode; | ||||
|         mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(nullptr), Nif::NodePtr(&mNiNode3)})); | ||||
|         mNiNode2.recType = Nif::RC_NiNode; | ||||
|         mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiNode2)})); | ||||
|         mNiNode.recType = Nif::RC_NiNode; | ||||
| 
 | ||||
|         EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1)); | ||||
|         EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode)); | ||||
|         EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif")); | ||||
|         const auto result = mLoader.load(mNifFile); | ||||
| 
 | ||||
|         std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false)); | ||||
|         triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0)); | ||||
|         Resource::BulletShape expected; | ||||
|         expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true); | ||||
| 
 | ||||
|         EXPECT_EQ(*result, expected); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										515
									
								
								cmake/FindGMock.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										515
									
								
								cmake/FindGMock.cmake
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,515 @@ | |||
| # Get the Google C++ Mocking Framework. | ||||
| # (This file is almost an copy of the original FindGTest.cmake file, | ||||
| #  altered to download and compile GMock and GTest if not found | ||||
| #  in GMOCK_ROOT or GTEST_ROOT respectively, | ||||
| #  feel free to use it as it is or modify it for your own needs.) | ||||
| # | ||||
| # Defines the following variables: | ||||
| # | ||||
| #   GMOCK_FOUND - Found or got the Google Mocking framework | ||||
| #   GTEST_FOUND - Found or got the Google Testing framework | ||||
| #   GMOCK_INCLUDE_DIRS - GMock include directory | ||||
| #   GTEST_INCLUDE_DIRS - GTest include direcotry | ||||
| # | ||||
| # Also defines the library variables below as normal variables | ||||
| # | ||||
| #   GMOCK_BOTH_LIBRARIES - Both libgmock & libgmock_main | ||||
| #   GMOCK_LIBRARIES - libgmock | ||||
| #   GMOCK_MAIN_LIBRARIES - libgmock-main | ||||
| # | ||||
| #   GTEST_BOTH_LIBRARIES - Both libgtest & libgtest_main | ||||
| #   GTEST_LIBRARIES - libgtest | ||||
| #   GTEST_MAIN_LIBRARIES - libgtest_main | ||||
| # | ||||
| # Accepts the following variables as input: | ||||
| # | ||||
| #   GMOCK_ROOT - The root directory of the gmock install prefix | ||||
| #   GTEST_ROOT - The root directory of the gtest install prefix | ||||
| #   GMOCK_SRC_DIR -The directory of the gmock sources | ||||
| #   GMOCK_VER - The version of the gmock sources to be downloaded | ||||
| # | ||||
| #----------------------- | ||||
| # Example Usage: | ||||
| # | ||||
| #    set(GMOCK_ROOT "~/gmock") | ||||
| #    find_package(GMock REQUIRED) | ||||
| #    include_directories(${GMOCK_INCLUDE_DIRS}) | ||||
| # | ||||
| #    add_executable(foo foo.cc) | ||||
| #    target_link_libraries(foo ${GMOCK_BOTH_LIBRARIES}) | ||||
| # | ||||
| #============================================================================= | ||||
| # Copyright (c) 2016 Michel Estermann | ||||
| # Copyright (c) 2016 Kamil Strzempowicz | ||||
| # Copyright (c) 2011 Matej Svec | ||||
| # | ||||
| # CMake - Cross Platform Makefile Generator | ||||
| # Copyright 2000-2016 Kitware, Inc. | ||||
| # Copyright 2000-2011 Insight Software Consortium | ||||
| # All rights reserved. | ||||
| # | ||||
| # Redistribution and use in source and binary forms, with or without | ||||
| # modification, are permitted provided that the following conditions | ||||
| # are met: | ||||
| # | ||||
| # * Redistributions of source code must retain the above copyright | ||||
| #   notice, this list of conditions and the following disclaimer. | ||||
| # | ||||
| # * Redistributions in binary form must reproduce the above copyright | ||||
| #   notice, this list of conditions and the following disclaimer in the | ||||
| #   documentation and/or other materials provided with the distribution. | ||||
| # | ||||
| # * Neither the names of Kitware, Inc., the Insight Software Consortium, | ||||
| #   nor the names of their contributors may be used to endorse or promote | ||||
| #   products derived from this software without specific prior written | ||||
| #   permission. | ||||
| # | ||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| # | ||||
| # ------------------------------------------------------------------------------ | ||||
| # | ||||
| # The above copyright and license notice applies to distributions of | ||||
| # CMake in source and binary form.  Some source files contain additional | ||||
| # notices of original copyright by their contributors; see each source | ||||
| # for details.  Third-party software packages supplied with CMake under | ||||
| # compatible licenses provide their own copyright notices documented in | ||||
| # corresponding subdirectories. | ||||
| # | ||||
| # ------------------------------------------------------------------------------ | ||||
| # | ||||
| # CMake was initially developed by Kitware with the following sponsorship: | ||||
| # | ||||
| #  * National Library of Medicine at the National Institutes of Health | ||||
| #    as part of the Insight Segmentation and Registration Toolkit (ITK). | ||||
| # | ||||
| #  * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel | ||||
| #    Visualization Initiative. | ||||
| # | ||||
| #  * National Alliance for Medical Image Computing (NAMIC) is funded by the | ||||
| #    National Institutes of Health through the NIH Roadmap for Medical Research, | ||||
| #    Grant U54 EB005149. | ||||
| # | ||||
| #  * Kitware, Inc. | ||||
| #============================================================================= | ||||
| # Thanks to Daniel Blezek <blezek@gmail.com> for the GTEST_ADD_TESTS code | ||||
| 
 | ||||
| function(gtest_add_tests executable extra_args) | ||||
|     if(NOT ARGN) | ||||
|         message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS") | ||||
|     endif() | ||||
|     if(ARGN STREQUAL "AUTO") | ||||
|         # obtain sources used for building that executable | ||||
|         get_property(ARGN TARGET ${executable} PROPERTY SOURCES) | ||||
|     endif() | ||||
|     set(gtest_case_name_regex ".*\\( *([A-Za-z_0-9]+) *, *([A-Za-z_0-9]+) *\\).*") | ||||
|     set(gtest_test_type_regex "(TYPED_TEST|TEST_?[FP]?)") | ||||
|     foreach(source ${ARGN}) | ||||
|         file(READ "${source}" contents) | ||||
|         string(REGEX MATCHALL "${gtest_test_type_regex} *\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents}) | ||||
|         foreach(hit ${found_tests}) | ||||
|             string(REGEX MATCH "${gtest_test_type_regex}" test_type ${hit}) | ||||
| 
 | ||||
|             # Parameterized tests have a different signature for the filter | ||||
|             if("x${test_type}" STREQUAL "xTEST_P") | ||||
|                 string(REGEX REPLACE ${gtest_case_name_regex} "*/\\1.\\2/*" test_name ${hit}) | ||||
|             elseif("x${test_type}" STREQUAL "xTEST_F" OR "x${test_type}" STREQUAL "xTEST") | ||||
|                 string(REGEX REPLACE ${gtest_case_name_regex} "\\1.\\2" test_name ${hit}) | ||||
|             elseif("x${test_type}" STREQUAL "xTYPED_TEST") | ||||
|                 string(REGEX REPLACE ${gtest_case_name_regex} "\\1/*.\\2" test_name ${hit}) | ||||
|             else() | ||||
|                 message(WARNING "Could not parse GTest ${hit} for adding to CTest.") | ||||
|                 continue() | ||||
|             endif() | ||||
|             add_test(NAME ${test_name} COMMAND ${executable} --gtest_filter=${test_name} ${extra_args}) | ||||
|         endforeach() | ||||
|     endforeach() | ||||
| endfunction() | ||||
| 
 | ||||
| function(_append_debugs _endvar _library) | ||||
|     if(${_library} AND ${_library}_DEBUG) | ||||
|         set(_output optimized ${${_library}} debug ${${_library}_DEBUG}) | ||||
|     else() | ||||
|         set(_output ${${_library}}) | ||||
|     endif() | ||||
|     set(${_endvar} ${_output} PARENT_SCOPE) | ||||
| endfunction() | ||||
| 
 | ||||
| function(_gmock_find_library _name) | ||||
|     find_library(${_name} | ||||
|         NAMES ${ARGN} | ||||
|         HINTS | ||||
|         ENV GMOCK_ROOT | ||||
|         ${GMOCK_ROOT} | ||||
|         PATH_SUFFIXES ${_gmock_libpath_suffixes} | ||||
|         ) | ||||
|     mark_as_advanced(${_name}) | ||||
| endfunction() | ||||
| 
 | ||||
| function(_gtest_find_library _name) | ||||
|     find_library(${_name} | ||||
|         NAMES ${ARGN} | ||||
|         HINTS | ||||
|         ENV GTEST_ROOT | ||||
|         ${GTEST_ROOT} | ||||
|         PATH_SUFFIXES ${_gtest_libpath_suffixes} | ||||
|         ) | ||||
|     mark_as_advanced(${_name}) | ||||
| endfunction() | ||||
| 
 | ||||
| if(NOT DEFINED GMOCK_MSVC_SEARCH) | ||||
|     set(GMOCK_MSVC_SEARCH MD) | ||||
| endif() | ||||
| 
 | ||||
| set(_gmock_libpath_suffixes lib) | ||||
| set(_gtest_libpath_suffixes lib) | ||||
| if(MSVC) | ||||
|     if(GMOCK_MSVC_SEARCH STREQUAL "MD") | ||||
|         list(APPEND _gmock_libpath_suffixes | ||||
|             msvc/gmock-md/Debug | ||||
|             msvc/gmock-md/Release) | ||||
|         list(APPEND _gtest_libpath_suffixes | ||||
|             msvc/gtest-md/Debug | ||||
|             msvc/gtest-md/Release) | ||||
|     elseif(GMOCK_MSVC_SEARCH STREQUAL "MT") | ||||
|         list(APPEND _gmock_libpath_suffixes | ||||
|             msvc/gmock/Debug | ||||
|             msvc/gmock/Release) | ||||
|         list(APPEND _gtest_libpath_suffixes | ||||
|             msvc/gtest/Debug | ||||
|             msvc/gtest/Release) | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| find_path(GMOCK_INCLUDE_DIR gmock/gmock.h | ||||
|     HINTS | ||||
|     $ENV{GMOCK_ROOT}/include | ||||
|     ${GMOCK_ROOT}/include | ||||
|     ) | ||||
| mark_as_advanced(GMOCK_INCLUDE_DIR) | ||||
| 
 | ||||
| find_path(GTEST_INCLUDE_DIR gtest/gtest.h | ||||
|     HINTS | ||||
|     $ENV{GTEST_ROOT}/include | ||||
|     ${GTEST_ROOT}/include | ||||
|     ) | ||||
| mark_as_advanced(GTEST_INCLUDE_DIR) | ||||
| 
 | ||||
| if(MSVC AND GMOCK_MSVC_SEARCH STREQUAL "MD") | ||||
|     # The provided /MD project files for Google Mock add -md suffixes to the | ||||
|     # library names. | ||||
|     _gmock_find_library(GMOCK_LIBRARY gmock-md gmock) | ||||
|     _gmock_find_library(GMOCK_LIBRARY_DEBUG gmock-mdd gmockd) | ||||
|     _gmock_find_library(GMOCK_MAIN_LIBRARY gmock_main-md gmock_main) | ||||
|     _gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_main-mdd gmock_maind) | ||||
| 
 | ||||
|     _gtest_find_library(GTEST_LIBRARY gtest-md gtest) | ||||
|     _gtest_find_library(GTEST_LIBRARY_DEBUG gtest-mdd gtestd) | ||||
|     _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main-md gtest_main) | ||||
|     _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind) | ||||
| else() | ||||
|     _gmock_find_library(GMOCK_LIBRARY gmock) | ||||
|     _gmock_find_library(GMOCK_LIBRARY_DEBUG gmockd) | ||||
|     _gmock_find_library(GMOCK_MAIN_LIBRARY gmock_main) | ||||
|     _gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_maind) | ||||
| 
 | ||||
|     _gtest_find_library(GTEST_LIBRARY gtest) | ||||
|     _gtest_find_library(GTEST_LIBRARY_DEBUG gtestd) | ||||
|     _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main) | ||||
|     _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind) | ||||
| endif() | ||||
| 
 | ||||
| if(NOT TARGET GTest::GTest) | ||||
|     add_library(GTest::GTest UNKNOWN IMPORTED) | ||||
| endif() | ||||
| if(NOT TARGET GTest::Main) | ||||
|     add_library(GTest::Main UNKNOWN IMPORTED) | ||||
| endif() | ||||
| 
 | ||||
| if(NOT TARGET GMock::GMock) | ||||
|     add_library(GMock::GMock UNKNOWN IMPORTED) | ||||
| endif() | ||||
| 
 | ||||
| if(NOT TARGET GMock::Main) | ||||
|     add_library(GMock::Main UNKNOWN IMPORTED) | ||||
| endif() | ||||
| 
 | ||||
| set(GMOCK_LIBRARY_EXISTS OFF) | ||||
| set(GTEST_LIBRARY_EXISTS OFF) | ||||
| 
 | ||||
| if(EXISTS "${GMOCK_LIBRARY}" OR EXISTS "${GMOCK_LIBRARY_DEBUG}" AND GMOCK_INCLUDE_DIR) | ||||
|     set(GMOCK_LIBRARY_EXISTS ON) | ||||
| endif() | ||||
| 
 | ||||
| if(EXISTS "${GTEST_LIBRARY}" OR EXISTS "${GTEST_LIBRARY_DEBUG}" AND GTEST_INCLUDE_DIR) | ||||
|     set(GTEST_LIBRARY_EXISTS ON) | ||||
| endif() | ||||
| 
 | ||||
| if(NOT (${GMOCK_LIBRARY_EXISTS} AND ${GTEST_LIBRARY_EXISTS})) | ||||
| 
 | ||||
|     include(ExternalProject) | ||||
| 
 | ||||
|     if(GTEST_USE_STATIC_LIBS) | ||||
|         set(GTEST_CMAKE_ARGS -Dgtest_force_shared_crt:BOOL=ON -DBUILD_SHARED_LIBS=OFF) | ||||
|         if(BUILD_SHARED_LIBS) | ||||
|             list(APPEND GTEST_CMAKE_ARGS | ||||
|                 -DCMAKE_POSITION_INDEPENDENT_CODE=ON | ||||
|                 -Dgtest_hide_internal_symbols=ON | ||||
|                 -DCMAKE_CXX_VISIBILITY_PRESET=hidden | ||||
|                 -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON | ||||
|                 -DCMAKE_POLICY_DEFAULT_CMP0063=NEW | ||||
|             ) | ||||
|         endif() | ||||
|         set(GTEST_LIBRARY_PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX}) | ||||
|     else() | ||||
|         set(GTEST_CMAKE_ARGS -DBUILD_SHARED_LIBS=ON) | ||||
|         set(GTEST_LIBRARY_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) | ||||
|     endif() | ||||
|     if(WIN32) | ||||
|         list(APPEND GTEST_CMAKE_ARGS -Dgtest_disable_pthreads=ON) | ||||
|     endif() | ||||
| 
 | ||||
|     if("${GMOCK_SRC_DIR}" STREQUAL "") | ||||
|         message(STATUS "Downloading GMock / GTest version ${GMOCK_VER} from git") | ||||
|         if("${GMOCK_VER}" STREQUAL "1.6.0" OR "${GMOCK_VER}" STREQUAL "1.7.0") | ||||
|             set(GTEST_BIN_DIR "${GMOCK_ROOT}/src/gtest-build") | ||||
|             set(GTEST_LIBRARY "${GTEST_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             set(GTEST_MAIN_LIBRARY "${GTEST_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             mark_as_advanced(GTEST_LIBRARY) | ||||
|             mark_as_advanced(GTEST_MAIN_LIBRARY) | ||||
| 
 | ||||
|             externalproject_add( | ||||
|                 gtest | ||||
|                 GIT_REPOSITORY "https://github.com/google/googletest.git" | ||||
|                 GIT_TAG "release-${GMOCK_VER}" | ||||
|                 PREFIX ${GMOCK_ROOT} | ||||
|                 INSTALL_COMMAND "" | ||||
|                 LOG_DOWNLOAD ON | ||||
|                 LOG_CONFIGURE ON | ||||
|                 LOG_BUILD ON | ||||
|                 CMAKE_ARGS | ||||
|                     ${GTEST_CMAKE_ARGS} | ||||
|                 BINARY_DIR ${GTEST_BIN_DIR} | ||||
|                 BUILD_BYPRODUCTS | ||||
|                     "${GTEST_LIBRARY}" | ||||
|                     "${GTEST_MAIN_LIBRARY}" | ||||
|             ) | ||||
| 
 | ||||
|             set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build") | ||||
|             set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             mark_as_advanced(GMOCK_LIBRARY) | ||||
|             mark_as_advanced(GMOCK_MAIN_LIBRARY) | ||||
| 
 | ||||
|             externalproject_add( | ||||
|                 gmock | ||||
|                 GIT_REPOSITORY "https://github.com/google/googlemock.git" | ||||
|                 GIT_TAG "release-${GMOCK_VER}" | ||||
|                 PREFIX ${GMOCK_ROOT} | ||||
|                 INSTALL_COMMAND "" | ||||
|                 LOG_DOWNLOAD ON | ||||
|                 LOG_CONFIGURE ON | ||||
|                 LOG_BUILD ON | ||||
|                 CMAKE_ARGS | ||||
|                     ${GTEST_CMAKE_ARGS} | ||||
|                 BINARY_DIR ${GMOCK_BIN_DIR} | ||||
|                 BUILD_BYPRODUCTS | ||||
|                     "${GMOCK_LIBRARY}" | ||||
|                     "${GMOCK_MAIN_LIBRARY}" | ||||
|             ) | ||||
| 
 | ||||
|             add_dependencies(gmock gtest) | ||||
| 
 | ||||
|             add_dependencies(GTest::GTest gtest) | ||||
|             add_dependencies(GTest::Main gtest) | ||||
|             add_dependencies(GMock::GMock gmock) | ||||
|             add_dependencies(GMock::Main gmock) | ||||
| 
 | ||||
|             externalproject_get_property(gtest source_dir) | ||||
|             set(GTEST_INCLUDE_DIR "${source_dir}/include") | ||||
|             mark_as_advanced(GTEST_INCLUDE_DIR) | ||||
|             externalproject_get_property(gmock source_dir) | ||||
|             set(GMOCK_INCLUDE_DIR "${source_dir}/include") | ||||
|             mark_as_advanced(GMOCK_INCLUDE_DIR) | ||||
|         else() #1.8.0 | ||||
|             set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build") | ||||
|             set(GTEST_LIBRARY "${GMOCK_BIN_DIR}/googlemock/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             set(GTEST_MAIN_LIBRARY "${GMOCK_BIN_DIR}/googlemock/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/googlemock/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/googlemock/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|             mark_as_advanced(GTEST_LIBRARY) | ||||
|             mark_as_advanced(GTEST_MAIN_LIBRARY) | ||||
|             mark_as_advanced(GMOCK_LIBRARY) | ||||
|             mark_as_advanced(GMOCK_MAIN_LIBRARY) | ||||
| 
 | ||||
|             externalproject_add( | ||||
|                 gmock | ||||
|                 GIT_REPOSITORY "https://github.com/google/googletest.git" | ||||
|                 GIT_TAG "release-${GMOCK_VER}" | ||||
|                 PREFIX ${GMOCK_ROOT} | ||||
|                 INSTALL_COMMAND "" | ||||
|                 LOG_DOWNLOAD ON | ||||
|                 LOG_CONFIGURE ON | ||||
|                 LOG_BUILD ON | ||||
|                 CMAKE_ARGS | ||||
|                     ${GTEST_CMAKE_ARGS} | ||||
|                 BINARY_DIR "${GMOCK_BIN_DIR}" | ||||
|                 BUILD_BYPRODUCTS | ||||
|                     "${GTEST_LIBRARY}" | ||||
|                     "${GTEST_MAIN_LIBRARY}" | ||||
|                     "${GMOCK_LIBRARY}" | ||||
|                     "${GMOCK_MAIN_LIBRARY}" | ||||
|             ) | ||||
| 
 | ||||
|             add_dependencies(GTest::GTest gmock) | ||||
|             add_dependencies(GTest::Main gmock) | ||||
|             add_dependencies(GMock::GMock gmock) | ||||
|             add_dependencies(GMock::Main gmock) | ||||
| 
 | ||||
|             externalproject_get_property(gmock source_dir) | ||||
|             set(GTEST_INCLUDE_DIR "${source_dir}/googletest/include") | ||||
|             set(GMOCK_INCLUDE_DIR "${source_dir}/googlemock/include") | ||||
|             mark_as_advanced(GMOCK_INCLUDE_DIR) | ||||
|             mark_as_advanced(GTEST_INCLUDE_DIR) | ||||
|         endif() | ||||
| 
 | ||||
|         # Prevent CMake from complaining about these directories missing when the libgtest/libgmock targets get used as dependencies | ||||
|         file(MAKE_DIRECTORY ${GTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR}) | ||||
|     else() | ||||
|         message(STATUS "Building Gmock / Gtest from dir ${GMOCK_SRC_DIR}") | ||||
| 
 | ||||
|         set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build") | ||||
|         set(GTEST_LIBRARY "${GMOCK_BIN_DIR}/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|         set(GTEST_MAIN_LIBRARY "${GMOCK_BIN_DIR}/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|         set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|         set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}") | ||||
|         mark_as_advanced(GTEST_LIBRARY) | ||||
|         mark_as_advanced(GTEST_MAIN_LIBRARY) | ||||
|         mark_as_advanced(GMOCK_LIBRARY) | ||||
|         mark_as_advanced(GMOCK_MAIN_LIBRARY) | ||||
| 
 | ||||
|         if(EXISTS "${GMOCK_SRC_DIR}/gtest/include/gtest/gtest.h") | ||||
|             set(GTEST_INCLUDE_DIR "${GMOCK_SRC_DIR}/gtest/include") | ||||
|             mark_as_advanced(GTEST_INCLUDE_DIR) | ||||
|         endif() | ||||
|         if(EXISTS "${GMOCK_SRC_DIR}/include/gmock/gmock.h") | ||||
|             set(GMOCK_INCLUDE_DIR "${GMOCK_SRC_DIR}/include") | ||||
|             mark_as_advanced(GMOCK_INCLUDE_DIR) | ||||
|         elseif(EXISTS "${GMOCK_SRC_DIR}/../../include/gmock/gmock.h") | ||||
|             set(GMOCK_INCLUDE_DIR "${GMOCK_SRC_DIR}/../../include") | ||||
|             if(IS_ABSOLUTE "${GMOCK_INCLUDE_DIR}") | ||||
|                 get_filename_component(GMOCK_INCLUDE_DIR "${GMOCK_INCLUDE_DIR}" ABSOLUTE) | ||||
|             endif() | ||||
|             mark_as_advanced(GMOCK_INCLUDE_DIR) | ||||
|         endif() | ||||
| 
 | ||||
|         externalproject_add( | ||||
|             gmock | ||||
|             SOURCE_DIR ${GMOCK_SRC_DIR} | ||||
|             PREFIX ${GMOCK_ROOT} | ||||
|             INSTALL_COMMAND "" | ||||
|             LOG_DOWNLOAD ON | ||||
|             LOG_CONFIGURE ON | ||||
|             LOG_BUILD ON | ||||
|             CMAKE_ARGS | ||||
|                 ${GTEST_CMAKE_ARGS} | ||||
|             BINARY_DIR "${GMOCK_BIN_DIR}" | ||||
|             BUILD_BYPRODUCTS | ||||
|                 "${GTEST_LIBRARY}" | ||||
|                 "${GTEST_MAIN_LIBRARY}" | ||||
|                 "${GMOCK_LIBRARY}" | ||||
|                 "${GMOCK_MAIN_LIBRARY}" | ||||
|         ) | ||||
| 
 | ||||
|         add_dependencies(GTest::GTest gmock) | ||||
|         add_dependencies(GTest::Main gmock) | ||||
|         add_dependencies(GMock::GMock gmock) | ||||
|         add_dependencies(GMock::Main gmock) | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| include(FindPackageHandleStandardArgs) | ||||
| find_package_handle_standard_args(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY) | ||||
| find_package_handle_standard_args(GMock DEFAULT_MSG GMOCK_LIBRARY GMOCK_INCLUDE_DIR GMOCK_MAIN_LIBRARY) | ||||
| 
 | ||||
| include(CMakeFindDependencyMacro) | ||||
| find_dependency(Threads) | ||||
| 
 | ||||
| set_target_properties(GTest::GTest PROPERTIES | ||||
|     INTERFACE_LINK_LIBRARIES "Threads::Threads" | ||||
|     IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" | ||||
|     IMPORTED_LOCATION "${GTEST_LIBRARY}" | ||||
|     ) | ||||
| 
 | ||||
| if(GTEST_INCLUDE_DIR) | ||||
|     set_target_properties(GTest::GTest PROPERTIES | ||||
|         INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}" | ||||
|         INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}" | ||||
|     ) | ||||
| endif() | ||||
| 
 | ||||
| set_target_properties(GTest::Main PROPERTIES | ||||
|     INTERFACE_LINK_LIBRARIES "GTest::GTest" | ||||
|     IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" | ||||
|     IMPORTED_LOCATION "${GTEST_MAIN_LIBRARY}") | ||||
| 
 | ||||
| set_target_properties(GMock::GMock PROPERTIES | ||||
|     INTERFACE_LINK_LIBRARIES "Threads::Threads" | ||||
|     IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" | ||||
|     IMPORTED_LOCATION "${GMOCK_LIBRARY}") | ||||
| 
 | ||||
| if(GMOCK_INCLUDE_DIR) | ||||
|     set_target_properties(GMock::GMock PROPERTIES | ||||
|         INTERFACE_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIR}" | ||||
|         INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIR}" | ||||
|     ) | ||||
|     if(GMOCK_VER VERSION_LESS "1.7") | ||||
|         # GMock 1.6 still has GTest as an external link-time dependency, | ||||
|         # so just specify it on the link interface. | ||||
|         set_property(TARGET GMock::GMock APPEND PROPERTY | ||||
|             INTERFACE_LINK_LIBRARIES GTest::GTest) | ||||
|     elseif(GTEST_INCLUDE_DIR) | ||||
|         # GMock 1.7 and beyond doesn't have it as a link-time dependency anymore, | ||||
|         # so merge it's compile-time interface (include dirs) with ours. | ||||
|         set_property(TARGET GMock::GMock APPEND PROPERTY | ||||
|             INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}") | ||||
|         set_property(TARGET GMock::GMock APPEND PROPERTY | ||||
|             INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}") | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| set_target_properties(GMock::Main PROPERTIES | ||||
|     INTERFACE_LINK_LIBRARIES "GMock::GMock" | ||||
|     IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" | ||||
|     IMPORTED_LOCATION "${GMOCK_MAIN_LIBRARY}") | ||||
| 
 | ||||
| if(GTEST_FOUND) | ||||
|     set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR}) | ||||
|     set(GTEST_LIBRARIES GTest::GTest) | ||||
|     set(GTEST_MAIN_LIBRARIES GTest::Main) | ||||
|     set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) | ||||
|     if(VERBOSE) | ||||
|         message(STATUS "GTest includes: ${GTEST_INCLUDE_DIRS}") | ||||
|         message(STATUS "GTest libs: ${GTEST_BOTH_LIBRARIES}") | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| if(GMOCK_FOUND) | ||||
|     set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR}) | ||||
|     set(GMOCK_LIBRARIES GMock::GMock) | ||||
|     set(GMOCK_MAIN_LIBRARIES GMock::Main) | ||||
|     set(GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARIES} ${GMOCK_MAIN_LIBRARIES}) | ||||
|     if(VERBOSE) | ||||
|         message(STATUS "GMock includes: ${GMOCK_INCLUDE_DIRS}") | ||||
|         message(STATUS "GMock libs: ${GMOCK_BOTH_LIBRARIES}") | ||||
|     endif() | ||||
| endif() | ||||
|  | @ -242,6 +242,11 @@ if (UNIX AND NOT APPLE) | |||
| target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) | ||||
| endif() | ||||
| 
 | ||||
| if (BUILD_WITH_CODE_COVERAGE) | ||||
|     add_definitions(--coverage) | ||||
|     target_link_libraries(components gcov) | ||||
| endif() | ||||
| 
 | ||||
| 
 | ||||
| # Make the variable accessible for other subdirectories | ||||
| set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE) | ||||
|  |  | |||
							
								
								
									
										34
									
								
								components/bullethelpers/processtrianglecallback.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								components/bullethelpers/processtrianglecallback.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| #ifndef OPENMW_COMPONENTS_BULLETHELPERS_PROCESSTRIANGLECALLBACK_H | ||||
| #define OPENMW_COMPONENTS_BULLETHELPERS_PROCESSTRIANGLECALLBACK_H | ||||
| 
 | ||||
| #include <BulletCollision/CollisionShapes/btTriangleCallback.h> | ||||
| 
 | ||||
| #include <type_traits> | ||||
| 
 | ||||
| namespace BulletHelpers | ||||
| { | ||||
|     template <class Impl> | ||||
|     class ProcessTriangleCallback : public btTriangleCallback | ||||
|     { | ||||
|     public: | ||||
|         ProcessTriangleCallback(Impl impl) | ||||
|             : mImpl(std::move(impl)) | ||||
|         {} | ||||
| 
 | ||||
|         void processTriangle(btVector3* triangle, int partId, int triangleIndex) override final | ||||
|         { | ||||
|             return mImpl(triangle, partId, triangleIndex); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         Impl mImpl; | ||||
|     }; | ||||
| 
 | ||||
|     template <class Impl> | ||||
|     ProcessTriangleCallback<typename std::decay<Impl>::type> makeProcessTriangleCallback(Impl&& impl) | ||||
|     { | ||||
|         return ProcessTriangleCallback<typename std::decay<Impl>::type>(std::forward<Impl>(impl)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -14,7 +14,30 @@ | |||
| namespace Nif | ||||
| { | ||||
| 
 | ||||
| class NIFFile | ||||
| struct File | ||||
| { | ||||
|     virtual ~File() = default; | ||||
| 
 | ||||
|     virtual void fail(const std::string &msg) const = 0; | ||||
| 
 | ||||
|     virtual void warn(const std::string &msg) const = 0; | ||||
| 
 | ||||
|     virtual Record *getRecord(size_t index) const = 0; | ||||
| 
 | ||||
|     virtual size_t numRecords() const = 0; | ||||
| 
 | ||||
|     virtual Record *getRoot(size_t index = 0) const = 0; | ||||
| 
 | ||||
|     virtual size_t numRoots() const = 0; | ||||
| 
 | ||||
|     virtual void setUseSkinning(bool skinning) = 0; | ||||
| 
 | ||||
|     virtual bool getUseSkinning() const = 0; | ||||
| 
 | ||||
|     virtual std::string getFilename() const = 0; | ||||
| }; | ||||
| 
 | ||||
| class NIFFile final : public File | ||||
| { | ||||
|     enum NIFVersion { | ||||
|         VER_MW    = 0x04000002    // Morrowind NIFs
 | ||||
|  | @ -48,14 +71,14 @@ class NIFFile | |||
| 
 | ||||
| public: | ||||
|     /// Used if file parsing fails
 | ||||
|     void fail(const std::string &msg) const | ||||
|     void fail(const std::string &msg) const override | ||||
|     { | ||||
|         std::string err = " NIFFile Error: " + msg; | ||||
|         err += "\nFile: " + filename; | ||||
|         throw std::runtime_error(err); | ||||
|     } | ||||
|     /// Used when something goes wrong, but not catastrophically so
 | ||||
|     void warn(const std::string &msg) const | ||||
|     void warn(const std::string &msg) const override | ||||
|     { | ||||
|         std::cerr << " NIFFile Warning: " << msg <<std::endl | ||||
|                   << "File: " << filename <<std::endl; | ||||
|  | @ -66,31 +89,31 @@ public: | |||
|     ~NIFFile(); | ||||
| 
 | ||||
|     /// Get a given record
 | ||||
|     Record *getRecord(size_t index) const | ||||
|     Record *getRecord(size_t index) const override | ||||
|     { | ||||
|         Record *res = records.at(index); | ||||
|         return res; | ||||
|     } | ||||
|     /// Number of records
 | ||||
|     size_t numRecords() const { return records.size(); } | ||||
|     size_t numRecords() const override { return records.size(); } | ||||
| 
 | ||||
|     /// Get a given root
 | ||||
|     Record *getRoot(size_t index=0) const | ||||
|     Record *getRoot(size_t index=0) const override | ||||
|     { | ||||
|         Record *res = roots.at(index); | ||||
|         return res; | ||||
|     } | ||||
|     /// Number of roots
 | ||||
|     size_t numRoots() const { return roots.size(); } | ||||
|     size_t numRoots() const override { return roots.size(); } | ||||
| 
 | ||||
|     /// Set whether there is skinning contained in this NIF file.
 | ||||
|     /// @note This is just a hint for users of the NIF file and has no effect on the loading procedure.
 | ||||
|     void setUseSkinning(bool skinning); | ||||
|     void setUseSkinning(bool skinning) override; | ||||
| 
 | ||||
|     bool getUseSkinning() const; | ||||
|     bool getUseSkinning() const override; | ||||
| 
 | ||||
|     /// Get the name of the file
 | ||||
|     std::string getFilename() const { return filename; } | ||||
|     std::string getFilename() const override { return filename; } | ||||
| }; | ||||
| typedef std::shared_ptr<const Nif::NIFFile> NIFFilePtr; | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,6 +23,8 @@ class RecordPtrT | |||
| public: | ||||
|     RecordPtrT() : index(-2) {} | ||||
| 
 | ||||
|     RecordPtrT(X* ptr) : ptr(ptr) {} | ||||
| 
 | ||||
|     /// Read the index from the nif
 | ||||
|     void read(NIFStream *nif) | ||||
|     { | ||||
|  | @ -87,6 +89,12 @@ class RecordListT | |||
|     std::vector<Ptr> list; | ||||
| 
 | ||||
| public: | ||||
|     RecordListT() = default; | ||||
| 
 | ||||
|     RecordListT(std::vector<Ptr> list) | ||||
|         : list(std::move(list)) | ||||
|     {} | ||||
| 
 | ||||
|     void read(NIFStream *nif) | ||||
|     { | ||||
|         int len = nif->getInt(); | ||||
|  |  | |||
|  | @ -47,8 +47,8 @@ namespace NifBullet | |||
| { | ||||
| 
 | ||||
| BulletNifLoader::BulletNifLoader() | ||||
|     : mCompoundShape(NULL) | ||||
|     , mStaticMesh(NULL) | ||||
|     : mCompoundShape() | ||||
|     , mStaticMesh() | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  | @ -56,20 +56,20 @@ BulletNifLoader::~BulletNifLoader() | |||
| { | ||||
| } | ||||
| 
 | ||||
| osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr& nif) | ||||
| osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif) | ||||
| { | ||||
|     mShape = new Resource::BulletShape; | ||||
| 
 | ||||
|     mCompoundShape = NULL; | ||||
|     mStaticMesh = NULL; | ||||
| 
 | ||||
|     if (nif->numRoots() < 1) | ||||
|     if (nif.numRoots() < 1) | ||||
|     { | ||||
|         warn("Found no root nodes in NIF."); | ||||
|         return mShape; | ||||
|     } | ||||
| 
 | ||||
|     Nif::Record *r = nif->getRoot(0); | ||||
|     Nif::Record *r = nif.getRoot(0); | ||||
|     assert(r != NULL); | ||||
| 
 | ||||
|     Nif::Node *node = dynamic_cast<Nif::Node*>(r); | ||||
|  | @ -84,10 +84,11 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr& | |||
|     { | ||||
|         std::unique_ptr<btCompoundShape> compound (new btCompoundShape); | ||||
| 
 | ||||
|         btBoxShape* boxShape = new btBoxShape(getbtVector(mShape->mCollisionBoxHalfExtents)); | ||||
|         std::unique_ptr<btBoxShape> boxShape(new btBoxShape(getbtVector(mShape->mCollisionBoxHalfExtents))); | ||||
|         btTransform transform = btTransform::getIdentity(); | ||||
|         transform.setOrigin(getbtVector(mShape->mCollisionBoxTranslate)); | ||||
|         compound->addChildShape(transform, boxShape); | ||||
|         compound->addChildShape(transform, boxShape.get()); | ||||
|         boxShape.release(); | ||||
| 
 | ||||
|         mShape->mCollisionShape = compound.release(); | ||||
|         return mShape; | ||||
|  | @ -96,27 +97,32 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::NIFFilePtr& | |||
|     { | ||||
|         // files with the name convention xmodel.nif usually have keyframes stored in a separate file xmodel.kf (see Animation::addAnimSource).
 | ||||
|         // assume all nodes in the file will be animated
 | ||||
|         const bool isAnimated = pathFileNameStartsWithX(nif->getFilename()); | ||||
|         const auto filename = nif.getFilename(); | ||||
|         const bool isAnimated = pathFileNameStartsWithX(filename); | ||||
| 
 | ||||
|         // If the mesh has RootCollisionNode, attached to actual root node, use it as collision mesh
 | ||||
|         const Nif::Node* rootCollisionNode = getCollisionNode(node); | ||||
|         if (rootCollisionNode) | ||||
|             handleNode(nif->getFilename(), rootCollisionNode, 0, false, isAnimated, false); | ||||
|             handleNode(filename, rootCollisionNode, 0, false, isAnimated, false); | ||||
|         else | ||||
|             handleNode(nif->getFilename(), node, 0, true, isAnimated, true); | ||||
|             handleNode(filename, node, 0, true, isAnimated, true); | ||||
| 
 | ||||
|         if (mCompoundShape) | ||||
|         { | ||||
|             mShape->mCollisionShape = mCompoundShape; | ||||
|             if (mStaticMesh) | ||||
|             { | ||||
|                 btTransform trans; | ||||
|                 trans.setIdentity(); | ||||
|                 mCompoundShape->addChildShape(trans, new Resource::TriangleMeshShape(mStaticMesh,true)); | ||||
|                 mCompoundShape->addChildShape(trans, new Resource::TriangleMeshShape(mStaticMesh.get(), true)); | ||||
|                 mStaticMesh.release(); | ||||
|             } | ||||
|             mShape->mCollisionShape = mCompoundShape.release(); | ||||
|         } | ||||
|         else if (mStaticMesh) | ||||
|             mShape->mCollisionShape = new Resource::TriangleMeshShape(mStaticMesh,true); | ||||
|         { | ||||
|             mShape->mCollisionShape = new Resource::TriangleMeshShape(mStaticMesh.get(), true); | ||||
|             mStaticMesh.release(); | ||||
|         } | ||||
| 
 | ||||
|         return mShape; | ||||
|     } | ||||
|  | @ -276,9 +282,9 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, | |||
|     if (isAnimated) | ||||
|     { | ||||
|         if (!mCompoundShape) | ||||
|             mCompoundShape = new btCompoundShape(); | ||||
|             mCompoundShape.reset(new btCompoundShape); | ||||
| 
 | ||||
|         btTriangleMesh* childMesh = new btTriangleMesh(); | ||||
|         std::unique_ptr<btTriangleMesh> childMesh(new btTriangleMesh); | ||||
| 
 | ||||
|         const Nif::NiTriShapeData *data = shape->data.getPtr(); | ||||
| 
 | ||||
|  | @ -296,7 +302,8 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, | |||
|             childMesh->addTriangle(getbtVector(b1), getbtVector(b2), getbtVector(b3)); | ||||
|         } | ||||
| 
 | ||||
|         Resource::TriangleMeshShape* childShape = new Resource::TriangleMeshShape(childMesh,true); | ||||
|         std::unique_ptr<Resource::TriangleMeshShape> childShape(new Resource::TriangleMeshShape(childMesh.get(), true)); | ||||
|         childMesh.release(); | ||||
| 
 | ||||
|         float scale = shape->trafo.scale; | ||||
|         const Nif::Node* parent = shape; | ||||
|  | @ -313,12 +320,13 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, | |||
| 
 | ||||
|         mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); | ||||
| 
 | ||||
|         mCompoundShape->addChildShape(trans, childShape); | ||||
|         mCompoundShape->addChildShape(trans, childShape.get()); | ||||
|         childShape.release(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (!mStaticMesh) | ||||
|             mStaticMesh = new btTriangleMesh(false); | ||||
|             mStaticMesh.reset(new btTriangleMesh(false)); | ||||
| 
 | ||||
|         // Static shape, just transform all vertices into position
 | ||||
|         const Nif::NiTriShapeData *data = shape->data.getPtr(); | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ public: | |||
|         abort(); | ||||
|     } | ||||
| 
 | ||||
|     osg::ref_ptr<Resource::BulletShape> load(const Nif::NIFFilePtr& file); | ||||
|     osg::ref_ptr<Resource::BulletShape> load(const Nif::File& file); | ||||
| 
 | ||||
| private: | ||||
|     bool findBoundingBox(const Nif::Node* node, int flags = 0); | ||||
|  | @ -61,9 +61,9 @@ private: | |||
| 
 | ||||
|     void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated); | ||||
| 
 | ||||
|     btCompoundShape* mCompoundShape; | ||||
|     std::unique_ptr<btCompoundShape> mCompoundShape; | ||||
| 
 | ||||
|     btTriangleMesh* mStaticMesh; | ||||
|     std::unique_ptr<btTriangleMesh> mStaticMesh; | ||||
| 
 | ||||
|     osg::ref_ptr<Resource::BulletShape> mShape; | ||||
| }; | ||||
|  |  | |||
|  | @ -127,7 +127,7 @@ osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string & | |||
|         if (ext == "nif") | ||||
|         { | ||||
|             NifBullet::BulletNifLoader loader; | ||||
|             shape = loader.load(mNifFileManager->get(normalized)); | ||||
|             shape = loader.load(*mNifFileManager->get(normalized)); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue