Last active
November 14, 2023 09:39
-
-
Save dzil123/34a2d798f3a9b38e795d707ca38646b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# ubuntu 20.04 | |
sudo apt update; sudo apt dist-upgrade; sudo apt install libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev build-essential git cmake | |
mkdir src | |
cd src | |
curl -L https://github.com/raysan5/raylib/archive/refs/tags/4.5.0.tar.gz | tar xz | |
pushd raylib-4.5.0/src | |
make PLATFORM=PLATFORM_DESKTOP | |
popd | |
curl -L https://github.com/jrouwe/JoltPhysics/archive/refs/tags/v4.0.0.tar.gz | tar xz | |
mkdir jolt | |
pushd jolt | |
for file in $(find ../JoltPhysics-4.0.0/Jolt -name '*.cpp'); do | |
echo $file | |
g++ $file -std=c++17 -I../JoltPhysics-4.0.0 -c -Wall | |
done | |
ar rvs libjolt.a *.o | |
popd | |
g++ main.cpp raylibmain.cpp joltmain.cpp -std=c++17 -Lraylib-4.5.0/src -Ljolt -Iraylib-4.5.0/src -IJoltPhysics-4.0.0 -lraylib -ljolt -lGL -lm -lpthread -ldl -lrt -lX11 -Wall -Wextra -o main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define main joltmain | |
// https://github.com/jrouwe/JoltPhysics/blob/b084d8f9054d78cb50bc851cc4db505462c4c634/HelloWorld/HelloWorld.cpp | |
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics) | |
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe | |
// SPDX-License-Identifier: MIT | |
// The Jolt headers don't include Jolt.h. Always include Jolt.h before including any other Jolt header. | |
// You can use Jolt.h in your precompiled header to speed up compilation. | |
#include <Jolt/Jolt.h> | |
// Jolt includes | |
#include <Jolt/RegisterTypes.h> | |
#include <Jolt/Core/Factory.h> | |
#include <Jolt/Core/TempAllocator.h> | |
#include <Jolt/Core/JobSystemThreadPool.h> | |
#include <Jolt/Physics/PhysicsSettings.h> | |
#include <Jolt/Physics/PhysicsSystem.h> | |
#include <Jolt/Physics/Collision/Shape/BoxShape.h> | |
#include <Jolt/Physics/Collision/Shape/SphereShape.h> | |
#include <Jolt/Physics/Body/BodyCreationSettings.h> | |
#include <Jolt/Physics/Body/BodyActivationListener.h> | |
// STL includes | |
#include <iostream> | |
#include <cstdarg> | |
#include <thread> | |
// Disable common warnings triggered by Jolt, you can use JPH_SUPPRESS_WARNING_PUSH / JPH_SUPPRESS_WARNING_POP to store and restore the warning state | |
JPH_SUPPRESS_WARNINGS | |
// All Jolt symbols are in the JPH namespace | |
using namespace JPH; | |
// If you want your code to compile using single or double precision write 0.0_r to get a Real value that compiles to double or float depending if JPH_DOUBLE_PRECISION is set or not. | |
using namespace JPH::literals; | |
// We're also using STL classes in this example | |
using namespace std; | |
// Callback for traces, connect this to your own trace function if you have one | |
static void TraceImpl(const char *inFMT, ...) | |
{ | |
// Format the message | |
va_list list; | |
va_start(list, inFMT); | |
char buffer[1024]; | |
vsnprintf(buffer, sizeof(buffer), inFMT, list); | |
va_end(list); | |
// Print to the TTY | |
cout << buffer << endl; | |
} | |
#ifdef JPH_ENABLE_ASSERTS | |
// Callback for asserts, connect this to your own assert handler if you have one | |
static bool AssertFailedImpl(const char *inExpression, const char *inMessage, const char *inFile, uint inLine) | |
{ | |
// Print to the TTY | |
cout << inFile << ":" << inLine << ": (" << inExpression << ") " << (inMessage != nullptr? inMessage : "") << endl; | |
// Breakpoint | |
return true; | |
}; | |
#endif // JPH_ENABLE_ASSERTS | |
// Layer that objects can be in, determines which other objects it can collide with | |
// Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more | |
// layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation | |
// but only if you do collision testing). | |
namespace Layers | |
{ | |
static constexpr ObjectLayer NON_MOVING = 0; | |
static constexpr ObjectLayer MOVING = 1; | |
static constexpr ObjectLayer NUM_LAYERS = 2; | |
}; | |
/// Class that determines if two object layers can collide | |
class ObjectLayerPairFilterImpl : public ObjectLayerPairFilter | |
{ | |
public: | |
virtual bool ShouldCollide(ObjectLayer inObject1, ObjectLayer inObject2) const override | |
{ | |
switch (inObject1) | |
{ | |
case Layers::NON_MOVING: | |
return inObject2 == Layers::MOVING; // Non moving only collides with moving | |
case Layers::MOVING: | |
return true; // Moving collides with everything | |
default: | |
JPH_ASSERT(false); | |
return false; | |
} | |
} | |
}; | |
// Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have | |
// a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame. | |
// You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have | |
// many object layers you'll be creating many broad phase trees, which is not efficient. If you want to fine tune | |
// your broadphase layers define JPH_TRACK_BROADPHASE_STATS and look at the stats reported on the TTY. | |
namespace BroadPhaseLayers | |
{ | |
static constexpr BroadPhaseLayer NON_MOVING(0); | |
static constexpr BroadPhaseLayer MOVING(1); | |
static constexpr uint NUM_LAYERS(2); | |
}; | |
// BroadPhaseLayerInterface implementation | |
// This defines a mapping between object and broadphase layers. | |
class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface | |
{ | |
public: | |
BPLayerInterfaceImpl() | |
{ | |
// Create a mapping table from object to broad phase layer | |
mObjectToBroadPhase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING; | |
mObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING; | |
} | |
virtual uint GetNumBroadPhaseLayers() const override | |
{ | |
return BroadPhaseLayers::NUM_LAYERS; | |
} | |
virtual BroadPhaseLayer GetBroadPhaseLayer(ObjectLayer inLayer) const override | |
{ | |
JPH_ASSERT(inLayer < Layers::NUM_LAYERS); | |
return mObjectToBroadPhase[inLayer]; | |
} | |
#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED) | |
virtual const char * GetBroadPhaseLayerName(BroadPhaseLayer inLayer) const override | |
{ | |
switch ((BroadPhaseLayer::Type)inLayer) | |
{ | |
case (BroadPhaseLayer::Type)BroadPhaseLayers::NON_MOVING: return "NON_MOVING"; | |
case (BroadPhaseLayer::Type)BroadPhaseLayers::MOVING: return "MOVING"; | |
default: JPH_ASSERT(false); return "INVALID"; | |
} | |
} | |
#endif // JPH_EXTERNAL_PROFILE || JPH_PROFILE_ENABLED | |
private: | |
BroadPhaseLayer mObjectToBroadPhase[Layers::NUM_LAYERS]; | |
}; | |
/// Class that determines if an object layer can collide with a broadphase layer | |
class ObjectVsBroadPhaseLayerFilterImpl : public ObjectVsBroadPhaseLayerFilter | |
{ | |
public: | |
virtual bool ShouldCollide(ObjectLayer inLayer1, BroadPhaseLayer inLayer2) const override | |
{ | |
switch (inLayer1) | |
{ | |
case Layers::NON_MOVING: | |
return inLayer2 == BroadPhaseLayers::MOVING; | |
case Layers::MOVING: | |
return true; | |
default: | |
JPH_ASSERT(false); | |
return false; | |
} | |
} | |
}; | |
// An example contact listener | |
class MyContactListener : public ContactListener | |
{ | |
public: | |
// See: ContactListener | |
virtual ValidateResult OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) override | |
{ | |
cout << "Contact validate callback" << endl; | |
// Allows you to ignore a contact before it is created (using layers to not make objects collide is cheaper!) | |
return ValidateResult::AcceptAllContactsForThisBodyPair; | |
} | |
virtual void OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override | |
{ | |
cout << "A contact was added" << endl; | |
} | |
virtual void OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override | |
{ | |
cout << "A contact was persisted" << endl; | |
} | |
virtual void OnContactRemoved(const SubShapeIDPair &inSubShapePair) override | |
{ | |
cout << "A contact was removed" << endl; | |
} | |
}; | |
// An example activation listener | |
class MyBodyActivationListener : public BodyActivationListener | |
{ | |
public: | |
virtual void OnBodyActivated(const BodyID &inBodyID, uint64 inBodyUserData) override | |
{ | |
cout << "A body got activated" << endl; | |
} | |
virtual void OnBodyDeactivated(const BodyID &inBodyID, uint64 inBodyUserData) override | |
{ | |
cout << "A body went to sleep" << endl; | |
} | |
}; | |
// Program entry point | |
int main(int argc, char** argv) | |
{ | |
// Register allocation hook | |
RegisterDefaultAllocator(); | |
// Install callbacks | |
Trace = TraceImpl; | |
JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl;) | |
// Create a factory | |
Factory::sInstance = new Factory(); | |
// Register all Jolt physics types | |
RegisterTypes(); | |
// We need a temp allocator for temporary allocations during the physics update. We're | |
// pre-allocating 10 MB to avoid having to do allocations during the physics update. | |
// B.t.w. 10 MB is way too much for this example but it is a typical value you can use. | |
// If you don't want to pre-allocate you can also use TempAllocatorMalloc to fall back to | |
// malloc / free. | |
TempAllocatorImpl temp_allocator(10 * 1024 * 1024); | |
// We need a job system that will execute physics jobs on multiple threads. Typically | |
// you would implement the JobSystem interface yourself and let Jolt Physics run on top | |
// of your own job scheduler. JobSystemThreadPool is an example implementation. | |
JobSystemThreadPool job_system(cMaxPhysicsJobs, cMaxPhysicsBarriers, thread::hardware_concurrency() - 1); | |
// This is the max amount of rigid bodies that you can add to the physics system. If you try to add more you'll get an error. | |
// Note: This value is low because this is a simple test. For a real project use something in the order of 65536. | |
const uint cMaxBodies = 1024; | |
// This determines how many mutexes to allocate to protect rigid bodies from concurrent access. Set it to 0 for the default settings. | |
const uint cNumBodyMutexes = 0; | |
// This is the max amount of body pairs that can be queued at any time (the broad phase will detect overlapping | |
// body pairs based on their bounding boxes and will insert them into a queue for the narrowphase). If you make this buffer | |
// too small the queue will fill up and the broad phase jobs will start to do narrow phase work. This is slightly less efficient. | |
// Note: This value is low because this is a simple test. For a real project use something in the order of 65536. | |
const uint cMaxBodyPairs = 1024; | |
// This is the maximum size of the contact constraint buffer. If more contacts (collisions between bodies) are detected than this | |
// number then these contacts will be ignored and bodies will start interpenetrating / fall through the world. | |
// Note: This value is low because this is a simple test. For a real project use something in the order of 10240. | |
const uint cMaxContactConstraints = 1024; | |
// Create mapping table from object layer to broadphase layer | |
// Note: As this is an interface, PhysicsSystem will take a reference to this so this instance needs to stay alive! | |
BPLayerInterfaceImpl broad_phase_layer_interface; | |
// Create class that filters object vs broadphase layers | |
// Note: As this is an interface, PhysicsSystem will take a reference to this so this instance needs to stay alive! | |
ObjectVsBroadPhaseLayerFilterImpl object_vs_broadphase_layer_filter; | |
// Create class that filters object vs object layers | |
// Note: As this is an interface, PhysicsSystem will take a reference to this so this instance needs to stay alive! | |
ObjectLayerPairFilterImpl object_vs_object_layer_filter; | |
// Now we can create the actual physics system. | |
PhysicsSystem physics_system; | |
physics_system.Init(cMaxBodies, cNumBodyMutexes, cMaxBodyPairs, cMaxContactConstraints, broad_phase_layer_interface, object_vs_broadphase_layer_filter, object_vs_object_layer_filter); | |
// A body activation listener gets notified when bodies activate and go to sleep | |
// Note that this is called from a job so whatever you do here needs to be thread safe. | |
// Registering one is entirely optional. | |
MyBodyActivationListener body_activation_listener; | |
physics_system.SetBodyActivationListener(&body_activation_listener); | |
// A contact listener gets notified when bodies (are about to) collide, and when they separate again. | |
// Note that this is called from a job so whatever you do here needs to be thread safe. | |
// Registering one is entirely optional. | |
MyContactListener contact_listener; | |
physics_system.SetContactListener(&contact_listener); | |
// The main way to interact with the bodies in the physics system is through the body interface. There is a locking and a non-locking | |
// variant of this. We're going to use the locking version (even though we're not planning to access bodies from multiple threads) | |
BodyInterface &body_interface = physics_system.GetBodyInterface(); | |
// Next we can create a rigid body to serve as the floor, we make a large box | |
// Create the settings for the collision volume (the shape). | |
// Note that for simple shapes (like boxes) you can also directly construct a BoxShape. | |
BoxShapeSettings floor_shape_settings(Vec3(100.0f, 1.0f, 100.0f)); | |
// Create the shape | |
ShapeSettings::ShapeResult floor_shape_result = floor_shape_settings.Create(); | |
ShapeRefC floor_shape = floor_shape_result.Get(); // We don't expect an error here, but you can check floor_shape_result for HasError() / GetError() | |
// Create the settings for the body itself. Note that here you can also set other properties like the restitution / friction. | |
BodyCreationSettings floor_settings(floor_shape, RVec3(0.0_r, -1.0_r, 0.0_r), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING); | |
// Create the actual rigid body | |
Body *floor = body_interface.CreateBody(floor_settings); // Note that if we run out of bodies this can return nullptr | |
// Add it to the world | |
body_interface.AddBody(floor->GetID(), EActivation::DontActivate); | |
// Now create a dynamic body to bounce on the floor | |
// Note that this uses the shorthand version of creating and adding a body to the world | |
BodyCreationSettings sphere_settings(new SphereShape(0.5f), RVec3(0.0_r, 2.0_r, 0.0_r), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING); | |
BodyID sphere_id = body_interface.CreateAndAddBody(sphere_settings, EActivation::Activate); | |
// Now you can interact with the dynamic body, in this case we're going to give it a velocity. | |
// (note that if we had used CreateBody then we could have set the velocity straight on the body before adding it to the physics system) | |
body_interface.SetLinearVelocity(sphere_id, Vec3(0.0f, -5.0f, 0.0f)); | |
// We simulate the physics world in discrete time steps. 60 Hz is a good rate to update the physics system. | |
const float cDeltaTime = 1.0f / 60.0f; | |
// Optional step: Before starting the physics simulation you can optimize the broad phase. This improves collision detection performance (it's pointless here because we only have 2 bodies). | |
// You should definitely not call this every frame or when e.g. streaming in a new level section as it is an expensive operation. | |
// Instead insert all new objects in batches instead of 1 at a time to keep the broad phase efficient. | |
physics_system.OptimizeBroadPhase(); | |
// Now we're ready to simulate the body, keep simulating until it goes to sleep | |
uint step = 0; | |
while (body_interface.IsActive(sphere_id)) | |
{ | |
// Next step | |
++step; | |
// Output current position and velocity of the sphere | |
RVec3 position = body_interface.GetCenterOfMassPosition(sphere_id); | |
Vec3 velocity = body_interface.GetLinearVelocity(sphere_id); | |
cout << "Step " << step << ": Position = (" << position.GetX() << ", " << position.GetY() << ", " << position.GetZ() << "), Velocity = (" << velocity.GetX() << ", " << velocity.GetY() << ", " << velocity.GetZ() << ")" << endl; | |
// If you take larger steps than 1 / 60th of a second you need to do multiple collision steps in order to keep the simulation stable. Do 1 collision step per 1 / 60th of a second (round up). | |
const int cCollisionSteps = 1; | |
// Step the world | |
physics_system.Update(cDeltaTime, cCollisionSteps, &temp_allocator, &job_system); | |
} | |
// Remove the sphere from the physics system. Note that the sphere itself keeps all of its state and can be re-added at any time. | |
body_interface.RemoveBody(sphere_id); | |
// Destroy the sphere. After this the sphere ID is no longer valid. | |
body_interface.DestroyBody(sphere_id); | |
// Remove and destroy the floor | |
body_interface.RemoveBody(floor->GetID()); | |
body_interface.DestroyBody(floor->GetID()); | |
// Unregisters all types with the factory and cleans up the default material | |
UnregisterTypes(); | |
// Destroy the factory | |
delete Factory::sInstance; | |
Factory::sInstance = nullptr; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int joltmain(int argc, char** argv); | |
int raylibmain(void); | |
int main(void) { | |
joltmain(0, 0); | |
raylibmain(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define main raylibmain | |
// https://github.com/raysan5/raylib/blob/a6c33193f718336c38e52a2affb31b3ea5fcb879/examples/core/core_basic_window.c | |
/******************************************************************************************* | |
* | |
* raylib [core] example - Basic window | |
* | |
* Welcome to raylib! | |
* | |
* To test examples, just press F6 and execute raylib_compile_execute script | |
* Note that compiled executable is placed in the same folder as .c file | |
* | |
* You can find all basic examples on C:\raylib\raylib\examples folder or | |
* raylib official webpage: www.raylib.com | |
* | |
* Enjoy using raylib. :) | |
* | |
* Example originally created with raylib 1.0, last time updated with raylib 1.0 | |
* | |
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, | |
* BSD-like license that allows static linking with closed source software | |
* | |
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) | |
* | |
********************************************************************************************/ | |
#include "raylib.h" | |
//------------------------------------------------------------------------------------ | |
// Program main entry point | |
//------------------------------------------------------------------------------------ | |
int main(void) | |
{ | |
// Initialization | |
//-------------------------------------------------------------------------------------- | |
const int screenWidth = 800; | |
const int screenHeight = 450; | |
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); | |
SetTargetFPS(60); // Set our game to run at 60 frames-per-second | |
//-------------------------------------------------------------------------------------- | |
// Main game loop | |
while (!WindowShouldClose()) // Detect window close button or ESC key | |
{ | |
// Update | |
//---------------------------------------------------------------------------------- | |
// TODO: Update your variables here | |
//---------------------------------------------------------------------------------- | |
// Draw | |
//---------------------------------------------------------------------------------- | |
BeginDrawing(); | |
ClearBackground(RAYWHITE); | |
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); | |
EndDrawing(); | |
//---------------------------------------------------------------------------------- | |
} | |
// De-Initialization | |
//-------------------------------------------------------------------------------------- | |
CloseWindow(); // Close window and OpenGL context | |
//-------------------------------------------------------------------------------------- | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment