Skip to content

Instantly share code, notes, and snippets.

@dzil123
Last active November 14, 2023 09:39
Show Gist options
  • Save dzil123/34a2d798f3a9b38e795d707ca38646b1 to your computer and use it in GitHub Desktop.
Save dzil123/34a2d798f3a9b38e795d707ca38646b1 to your computer and use it in GitHub Desktop.
#!/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
#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;
}
int joltmain(int argc, char** argv);
int raylibmain(void);
int main(void) {
joltmain(0, 0);
raylibmain();
}
#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