2020-08-11 12:07:21 -04:00
|
|
|
#include "physics.hpp"
|
|
|
|
|
2020-09-21 09:37:52 -04:00
|
|
|
#include <btBulletDynamicsCommon.h>
|
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
#include "engine.hpp"
|
2020-09-21 09:37:52 -04:00
|
|
|
#include "scene.hpp"
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
Physics::Physics() {
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
2020-09-21 09:37:52 -04:00
|
|
|
Physics::~Physics() {}
|
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
void Physics::update(float deltaTime) {
|
|
|
|
if(engine->get_scene() == nullptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(auto [obj, rigidbody] : engine->get_scene()->get_all<Rigidbody>()) {
|
|
|
|
if(rigidbody.body != nullptr) {
|
|
|
|
if(rigidbody.type == Rigidbody::Type::Dynamic) {
|
2021-05-12 09:56:44 -04:00
|
|
|
if(rigidbody.stored_force != prism::float3(0.0f)) {
|
2020-08-11 12:07:21 -04:00
|
|
|
rigidbody.body->setLinearVelocity(btVector3(rigidbody.stored_force.x, rigidbody.stored_force.y, rigidbody.stored_force.z));
|
2021-05-12 09:56:44 -04:00
|
|
|
rigidbody.stored_force = prism::float3(0.0f);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
world->stepSimulation(deltaTime);
|
|
|
|
|
|
|
|
for(auto [object, collision] : engine->get_scene()->get_all<Collision>()) {
|
|
|
|
if(collision.shape == nullptr && !collision.is_trigger) {
|
|
|
|
switch(collision.type) {
|
|
|
|
case Collision::Type::Cube:
|
|
|
|
collision.shape = new btBoxShape(btVector3(collision.size.x / 2.0f, collision.size.y / 2.0f, collision.size.z / 2.0f));
|
|
|
|
break;
|
|
|
|
case Collision::Type::Capsule:
|
|
|
|
collision.shape = new btCapsuleShape(0.5f, collision.size.y);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(auto [obj, rigidbody] : engine->get_scene()->get_all<Rigidbody>()) {
|
|
|
|
auto& transform = engine->get_scene()->get<Transform>(obj);
|
|
|
|
|
|
|
|
if(rigidbody.body == nullptr) {
|
|
|
|
btTransform t;
|
|
|
|
t.setIdentity();
|
|
|
|
|
|
|
|
t.setOrigin(btVector3(transform.position.x, transform.position.y, transform.position.z));
|
|
|
|
t.setRotation(btQuaternion(transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w));
|
|
|
|
|
|
|
|
btDefaultMotionState* motionState = new btDefaultMotionState(t);
|
|
|
|
|
|
|
|
btScalar bodyMass = rigidbody.mass;
|
|
|
|
btVector3 bodyInertia;
|
|
|
|
|
|
|
|
if(rigidbody.mass != 0)
|
|
|
|
engine->get_scene()->get<Collision>(obj).shape->calculateLocalInertia(bodyMass, bodyInertia);
|
|
|
|
|
|
|
|
btRigidBody::btRigidBodyConstructionInfo bodyCI = btRigidBody::btRigidBodyConstructionInfo(bodyMass, motionState, engine->get_scene()->get<Collision>(obj).shape, bodyInertia);
|
|
|
|
|
|
|
|
bodyCI.m_friction = rigidbody.friction;
|
|
|
|
|
|
|
|
rigidbody.body = new btRigidBody(bodyCI);
|
|
|
|
|
|
|
|
if(!rigidbody.enable_deactivation)
|
|
|
|
rigidbody.body->setActivationState(DISABLE_DEACTIVATION);
|
|
|
|
|
|
|
|
if(!rigidbody.enable_rotation)
|
|
|
|
rigidbody.body->setAngularFactor(btVector3(0, 0, 0));
|
|
|
|
|
|
|
|
world->addRigidBody(rigidbody.body);
|
|
|
|
|
|
|
|
rigidbody.body->setUserIndex(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(rigidbody.type == Rigidbody::Type::Dynamic) {
|
|
|
|
btTransform trans = rigidbody.body->getWorldTransform();
|
2021-05-12 09:56:44 -04:00
|
|
|
transform.position = prism::float3(trans.getOrigin().x(), trans.getOrigin().y(), trans.getOrigin().z());
|
2020-08-11 12:07:21 -04:00
|
|
|
} else {
|
|
|
|
btTransform t;
|
|
|
|
t.setIdentity();
|
|
|
|
|
|
|
|
t.setOrigin(btVector3(transform.position.x, transform.position.y, transform.position.z));
|
|
|
|
t.setRotation(btQuaternion(transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w));
|
|
|
|
|
|
|
|
rigidbody.body->setWorldTransform(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Physics::remove_object(Object object) {
|
|
|
|
if(engine->get_scene()->has<Rigidbody>(object)) {
|
|
|
|
for(int i = 0 ; i < world->getNumCollisionObjects(); i++) {
|
|
|
|
auto obj = world->getCollisionObjectArray()[i];
|
|
|
|
|
|
|
|
if(obj->getUserIndex() == object) {
|
|
|
|
world->removeCollisionObject(obj);
|
|
|
|
delete obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-12 09:56:44 -04:00
|
|
|
Physics::RayResult Physics::raycast(prism::float3 from, prism::float3 to) {
|
2020-08-11 12:07:21 -04:00
|
|
|
Physics::RayResult result;
|
|
|
|
|
|
|
|
btVector3 btFrom(from.x, from.y, from.z);
|
|
|
|
btVector3 btTo(to.x, to.y, to.z);
|
|
|
|
|
|
|
|
btCollisionWorld::AllHitsRayResultCallback res(btFrom, btTo);
|
|
|
|
|
|
|
|
world->rayTest(btFrom, btTo, res);
|
|
|
|
|
|
|
|
int closestCollisionObject = NullObject;
|
|
|
|
float closestHitFraction = 1000.0f;
|
|
|
|
|
|
|
|
for(int i = 0; i < res.m_collisionObjects.size(); i++) {
|
|
|
|
if(!engine->get_scene()->get<Collision>(res.m_collisionObjects[i]->getUserIndex()).exclude_from_raycast) {
|
|
|
|
if(res.m_hitFractions[i] < closestHitFraction) {
|
|
|
|
closestCollisionObject = i;
|
|
|
|
closestHitFraction = res.m_hitFractions[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(closestCollisionObject != NullObject) {
|
|
|
|
result.hasHit = true;
|
|
|
|
|
2021-10-14 08:51:58 -04:00
|
|
|
auto vec = res.m_hitPointWorld[closestCollisionObject];
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-05-12 09:56:44 -04:00
|
|
|
result.location = prism::float3(vec.x(), vec.y(), vec.z());
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Physics::reset() {
|
|
|
|
if(world != nullptr)
|
|
|
|
world.reset();
|
|
|
|
|
|
|
|
broadphase = std::make_unique<btDbvtBroadphase>();
|
|
|
|
|
|
|
|
collisionConfiguration = std::make_unique<btDefaultCollisionConfiguration>();
|
|
|
|
dispatcher = std::make_unique<btCollisionDispatcher>(collisionConfiguration.get());
|
|
|
|
|
|
|
|
solver = std::make_unique<btSequentialImpulseConstraintSolver>();
|
|
|
|
|
|
|
|
world = std::make_unique<btDiscreteDynamicsWorld>(dispatcher.get(), broadphase.get(), solver.get(), collisionConfiguration.get());
|
|
|
|
world->setGravity(btVector3(0.0f, -9.8f, 0.0f));
|
|
|
|
}
|