Browse Source

ADDED WORKING COLLISION RESOLUTION! (works for rectangles at least)

Iver 1 month ago
parent
commit
c16041abfa
13 changed files with 200 additions and 65 deletions
  1. BIN
      builds/libfizzix.so
  2. BIN
      builds/main.bin
  3. 1 1
      changelog.txt
  4. 3 0
      issues.txt
  5. BIN
      notes.pdf
  6. 3 1
      readme.md
  7. BIN
      research.png
  8. 1 1
      src/headers/FZ_functions.h
  9. 13 1
      src/headers/FZ_math.h
  10. 5 3
      src/headers/FZ_types.h
  11. 1 1
      src/headers/fizzix.h
  12. 18 9
      src/launch program/main.c
  13. 155 48
      src/main/main.c

BIN
builds/libfizzix.so


BIN
builds/main.bin


+ 1 - 1
changelog.txt

@@ -1 +1 @@
--removed licence
+-completed basic collision solving and resolution

+ 3 - 0
issues.txt

@@ -0,0 +1,3 @@
+-unoptimized
+-concave polygons wont work, need to add splitting into tris
+-moment of interia formula assumes rectangle

BIN
notes.pdf


+ 3 - 1
readme.md

@@ -1,6 +1,8 @@
 # Fizzix, a 2D and 3D Physics Engine
 # Fizzix, a 2D and 3D Physics Engine
 
 
-# NOT FINISHED. CANNOT SOLVE 2D or 3D PHYSICS YET
+## Milestones
+
+ * Working collision resolution for convex shapes!!! `Completed January 25th, 2026`
 
 
 ### Etymology
 ### Etymology
 
 

BIN
research.png


+ 1 - 1
src/headers/FZ_functions.h

@@ -1,7 +1,7 @@
 #ifndef FZ_FUNCTIONS_H
 #ifndef FZ_FUNCTIONS_H
 #define FZ_FUNCTIONS_H
 #define FZ_FUNCTIONS_H
 
 
-#include "FZ_structs.h"
+#include "FZ_types.h"
 
 
 FZ_scene* FZ_new_scene();
 FZ_scene* FZ_new_scene();
 FZ_shape* FZ_new_shape();
 FZ_shape* FZ_new_shape();

+ 13 - 1
src/headers/FZ_math.h

@@ -1,12 +1,16 @@
 #ifndef FZ_MATH_H
 #ifndef FZ_MATH_H
 #define FZ_MATH_H
 #define FZ_MATH_H
 
 
-#include "FZ_structs.h"
+#include "FZ_types.h"
 
 
 double distance_2(FZ_vector_2 a, FZ_vector_2 b){
 double distance_2(FZ_vector_2 a, FZ_vector_2 b){
     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
 }
 }
 
 
+double squared_distance_2(FZ_vector_2 a, FZ_vector_2 b){
+    return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
+}
+
 FZ_vector_2 v2_mul(FZ_vector_2 vector, double value){
 FZ_vector_2 v2_mul(FZ_vector_2 vector, double value){
     vector.x *= value;
     vector.x *= value;
     vector.y *= value;
     vector.y *= value;
@@ -92,4 +96,12 @@ double project_along_vectors_normal(FZ_vector_2 a, FZ_vector_2 b, FZ_vector_2 c)
     return (v2_dot(c, b) / v2_dot(b, b));
     return (v2_dot(c, b) / v2_dot(b, b));
 }
 }
 
 
+FZ_vector_2 v2_scalar_cross(FZ_vector_2 vector, double value){
+    return v2_mul(v2_rotate_neg_90(vector), value);
+}
+
+double v2_v2_cross(FZ_vector_2 a, FZ_vector_2 b) {
+    return a.x * b.y - a.y * b.x;
+}
+
 #endif
 #endif

+ 5 - 3
src/headers/FZ_structs.h → src/headers/FZ_types.h

