1 /********************************************************************************
2 * ReactPhysics3D physics library, http://www.reactphysics3d.com                 *
3 * Copyright (c) 2010-2020 Daniel Chappuis                                       *
4 *********************************************************************************
5 *                                                                               *
6 * This software is provided 'as-is', without any express or implied warranty.   *
7 * In no event will the authors be held liable for any damages arising from the  *
8 * use of this software.                                                         *
9 *                                                                               *
10 * Permission is granted to anyone to use this software for any purpose,         *
11 * including commercial applications, and to alter it and redistribute it        *
12 * freely, subject to the following restrictions:                                *
13 *                                                                               *
14 * 1. The origin of this software must not be misrepresented; you must not claim *
15 *    that you wrote the original software. If you use this software in a        *
16 *    product, an acknowledgment in the product documentation would be           *
17 *    appreciated but is not required.                                           *
18 *                                                                               *
19 * 2. Altered source versions must be plainly marked as such, and must not be    *
20 *    misrepresented as being the original software.                             *
21 *                                                                               *
22 * 3. This notice may not be removed or altered from any source distribution.    *
23 *                                                                               *
24 ********************************************************************************/
25 
26 // Libraries
27 #include <reactphysics3d/engine/PhysicsCommon.h>
28 
29 using namespace reactphysics3d;
30 
31 // Static variables
32 Logger* PhysicsCommon::mLogger = nullptr;
33 
34 /// Constructor
35 /**
36  * @param baseMemoryAllocator Pointer to a user custom memory allocator
37  */
PhysicsCommon(MemoryAllocator * baseMemoryAllocator)38 PhysicsCommon::PhysicsCommon(MemoryAllocator* baseMemoryAllocator)
39               : mMemoryManager(baseMemoryAllocator),
40                 mPhysicsWorlds(mMemoryManager.getHeapAllocator()), mSphereShapes(mMemoryManager.getHeapAllocator()),
41                 mBoxShapes(mMemoryManager.getHeapAllocator()), mCapsuleShapes(mMemoryManager.getHeapAllocator()),
42                 mConvexMeshShapes(mMemoryManager.getHeapAllocator()), mConcaveMeshShapes(mMemoryManager.getHeapAllocator()),
43                 mHeightFieldShapes(mMemoryManager.getHeapAllocator()), mPolyhedronMeshes(mMemoryManager.getHeapAllocator()),
44                 mTriangleMeshes(mMemoryManager.getHeapAllocator()),
45                 mProfilers(mMemoryManager.getHeapAllocator()), mDefaultLoggers(mMemoryManager.getHeapAllocator()) {
46 
47 }
48 
49 // Destructor
~PhysicsCommon()50 PhysicsCommon::~PhysicsCommon() {
51 
52     // Release the allocated memory
53     release();
54 }
55 
56 // Destroy and release everything that has been allocated
release()57 void PhysicsCommon::release() {
58 
59     // Destroy the physics worlds
60     for (auto it = mPhysicsWorlds.begin(); it != mPhysicsWorlds.end(); ++it) {
61         destroyPhysicsWorld(*it);
62     }
63 
64     // Destroy the sphere shapes
65     for (auto it = mSphereShapes.begin(); it != mSphereShapes.end(); ++it) {
66         destroySphereShape(*it);
67     }
68 
69     // Destroy the box shapes
70     for (auto it = mBoxShapes.begin(); it != mBoxShapes.end(); ++it) {
71         destroyBoxShape(*it);
72     }
73 
74     // Destroy the capsule shapes
75     for (auto it = mCapsuleShapes.begin(); it != mCapsuleShapes.end(); ++it) {
76         destroyCapsuleShape(*it);
77     }
78 
79     // Destroy the convex mesh shapes
80     for (auto it = mConvexMeshShapes.begin(); it != mConvexMeshShapes.end(); ++it) {
81         destroyConvexMeshShape(*it);
82     }
83 
84     // Destroy the heigh-field shapes
85     for (auto it = mHeightFieldShapes.begin(); it != mHeightFieldShapes.end(); ++it) {
86         destroyHeightFieldShape(*it);
87     }
88 
89     // Destroy the concave mesh shapes
90     for (auto it = mConcaveMeshShapes.begin(); it != mConcaveMeshShapes.end(); ++it) {
91         destroyConcaveMeshShape(*it);
92     }
93 
94     // Destroy the polyhedron mesh
95     for (auto it = mPolyhedronMeshes.begin(); it != mPolyhedronMeshes.end(); ++it) {
96         destroyPolyhedronMesh(*it);
97     }
98 
99     // Destroy the triangle mesh
100     for (auto it = mTriangleMeshes.begin(); it != mTriangleMeshes.end(); ++it) {
101         destroyTriangleMesh(*it);
102     }
103 
104     // Destroy the default loggers
105     for (auto it = mDefaultLoggers.begin(); it != mDefaultLoggers.end(); ++it) {
106         destroyDefaultLogger(*it);
107     }
108 
109 // If profiling is enabled
110 #ifdef IS_RP3D_PROFILING_ENABLED
111 
112 
113     // Destroy the profilers
114     for (auto it = mProfilers.begin(); it != mProfilers.end(); ++it) {
115         destroyProfiler(*it);
116     }
117 
118 #endif
119 
120 }
121 
122 // Create and return an instance of PhysicsWorld
123 /**
124  * @param worldSettings The settings of the physics world
125  * @return A pointer to the created physics world
126  */
createPhysicsWorld(const PhysicsWorld::WorldSettings & worldSettings)127 PhysicsWorld* PhysicsCommon::createPhysicsWorld(const PhysicsWorld::WorldSettings& worldSettings) {
128 
129     Profiler* profiler = nullptr;
130 
131 #ifdef IS_RP3D_PROFILING_ENABLED
132 
133 
134     profiler = createProfiler();
135 
136     // Add a destination file for the profiling data
137     profiler->addFileDestination("rp3d_profiling_" + worldSettings.worldName + ".txt", Profiler::Format::Text);
138 
139 #endif
140 
141     PhysicsWorld* world = new(mMemoryManager.allocate(MemoryManager::AllocationType::Heap, sizeof(PhysicsWorld))) PhysicsWorld(mMemoryManager, worldSettings, profiler);
142 
143     mPhysicsWorlds.add(world);
144 
145     return world;
146 }
147 
148 // Destroy an instance of PhysicsWorld
149 /**
150  * @param world A pointer to the physics world to destroy
151  */
destroyPhysicsWorld(PhysicsWorld * world)152 void PhysicsCommon::destroyPhysicsWorld(PhysicsWorld* world) {
153 
154    // Call the destructor of the world
155    world->~PhysicsWorld();
156 
157    // Release allocated memory
158    mMemoryManager.release(MemoryManager::AllocationType::Heap, world, sizeof(PhysicsWorld));
159 
160    mPhysicsWorlds.remove(world);
161 }
162 
163 // Create and return a sphere collision shape
164 /**
165  * @param radius The radius of the sphere collision shape
166  * @return A pointer to the created sphere shape
167  */
createSphereShape(const decimal radius)168 SphereShape* PhysicsCommon::createSphereShape(const decimal radius) {
169 
170     if (radius <= decimal(0.0)) {
171 
172         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
173                  "Error when creating a SphereShape: radius must be a positive value",  __FILE__, __LINE__);
174     }
175 
176     SphereShape* shape = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(SphereShape))) SphereShape(radius, mMemoryManager.getHeapAllocator());
177     mSphereShapes.add(shape);
178 
179     return shape;
180 }
181 
182 // Destroy a sphere collision shape
183 /**
184  * @param sphereShape A pointer to the sphere collision shape to destroy
185  */
destroySphereShape(SphereShape * sphereShape)186 void PhysicsCommon::destroySphereShape(SphereShape* sphereShape) {
187 
188     // If the shape is still part of some colliders
189     if (sphereShape->mColliders.size() > 0) {
190 
191         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
192                  "Error when destroying the SphereShape because it is still used by some colliders",  __FILE__, __LINE__);
193     }
194 
195    // Call the destructor of the shape
196    sphereShape->~SphereShape();
197 
198    // Release allocated memory
199    mMemoryManager.release(MemoryManager::AllocationType::Pool, sphereShape, sizeof(SphereShape));
200 
201    mSphereShapes.remove(sphereShape);
202 }
203 
204 // Create and return a box collision shape
205 /**
206  * @param halfExtents A vector with the three half-extents of the box shape
207  * @return A pointer to the created box shape
208  */
createBoxShape(const Vector3 & halfExtents)209 BoxShape* PhysicsCommon::createBoxShape(const Vector3& halfExtents) {
210 
211     if (halfExtents.x <= decimal(0.0) || halfExtents.y <= decimal(0.0) || halfExtents.z <= decimal(0.0)) {
212 
213         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
214                  "Error when creating a BoxShape: the half extents must be positive values",  __FILE__, __LINE__);
215     }
216     BoxShape* shape = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(BoxShape))) BoxShape(halfExtents, mMemoryManager.getHeapAllocator());
217 
218     mBoxShapes.add(shape);
219 
220     return shape;
221 }
222 
223 // Destroy a box collision shape
224 /**
225  * @param boxShape A pointer to the box shape to destroy
226  */
destroyBoxShape(BoxShape * boxShape)227 void PhysicsCommon::destroyBoxShape(BoxShape* boxShape) {
228 
229     // If the shape is still part of some colliders
230     if (boxShape->mColliders.size() > 0) {
231 
232         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
233                  "Error when destroying the BoxShape because it is still used by some colliders",  __FILE__, __LINE__);
234     }
235 
236    // Call the destructor of the shape
237    boxShape->~BoxShape();
238 
239    // Release allocated memory
240    mMemoryManager.release(MemoryManager::AllocationType::Pool, boxShape, sizeof(BoxShape));
241 
242    mBoxShapes.remove(boxShape);
243 }
244 
245 // Create and return a capsule shape
246 /**
247  * @param radius The radius of the sphere of the capsule shape
248  * @param height The height of the capsule shape (distance betwen the two spheres centers)
249  * @return boxShape A pointer to the created capsule shape
250  */
createCapsuleShape(decimal radius,decimal height)251 CapsuleShape* PhysicsCommon::createCapsuleShape(decimal radius, decimal height) {
252 
253     if (radius <= decimal(0.0)) {
254 
255         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
256                  "Error when creating a CapsuleShape: radius must be a positive value",  __FILE__, __LINE__);
257     }
258 
259     if (height <= decimal(0.0)) {
260 
261         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
262                  "Error when creating a CapsuleShape: height must be a positive value",  __FILE__, __LINE__);
263     }
264 
265     CapsuleShape* shape = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(CapsuleShape))) CapsuleShape(radius, height, mMemoryManager.getHeapAllocator());
266 
267     mCapsuleShapes.add(shape);
268 
269     return shape;
270 }
271 
272 // Destroy a capsule collision shape
273 /**
274  * @param capsuleShape A pointer to the capsule shape to destroy
275  */
destroyCapsuleShape(CapsuleShape * capsuleShape)276 void PhysicsCommon::destroyCapsuleShape(CapsuleShape* capsuleShape) {
277 
278     // If the shape is still part of some colliders
279     if (capsuleShape->mColliders.size() > 0) {
280 
281         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
282                  "Error when destroying the CapsuleShape because it is still used by some colliders",  __FILE__, __LINE__);
283     }
284 
285    // Call the destructor of the shape
286    capsuleShape->~CapsuleShape();
287 
288    // Release allocated memory
289    mMemoryManager.release(MemoryManager::AllocationType::Pool, capsuleShape, sizeof(CapsuleShape));
290 
291    mCapsuleShapes.remove(capsuleShape);
292 }
293 
294 // Create and return a convex mesh shape
295 /**
296  * @param polyhedronMesh A pointer to the polyhedron mesh used to create the convex shape
297  * @param scaling Scaling factor to scale the polyhedron mesh if necessary
298  * @return A pointer to the created convex mesh shape
299  */
createConvexMeshShape(PolyhedronMesh * polyhedronMesh,const Vector3 & scaling)300 ConvexMeshShape* PhysicsCommon::createConvexMeshShape(PolyhedronMesh* polyhedronMesh, const Vector3& scaling) {
301 
302     ConvexMeshShape* shape = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(ConvexMeshShape))) ConvexMeshShape(polyhedronMesh, mMemoryManager.getHeapAllocator(), scaling);
303 
304     mConvexMeshShapes.add(shape);
305 
306     return shape;
307 }
308 
309 // Destroy a convex mesh shape
310 /**
311  * @param convexMeshShape A pointer to the convex mesh shape to destroy
312  */
destroyConvexMeshShape(ConvexMeshShape * convexMeshShape)313 void PhysicsCommon::destroyConvexMeshShape(ConvexMeshShape* convexMeshShape) {
314 
315     // If the shape is still part of some colliders
316     if (convexMeshShape->mColliders.size() > 0) {
317 
318         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
319                  "Error when destroying the ConvexMeshShape because it is still used by some colliders",  __FILE__, __LINE__);
320     }
321 
322    // Call the destructor of the shape
323    convexMeshShape->~ConvexMeshShape();
324 
325    // Release allocated memory
326    mMemoryManager.release(MemoryManager::AllocationType::Pool, convexMeshShape, sizeof(ConvexMeshShape));
327 
328    mConvexMeshShapes.remove(convexMeshShape);
329 }
330 
331 // Create and return a height-field shape
332 /**
333  * @param nbGridColumns Number of columns in the grid of the height field
334  * @param nbGridRows Number of rows in the grid of the height field
335  * @param minHeight Minimum height value of the height field
336  * @param maxHeight Maximum height value of the height field
337  * @param heightFieldData Pointer to the first height value data (note that values are shared and not copied)
338  * @param dataType Data type for the height values (int, float, double)
339  * @param upAxis Integer representing the up axis direction (0 for x, 1 for y and 2 for z)
340  * @param integerHeightScale Scaling factor used to scale the height values (only when height values type is integer)
341  * @return A pointer to the created height field shape
342  */
createHeightFieldShape(int nbGridColumns,int nbGridRows,decimal minHeight,decimal maxHeight,const void * heightFieldData,HeightFieldShape::HeightDataType dataType,int upAxis,decimal integerHeightScale,const Vector3 & scaling)343 HeightFieldShape* PhysicsCommon::createHeightFieldShape(int nbGridColumns, int nbGridRows, decimal minHeight, decimal maxHeight,
344                                          const void* heightFieldData, HeightFieldShape::HeightDataType dataType,
345                                          int upAxis, decimal integerHeightScale, const Vector3& scaling) {
346 
347     HeightFieldShape* shape = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(HeightFieldShape))) HeightFieldShape(nbGridColumns, nbGridRows, minHeight, maxHeight,
348                                          heightFieldData, dataType, mMemoryManager.getHeapAllocator(), upAxis, integerHeightScale, scaling);
349 
350     mHeightFieldShapes.add(shape);
351 
352     return shape;
353 }
354 
355 // Destroy a height-field shape
356 /**
357  * @param heightFieldShape A pointer to the height field shape to destroy
358  */
destroyHeightFieldShape(HeightFieldShape * heightFieldShape)359 void PhysicsCommon::destroyHeightFieldShape(HeightFieldShape* heightFieldShape) {
360 
361     // If the shape is still part of some colliders
362     if (heightFieldShape->mColliders.size() > 0) {
363 
364         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
365                  "Error when destroying the HeightFieldShape because it is still used by some colliders",  __FILE__, __LINE__);
366     }
367 
368    // Call the destructor of the shape
369    heightFieldShape->~HeightFieldShape();
370 
371    // Release allocated memory
372    mMemoryManager.release(MemoryManager::AllocationType::Pool, heightFieldShape, sizeof(HeightFieldShape));
373 
374    mHeightFieldShapes.remove(heightFieldShape);
375 }
376 
377 // Create and return a concave mesh shape
378 /**
379  * @param triangleMesh A pointer to the triangle mesh to use to create the concave mesh shape
380  * @param scaling An optional scaling factor to scale the triangle mesh
381  * @return A pointer to the created concave mesh shape
382  */
createConcaveMeshShape(TriangleMesh * triangleMesh,const Vector3 & scaling)383 ConcaveMeshShape* PhysicsCommon::createConcaveMeshShape(TriangleMesh* triangleMesh, const Vector3& scaling) {
384 
385     ConcaveMeshShape* shape = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(ConcaveMeshShape))) ConcaveMeshShape(triangleMesh, mMemoryManager.getHeapAllocator(), scaling);
386 
387     mConcaveMeshShapes.add(shape);
388 
389     return shape;
390 }
391 
392 // Destroy a concave mesh shape
393 /**
394  * @param concaveMeshShape A pointer to the concave mesh shape to destroy
395  */
destroyConcaveMeshShape(ConcaveMeshShape * concaveMeshShape)396 void PhysicsCommon::destroyConcaveMeshShape(ConcaveMeshShape* concaveMeshShape) {
397 
398     // If the shape is still part of some colliders
399     if (concaveMeshShape->mColliders.size() > 0) {
400 
401         RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
402                  "Error when destroying the ConcaveMeshShape because it is still used by some colliders",  __FILE__, __LINE__);
403     }
404 
405    // Call the destructor of the shape
406    concaveMeshShape->~ConcaveMeshShape();
407 
408    // Release allocated memory
409    mMemoryManager.release(MemoryManager::AllocationType::Pool, concaveMeshShape, sizeof(ConcaveMeshShape));
410 
411    mConcaveMeshShapes.remove(concaveMeshShape);
412 }
413 
414 // Create a polyhedron mesh
415 /**
416  * @param polygonVertexArray A pointer to the polygon vertex array to use to create the polyhedron mesh
417  * @return A pointer to the created polyhedron mesh
418  */
createPolyhedronMesh(PolygonVertexArray * polygonVertexArray)419 PolyhedronMesh* PhysicsCommon::createPolyhedronMesh(PolygonVertexArray* polygonVertexArray) {
420 
421     PolyhedronMesh* mesh = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(PolyhedronMesh))) PolyhedronMesh(polygonVertexArray, mMemoryManager.getHeapAllocator());
422 
423     mPolyhedronMeshes.add(mesh);
424 
425     return mesh;
426 }
427 
428 // Destroy a polyhedron mesh
429 /**
430  * @param polyhedronMesh A pointer to the polyhedron mesh to destroy
431  */
destroyPolyhedronMesh(PolyhedronMesh * polyhedronMesh)432 void PhysicsCommon::destroyPolyhedronMesh(PolyhedronMesh* polyhedronMesh) {
433 
434    // Call the destructor of the shape
435    polyhedronMesh->~PolyhedronMesh();
436 
437    // Release allocated memory
438    mMemoryManager.release(MemoryManager::AllocationType::Pool, polyhedronMesh, sizeof(PolyhedronMesh));
439 
440    mPolyhedronMeshes.remove(polyhedronMesh);
441 }
442 
443 // Create a triangle mesh
444 /**
445  * @return A pointer to the created triangle mesh
446  */
createTriangleMesh()447 TriangleMesh* PhysicsCommon::createTriangleMesh() {
448 
449     TriangleMesh* mesh = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(TriangleMesh))) TriangleMesh(mMemoryManager.getHeapAllocator());
450 
451     mTriangleMeshes.add(mesh);
452 
453     return mesh;
454 }
455 
456 // Destroy a triangle mesh
457 /**
458  * @param A pointer to the triangle mesh to destroy
459  */
destroyTriangleMesh(TriangleMesh * triangleMesh)460 void PhysicsCommon::destroyTriangleMesh(TriangleMesh* triangleMesh) {
461 
462    // Call the destructor of the shape
463    triangleMesh->~TriangleMesh();
464 
465    // Release allocated memory
466    mMemoryManager.release(MemoryManager::AllocationType::Pool, triangleMesh, sizeof(TriangleMesh));
467 
468    mTriangleMeshes.remove(triangleMesh);
469 }
470 
471 // Create and return a new logger
472 /**
473  * @return A pointer to the created default logger
474  */
createDefaultLogger()475 DefaultLogger* PhysicsCommon::createDefaultLogger() {
476 
477     DefaultLogger* logger = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(DefaultLogger))) DefaultLogger(mMemoryManager.getHeapAllocator());
478 
479     mDefaultLoggers.add(logger);
480 
481     return logger;
482 }
483 
484 // Destroy a logger
485 /**
486  * @param A pointer to the default logger to destroy
487  */
destroyDefaultLogger(DefaultLogger * logger)488 void PhysicsCommon::destroyDefaultLogger(DefaultLogger* logger) {
489 
490    // Call the destructor of the logger
491    logger->~DefaultLogger();
492 
493    // Release allocated memory
494    mMemoryManager.release(MemoryManager::AllocationType::Pool, logger, sizeof(DefaultLogger));
495 
496    mDefaultLoggers.remove(logger);
497 }
498 
499 // If profiling is enabled
500 #ifdef IS_RP3D_PROFILING_ENABLED
501 
502 
503 // Create and return a new profiler
504 /// Note that you need to use a different profiler for each PhysicsWorld.
createProfiler()505 Profiler* PhysicsCommon::createProfiler() {
506 
507     Profiler* profiler = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(Profiler))) Profiler();
508 
509     mProfilers.add(profiler);
510 
511     return profiler;
512 }
513 
514 // Destroy a profiler
destroyProfiler(Profiler * profiler)515 void PhysicsCommon::destroyProfiler(Profiler* profiler) {
516 
517    // Call the destructor of the profiler
518    profiler->~Profiler();
519 
520    // Release allocated memory
521    mMemoryManager.release(MemoryManager::AllocationType::Pool, profiler, sizeof(Profiler));
522 
523    mProfilers.remove(profiler);
524 }
525 
526 #endif
527