1 #include <components/nifbullet/bulletnifloader.hpp>
2 #include <components/bullethelpers/processtrianglecallback.hpp>
3 #include <components/nif/node.hpp>
4
5 #include <BulletCollision/CollisionShapes/btBoxShape.h>
6 #include <BulletCollision/CollisionShapes/btCompoundShape.h>
7 #include <BulletCollision/CollisionShapes/btTriangleMesh.h>
8
9 #include <gtest/gtest.h>
10 #include <gmock/gmock.h>
11
12 #include <algorithm>
13
14 namespace
15 {
16 template <class T>
compareObjects(const T * lhs,const T * rhs)17 bool compareObjects(const T* lhs, const T* rhs)
18 {
19 return (!lhs && !rhs) || (lhs && rhs && *lhs == *rhs);
20 }
21
getTriangles(const btBvhTriangleMeshShape & shape)22 std::vector<btVector3> getTriangles(const btBvhTriangleMeshShape& shape)
23 {
24 std::vector<btVector3> result;
25 auto callback = BulletHelpers::makeProcessTriangleCallback([&] (btVector3* triangle, int, int) {
26 for (std::size_t i = 0; i < 3; ++i)
27 result.push_back(triangle[i]);
28 });
29 btVector3 aabbMin;
30 btVector3 aabbMax;
31 shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
32 shape.processAllTriangles(&callback, aabbMin, aabbMax);
33 return result;
34 }
35
isNear(btScalar lhs,btScalar rhs)36 bool isNear(btScalar lhs, btScalar rhs)
37 {
38 return std::abs(lhs - rhs) <= 1e-5;
39 }
40
isNear(const btVector3 & lhs,const btVector3 & rhs)41 bool isNear(const btVector3& lhs, const btVector3& rhs)
42 {
43 return std::equal(
44 static_cast<const btScalar*>(lhs),
45 static_cast<const btScalar*>(lhs) + 3,
46 static_cast<const btScalar*>(rhs),
47 [] (btScalar lhs, btScalar rhs) { return isNear(lhs, rhs); }
48 );
49 }
50
isNear(const btMatrix3x3 & lhs,const btMatrix3x3 & rhs)51 bool isNear(const btMatrix3x3& lhs, const btMatrix3x3& rhs)
52 {
53 for (int i = 0; i < 3; ++i)
54 if (!isNear(lhs[i], rhs[i]))
55 return false;
56 return true;
57 }
58
isNear(const btTransform & lhs,const btTransform & rhs)59 bool isNear(const btTransform& lhs, const btTransform& rhs)
60 {
61 return isNear(lhs.getOrigin(), rhs.getOrigin()) && isNear(lhs.getBasis(), rhs.getBasis());
62 }
63 }
64
operator <<(std::ostream & stream,const btVector3 & value)65 static std::ostream& operator <<(std::ostream& stream, const btVector3& value)
66 {
67 return stream << "btVector3 {"
68 << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getX() << ", "
69 << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getY() << ", "
70 << std::setprecision(std::numeric_limits<float>::max_exponent10) << value.getZ() << "}";
71 }
72
operator <<(std::ostream & stream,const btMatrix3x3 & value)73 static std::ostream& operator <<(std::ostream& stream, const btMatrix3x3& value)
74 {
75 stream << "btMatrix3x3 {";
76 for (int i = 0; i < 3; ++i)
77 stream << value.getRow(i) << ", ";
78 return stream << "}";
79 }
80
operator <<(std::ostream & stream,const btTransform & value)81 static std::ostream& operator <<(std::ostream& stream, const btTransform& value)
82 {
83 return stream << "btTransform {" << value.getBasis() << ", " << value.getOrigin() << "}";
84 }
85
86 static std::ostream& operator <<(std::ostream& stream, const btCollisionShape* value);
87
operator <<(std::ostream & stream,const btCompoundShape & value)88 static std::ostream& operator <<(std::ostream& stream, const btCompoundShape& value)
89 {
90 stream << "btCompoundShape {" << value.getLocalScaling() << ", ";
91 stream << "{";
92 for (int i = 0; i < value.getNumChildShapes(); ++i)
93 stream << value.getChildShape(i) << ", ";
94 stream << "},";
95 stream << "{";
96 for (int i = 0; i < value.getNumChildShapes(); ++i)
97 stream << value.getChildTransform(i) << ", ";
98 stream << "}";
99 return stream << "}";
100 }
101
operator <<(std::ostream & stream,const btBoxShape & value)102 static std::ostream& operator <<(std::ostream& stream, const btBoxShape& value)
103 {
104 return stream << "btBoxShape {" << value.getLocalScaling() << ", " << value.getHalfExtentsWithoutMargin() << "}";
105 }
106
107 namespace Resource
108 {
109
operator <<(std::ostream & stream,const TriangleMeshShape & value)110 static std::ostream& operator <<(std::ostream& stream, const TriangleMeshShape& value)
111 {
112 stream << "Resource::TriangleMeshShape {" << value.getLocalScaling() << ", "
113 << value.usesQuantizedAabbCompression() << ", " << value.getOwnsBvh() << ", {";
114 auto callback = BulletHelpers::makeProcessTriangleCallback([&] (btVector3* triangle, int, int) {
115 for (std::size_t i = 0; i < 3; ++i)
116 stream << triangle[i] << ", ";
117 });
118 btVector3 aabbMin;
119 btVector3 aabbMax;
120 value.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
121 value.processAllTriangles(&callback, aabbMin, aabbMax);
122 return stream << "}}";
123 }
124
125 }
126
operator <<(std::ostream & stream,const btCollisionShape & value)127 static std::ostream& operator <<(std::ostream& stream, const btCollisionShape& value)
128 {
129 switch (value.getShapeType())
130 {
131 case COMPOUND_SHAPE_PROXYTYPE:
132 return stream << static_cast<const btCompoundShape&>(value);
133 case BOX_SHAPE_PROXYTYPE:
134 return stream << static_cast<const btBoxShape&>(value);
135 case TRIANGLE_MESH_SHAPE_PROXYTYPE:
136 if (const auto casted = dynamic_cast<const Resource::TriangleMeshShape*>(&value))
137 return stream << *casted;
138 break;
139 }
140 return stream << "btCollisionShape {" << value.getShapeType() << "}";
141 }
142
operator <<(std::ostream & stream,const btCollisionShape * value)143 static std::ostream& operator <<(std::ostream& stream, const btCollisionShape* value)
144 {
145 return value ? stream << "&" << *value : stream << "nullptr";
146 }
147
148 namespace std
149 {
operator <<(std::ostream & stream,const map<int,int> & value)150 static std::ostream& operator <<(std::ostream& stream, const map<int, int>& value)
151 {
152 stream << "std::map<int, int> {";
153 for (const auto& v : value)
154 stream << "{" << v.first << ", " << v.second << "},";
155 return stream << "}";
156 }
157 }
158
159 namespace Resource
160 {
operator ==(const Resource::BulletShape & lhs,const Resource::BulletShape & rhs)161 static bool operator ==(const Resource::BulletShape& lhs, const Resource::BulletShape& rhs)
162 {
163 return compareObjects(lhs.mCollisionShape, rhs.mCollisionShape)
164 && compareObjects(lhs.mAvoidCollisionShape, rhs.mAvoidCollisionShape)
165 && lhs.mCollisionBox.extents == rhs.mCollisionBox.extents
166 && lhs.mCollisionBox.center == rhs.mCollisionBox.center
167 && lhs.mAnimatedShapes == rhs.mAnimatedShapes;
168 }
169
operator <<(std::ostream & stream,const Resource::BulletShape & value)170 static std::ostream& operator <<(std::ostream& stream, const Resource::BulletShape& value)
171 {
172 return stream << "Resource::BulletShape {"
173 << value.mCollisionShape << ", "
174 << value.mAvoidCollisionShape << ", "
175 << "osg::Vec3f {" << value.mCollisionBox.extents << "}" << ", "
176 << "osg::Vec3f {" << value.mCollisionBox.center << "}" << ", "
177 << value.mAnimatedShapes
178 << "}";
179 }
180 }
181
182 static bool operator ==(const btCollisionShape& lhs, const btCollisionShape& rhs);
183
operator ==(const btCompoundShape & lhs,const btCompoundShape & rhs)184 static bool operator ==(const btCompoundShape& lhs, const btCompoundShape& rhs)
185 {
186 if (lhs.getNumChildShapes() != rhs.getNumChildShapes() || lhs.getLocalScaling() != rhs.getLocalScaling())
187 return false;
188 for (int i = 0; i < lhs.getNumChildShapes(); ++i)
189 {
190 if (!compareObjects(lhs.getChildShape(i), rhs.getChildShape(i))
191 || !isNear(lhs.getChildTransform(i), rhs.getChildTransform(i)))
192 return false;
193 }
194 return true;
195 }
196
operator ==(const btBoxShape & lhs,const btBoxShape & rhs)197 static bool operator ==(const btBoxShape& lhs, const btBoxShape& rhs)
198 {
199 return isNear(lhs.getLocalScaling(), rhs.getLocalScaling())
200 && lhs.getHalfExtentsWithoutMargin() == rhs.getHalfExtentsWithoutMargin();
201 }
202
operator ==(const btBvhTriangleMeshShape & lhs,const btBvhTriangleMeshShape & rhs)203 static bool operator ==(const btBvhTriangleMeshShape& lhs, const btBvhTriangleMeshShape& rhs)
204 {
205 return isNear(lhs.getLocalScaling(), rhs.getLocalScaling())
206 && lhs.usesQuantizedAabbCompression() == rhs.usesQuantizedAabbCompression()
207 && lhs.getOwnsBvh() == rhs.getOwnsBvh()
208 && getTriangles(lhs) == getTriangles(rhs);
209 }
210
operator ==(const btCollisionShape & lhs,const btCollisionShape & rhs)211 static bool operator ==(const btCollisionShape& lhs, const btCollisionShape& rhs)
212 {
213 if (lhs.getShapeType() != rhs.getShapeType())
214 return false;
215 switch (lhs.getShapeType())
216 {
217 case COMPOUND_SHAPE_PROXYTYPE:
218 return static_cast<const btCompoundShape&>(lhs) == static_cast<const btCompoundShape&>(rhs);
219 case BOX_SHAPE_PROXYTYPE:
220 return static_cast<const btBoxShape&>(lhs) == static_cast<const btBoxShape&>(rhs);
221 case TRIANGLE_MESH_SHAPE_PROXYTYPE:
222 if (const auto lhsCasted = dynamic_cast<const Resource::TriangleMeshShape*>(&lhs))
223 if (const auto rhsCasted = dynamic_cast<const Resource::TriangleMeshShape*>(&rhs))
224 return *lhsCasted == *rhsCasted;
225 return false;
226 }
227 return false;
228 }
229
230 namespace
231 {
232 using namespace testing;
233 using NifBullet::BulletNifLoader;
234
init(Nif::Transformation & value)235 void init(Nif::Transformation& value)
236 {
237 value = Nif::Transformation::getIdentity();
238 }
239
init(Nif::Extra & value)240 void init(Nif::Extra& value)
241 {
242 value.next = Nif::ExtraPtr(nullptr);
243 }
244
init(Nif::Named & value)245 void init(Nif::Named& value)
246 {
247 value.extra = Nif::ExtraPtr(nullptr);
248 value.extralist = Nif::ExtraList();
249 value.controller = Nif::ControllerPtr(nullptr);
250 }
251
init(Nif::Node & value)252 void init(Nif::Node& value)
253 {
254 init(static_cast<Nif::Named&>(value));
255 value.flags = 0;
256 init(value.trafo);
257 value.hasBounds = false;
258 value.parent = nullptr;
259 value.isBone = false;
260 }
261
init(Nif::NiGeometry & value)262 void init(Nif::NiGeometry& value)
263 {
264 init(static_cast<Nif::Node&>(value));
265 value.data = Nif::NiGeometryDataPtr(nullptr);
266 value.skin = Nif::NiSkinInstancePtr(nullptr);
267 }
268
init(Nif::NiTriShape & value)269 void init(Nif::NiTriShape& value)
270 {
271 init(static_cast<Nif::NiGeometry&>(value));
272 value.recType = Nif::RC_NiTriShape;
273 }
274
init(Nif::NiSkinInstance & value)275 void init(Nif::NiSkinInstance& value)
276 {
277 value.data = Nif::NiSkinDataPtr(nullptr);
278 value.root = Nif::NodePtr(nullptr);
279 }
280
init(Nif::Controller & value)281 void init(Nif::Controller& value)
282 {
283 value.next = Nif::ControllerPtr(nullptr);
284 value.flags = 0;
285 value.frequency = 0;
286 value.phase = 0;
287 value.timeStart = 0;
288 value.timeStop = 0;
289 value.target = Nif::NamedPtr(nullptr);
290 }
291
copy(const btTransform & src,Nif::Transformation & dst)292 void copy(const btTransform& src, Nif::Transformation& dst)
293 {
294 dst.pos = osg::Vec3f(src.getOrigin().x(), src.getOrigin().y(), src.getOrigin().z());
295 for (int row = 0; row < 3; ++row)
296 for (int column = 0; column < 3; ++column)
297 dst.rotation.mValues[column][row] = src.getBasis().getRow(row)[column];
298 }
299
300 struct NifFileMock : Nif::File
301 {
302 MOCK_METHOD(Nif::Record*, getRecord, (std::size_t), (const, override));
303 MOCK_METHOD(std::size_t, numRecords, (), (const, override));
304 MOCK_METHOD(Nif::Record*, getRoot, (std::size_t), (const, override));
305 MOCK_METHOD(std::size_t, numRoots, (), (const, override));
306 MOCK_METHOD(std::string, getString, (uint32_t), (const, override));
307 MOCK_METHOD(void, setUseSkinning, (bool), (override));
308 MOCK_METHOD(bool, getUseSkinning, (), (const, override));
309 MOCK_METHOD(std::string, getFilename, (), (const, override));
310 MOCK_METHOD(unsigned int, getVersion, (), (const, override));
311 MOCK_METHOD(unsigned int, getUserVersion, (), (const, override));
312 MOCK_METHOD(unsigned int, getBethVersion, (), (const, override));
313 };
314
315 struct RecordMock : Nif::Record
316 {
317 MOCK_METHOD(void, read, (Nif::NIFStream *nif), (override));
318 };
319
320 struct TestBulletNifLoader : Test
321 {
322 BulletNifLoader mLoader;
323 const StrictMock<const NifFileMock> mNifFile;
324 Nif::Node mNode;
325 Nif::Node mNode2;
326 Nif::NiNode mNiNode;
327 Nif::NiNode mNiNode2;
328 Nif::NiNode mNiNode3;
329 Nif::NiTriShapeData mNiTriShapeData;
330 Nif::NiTriShape mNiTriShape;
331 Nif::NiTriShapeData mNiTriShapeData2;
332 Nif::NiTriShape mNiTriShape2;
333 Nif::NiSkinInstance mNiSkinInstance;
334 Nif::NiStringExtraData mNiStringExtraData;
335 Nif::NiStringExtraData mNiStringExtraData2;
336 Nif::Controller mController;
337 btTransform mTransform {btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(1, 2, 3)};
338 btTransform mResultTransform {
339 btMatrix3x3(
340 1, 0, 0,
341 0, 0.82417738437652587890625, 0.56633174419403076171875,
342 0, -0.56633174419403076171875, 0.82417738437652587890625
343 ),
344 btVector3(1, 2, 3)
345 };
346 btTransform mResultTransform2 {
347 btMatrix3x3(
348 1, 0, 0,
349 0, 0.7951543331146240234375, 0.606407105922698974609375,
350 0, -0.606407105922698974609375, 0.7951543331146240234375
351 ),
352 btVector3(4, 8, 12)
353 };
354
TestBulletNifLoader__anon6cda9ea70511::TestBulletNifLoader355 TestBulletNifLoader()
356 {
357 init(mNode);
358 init(mNode2);
359 init(mNiNode);
360 init(mNiNode2);
361 init(mNiNode3);
362 init(mNiTriShape);
363 init(mNiTriShape2);
364 init(mNiSkinInstance);
365 init(mNiStringExtraData);
366 init(mNiStringExtraData2);
367 init(mController);
368
369 mNiTriShapeData.recType = Nif::RC_NiTriShapeData;
370 mNiTriShapeData.vertices = {osg::Vec3f(0, 0, 0), osg::Vec3f(1, 0, 0), osg::Vec3f(1, 1, 0)};
371 mNiTriShapeData.triangles = {0, 1, 2};
372 mNiTriShape.data = Nif::NiGeometryDataPtr(&mNiTriShapeData);
373
374 mNiTriShapeData2.recType = Nif::RC_NiTriShapeData;
375 mNiTriShapeData2.vertices = {osg::Vec3f(0, 0, 1), osg::Vec3f(1, 0, 1), osg::Vec3f(1, 1, 1)};
376 mNiTriShapeData2.triangles = {0, 1, 2};
377 mNiTriShape2.data = Nif::NiGeometryDataPtr(&mNiTriShapeData2);
378 }
379 };
380
TEST_F(TestBulletNifLoader,for_zero_num_roots_should_return_default)381 TEST_F(TestBulletNifLoader, for_zero_num_roots_should_return_default)
382 {
383 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(0));
384 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
385 const auto result = mLoader.load(mNifFile);
386
387 Resource::BulletShape expected;
388
389 EXPECT_EQ(*result, expected);
390 }
391
TEST_F(TestBulletNifLoader,for_default_root_nif_node_should_return_default)392 TEST_F(TestBulletNifLoader, for_default_root_nif_node_should_return_default)
393 {
394 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
395 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
396 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
397 const auto result = mLoader.load(mNifFile);
398
399 Resource::BulletShape expected;
400
401 EXPECT_EQ(*result, expected);
402 }
403
TEST_F(TestBulletNifLoader,for_default_root_collision_node_nif_node_should_return_default)404 TEST_F(TestBulletNifLoader, for_default_root_collision_node_nif_node_should_return_default)
405 {
406 mNode.recType = Nif::RC_RootCollisionNode;
407
408 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
409 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
410 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
411 const auto result = mLoader.load(mNifFile);
412
413 Resource::BulletShape expected;
414
415 EXPECT_EQ(*result, expected);
416 }
417
TEST_F(TestBulletNifLoader,for_default_root_nif_node_and_filename_starting_with_x_should_return_default)418 TEST_F(TestBulletNifLoader, for_default_root_nif_node_and_filename_starting_with_x_should_return_default)
419 {
420 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
421 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
422 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
423 const auto result = mLoader.load(mNifFile);
424
425 Resource::BulletShape expected;
426
427 EXPECT_EQ(*result, expected);
428 }
429
TEST_F(TestBulletNifLoader,for_root_nif_node_with_bounding_box_should_return_shape_with_compound_shape_and_box_inside)430 TEST_F(TestBulletNifLoader, for_root_nif_node_with_bounding_box_should_return_shape_with_compound_shape_and_box_inside)
431 {
432 mNode.hasBounds = true;
433 mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
434 mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
435 mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
436 mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
437
438 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
439 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
440 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
441 const auto result = mLoader.load(mNifFile);
442
443 Resource::BulletShape expected;
444 expected.mCollisionBox.extents = osg::Vec3f(1, 2, 3);
445 expected.mCollisionBox.center = osg::Vec3f(-1, -2, -3);
446 std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
447 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
448 shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
449 expected.mCollisionShape = shape.release();
450
451 EXPECT_EQ(*result, expected);
452 }
453
TEST_F(TestBulletNifLoader,for_child_nif_node_with_bounding_box)454 TEST_F(TestBulletNifLoader, for_child_nif_node_with_bounding_box)
455 {
456 mNode.hasBounds = true;
457 mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
458 mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
459 mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
460 mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
461 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode)}));
462
463 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
464 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
465 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
466 const auto result = mLoader.load(mNifFile);
467
468 Resource::BulletShape expected;
469 expected.mCollisionBox.extents = osg::Vec3f(1, 2, 3);
470 expected.mCollisionBox.center = osg::Vec3f(-1, -2, -3);
471 std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
472 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
473 shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
474 expected.mCollisionShape = shape.release();
475
476 EXPECT_EQ(*result, expected);
477 }
478
TEST_F(TestBulletNifLoader,for_root_and_child_nif_node_with_bounding_box_but_root_without_flag_should_use_child_bounds)479 TEST_F(TestBulletNifLoader, for_root_and_child_nif_node_with_bounding_box_but_root_without_flag_should_use_child_bounds)
480 {
481 mNode.hasBounds = true;
482 mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
483 mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
484 mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
485 mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
486
487 mNiNode.hasBounds = true;
488 mNiNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
489 mNiNode.bounds.box.extents = osg::Vec3f(4, 5, 6);
490 mNiNode.bounds.box.center = osg::Vec3f(-4, -5, -6);
491 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode)}));
492
493 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
494 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
495 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
496 const auto result = mLoader.load(mNifFile);
497
498 Resource::BulletShape expected;
499 expected.mCollisionBox.extents = osg::Vec3f(1, 2, 3);
500 expected.mCollisionBox.center = osg::Vec3f(-1, -2, -3);
501 std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
502 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
503 shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
504 expected.mCollisionShape = shape.release();
505
506 EXPECT_EQ(*result, expected);
507 }
508
TEST_F(TestBulletNifLoader,for_root_and_two_children_where_both_with_bounds_but_only_first_with_flag_should_use_first_bounds)509 TEST_F(TestBulletNifLoader, for_root_and_two_children_where_both_with_bounds_but_only_first_with_flag_should_use_first_bounds)
510 {
511 mNode.hasBounds = true;
512 mNode.flags |= Nif::NiNode::Flag_BBoxCollision;
513 mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
514 mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
515 mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
516
517 mNode2.hasBounds = true;
518 mNode2.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
519 mNode2.bounds.box.extents = osg::Vec3f(4, 5, 6);
520 mNode2.bounds.box.center = osg::Vec3f(-4, -5, -6);
521
522 mNiNode.hasBounds = true;
523 mNiNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
524 mNiNode.bounds.box.extents = osg::Vec3f(7, 8, 9);
525 mNiNode.bounds.box.center = osg::Vec3f(-7, -8, -9);
526 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2)}));
527
528 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
529 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
530 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
531 const auto result = mLoader.load(mNifFile);
532
533 Resource::BulletShape expected;
534 expected.mCollisionBox.extents = osg::Vec3f(1, 2, 3);
535 expected.mCollisionBox.center = osg::Vec3f(-1, -2, -3);
536 std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(1, 2, 3)));
537 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
538 shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-1, -2, -3)), box.release());
539 expected.mCollisionShape = shape.release();
540
541 EXPECT_EQ(*result, expected);
542 }
543
TEST_F(TestBulletNifLoader,for_root_and_two_children_where_both_with_bounds_but_only_second_with_flag_should_use_second_bounds)544 TEST_F(TestBulletNifLoader, for_root_and_two_children_where_both_with_bounds_but_only_second_with_flag_should_use_second_bounds)
545 {
546 mNode.hasBounds = true;
547 mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
548 mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
549 mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
550
551 mNode2.hasBounds = true;
552 mNode2.flags |= Nif::NiNode::Flag_BBoxCollision;
553 mNode2.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
554 mNode2.bounds.box.extents = osg::Vec3f(4, 5, 6);
555 mNode2.bounds.box.center = osg::Vec3f(-4, -5, -6);
556
557 mNiNode.hasBounds = true;
558 mNiNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
559 mNiNode.bounds.box.extents = osg::Vec3f(7, 8, 9);
560 mNiNode.bounds.box.center = osg::Vec3f(-7, -8, -9);
561 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNode), Nif::NodePtr(&mNode2)}));
562
563 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
564 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
565 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
566 const auto result = mLoader.load(mNifFile);
567
568 Resource::BulletShape expected;
569 expected.mCollisionBox.extents = osg::Vec3f(4, 5, 6);
570 expected.mCollisionBox.center = osg::Vec3f(-4, -5, -6);
571 std::unique_ptr<btBoxShape> box(new btBoxShape(btVector3(4, 5, 6)));
572 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
573 shape->addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(-4, -5, -6)), box.release());
574 expected.mCollisionShape = shape.release();
575
576 EXPECT_EQ(*result, expected);
577 }
578
TEST_F(TestBulletNifLoader,for_root_nif_node_with_bounds_but_without_flag_should_return_shape_with_bounds_but_with_null_collision_shape)579 TEST_F(TestBulletNifLoader, for_root_nif_node_with_bounds_but_without_flag_should_return_shape_with_bounds_but_with_null_collision_shape)
580 {
581 mNode.hasBounds = true;
582 mNode.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
583 mNode.bounds.box.extents = osg::Vec3f(1, 2, 3);
584 mNode.bounds.box.center = osg::Vec3f(-1, -2, -3);
585
586 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
587 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNode));
588 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
589 const auto result = mLoader.load(mNifFile);
590
591 Resource::BulletShape expected;
592 expected.mCollisionBox.extents = osg::Vec3f(1, 2, 3);
593 expected.mCollisionBox.center = osg::Vec3f(-1, -2, -3);
594
595 EXPECT_EQ(*result, expected);
596 }
597
TEST_F(TestBulletNifLoader,for_tri_shape_root_node_should_return_shape_with_triangle_mesh_shape)598 TEST_F(TestBulletNifLoader, for_tri_shape_root_node_should_return_shape_with_triangle_mesh_shape)
599 {
600 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
601 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape));
602 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
603 const auto result = mLoader.load(mNifFile);
604
605 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
606 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
607 Resource::BulletShape expected;
608 expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
609
610 EXPECT_EQ(*result, expected);
611 }
612
TEST_F(TestBulletNifLoader,for_tri_shape_root_node_with_bounds_should_return_shape_with_bounds_but_with_null_collision_shape)613 TEST_F(TestBulletNifLoader, for_tri_shape_root_node_with_bounds_should_return_shape_with_bounds_but_with_null_collision_shape)
614 {
615 mNiTriShape.hasBounds = true;
616 mNiTriShape.bounds.type = Nif::NiBoundingVolume::Type::BOX_BV;
617 mNiTriShape.bounds.box.extents = osg::Vec3f(1, 2, 3);
618 mNiTriShape.bounds.box.center = osg::Vec3f(-1, -2, -3);
619
620 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
621 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape));
622 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
623 const auto result = mLoader.load(mNifFile);
624
625 Resource::BulletShape expected;
626 expected.mCollisionBox.extents = osg::Vec3f(1, 2, 3);
627 expected.mCollisionBox.center = osg::Vec3f(-1, -2, -3);
628
629 EXPECT_EQ(*result, expected);
630 }
631
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_should_return_shape_with_triangle_mesh_shape)632 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_should_return_shape_with_triangle_mesh_shape)
633 {
634 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
635
636 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
637 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
638 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
639 const auto result = mLoader.load(mNifFile);
640
641 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
642 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
643 Resource::BulletShape expected;
644 expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
645
646 EXPECT_EQ(*result, expected);
647 }
648
TEST_F(TestBulletNifLoader,for_nested_tri_shape_child_should_return_shape_with_triangle_mesh_shape)649 TEST_F(TestBulletNifLoader, for_nested_tri_shape_child_should_return_shape_with_triangle_mesh_shape)
650 {
651 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiNode2)}));
652 mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
653
654 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
655 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
656 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
657 const auto result = mLoader.load(mNifFile);
658
659 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
660 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
661 Resource::BulletShape expected;
662 expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
663
664 EXPECT_EQ(*result, expected);
665 }
666
TEST_F(TestBulletNifLoader,for_two_tri_shape_children_should_return_shape_with_triangle_mesh_shape_with_all_meshes)667 TEST_F(TestBulletNifLoader, for_two_tri_shape_children_should_return_shape_with_triangle_mesh_shape_with_all_meshes)
668 {
669 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
670 Nif::NodePtr(&mNiTriShape),
671 Nif::NodePtr(&mNiTriShape2)
672 }));
673
674 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
675 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
676 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
677 const auto result = mLoader.load(mNifFile);
678
679 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
680 triangles->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
681 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
682 Resource::BulletShape expected;
683 expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
684
685 EXPECT_EQ(*result, expected);
686 }
687
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_shape_with_triangle_mesh_shape)688 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_and_not_empty_skin_should_return_shape_with_triangle_mesh_shape)
689 {
690 mNiTriShape.skin = Nif::NiSkinInstancePtr(&mNiSkinInstance);
691 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
692
693 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
694 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
695 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
696 const auto result = mLoader.load(mNifFile);
697
698 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
699 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
700 Resource::BulletShape expected;
701 expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
702
703 EXPECT_EQ(*result, expected);
704 }
705
TEST_F(TestBulletNifLoader,for_tri_shape_root_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)706 TEST_F(TestBulletNifLoader, for_tri_shape_root_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)
707 {
708 copy(mTransform, mNiTriShape.trafo);
709 mNiTriShape.trafo.scale = 3;
710
711 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
712 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiTriShape));
713 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
714 const auto result = mLoader.load(mNifFile);
715
716 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
717 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
718 std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
719 mesh->setLocalScaling(btVector3(3, 3, 3));
720 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
721 shape->addChildShape(mResultTransform, mesh.release());
722 Resource::BulletShape expected;
723 expected.mCollisionShape = shape.release();
724 expected.mAnimatedShapes = {{-1, 0}};
725
726 EXPECT_EQ(*result, expected);
727 }
728
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)729 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_and_filename_starting_with_x_should_return_shape_with_compound_shape)
730 {
731 copy(mTransform, mNiTriShape.trafo);
732 mNiTriShape.trafo.scale = 3;
733 mNiTriShape.parent = &mNiNode;
734 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
735 mNiNode.trafo.scale = 4;
736
737 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
738 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
739 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
740 const auto result = mLoader.load(mNifFile);
741
742 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
743 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
744 std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
745 mesh->setLocalScaling(btVector3(12, 12, 12));
746 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
747 shape->addChildShape(mResultTransform2, mesh.release());
748 Resource::BulletShape expected;
749 expected.mCollisionShape = shape.release();
750 expected.mAnimatedShapes = {{-1, 0}};
751
752 EXPECT_EQ(*result, expected);
753 }
754
TEST_F(TestBulletNifLoader,for_two_tri_shape_children_nodes_and_filename_starting_with_x_should_return_shape_with_compound_shape)755 TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_and_filename_starting_with_x_should_return_shape_with_compound_shape)
756 {
757 copy(mTransform, mNiTriShape.trafo);
758 mNiTriShape.trafo.scale = 3;
759
760 copy(mTransform, mNiTriShape2.trafo);
761 mNiTriShape2.trafo.scale = 3;
762
763 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
764 Nif::NodePtr(&mNiTriShape),
765 Nif::NodePtr(&mNiTriShape2),
766 }));
767
768 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
769 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
770 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("xtest.nif"));
771 const auto result = mLoader.load(mNifFile);
772
773 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
774 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
775 std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
776 mesh->setLocalScaling(btVector3(3, 3, 3));
777
778 std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false));
779 triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
780 std::unique_ptr<Resource::TriangleMeshShape> mesh2(new Resource::TriangleMeshShape(triangles2.release(), true));
781 mesh2->setLocalScaling(btVector3(3, 3, 3));
782
783 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
784 shape->addChildShape(mResultTransform, mesh.release());
785 shape->addChildShape(mResultTransform, mesh2.release());
786 Resource::BulletShape expected;
787 expected.mCollisionShape = shape.release();
788 expected.mAnimatedShapes = {{-1, 0}};
789
790 EXPECT_EQ(*result, expected);
791 }
792
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_with_controller_should_return_shape_with_compound_shape)793 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_controller_should_return_shape_with_compound_shape)
794 {
795 mController.recType = Nif::RC_NiKeyframeController;
796 mController.flags |= Nif::NiNode::ControllerFlag_Active;
797 copy(mTransform, mNiTriShape.trafo);
798 mNiTriShape.trafo.scale = 3;
799 mNiTriShape.parent = &mNiNode;
800 mNiTriShape.controller = Nif::ControllerPtr(&mController);
801 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
802 mNiNode.trafo.scale = 4;
803
804 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
805 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
806 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
807 const auto result = mLoader.load(mNifFile);
808
809 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
810 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
811 std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
812 mesh->setLocalScaling(btVector3(12, 12, 12));
813 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
814 shape->addChildShape(mResultTransform2, mesh.release());
815 Resource::BulletShape expected;
816 expected.mCollisionShape = shape.release();
817 expected.mAnimatedShapes = {{-1, 0}};
818
819 EXPECT_EQ(*result, expected);
820 }
821
TEST_F(TestBulletNifLoader,for_two_tri_shape_children_nodes_where_one_with_controller_should_return_shape_with_compound_shape)822 TEST_F(TestBulletNifLoader, for_two_tri_shape_children_nodes_where_one_with_controller_should_return_shape_with_compound_shape)
823 {
824 mController.recType = Nif::RC_NiKeyframeController;
825 mController.flags |= Nif::NiNode::ControllerFlag_Active;
826 copy(mTransform, mNiTriShape.trafo);
827 mNiTriShape.trafo.scale = 3;
828 copy(mTransform, mNiTriShape2.trafo);
829 mNiTriShape2.trafo.scale = 3;
830 mNiTriShape2.parent = &mNiNode;
831 mNiTriShape2.controller = Nif::ControllerPtr(&mController);
832 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({
833 Nif::NodePtr(&mNiTriShape),
834 Nif::NodePtr(&mNiTriShape2),
835 }));
836 mNiNode.trafo.scale = 4;
837
838 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
839 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
840 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
841 const auto result = mLoader.load(mNifFile);
842
843 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
844 triangles->addTriangle(btVector3(1, 2, 3), btVector3(4, 2, 3), btVector3(4, 4.632747650146484375, 1.56172335147857666015625));
845 std::unique_ptr<Resource::TriangleMeshShape> mesh(new Resource::TriangleMeshShape(triangles.release(), true));
846 mesh->setLocalScaling(btVector3(1, 1, 1));
847
848 std::unique_ptr<btTriangleMesh> triangles2(new btTriangleMesh(false));
849 triangles2->addTriangle(btVector3(0, 0, 1), btVector3(1, 0, 1), btVector3(1, 1, 1));
850 std::unique_ptr<Resource::TriangleMeshShape> mesh2(new Resource::TriangleMeshShape(triangles2.release(), true));
851 mesh2->setLocalScaling(btVector3(12, 12, 12));
852
853 std::unique_ptr<btCompoundShape> shape(new btCompoundShape);
854 shape->addChildShape(mResultTransform2, mesh2.release());
855 shape->addChildShape(btTransform::getIdentity(), mesh.release());
856 Resource::BulletShape expected;
857 expected.mCollisionShape = shape.release();
858 expected.mAnimatedShapes = {{-1, 0}};
859
860 EXPECT_EQ(*result, expected);
861 }
862
TEST_F(TestBulletNifLoader,for_root_avoid_node_and_tri_shape_child_node_should_return_shape_with_null_collision_shape)863 TEST_F(TestBulletNifLoader, for_root_avoid_node_and_tri_shape_child_node_should_return_shape_with_null_collision_shape)
864 {
865 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
866 mNiNode.recType = Nif::RC_AvoidNode;
867
868 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
869 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
870 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
871 const auto result = mLoader.load(mNifFile);
872
873 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
874 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
875 Resource::BulletShape expected;
876 expected.mAvoidCollisionShape = new Resource::TriangleMeshShape(triangles.release(), false);
877
878 EXPECT_EQ(*result, expected);
879 }
880
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_with_empty_data_should_return_shape_with_null_collision_shape)881 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_should_return_shape_with_null_collision_shape)
882 {
883 mNiTriShape.data = Nif::NiGeometryDataPtr(nullptr);
884 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
885
886 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
887 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
888 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
889 const auto result = mLoader.load(mNifFile);
890
891 Resource::BulletShape expected;
892
893 EXPECT_EQ(*result, expected);
894 }
895
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_with_empty_data_triangles_should_return_shape_with_null_collision_shape)896 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_empty_data_triangles_should_return_shape_with_null_collision_shape)
897 {
898 auto data = static_cast<Nif::NiTriShapeData*>(mNiTriShape.data.getPtr());
899 data->triangles.clear();
900 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
901
902 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
903 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
904 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
905 const auto result = mLoader.load(mNifFile);
906
907 Resource::BulletShape expected;
908
909 EXPECT_EQ(*result, expected);
910 }
911
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_with_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape)912 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape)
913 {
914 mNiStringExtraData.string = "NC___";
915 mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
916 mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
917 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
918
919 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
920 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
921 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
922 const auto result = mLoader.load(mNifFile);
923
924 Resource::BulletShape expected;
925
926 EXPECT_EQ(*result, expected);
927 }
928
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape)929 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_not_first_extra_data_string_starting_with_nc_should_return_shape_with_null_collision_shape)
930 {
931 mNiStringExtraData.next = Nif::ExtraPtr(&mNiStringExtraData2);
932 mNiStringExtraData2.string = "NC___";
933 mNiStringExtraData2.recType = Nif::RC_NiStringExtraData;
934 mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
935 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
936
937 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
938 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
939 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
940 const auto result = mLoader.load(mNifFile);
941
942 Resource::BulletShape expected;
943
944 EXPECT_EQ(*result, expected);
945 }
946
TEST_F(TestBulletNifLoader,for_tri_shape_child_node_with_extra_data_string_mrk_should_return_shape_with_null_collision_shape)947 TEST_F(TestBulletNifLoader, for_tri_shape_child_node_with_extra_data_string_mrk_should_return_shape_with_null_collision_shape)
948 {
949 mNiStringExtraData.string = "MRK";
950 mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
951 mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
952 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
953
954 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
955 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
956 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
957 const auto result = mLoader.load(mNifFile);
958
959 Resource::BulletShape expected;
960
961 EXPECT_EQ(*result, expected);
962 }
963
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)964 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)
965 {
966 mNiStringExtraData.string = "MRK";
967 mNiStringExtraData.recType = Nif::RC_NiStringExtraData;
968 mNiTriShape.extra = Nif::ExtraPtr(&mNiStringExtraData);
969 mNiNode2.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiTriShape)}));
970 mNiNode2.recType = Nif::RC_RootCollisionNode;
971 mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({Nif::NodePtr(&mNiNode2)}));
972 mNiNode.recType = Nif::RC_NiNode;
973
974 EXPECT_CALL(mNifFile, numRoots()).WillOnce(Return(1));
975 EXPECT_CALL(mNifFile, getRoot(0)).WillOnce(Return(&mNiNode));
976 EXPECT_CALL(mNifFile, getFilename()).WillOnce(Return("test.nif"));
977 const auto result = mLoader.load(mNifFile);
978
979 std::unique_ptr<btTriangleMesh> triangles(new btTriangleMesh(false));
980 triangles->addTriangle(btVector3(0, 0, 0), btVector3(1, 0, 0), btVector3(1, 1, 0));
981 Resource::BulletShape expected;
982 expected.mCollisionShape = new Resource::TriangleMeshShape(triangles.release(), true);
983
984 EXPECT_EQ(*result, expected);
985 }
986 }
987