├── .gitignore ├── CMakeLists.txt ├── Makefile ├── README.md ├── build └── .gitkeep ├── raylib-cpp-bullet3.gif ├── resources └── raylib-cpp.png └── src ├── CMakeLists.txt └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directory. 2 | build/* 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Object files 8 | *.o 9 | *.ko 10 | *.obj 11 | *.elf 12 | 13 | # Linker output 14 | *.ilk 15 | *.map 16 | *.exp 17 | 18 | # Precompiled Headers 19 | *.gch 20 | *.pch 21 | 22 | # Libraries 23 | *.lib 24 | *.a 25 | *.la 26 | *.lo 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | # Debug files 43 | *.dSYM/ 44 | *.su 45 | *.idb 46 | *.pdb 47 | 48 | # Kernel Module Compile Results 49 | *.mod* 50 | *.cmd 51 | .tmp_versions/ 52 | modules.order 53 | Module.symvers 54 | Mkfile.old 55 | dkms.conf 56 | 57 | # IDE and editor private config/settings 58 | .vscode 59 | .cache 60 | 61 | # Ignores 62 | !build/.gitkeep 63 | !resources/*.obj 64 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Setup 2 | cmake_minimum_required(VERSION 3.20) 3 | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 4 | include(FetchContent) 5 | set(FETCHCONTENT_QUIET 0) 6 | 7 | project (raylib-cpp-bullet3 8 | VERSION 0.0.1 9 | DESCRIPTION "raylib-cpp C++ & bullet3" 10 | HOMEPAGE_URL "https://github.com/rafaeldelboni/raylib-cpp-bullet3" 11 | LANGUAGES C CXX) 12 | 13 | # Fetch Raylib 14 | FetchContent_Declare( 15 | raylib 16 | GIT_REPOSITORY https://github.com/raysan5/raylib.git 17 | GIT_SHALLOW TRUE 18 | GIT_PROGRESS TRUE 19 | GIT_TAG master) 20 | set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples 21 | set(BUILD_GAMES OFF CACHE BOOL "" FORCE) # or games 22 | 23 | FetchContent_MakeAvailable(raylib) 24 | 25 | # Fetch Raylib-cpp 26 | FetchContent_Declare( 27 | raylib_cpp 28 | GIT_REPOSITORY https://github.com/robloach/raylib-cpp 29 | GIT_SHALLOW TRUE 30 | GIT_PROGRESS TRUE 31 | GIT_TAG master) 32 | set(BUILD_RAYLIB_CPP_EXAMPLES OFF CACHE BOOL "" FORCE) 33 | 34 | FetchContent_GetProperties(raylib_cpp) 35 | if(NOT raylib_cpp_POPULATED) 36 | FetchContent_Populate(raylib_cpp) 37 | 38 | file(COPY ${raylib_cpp_SOURCE_DIR}/vendor/raylib/src/raylib.h DESTINATION ${raylib_cpp_SOURCE_DIR}/include) 39 | file(COPY ${raylib_cpp_SOURCE_DIR}/vendor/raylib/src/raymath.h DESTINATION ${raylib_cpp_SOURCE_DIR}/include) 40 | 41 | add_subdirectory(${raylib_cpp_SOURCE_DIR} ${raylib_cpp_BINARY_DIR}) 42 | endif() 43 | 44 | # Fetch Bullet3 45 | FetchContent_Declare( 46 | bullet 47 | GIT_REPOSITORY https://github.com/bulletphysics/bullet3 48 | GIT_SHALLOW TRUE 49 | GIT_PROGRESS TRUE 50 | GIT_TAG master) 51 | set(BUILD_EXTRAS OFF CACHE BOOL "" FORCE) 52 | set(BUILD_PYBULLET OFF CACHE BOOL "" FORCE) 53 | set(BUILD_BULLET2_DEMOS OFF CACHE BOOL "" FORCE) 54 | set(BUILD_UNIT_TESTS OFF CACHE BOOL "" FORCE) 55 | set(BUILD_CPU_DEMOS OFF CACHE BOOL "" FORCE) 56 | set(BUILD_OPENGL3_DEMOS OFF CACHE BOOL "" FORCE) 57 | 58 | FetchContent_GetProperties(bullet) 59 | if(NOT bullet_POPULATED) 60 | FetchContent_Populate(bullet) 61 | add_subdirectory(${bullet_SOURCE_DIR} ${bullet_BINARY_DIR}) 62 | target_include_directories(Bullet3Collision PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 63 | target_include_directories(Bullet3Common PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 64 | target_include_directories(Bullet3Dynamics PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 65 | target_include_directories(Bullet3Geometry PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 66 | target_include_directories(Bullet3OpenCL_clew PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 67 | target_include_directories(Bullet2FileLoader PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 68 | target_include_directories(BulletCollision PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 69 | target_include_directories(BulletDynamics PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 70 | target_include_directories(BulletInverseDynamics PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 71 | target_include_directories(BulletSoftBody PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 72 | target_include_directories(LinearMath PUBLIC ${BULLET_PHYSICS_SOURCE_DIR}/src) 73 | endif() 74 | 75 | # Add symbolic link to resources folder in build 76 | add_custom_target(resources) 77 | FILE(TO_NATIVE_PATH "${PROJECT_SOURCE_DIR}/resources" source) 78 | FILE(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/resources" destination) 79 | IF (WIN32) 80 | add_custom_command( 81 | TARGET resources POST_BUILD 82 | COMMAND mklink /D ${destination} ${source} 83 | DEPENDS ${destination} 84 | COMMENT "symbolic link resources folder from ${source} => ${destination}" 85 | ) 86 | ELSE() 87 | add_custom_command( 88 | TARGET resources POST_BUILD 89 | COMMAND ${CMAKE_COMMAND} -E create_symlink ${source} ${destination} 90 | DEPENDS ${destination} 91 | COMMENT "symbolic link resources folder from ${source} => ${destination}" 92 | ) 93 | ENDIF() 94 | 95 | # C++ 96 | set(CMAKE_CXX_STANDARD 11) 97 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 98 | set(CMAKE_CXX_EXTENSIONS OFF) 99 | 100 | # Generates a compile_commands.json file containing the exact compiler calls 101 | set(CMAKE_EXPORT_COMPILE_COMMANDS 1) 102 | 103 | # Include Directory 104 | add_subdirectory(src) 105 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Lists phony targets for Makefile 2 | .PHONY: setup build 3 | 4 | setup: 5 | cmake -B build 6 | 7 | build: 8 | make --no-print-directory -C build 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # raylib-cpp-bullet3 2 | C, Cpp, Cmake, Raylib, Raylib-cpp and Bullet3 Boilerplate 3 | 4 | ![raylib-cpp-bullet3](raylib-cpp-bullet3.gif) 5 | 6 | ## Usage 7 | 8 | ```bash 9 | make setup 10 | make build 11 | ./build/src/main 12 | ``` 13 | 14 | ## Features 15 | This is a Cpp project template with the following features: 16 | 17 | - CMake build scripts for building libraries, applications, and tests. 18 | - Integrated with [Raylib](https://www.raylib.com/). 19 | - Integrated with [Bullet3](https://bulletphysics.org). 20 | - Resource folder to include assets 21 | 22 | ## License 23 | This is free and unencumbered software released into the public domain. 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /build/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rafaeldelboni/raylib-cpp-bullet3/52811a524072f07004280c285c39eb9194b3e001/build/.gitkeep -------------------------------------------------------------------------------- /raylib-cpp-bullet3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rafaeldelboni/raylib-cpp-bullet3/52811a524072f07004280c285c39eb9194b3e001/raylib-cpp-bullet3.gif -------------------------------------------------------------------------------- /resources/raylib-cpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rafaeldelboni/raylib-cpp-bullet3/52811a524072f07004280c285c39eb9194b3e001/resources/raylib-cpp.png -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable( 2 | main 3 | main.cpp) 4 | 5 | add_dependencies( 6 | main 7 | resources) 8 | 9 | target_link_libraries( 10 | main 11 | raylib 12 | raylib-cpp 13 | BulletDynamics 14 | BulletCollision 15 | LinearMath) 16 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" 2 | 3 | #include "BulletCollision/CollisionShapes/btCollisionShape.h" 4 | #include "BulletCollision/CollisionShapes/btConvexPolyhedron.h" 5 | #include "BulletCollision/CollisionShapes/btShapeHull.h" 6 | 7 | #include "LinearMath/btVector3.h" 8 | #include "btBulletDynamicsCommon.h" 9 | #include "raylib-cpp.hpp" 10 | #include "raylib.h" 11 | 12 | void setTransform(btScalar m[16], Matrix *matrix) { 13 | matrix->m0 = m[0]; 14 | matrix->m1 = m[1]; 15 | matrix->m2 = m[2]; 16 | matrix->m3 = m[3]; 17 | matrix->m4 = m[4]; 18 | matrix->m5 = m[5]; 19 | matrix->m6 = m[6]; 20 | matrix->m7 = m[7]; 21 | matrix->m8 = m[8]; 22 | matrix->m9 = m[9]; 23 | matrix->m10 = m[10]; 24 | matrix->m11 = m[11]; 25 | matrix->m12 = m[12]; 26 | matrix->m13 = m[13]; 27 | matrix->m14 = m[14]; 28 | matrix->m15 = m[15]; 29 | } 30 | 31 | void AllocateMeshData(Mesh *mesh, int triangleCount) { 32 | mesh->vertexCount = triangleCount * 3; 33 | mesh->triangleCount = triangleCount; 34 | 35 | mesh->vertices = (float *)MemAlloc(mesh->vertexCount * 3 * sizeof(float)); 36 | mesh->texcoords = (float *)MemAlloc(mesh->vertexCount * 2 * sizeof(float)); 37 | mesh->normals = (float *)MemAlloc(mesh->vertexCount * 3 * sizeof(float)); 38 | } 39 | 40 | Mesh ShapeToMesh(btCollisionShape *shape) { 41 | Mesh mesh = {0}; 42 | 43 | if (shape->isConvex()) { 44 | 45 | const btConvexPolyhedron *poly = 46 | shape->isPolyhedral() 47 | ? ((btPolyhedralConvexShape *)shape)->getConvexPolyhedron() 48 | : 0; 49 | 50 | if (poly) { 51 | int i; 52 | AllocateMeshData(&mesh, poly->m_faces.size()); 53 | int currentVertice = 0; 54 | for (i = 0; i < poly->m_faces.size(); i++) { 55 | btVector3 centroid(0, 0, 0); 56 | int numVerts = poly->m_faces[i].m_indices.size(); 57 | if (numVerts > 2) { 58 | btVector3 v1 = poly->m_vertices[poly->m_faces[i].m_indices[0]]; 59 | for (int v = 0; v < poly->m_faces[i].m_indices.size() - 2; v++) { 60 | btVector3 v2 = poly->m_vertices[poly->m_faces[i].m_indices[v + 1]]; 61 | btVector3 v3 = poly->m_vertices[poly->m_faces[i].m_indices[v + 2]]; 62 | btVector3 normal = (v3 - v1).cross(v2 - v1); 63 | normal.normalize(); 64 | 65 | mesh.vertices[currentVertice] = v1.x(); 66 | mesh.vertices[currentVertice + 1] = v1.y(); 67 | mesh.vertices[currentVertice + 2] = v1.z(); 68 | mesh.normals[currentVertice] = normal.getX(); 69 | mesh.normals[currentVertice + 1] = normal.getY(); 70 | mesh.normals[currentVertice + 2] = normal.getZ(); 71 | 72 | mesh.vertices[currentVertice + 3] = v2.x(); 73 | mesh.vertices[currentVertice + 4] = v2.y(); 74 | mesh.vertices[currentVertice + 5] = v2.z(); 75 | mesh.normals[currentVertice + 3] = normal.getX(); 76 | mesh.normals[currentVertice + 4] = normal.getY(); 77 | mesh.normals[currentVertice + 5] = normal.getZ(); 78 | 79 | mesh.vertices[currentVertice + 6] = v3.x(); 80 | mesh.vertices[currentVertice + 7] = v3.y(); 81 | mesh.vertices[currentVertice + 8] = v3.z(); 82 | mesh.normals[currentVertice + 6] = normal.getX(); 83 | mesh.normals[currentVertice + 7] = normal.getY(); 84 | mesh.normals[currentVertice + 8] = normal.getZ(); 85 | 86 | currentVertice += 9; 87 | } 88 | } 89 | } 90 | } else { 91 | btConvexShape *convexShape = (btConvexShape *)shape; 92 | btShapeHull *hull = new btShapeHull(convexShape); 93 | hull->buildHull(shape->getMargin()); 94 | 95 | AllocateMeshData(&mesh, hull->numTriangles()); 96 | int currentVertice = 0; 97 | if (hull->numTriangles() > 0) { 98 | 99 | int index = 0; 100 | const unsigned int *idx = hull->getIndexPointer(); 101 | const btVector3 *vtx = hull->getVertexPointer(); 102 | 103 | for (int i = 0; i < hull->numTriangles(); i++) { 104 | int i1 = index++; 105 | int i2 = index++; 106 | int i3 = index++; 107 | btAssert(i1 < hull->numIndices() && i2 < hull->numIndices() && 108 | i3 < hull->numIndices()); 109 | 110 | int index1 = idx[i1]; 111 | int index2 = idx[i2]; 112 | int index3 = idx[i3]; 113 | btAssert(index1 < hull->numVertices() && 114 | index2 < hull->numVertices() && 115 | index3 < hull->numVertices()); 116 | 117 | btVector3 v1 = vtx[index1]; 118 | btVector3 v2 = vtx[index2]; 119 | btVector3 v3 = vtx[index3]; 120 | btVector3 normal = (v3 - v1).cross(v2 - v1); 121 | normal.normalize(); 122 | 123 | mesh.vertices[currentVertice] = v1.x(); 124 | mesh.vertices[currentVertice + 1] = v1.y(); 125 | mesh.vertices[currentVertice + 2] = v1.z(); 126 | mesh.normals[currentVertice] = normal.getX(); 127 | mesh.normals[currentVertice + 1] = normal.getY(); 128 | mesh.normals[currentVertice + 2] = normal.getZ(); 129 | 130 | mesh.vertices[currentVertice + 3] = v2.x(); 131 | mesh.vertices[currentVertice + 4] = v2.y(); 132 | mesh.vertices[currentVertice + 5] = v2.z(); 133 | mesh.normals[currentVertice + 3] = normal.getX(); 134 | mesh.normals[currentVertice + 4] = normal.getY(); 135 | mesh.normals[currentVertice + 5] = normal.getZ(); 136 | 137 | mesh.vertices[currentVertice + 6] = v3.x(); 138 | mesh.vertices[currentVertice + 7] = v3.y(); 139 | mesh.vertices[currentVertice + 8] = v3.z(); 140 | mesh.normals[currentVertice + 6] = normal.getX(); 141 | mesh.normals[currentVertice + 7] = normal.getY(); 142 | mesh.normals[currentVertice + 8] = normal.getZ(); 143 | 144 | currentVertice += 9; 145 | } 146 | } 147 | } 148 | UploadMesh(&mesh, false); 149 | } 150 | return mesh; 151 | } 152 | 153 | struct PhysicsWorld { 154 | // keep the collision shapes, for deletion/cleanup 155 | btAlignedObjectArray m_collisionShapes; 156 | btAlignedObjectArray m_models; 157 | btBroadphaseInterface *m_broadphase; 158 | btCollisionDispatcher *m_dispatcher; 159 | btConstraintSolver *m_solver; 160 | btDefaultCollisionConfiguration *m_collisionConfiguration; 161 | btDiscreteDynamicsWorld *m_dynamicsWorld; 162 | 163 | PhysicsWorld() 164 | : m_broadphase(0), m_dispatcher(0), m_solver(0), 165 | m_collisionConfiguration(0), m_dynamicsWorld(0) {} 166 | 167 | virtual ~PhysicsWorld() {} 168 | 169 | btDiscreteDynamicsWorld *getDynamicsWorld() { return m_dynamicsWorld; } 170 | 171 | virtual void initPhysics() { 172 | /// collision configuration contains default setup for memory, collision 173 | /// setup 174 | m_collisionConfiguration = new btDefaultCollisionConfiguration(); 175 | 176 | /// use the default collision dispatcher. For parallel processing you can 177 | /// use a diffent dispatcher (see Extras/BulletMultiThreaded) 178 | m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); 179 | m_broadphase = new btDbvtBroadphase(); 180 | 181 | /// the default constraint solver. For parallel processing you can use a 182 | /// different solver (see Extras/BulletMultiThreaded) 183 | btSequentialImpulseConstraintSolver *sol = 184 | new btSequentialImpulseConstraintSolver; 185 | m_solver = sol; 186 | 187 | m_dynamicsWorld = new btDiscreteDynamicsWorld( 188 | m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); 189 | 190 | m_dynamicsWorld->setGravity(btVector3(0, -10, 0)); 191 | } 192 | 193 | virtual void exitPhysics() { 194 | // cleanup in the reverse order of creation/initialization 195 | // remove the rigidbodies from the dynamics world and delete them 196 | 197 | if (m_dynamicsWorld) { 198 | int i; 199 | for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--) { 200 | m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i)); 201 | } 202 | for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) { 203 | btCollisionObject *obj = m_dynamicsWorld->getCollisionObjectArray()[i]; 204 | btRigidBody *body = btRigidBody::upcast(obj); 205 | if (body && body->getMotionState()) { 206 | delete body->getMotionState(); 207 | } 208 | m_dynamicsWorld->removeCollisionObject(obj); 209 | delete obj; 210 | } 211 | } 212 | // delete collision shapes 213 | for (int j = 0; j < m_collisionShapes.size(); j++) { 214 | btCollisionShape *shape = m_collisionShapes[j]; 215 | delete shape; 216 | } 217 | m_collisionShapes.clear(); 218 | 219 | // delete raylib's models 220 | for (int j = 0; j < m_models.size(); j++) { 221 | UnloadModel(m_models[j]); 222 | } 223 | m_models.clear(); 224 | 225 | delete m_dynamicsWorld; 226 | m_dynamicsWorld = 0; 227 | 228 | delete m_solver; 229 | m_solver = 0; 230 | 231 | delete m_broadphase; 232 | m_broadphase = 0; 233 | 234 | delete m_dispatcher; 235 | m_dispatcher = 0; 236 | 237 | delete m_collisionConfiguration; 238 | m_collisionConfiguration = 0; 239 | } 240 | 241 | btRigidBody *createRigidBody(float mass, const btTransform &startTransform, 242 | btCollisionShape *shape, int modelIndex, 243 | btVector3 colorRGB = btVector3(130, 130, 130)) { 244 | 245 | btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); 246 | 247 | // rigidbody is dynamic if and only if mass is non zero, otherwise static 248 | bool isDynamic = (mass != 0.f); 249 | 250 | btVector3 localInertia(0, 0, 0); 251 | if (isDynamic) 252 | shape->calculateLocalInertia(mass, localInertia); 253 | 254 | // using motionstate is recommended, it provides interpolation 255 | // capabilities, and only synchronizes 'active' objects 256 | btDefaultMotionState *myMotionState = 257 | new btDefaultMotionState(startTransform); 258 | 259 | btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, 260 | localInertia); 261 | 262 | btRigidBody *body = new btRigidBody(cInfo); 263 | 264 | body->setUserIndex(-1); 265 | body->setUserIndex3(modelIndex); 266 | 267 | body->setCustomDebugColor(colorRGB); 268 | 269 | m_dynamicsWorld->addRigidBody(body); 270 | return body; 271 | } 272 | 273 | void deleteRigidBody(btRigidBody *body) { 274 | int graphicsUid = body->getUserIndex(); 275 | m_dynamicsWorld->removeRigidBody(body); 276 | btMotionState *ms = body->getMotionState(); 277 | delete body; 278 | delete ms; 279 | } 280 | 281 | void drawDebug() { 282 | for (int j = m_dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--) { 283 | btCollisionObject *obj = m_dynamicsWorld->getCollisionObjectArray()[j]; 284 | btRigidBody *body = btRigidBody::upcast(obj); 285 | btTransform trans; 286 | if (body && body->getMotionState()) { 287 | body->getMotionState()->getWorldTransform(trans); 288 | } else { 289 | trans = obj->getWorldTransform(); 290 | } 291 | 292 | btScalar m[16]; 293 | trans.getOpenGLMatrix(m); 294 | Vector3 position = (Vector3){0, 0, 0}; 295 | Model model = this->m_models[body->getUserIndex3()]; 296 | setTransform(m, &model.transform); 297 | 298 | btVector3 vecColor = btVector3(230, 41, 55); 299 | body->getCustomDebugColor(vecColor); 300 | Color color = raylib::Color((int)vecColor.getX(), (int)vecColor.getY(), 301 | (int)vecColor.getZ(), 255); 302 | 303 | DrawModelWires(model, position, 1.0f, color); 304 | } 305 | } 306 | }; 307 | 308 | int main() { 309 | const int screenWidth = 1024; 310 | const int screenHeight = 720; 311 | raylib::Window window(screenWidth, screenHeight, "raylib"); 312 | raylib::Camera3D camera( 313 | raylib::Vector3(0.0f, 10.0f, 10.0f), raylib::Vector3(0.0f, -5.0f, 0.0f), 314 | raylib::Vector3(0.0f, 10.0f, 0.0f), 45.0f, CAMERA_PERSPECTIVE); 315 | camera.SetMode(CAMERA_ORBITAL); // Set an orbital camera mode 316 | 317 | SetTargetFPS(60); // Set our game to run at 60 frames-per-second 318 | 319 | // physics 320 | //-------------------------------------------------------------------------------------- 321 | PhysicsWorld world = *new PhysicsWorld(); 322 | world.initPhysics(); 323 | 324 | { 325 | btCollisionShape *groundShape = 326 | new btBoxShape(btVector3(btScalar(50.), btScalar(50.), btScalar(50.))); 327 | world.m_collisionShapes.push_back(groundShape); 328 | 329 | Model model = LoadModelFromMesh(ShapeToMesh(groundShape)); 330 | world.m_models.push_back(model); 331 | 332 | btTransform groundTransform; 333 | groundTransform.setIdentity(); 334 | groundTransform.setOrigin(btVector3(0, -56, 0)); 335 | 336 | btRigidBody *ground = world.createRigidBody( 337 | 0., groundTransform, groundShape, world.m_models.size() - 1); 338 | } 339 | 340 | { 341 | btCollisionShape *colShape = new btSphereShape(btScalar(1.)); 342 | world.m_collisionShapes.push_back(colShape); 343 | world.m_collisionShapes.push_back(colShape); 344 | 345 | Model model = LoadModelFromMesh(ShapeToMesh(colShape)); 346 | world.m_models.push_back(model); 347 | 348 | btTransform startTransform; 349 | startTransform.setIdentity(); 350 | startTransform.setOrigin(btVector3(2, 10, 0)); 351 | 352 | btRigidBody *sphere = world.createRigidBody(1.f, startTransform, colShape, 353 | world.m_models.size() - 1, 354 | btVector3(255, 161, 0)); 355 | } 356 | 357 | { 358 | // create a few dynamic rigidbodies 359 | // Re-using the same collision is better for memory usage and performance 360 | 361 | btBoxShape *colShape = 362 | new btBoxShape(btVector3(btScalar(.1), btScalar(.1), btScalar(.1))); 363 | 364 | // btCollisionShape* colShape = new btSphereShape(btScalar(1.)); 365 | world.m_collisionShapes.push_back(colShape); 366 | 367 | Model model = LoadModelFromMesh(ShapeToMesh(colShape)); 368 | world.m_models.push_back(model); 369 | 370 | /// Create Dynamic Objects 371 | btTransform startTransform; 372 | startTransform.setIdentity(); 373 | 374 | btScalar mass(1.f); 375 | 376 | // rigidbody is dynamic if and only if mass is non zero, otherwise static 377 | bool isDynamic = (mass != 0.f); 378 | 379 | btVector3 localInertia(0, 0, 0); 380 | if (isDynamic) 381 | colShape->calculateLocalInertia(mass, localInertia); 382 | 383 | int arraySizeY = 5; 384 | int arraySizeX = 5; 385 | int arraySizeZ = 5; 386 | 387 | for (int k = 0; k < arraySizeY; k++) { 388 | for (int i = 0; i < arraySizeX; i++) { 389 | for (int j = 0; j < arraySizeZ; j++) { 390 | startTransform.setOrigin(btVector3( 391 | btScalar(0.2 * i), btScalar(2 + .2 * k), btScalar(0.2 * j))); 392 | 393 | world.createRigidBody(mass, startTransform, colShape, 394 | world.m_models.size() - 1, 395 | btVector3(0, 121, 241)); 396 | } 397 | } 398 | } 399 | } 400 | 401 | //-------------------------------------------------------------------------------------- 402 | 403 | // Main game loop 404 | while (!window.ShouldClose()) { // Detect window close button or ESC key 405 | // Update 406 | //---------------------------------------------------------------------------------- 407 | world.m_dynamicsWorld->stepSimulation(GetFrameTime(), 10); 408 | camera.Update(); // Update camera 409 | //---------------------------------------------------------------------------------- 410 | 411 | // Draw 412 | //---------------------------------------------------------------------------------- 413 | BeginDrawing(); 414 | { 415 | window.ClearBackground(RAYWHITE); 416 | 417 | camera.BeginMode(); 418 | { world.drawDebug(); } 419 | camera.EndMode(); 420 | 421 | DrawFPS(10, 10); 422 | } 423 | EndDrawing(); 424 | //---------------------------------------------------------------------------------- 425 | } 426 | 427 | world.exitPhysics(); 428 | return 0; 429 | } 430 | --------------------------------------------------------------------------------