192 lines
6.4 KiB
C++
192 lines
6.4 KiB
C++
#ifndef PHYSICS_HPP
|
|
#define PHYSICS_HPP
|
|
|
|
#include "logging.hpp"
|
|
|
|
#include <Jolt/Jolt.h>
|
|
#include <Jolt/Physics/Body/BodyInterface.h>
|
|
#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>
|
|
|
|
#include <cstdarg>
|
|
#include <glm/glm.hpp>
|
|
|
|
using namespace JPH;
|
|
using namespace JPH::literals;
|
|
|
|
// Callback for traces, connect this to your own trace function if you have one
|
|
static void TraceImpl(const char *in_fmt, ...)
|
|
{
|
|
// Format the message
|
|
va_list list;
|
|
va_start(list, in_fmt);
|
|
char buffer[1024];
|
|
vsnprintf(buffer, sizeof(buffer), in_fmt, list);
|
|
va_end(list);
|
|
|
|
OE_CORE_TRACE("Jolt: {}", buffer);
|
|
}
|
|
|
|
#ifdef JPH_ENABLE_ASSERTS
|
|
// Callback for asserts, connect this to your own assert handler if you have one
|
|
static bool AssertFailedImpl(const char *in_expression, const char *in_message, const char *in_file, uint in_line)
|
|
{
|
|
OE_CORE_ERROR("Jolt: Assert in file: {}:{} :({}) {}", in_file, in_line, in_expression, (in_message != nullptr? in_message : ""));
|
|
|
|
// 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 ObjectLayerPairFilterImpl : public ObjectLayerPairFilter
|
|
{
|
|
public:
|
|
virtual bool ShouldCollide(ObjectLayer object1, ObjectLayer object2) const override;
|
|
};
|
|
|
|
// 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);
|
|
};
|
|
|
|
inline JPH::Vec3 ToJolt(const glm::vec3& v) { return JPH::Vec3(v.x, v.y, v.z); };
|
|
|
|
class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface
|
|
{
|
|
public:
|
|
BPLayerInterfaceImpl()
|
|
{
|
|
object_to_broad_phase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING;
|
|
object_to_broad_phase[Layers::MOVING] = BroadPhaseLayers::MOVING;
|
|
}
|
|
|
|
virtual uint GetNumBroadPhaseLayers() const override { return BroadPhaseLayers::NUM_LAYERS; };
|
|
|
|
virtual BroadPhaseLayer GetBroadPhaseLayer(ObjectLayer layer) const override
|
|
{
|
|
JPH_ASSERT(layer < Layers::NUM_LAYERS);
|
|
return object_to_broad_phase[layer];
|
|
}
|
|
|
|
private:
|
|
BroadPhaseLayer object_to_broad_phase[Layers::NUM_LAYERS];
|
|
};
|
|
|
|
class ObjectVsBroadPhaseLayerFilterImpl : public ObjectVsBroadPhaseLayerFilter
|
|
{
|
|
public:
|
|
virtual bool ShouldCollide(ObjectLayer layer1, BroadPhaseLayer layer2) const override
|
|
{
|
|
switch (layer1)
|
|
{
|
|
case Layers::NON_MOVING:
|
|
return layer2 == 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
|
|
{
|
|
OE_CORE_TRACE("Jolt: Contact validate callback");
|
|
|
|
// 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
|
|
{
|
|
OE_CORE_TRACE("Jolt: A contact was added");
|
|
}
|
|
|
|
virtual void OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
|
|
{
|
|
OE_CORE_TRACE("Jolt: A contact was persisted");
|
|
}
|
|
|
|
virtual void OnContactRemoved(const SubShapeIDPair &inSubShapePair) override
|
|
{
|
|
OE_CORE_TRACE("Jolt: A contact was removed");
|
|
}
|
|
};
|
|
|
|
// An example activation listener
|
|
class MyBodyActivationListener : public BodyActivationListener
|
|
{
|
|
public:
|
|
virtual void OnBodyActivated(const BodyID &inBodyID, uint64 inBodyUserData) override
|
|
{
|
|
OE_CORE_TRACE("Jolt: A body got activated");
|
|
}
|
|
|
|
virtual void OnBodyDeactivated(const BodyID &inBodyID, uint64 inBodyUserData) override
|
|
{
|
|
OE_CORE_TRACE("Jolt: A body went to sleep");
|
|
}
|
|
};
|
|
|
|
namespace OpenEngine {
|
|
|
|
// Consider making this static like the renderer
|
|
class PhysicsEngine
|
|
{
|
|
public:
|
|
PhysicsEngine();
|
|
~PhysicsEngine();
|
|
|
|
// TODO: Temp, make abstract function to create a body
|
|
BodyInterface& GetBodyInterface() { return physics_system.GetBodyInterface(); };
|
|
void Update( float delta_time, int collision_steps);
|
|
|
|
private:
|
|
PhysicsSystem physics_system;
|
|
|
|
Ref<TempAllocatorImpl> tmp_allocator;
|
|
Ref<JobSystemThreadPool> job_system;
|
|
|
|
MyBodyActivationListener body_activation_listener;
|
|
MyContactListener contact_listener;
|
|
|
|
BPLayerInterfaceImpl broad_phase_layer_interface;
|
|
ObjectVsBroadPhaseLayerFilterImpl object_vs_broadphase_layer_filter;
|
|
ObjectLayerPairFilterImpl object_vs_object_layer_filter;
|
|
|
|
};
|
|
}
|
|
|
|
#endif // PHYSICS_HPP
|