fencer/src/rigidbody.c
2023-11-12 13:59:52 +01:00

162 lines
4.4 KiB
C

#include "rigidbody.h"
#include "camera.h"
#include "debug.h"
#include "program.h"
#include "collision.h"
#include "transformable.h"
struct RigidBody {
Transformable transformable;
float mass;
float bounce;
Vector last_linear_force;
Vector next_linear_force;
Vector linear_velocity;
Transform internal_transform;
int is_static;
List contacts;
};
RigidBody* rigidbody_make(Transformable transform) {
RigidBody* self = malloc(sizeof(RigidBody));
ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for rigidbody");
*self = (RigidBody){
.transformable = transform,
.mass = 1.0f,
.bounce = 0.0f,
.linear_velocity = ZeroVector,
.next_linear_force = ZeroVector,
.last_linear_force = ZeroVector,
.internal_transform = *transform.tc->get_transform(transform.data),
.is_static = 0,
.contacts = list_from_type(Contact),
};
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_RenderDrawLine(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_RenderDrawLine(g_renderer, a.x, a.y, b.x, b.y);
#endif
}
void rigidbody_integrate_forces(RigidBody* self) {
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;
transformable_set_position(self->transformable, 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);
}
int rigidbody_is_static(const RigidBody* self) {
return self->is_static;
}
void rigidbody_set_static(RigidBody* self, int is_static) {
self->is_static = is_static;
}
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_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;
}