@@ -21,9 +21,9 @@ typedef struct {
     FZ_vector_2 position;
     FZ_vector_2 position;
     FZ_vector_2 velocity;
     FZ_vector_2 velocity;
     double angle;
     double angle;
-    double angular_veclocity;
+    double angular_velocity;
     double mass;
     double mass;
-    double moment_of_intertia;
+    double moment_of_inertia;
     void (*tick_transform_function)(FZ_vector_2 position, double angle);
     void (*tick_transform_function)(FZ_vector_2 position, double angle);
     void (*tick_points_function)(FZ_vector_2* points, uint16_t point_count);
     void (*tick_points_function)(FZ_vector_2* points, uint16_t point_count);
     uint16_t flags; 
     uint16_t flags; 
@@ -31,9 +31,10 @@ typedef struct {
 
 
 typedef struct {
 typedef struct {
     double penetration;
     double penetration;
-    FZ_vector_2 contact_point;
     int reference_line_index;
     int reference_line_index;
     int incident_line_index;
     int incident_line_index;
+    FZ_vector_2 point_a;
+    FZ_vector_2 point_b;
     FZ_shape* reference_shape;
     FZ_shape* reference_shape;
     FZ_shape* incident_shape;
     FZ_shape* incident_shape;
 } projected_points_data;
 } projected_points_data;
@@ -42,6 +43,7 @@ typedef struct {
     FZ_shape** shapes;
     FZ_shape** shapes;
     uint16_t shape_count;
     uint16_t shape_count;
     FZ_vector_2 gravity;
     FZ_vector_2 gravity;
+    double restitution;
 } FZ_scene; 
 } FZ_scene; 
 
 
 typedef struct {
 typedef struct {

+ 1 - 1
src/headers/fizzix.h

@@ -2,7 +2,7 @@
 #define FIZZIX_H
 #define FIZZIX_H
 
 
 #include "FZ_functions.h"
 #include "FZ_functions.h"
-#include "FZ_structs.h"
+#include "FZ_types.h"
 #include "FZ_math.h"
 #include "FZ_math.h"
 
 
 #endif
 #endif

+ 18 - 9
src/launch program/main.c

@@ -10,26 +10,34 @@ int main(){
 
 
     FZ_shape* shape_1 = FZ_new_shape();
     FZ_shape* shape_1 = FZ_new_shape();
     FZ_shape* shape_2 = FZ_new_shape();
     FZ_shape* shape_2 = FZ_new_shape();
+    FZ_shape* shape_3 = FZ_new_shape();
 
 
-    scene->shapes = malloc(sizeof(FZ_shape*) * 2);
+    scene->shapes = malloc(sizeof(FZ_shape*) * 3);
 
 
     scene->shapes[0] = shape_1;
     scene->shapes[0] = shape_1;
     scene->shapes[1] = shape_2;
     scene->shapes[1] = shape_2;
+    scene->shapes[2] = shape_3;
 
 
     shape_2->flags = FZ_SHAPE_IS_STATIC;
     shape_2->flags = FZ_SHAPE_IS_STATIC;
 
 
-    shape_1->scale = (FZ_vector_2){50, 50};
-    shape_2->scale = (FZ_vector_2){190, 100};
+    shape_1->scale = (FZ_vector_2){100, 20};
+    shape_3->scale = (FZ_vector_2){100, 20};
+    shape_2->scale = (FZ_vector_2){2000, 100};
 
 
-    shape_1->position = (FZ_vector_2){-100, 50};
+    shape_1->position = (FZ_vector_2){-150, 50};
+    shape_3->position = (FZ_vector_2){150, 50};
     shape_2->position = (FZ_vector_2){0, -150};
     shape_2->position = (FZ_vector_2){0, -150};
 
 
-    scene->shape_count = 2;
+    scene->shape_count = 3;
 
 
     shape_1->velocity = (FZ_vector_2){60, 300};
     shape_1->velocity = (FZ_vector_2){60, 300};
+    shape_3->velocity = (FZ_vector_2){-60, 300};
     
     
-    shape_1->angular_veclocity = 5;
-    // shape_2->angular_veclocity = 2;
+    shape_1->angular_velocity = 4;
+    shape_3->angular_velocity = -5;
+    // shape_2->angular_velocity = 2;
+
+    shape_3->mass = 1;
 
 
     long int start, end;
     long int start, end;
     double fps = 0;
     double fps = 0;
@@ -40,6 +48,7 @@ int main(){
     double delta_min = 0.0001;
     double delta_min = 0.0001;
     double delta_max = 100000;
     double delta_max = 100000;
 
 
+    
     while (context->is_running){
     while (context->is_running){
         start = clock();
         start = clock();
 
 
@@ -49,8 +58,8 @@ int main(){
         end = clock();
         end = clock();
 
 
         deltatime = fmin(fmax((double)(end - start) / (double)(CLOCKS_PER_SEC), delta_min), delta_max);
         deltatime = fmin(fmax((double)(end - start) / (double)(CLOCKS_PER_SEC), delta_min), delta_max);
-    
-        printf("%d fps      \r", (int)(1.0 / deltatime));
+
+        // printf("%d fps      \r", (int)(1.0 / deltatime));
     }
     }
 
 
     return 0;
     return 0;

+ 155 - 48
src/main/main.c

@@ -10,12 +10,12 @@ FZ_shape* FZ_new_shape(){
     new_shape->position = (FZ_vector_2){0, 0};
     new_shape->position = (FZ_vector_2){0, 0};
     new_shape->velocity = (FZ_vector_2){0, 0};
     new_shape->velocity = (FZ_vector_2){0, 0};
     new_shape->angle = 0;
     new_shape->angle = 0;
-    new_shape->angular_veclocity = 0;
+    new_shape->angular_velocity = 0;
 
 
     // default otha stuff
     // default otha stuff
     new_shape->flags = 0;
     new_shape->flags = 0;
     new_shape->mass = 1;
     new_shape->mass = 1;
-    new_shape->moment_of_intertia = 1;
+    new_shape->moment_of_inertia = 1;
     new_shape->point_count = 4;
     new_shape->point_count = 4;
     new_shape->points = malloc(sizeof(FZ_vector_2) * 4);
     new_shape->points = malloc(sizeof(FZ_vector_2) * 4);
     new_shape->transformed_points = malloc(sizeof(FZ_vector_2) * 4);
     new_shape->transformed_points = malloc(sizeof(FZ_vector_2) * 4);
@@ -36,6 +36,7 @@ FZ_scene* FZ_new_scene(){
     new_scene->shape_count = 0;
     new_scene->shape_count = 0;
     new_scene->shapes = NULL;
     new_scene->shapes = NULL;
     new_scene->gravity = (FZ_vector_2){0, -300};
     new_scene->gravity = (FZ_vector_2){0, -300};
+    new_scene->restitution = 0.7;
 
 
     return new_scene;
     return new_scene;
 }
 }
@@ -119,7 +120,7 @@ projected_points_data project_points(FZ_shape* shape_a, FZ_shape* shape_b){
         uint16_t point_a = i;
         uint16_t point_a = i;
         uint16_t point_b = (i + 1) % shape_b->point_count;
         uint16_t point_b = (i + 1) % shape_b->point_count;
 
 
-        FZ_vector_2 line_normal = v2_normalize(v2_rotate_90(v2_ew_sub(shape_a->transformed_points[point_a], shape_a->transformed_points[point_b])));
+        FZ_vector_2 line_normal = v2_normalize(v2_rotate_90(v2_ew_sub(shape_b->transformed_points[point_a], shape_b->transformed_points[point_b])));
 
 
         double a_max = -INFINITY;
         double a_max = -INFINITY;
         double a_min = INFINITY;
         double a_min = INFINITY;
@@ -170,8 +171,12 @@ projected_points_data project_points(FZ_shape* shape_a, FZ_shape* shape_b){
     uint16_t incident_line_index;
     uint16_t incident_line_index;
     double lowest_dot = INFINITY;
     double lowest_dot = INFINITY;
 
 
-    draw_line(vector_2_lerp(data.reference_shape->transformed_points[data.reference_line_index], data.reference_shape->transformed_points[(data.reference_line_index + 1) % data.reference_shape->point_count], 0.5), v2_ew_add(vector_2_lerp(data.reference_shape->transformed_points[data.reference_line_index], data.reference_shape->transformed_points[(data.reference_line_index + 1) % data.reference_shape->point_count], 0.5), v2_mul(smallest_penetrations_normal, 40)), 0x22FFFFFF);
+    double highest_dot = -INFINITY;
+
+    // draw_line(vector_2_lerp(data.reference_shape->transformed_points[data.reference_line_index], data.reference_shape->transformed_points[(data.reference_line_index + 1) % data.reference_shape->point_count], 0.5), v2_ew_add(vector_2_lerp(data.reference_shape->transformed_points[data.reference_line_index], data.reference_shape->transformed_points[(data.reference_line_index + 1) % data.reference_shape->point_count], 0.5), v2_mul(smallest_penetrations_normal, 40)), 0x22FFFFFF);
 
 
+    // find the incident line that is most opposite of the reference line normal
+    // also finding the most penetrating point
     for (int i = 0; i < data.incident_shape->point_count; i++){
     for (int i = 0; i < data.incident_shape->point_count; i++){
         FZ_vector_2 line_start = data.incident_shape->transformed_points[i];
         FZ_vector_2 line_start = data.incident_shape->transformed_points[i];
         FZ_vector_2 line_end = data.incident_shape->transformed_points[(i + 1) % data.incident_shape->point_count];
         FZ_vector_2 line_end = data.incident_shape->transformed_points[(i + 1) % data.incident_shape->point_count];
@@ -179,7 +184,7 @@ projected_points_data project_points(FZ_shape* shape_a, FZ_shape* shape_b){
         // normal of this line
         // normal of this line
         FZ_vector_2 normal = v2_normalize(v2_rotate_90(v2_ew_sub(line_start, line_end)));
         FZ_vector_2 normal = v2_normalize(v2_rotate_90(v2_ew_sub(line_start, line_end)));
         
         
-        draw_line(vector_2_lerp(line_start, line_end, 0.5), v2_ew_add(vector_2_lerp(line_start, line_end, 0.5), v2_mul(normal, 40)), 0xFF22FFFF);
+        // draw_line(vector_2_lerp(line_start, line_end, 0.5), v2_ew_add(vector_2_lerp(line_start, line_end, 0.5), v2_mul(normal, 40)), 0xFF22FFFF);
 
 
         // check if this normal and the reference normal are opposite
         // check if this normal and the reference normal are opposite
         double dot = v2_dot(normal, smallest_penetrations_normal);
         double dot = v2_dot(normal, smallest_penetrations_normal);
@@ -187,24 +192,44 @@ projected_points_data project_points(FZ_shape* shape_a, FZ_shape* shape_b){
             lowest_dot = dot;
             lowest_dot = dot;
             incident_line_index = i;
             incident_line_index = i;
         }
         }
+
+        // find most penetrating point
+        dot = v2_dot(v2_ew_sub(line_start, data.reference_shape->position), v2_mul(smallest_penetrations_normal, -1));
+        if (dot > highest_dot){
+            highest_dot = dot;
+
+            data.point_b = line_start;
+        }
     }
     }
 
 
     data.incident_line_index = incident_line_index;
     data.incident_line_index = incident_line_index;
 
 
-    FZ_vector_2 line_ab_vector = v2_ew_sub((data.incident_line_index - 1) < 0 ? data.incident_shape->transformed_points[data.incident_shape->point_count - 1] : data.incident_shape->transformed_points[data.incident_line_index - 1], data.incident_shape->transformed_points[data.incident_line_index]);
-    FZ_vector_2 line_bc_vector = v2_ew_sub(data.incident_shape->transformed_points[data.incident_line_index], data.incident_shape->transformed_points[(data.incident_line_index + 1) % data.incident_shape->point_count]);
+    // find point a
+    
+    FZ_vector_2 reference_a = data.reference_shape->transformed_points[(data.reference_line_index) % data.reference_shape->point_count];
+    FZ_vector_2 reference_b = data.reference_shape->transformed_points[(data.reference_line_index + 1) % data.reference_shape->point_count];
 
 
-    double offset = v2_dot(data.reference_shape->transformed_points[data.reference_line_index], smallest_penetrations_normal);
+    FZ_vector_2 reference_vector = v2_ew_sub(reference_b, reference_a);
+    FZ_vector_2 point_to_project = v2_ew_sub(data.point_b, reference_a);
 
 
-    double dot_ab = v2_dot(line_ab_vector, smallest_penetrations_normal);
-    double dot_bc = v2_dot(line_bc_vector, smallest_penetrations_normal);
+    double c = v2_dot(reference_vector, point_to_project) / v2_dot(reference_vector, reference_vector);
 
 
+    data.point_a = v2_ew_add(
+            v2_mul(reference_vector, c), 
+            reference_a
+        );
 
 
+    // debug points
+    // for (int i = 0; i < 8; i++){
+        // draw_line(data.point_a, v2_ew_add(data.point_a, v2_rot((FZ_vector_2){0, 40}, (FZ_vector_2){0, 0}, 6.28318530718 * ((double)i / (double)8.0))), 0xFFFFFFFF);
+        // draw_line(data.point_b, v2_ew_add(data.point_b, v2_rot((FZ_vector_2){0, 40}, (FZ_vector_2){0, 0}, 6.28318530718 * ((double)i / (double)8.0))), 0xFFFFFFFF);
+    // }
 
 
     return data;
     return data;
 }
 }
 
 
 int FZ_tick(FZ_scene* scene, double deltatime){
 int FZ_tick(FZ_scene* scene, double deltatime){
+    // update objects based on velocities
     for (int i = 0; i < scene->shape_count; i++){
     for (int i = 0; i < scene->shape_count; i++){
         FZ_shape* shape = scene->shapes[i];
         FZ_shape* shape = scene->shapes[i];
 
 
@@ -215,7 +240,7 @@ int FZ_tick(FZ_scene* scene, double deltatime){
             shape->velocity = v2_ew_add(shape->velocity, v2_mul(scene->gravity, deltatime));
             shape->velocity = v2_ew_add(shape->velocity, v2_mul(scene->gravity, deltatime));
 
 
             shape->position = v2_ew_add(shape->position, v2_mul(shape->velocity, deltatime));
             shape->position = v2_ew_add(shape->position, v2_mul(shape->velocity, deltatime));
-            shape->angle += shape->angular_veclocity * deltatime;
+            shape->angle += shape->angular_velocity * deltatime;
         }
         }
 
 
         for (int j = 0; j < shape->point_count; j++){
         for (int j = 0; j < shape->point_count; j++){
@@ -228,46 +253,128 @@ int FZ_tick(FZ_scene* scene, double deltatime){
         // printf("%f %f\n", shape->transformed_points[0].x, shape->transformed_points[0].y);
         // printf("%f %f\n", shape->transformed_points[0].x, shape->transformed_points[0].y);
     }
     }
     
     
-    for (int i = 0; i < scene->shape_count; i++){
-        FZ_shape* shape_1 = scene->shapes[i];
-        
-        for (int j = 0; j < scene->shape_count; j++){
-            if (i <= j) continue;
-            
-            FZ_shape* shape_2 = scene->shapes[j];
-
-            projected_points_data data = project_points(shape_1, shape_2);
+    // check for colisions
+    double iterations = 1;
 
 
-            if (data.penetration != 0){
-                shape_1->flags |= FZ_SHAPE_IS_COLLIDING;
-                shape_2->flags |= FZ_SHAPE_IS_COLLIDING;
-
-                int i0 = data.reference_line_index;
-                int i1 = (i0 + 1) % data.reference_shape->point_count;
-
-                FZ_vector_2 p0 = data.reference_shape->transformed_points[i0];
-                FZ_vector_2 p1 = data.reference_shape->transformed_points[i1];
-
-                FZ_vector_2 start = v2_mul(v2_ew_add(p0, p1), 0.5);
-
-                FZ_vector_2 edge = v2_ew_sub(p1, p0);
-
-                FZ_vector_2 normal = (FZ_vector_2){ edge.y, -edge.x };
-
-                double len2 = v2_dot(normal, normal);
+    for (int k = 0; k < (int)iterations; k++){ 
+        for (int i = 0; i < scene->shape_count; i++){
+            FZ_shape* shape_1 = scene->shapes[i];
+            
+            for (int j = 0; j < scene->shape_count; j++){
+                if (i <= j) continue;
+                
+                FZ_shape* shape_2 = scene->shapes[j];
+
+                projected_points_data data = project_points(shape_1, shape_2);
+
+                if (shape_1->flags & FZ_SHAPE_IS_STATIC && shape_2->flags & FZ_SHAPE_IS_STATIC) continue;
+
+                // shapes are colliding
+                if (data.penetration != 0){
+                    shape_1->flags |= FZ_SHAPE_IS_COLLIDING;
+                    shape_2->flags |= FZ_SHAPE_IS_COLLIDING;
+
+                    int i0 = data.reference_line_index;
+                    int i1 = (i0 + 1) % data.reference_shape->point_count;
+
+                    FZ_vector_2 p0 = data.reference_shape->transformed_points[i0];
+                    FZ_vector_2 p1 = data.reference_shape->transformed_points[i1];
+
+                    FZ_vector_2 start = v2_mul(v2_ew_add(p0, p1), 0.5);
+
+                    FZ_vector_2 edge = v2_ew_sub(p1, p0);
+
+                    FZ_vector_2 reference_normal = v2_normalize((FZ_vector_2){ edge.y, -edge.x });
+
+                    FZ_vector_2 pc_a = v2_ew_sub(
+                                    data.point_a,
+                                    data.reference_shape->position
+                                );
+
+                    FZ_vector_2 pc_b = v2_ew_sub(
+                                    data.point_b,
+                                    data.incident_shape->position
+                                );
+                                
+
+                    FZ_vector_2 point_a_velocity = v2_ew_add(
+                            data.reference_shape->velocity,
+                            v2_scalar_cross(
+                                pc_a,
+                                data.reference_shape->angular_velocity
+                            )
+                        );
+
+                    
+                    FZ_vector_2 point_b_velocity = v2_ew_add(
+                            data.incident_shape->velocity,
+                            v2_scalar_cross(
+                                pc_b,
+                                data.incident_shape->angular_velocity
+                            )
+                        );
+                    
+                    double normal_velocity_scalar = v2_dot(v2_ew_sub(
+                                point_a_velocity,
+                                point_b_velocity
+                            ),
+                            reference_normal
+                        );
+
+                    double J_numerator = -(1 + scene->restitution) * normal_velocity_scalar;
+                    
+                    data.reference_shape->moment_of_inertia = data.reference_shape->mass * (pow(data.reference_shape->scale.x, 2) + pow(data.reference_shape->scale.y, 2)) / 12.0;
+                    data.incident_shape->moment_of_inertia = data.incident_shape->mass * (pow(data.incident_shape->scale.x, 2) + pow(data.incident_shape->scale.y, 2)) / 12.0;
+
+                    double m̃_a = data.reference_shape->flags & FZ_SHAPE_IS_STATIC ? 0.0 : 1.0 / data.reference_shape->mass + squared_distance_2(data.reference_shape->position, data.point_a) / data.reference_shape->moment_of_inertia;
+                    double m̃_b = data.incident_shape->flags & FZ_SHAPE_IS_STATIC ? 0.0 : 1.0 / data.incident_shape->mass + squared_distance_2(data.incident_shape->position, data.point_b) / data.incident_shape->moment_of_inertia;
+                    double J_denominator = m̃_a + m̃_b;
+                
+                    double J = J_numerator / J_denominator;
 
 
-                if (len2 > 0.0) {
-                    normal = v2_mul(normal, 1.0 / sqrt(len2));
+                    FZ_vector_2 delta_a_v = v2_mul(reference_normal, J / data.reference_shape->mass);
+                    FZ_vector_2 delta_b_v = v2_mul(reference_normal, -J / data.incident_shape->mass);
+                
+                    double delta_a_w = (J * v2_v2_cross(pc_a, reference_normal)) / data.reference_shape->moment_of_inertia;
+                    double delta_b_w = (-J * v2_v2_cross(pc_b, reference_normal)) / data.incident_shape->moment_of_inertia;
 
 
-                    FZ_vector_2 end =
-                        v2_ew_add(start,
-                            v2_mul(normal, data.penetration));
+                    double separation = data.penetration / (double)(!(data.reference_shape->flags & FZ_SHAPE_IS_STATIC) + !(data.incident_shape->flags & FZ_SHAPE_IS_STATIC));
 
 
-                    draw_line(start, end, 0xFF5555FF);
+                    if(!(data.reference_shape->flags & FZ_SHAPE_IS_STATIC)){
+                        data.reference_shape->velocity = v2_ew_add(
+                            data.reference_shape->velocity,
+                            delta_a_v
+                        );
                 
                 
-                    draw_line(data.incident_shape->transformed_points[data.incident_line_index], data.incident_shape->transformed_points[(data.incident_line_index + 1) % data.incident_shape->point_count], 0xFFFFFFFF);
+                        data.reference_shape->angular_velocity += delta_a_w;
+
+                        data.reference_shape->position = v2_ew_add(
+                            data.reference_shape->position, 
+                            v2_mul(
+                                reference_normal, 
+                                separation
+                            )
+                        );
+                    }
+
+                    if(!(data.incident_shape->flags & FZ_SHAPE_IS_STATIC)){
+                        data.incident_shape->velocity = v2_ew_add(
+                            data.incident_shape->velocity,
+                            delta_b_v
+                        );
+                    
+                        data.incident_shape->angular_velocity += delta_b_w;
+                    
+                        data.incident_shape->position = v2_ew_add(
+                            data.incident_shape->position, 
+                            v2_mul(
+                                reference_normal, 
+                                -separation
+                            )
+                        );
+                    }
+                } else {
                 }
                 }
-            } else {
             }
             }
         }
         }
     }
     }
@@ -281,7 +388,7 @@ int FZ_render_debug(FZ_scene* scene){
         FZ_shape* shape = scene->shapes[i];
         FZ_shape* shape = scene->shapes[i];
         
         
         for (int j = 0; j < shape->point_count; j++){
         for (int j = 0; j < shape->point_count; j++){
-            // draw_line(shape->transformed_points[j], j < shape->point_count - 1 ? shape->transformed_points[j + 1] : shape->transformed_points[0], shape->flags & FZ_SHAPE_IS_COLLIDING ? 0x5555FFFF : 0x55FF55FF);
+            draw_line(shape->transformed_points[j], j < shape->point_count - 1 ? shape->transformed_points[j + 1] : shape->transformed_points[0], shape->flags & FZ_SHAPE_IS_COLLIDING ? 0x5555FFFF : 0x55FF55FF);
         }
         }
         
         
         for (int j = 0; j < shape->point_count; j++){
         for (int j = 0; j < shape->point_count; j++){
@@ -342,8 +449,8 @@ int FZ_init(){
 
 
     context.flags = 0;
     context.flags = 0;
 
 
-    context.sdl.width = 500;
-    context.sdl.height = 500;
+    context.sdl.width = 2000;
+    context.sdl.height = 1000;
 
 
     context.sdl.half_width = context.sdl.width / 2;
     context.sdl.half_width = context.sdl.width / 2;
     context.sdl.half_height = context.sdl.height / 2;
     context.sdl.half_height = context.sdl.height / 2;