
forward declarations are simplified with decl_typeclass_impl impl_Typeclass_for now instead only define static inline impl_Typeclass_for can be used to achieve the old behaviour
214 lines
5.7 KiB
C
214 lines
5.7 KiB
C
#include "rigidbody.h"
|
|
#include "camera.h"
|
|
#include "debug.h"
|
|
#include "program.h"
|
|
#include "collision.h"
|
|
#include "transformable.h"
|
|
|
|
struct RigidBody {
|
|
PhysicsEntity owner;
|
|
|
|
float mass;
|
|
float bounce;
|
|
|
|
Vector last_linear_force;
|
|
Vector next_linear_force;
|
|
Vector linear_velocity;
|
|
Transform internal_transform;
|
|
|
|
PhysicsMask layers;
|
|
PhysicsMask collision_mask;
|
|
|
|
List colliders;
|
|
|
|
int is_static;
|
|
|
|
List contacts;
|
|
};
|
|
|
|
impl_Transformable_for(RigidBody,
|
|
rigidbody_get_transform
|
|
)
|
|
|
|
RigidBody* rigidbody_make(PhysicsEntity owner) {
|
|
RigidBody* self = malloc(sizeof(RigidBody));
|
|
ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for rigidbody");
|
|
*self = (RigidBody){
|
|
.owner = owner,
|
|
.mass = 1.0f,
|
|
.bounce = 0.0f,
|
|
|
|
.linear_velocity = ZeroVector,
|
|
.next_linear_force = ZeroVector,
|
|
.last_linear_force = ZeroVector,
|
|
|
|
.internal_transform = *owner.transformable->get_transform(owner.data),
|
|
|
|
.layers = 0x1,
|
|
.collision_mask = 0x1,
|
|
|
|
.colliders = list_from_type(Collider*),
|
|
|
|
.is_static = 0,
|
|
|
|
.contacts = list_from_type(Contact),
|
|
};
|
|
self->internal_transform.scale = OneVector;
|
|
return self;
|
|
}
|
|
|
|
void rigidbody_destroy(RigidBody* self) {
|
|
list_empty(&self->contacts);
|
|
free(self);
|
|
}
|
|
|
|
void rigidbody_add_contact(RigidBody* self, Collision hit) {
|
|
list_add(&self->contacts,
|
|
&(Contact) {
|
|
.hit = hit,
|
|
.duration = delta_time()
|
|
});
|
|
}
|
|
|
|
void rigidbody_collect_contacts(RigidBody* self) {
|
|
list_empty(&self->contacts);
|
|
}
|
|
|
|
List* rigidbody_get_contacts(RigidBody* self) {
|
|
return &self->contacts;
|
|
}
|
|
|
|
static inline
|
|
void _internal_debug_draw_collision_edge(RigidBody* self, Contact* contact) {
|
|
#if !NDEBUG
|
|
Vector left = contact->hit.edge_left;
|
|
Vector right = contact->hit.edge_right;
|
|
Vector point = transform_point(&self->internal_transform, contact->hit.point);
|
|
Vector a = camera_world_to_pixel_point(&g_camera, left);
|
|
Vector b = camera_world_to_pixel_point(&g_camera, right);
|
|
Vector n = transform_direction(&g_camera.transform, contact->hit.normal);
|
|
SDL_SetRenderDrawColor(g_renderer, 255, 2, 255, 255);
|
|
SDL_RenderDrawLineF(g_renderer, a.x, a.y, b.x, b.y);
|
|
a = camera_world_to_pixel_point(&g_camera, point);
|
|
b = vaddf(a, vmulff(n, 100.f));
|
|
SDL_SetRenderDrawColor(g_renderer, 255, 0, 0, 255);
|
|
SDL_RenderDrawLineF(g_renderer, a.x, a.y, b.x, b.y);
|
|
#endif
|
|
}
|
|
|
|
void rigidbody_integrate_forces(RigidBody* self) {
|
|
if(self->is_static)
|
|
return;
|
|
|
|
const float dt = delta_time();
|
|
|
|
Vector position = self->internal_transform.position;
|
|
Vector velocity = self->linear_velocity;
|
|
Vector acceleration = vmulff(self->last_linear_force, 0.5f * dt * dt);
|
|
|
|
position = vaddf(position, vmulff(velocity, dt));
|
|
position = vaddf(position, acceleration);
|
|
|
|
acceleration = vmulff(vaddf(self->next_linear_force, acceleration), dt * 0.5f);
|
|
velocity = vaddf(velocity, acceleration);
|
|
|
|
self->linear_velocity = velocity;
|
|
self->internal_transform.position = position;
|
|
Transform* owner_trans = self->owner.transformable->get_transform(self->owner.data);
|
|
owner_trans->position = position;
|
|
|
|
self->last_linear_force = self->next_linear_force;
|
|
self->next_linear_force = ZeroVector;
|
|
}
|
|
|
|
float rigidbody_get_mass(const RigidBody* self) {
|
|
return self->mass;
|
|
}
|
|
|
|
void rigidbody_set_mass(RigidBody* self, float mass) {
|
|
self->mass = mass;
|
|
}
|
|
|
|
float rigidbody_get_bounce(const RigidBody* self) {
|
|
return self->bounce;
|
|
}
|
|
|
|
void rigidbody_set_bounce(RigidBody* self, float bounce) {
|
|
self->bounce = bounce;
|
|
}
|
|
|
|
void rigidbody_add_impulse(RigidBody* self, Vector force, int use_mass) {
|
|
rigidbody_accelerate(self, vmulff(force, 1.0f/delta_time()), use_mass);
|
|
}
|
|
|
|
void rigidbody_accelerate(RigidBody* self, Vector force, int use_mass) {
|
|
if(use_mass)
|
|
force = vmulff(force, 1.0f / self->mass);
|
|
if(vsqrmagnitudef(force) > powf(0.01f, 2))
|
|
self->next_linear_force = vaddf(self->next_linear_force, force);
|
|
}
|
|
|
|
PhysicsMask rigidbody_get_layers(RigidBody* self) {
|
|
return self->layers;
|
|
}
|
|
|
|
void rigidbody_set_layers(RigidBody* self, PhysicsMask layers) {
|
|
self->layers = layers;
|
|
}
|
|
|
|
PhysicsMask rigidbody_get_collision_mask(RigidBody* self) {
|
|
return self->collision_mask;
|
|
}
|
|
|
|
void rigidbody_set_collision_mask(RigidBody* self, PhysicsMask mask) {
|
|
self->collision_mask = mask;
|
|
}
|
|
|
|
int rigidbody_is_static(RigidBody* self) {
|
|
return self->is_static;
|
|
}
|
|
|
|
void rigidbody_set_static(RigidBody* self, int value) {
|
|
self->is_static = value != 0;
|
|
}
|
|
|
|
Vector rigidbody_get_velocity(const RigidBody* self) {
|
|
return self->linear_velocity;
|
|
}
|
|
|
|
void rigidbody_set_velocity(RigidBody* self, Vector velocity) {
|
|
self->next_linear_force = vaddf(self->next_linear_force, vsubf(velocity, self->next_linear_force));
|
|
self->linear_velocity = velocity;
|
|
}
|
|
|
|
Vector rigidbody_get_force(RigidBody* self) {
|
|
return self->next_linear_force;
|
|
}
|
|
|
|
void rigidbody_add_collider(RigidBody *self, Collider* collider) {
|
|
list_add(&self->colliders, &collider);
|
|
}
|
|
|
|
void rigidbody_remove_collider(RigidBody *self, Collider* collider) {
|
|
for(size_t i = 0; i < self->colliders.len; ++i) {
|
|
if(collider == *list_at_as(Collider*, &self->colliders, i)) {
|
|
list_erase(&self->colliders, i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
List* rigidbody_get_colliders(RigidBody* self) {
|
|
return &self->colliders;
|
|
}
|
|
|
|
void rigidbody_debug_draw_contacts(RigidBody* self) {
|
|
list_foreach(Contact*, contact, &self->contacts) {
|
|
_internal_debug_draw_collision_edge(self, contact);
|
|
}
|
|
}
|
|
|
|
Transform* rigidbody_get_transform(RigidBody* self) {
|
|
return &self->internal_transform;
|
|
}
|