 0c6f1dd8cf
			
		
	
	
		0c6f1dd8cf
		
	
	
	
	
		
			
			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;
 | |
| }
 |