Browse Source

added tri split & shrink culling, edited example scene, updated todo list

IverMartinson 5 months ago
parent
commit
28c0e7f778
7 changed files with 280 additions and 23 deletions
  1. BIN
      build/librasteriver.so
  2. BIN
      build/main.bin
  3. 8 1
      readme.md
  4. 1 0
      src/headers/custom_types.h
  5. 35 0
      src/headers/math.h
  6. 6 6
      src/launch_program/main.c
  7. 230 16
      src/library/rasteriver.c

BIN
build/librasteriver.so


BIN
build/main.bin


+ 8 - 1
readme.md

@@ -6,4 +6,11 @@ To run the binary, it needs to be in the same folder as librasteriver.so (if you
 [ ] checks for missing files
 [ ] checks for missing files
 [ ] debugging
 [ ] debugging
 [ ] support for 4 side+ polygons in the OBJ parser
 [ ] support for 4 side+ polygons in the OBJ parser
-[ ] support for negative UV and normals in the OBJ parser
+[ ] support for negative UV and normals in the OBJ parser
+[ ] .MTL support
+[ ] save scenes as templates? (files)
+[ ] fix camera rotation code
+[ ] fix OBJ parser issue with larger models? (idk, the teapot and gordon both dont work and I don't know why)
+[x] allow for aspect ratios other than 1:1
+[ ] fix strange visual issue that happens when (speculation) a triangle gets culled and split very close to the clipped point
+[ ] port CPU renderer to GPU

+ 1 - 0
src/headers/custom_types.h

@@ -97,6 +97,7 @@ typedef struct {
     RI_actor **actors;
     RI_actor **actors;
     int actor_count;
     int actor_count;
     float FOV;
     float FOV;
+    float minimum_clip_distance;
     float min_clip;
     float min_clip;
     RI_vector_3f camera_position;
     RI_vector_3f camera_position;
     RI_vector_4f camera_rotation;
     RI_vector_4f camera_rotation;

+ 35 - 0
src/headers/math.h

@@ -26,6 +26,11 @@ typedef struct {
     float z; 
     float z; 
 } RI_vector_4f;
 } RI_vector_4f;
 
 
+void vector_2f_times_float(RI_vector_2f *vector, float value){
+    vector->x *= value;
+    vector->y *= value;
+}
+
 void vector_3f_times_float(RI_vector_3f *vector, float value){
 void vector_3f_times_float(RI_vector_3f *vector, float value){
     vector->x *= value;
     vector->x *= value;
     vector->y *= value;
     vector->y *= value;
@@ -38,6 +43,11 @@ void vector_3f_hadamard(RI_vector_3f *multiplicand, RI_vector_3f multiplicator){
     multiplicand->z *= multiplicator.z;
     multiplicand->z *= multiplicator.z;
 }
 }
 
 
+void vector_2f_element_wise_add(RI_vector_2f *addend_a, RI_vector_2f addend_b){
+    addend_a->x += addend_b.x;
+    addend_a->y += addend_b.y;
+}
+
 void vector_3f_element_wise_add(RI_vector_3f *addend_a, RI_vector_3f addend_b){
 void vector_3f_element_wise_add(RI_vector_3f *addend_a, RI_vector_3f addend_b){
     addend_a->x += addend_b.x;
     addend_a->x += addend_b.x;
     addend_a->y += addend_b.y;
     addend_a->y += addend_b.y;
@@ -74,4 +84,29 @@ void quaternion_multiply(RI_vector_4f* a, RI_vector_4f b){
     *a = (RI_vector_4f){w, x, y, z};
     *a = (RI_vector_4f){w, x, y, z};
 }
 }
 
 
+void vector_2f_lerp(RI_vector_2f vector_a, RI_vector_2f vector_b, RI_vector_2f *result, float w1){
+    float w0 = 1.0 - w1;
+
+    vector_2f_times_float(result, 0);
+
+    vector_2f_times_float(&vector_a, w0);
+    vector_2f_times_float(&vector_b, w1);
+
+    vector_2f_element_wise_add(result, vector_a);
+    vector_2f_element_wise_add(result, vector_b);
+}
+
+void vector_3f_lerp(RI_vector_3f vector_a, RI_vector_3f vector_b, RI_vector_3f *result, float w1){
+    float w0 = 1.0 - w1;
+
+    vector_3f_times_float(result, 0);
+
+    vector_3f_times_float(&vector_a, w0);
+    vector_3f_times_float(&vector_b, w1);
+
+    vector_3f_element_wise_add(result, vector_a);
+    vector_3f_element_wise_add(result, vector_b);
+}
+
+
 #endif
 #endif

+ 6 - 6
src/launch_program/main.c

@@ -29,12 +29,12 @@ int main(){
 
 
     // materials
     // materials
     RI_material* floor_material = &materials[0];
     RI_material* floor_material = &materials[0];
-    floor_material->flags = RI_MATERIAL_HAS_TEXTURE;
+    floor_material->flags = RI_MATERIAL_HAS_TEXTURE | RI_MATERIAL_DOUBLE_SIDED;
     floor_material->texture_reference = floor_texture;
     floor_material->texture_reference = floor_texture;
     floor_material->albedo = 0xFFFFFFFF;
     floor_material->albedo = 0xFFFFFFFF;
     
     
     RI_material* wall_material = &materials[1];
     RI_material* wall_material = &materials[1];
-    wall_material->flags = 0;
+    wall_material->flags = RI_MATERIAL_DOUBLE_SIDED;
     wall_material->albedo = 0xFF7777FF;
     wall_material->albedo = 0xFF7777FF;
 
 
     RI_material* bill_cube_material = &materials[2];
     RI_material* bill_cube_material = &materials[2];
@@ -43,7 +43,7 @@ int main(){
     bill_cube_material->albedo = 0xFFFFFFFF;
     bill_cube_material->albedo = 0xFFFFFFFF;
 
 
     RI_material* screen_material = &materials[3];
     RI_material* screen_material = &materials[3];
-    screen_material->flags = RI_MATERIAL_HAS_TEXTURE;
+    screen_material->flags = RI_MATERIAL_HAS_TEXTURE | RI_MATERIAL_DOUBLE_SIDED;
     screen_material->texture_reference = ri->frame_buffer;
     screen_material->texture_reference = ri->frame_buffer;
     screen_material->albedo = 0xFFFFFFFF;
     screen_material->albedo = 0xFFFFFFFF;
 
 
@@ -51,7 +51,7 @@ int main(){
     RI_actor* floor = &actors[0];
     RI_actor* floor = &actors[0];
     floor->material_reference = floor_material;
     floor->material_reference = floor_material;
     floor->mesh_reference = unit_plane_mesh;
     floor->mesh_reference = unit_plane_mesh;
-    floor->transform.scale = (RI_vector_3f){100, 100, 100};
+    floor->transform.scale = (RI_vector_3f){100, 100, 500};
     floor->transform.position = (RI_vector_3f){0, -100, 200};
     floor->transform.position = (RI_vector_3f){0, -100, 200};
     floor->transform.rotation = (RI_vector_4f){0, 1, 0, 0};
     floor->transform.rotation = (RI_vector_4f){0, 1, 0, 0};
 
 
@@ -79,7 +79,7 @@ int main(){
     RI_add_actors_to_scene(4, actors, scene);
     RI_add_actors_to_scene(4, actors, scene);
 
 
     scene->FOV = 1.5; // 90 degrees in radians
     scene->FOV = 1.5; // 90 degrees in radians
-    scene->min_clip = 100;
+    scene->minimum_clip_distance = 0.1;
 
 
     float y_rotation = 0;
     float y_rotation = 0;
 
 
@@ -88,7 +88,7 @@ int main(){
 
 
         RI_euler_rotation_to_quaternion(&screen->transform.rotation, (RI_vector_3f){-3.14159 / 2, 0, ri->frame * 0.03});
         RI_euler_rotation_to_quaternion(&screen->transform.rotation, (RI_vector_3f){-3.14159 / 2, 0, ri->frame * 0.03});
 
 
-        scene->camera_position = (RI_vector_3f){cos(ri->frame * 0.07) * 10 * sin(ri->frame * 0.2), sin(ri->frame * 0.07) * 10 * sin(ri->frame * 0.2), -200};
+        scene->camera_position = (RI_vector_3f){cos(ri->frame * 0.07) * 10 * sin(ri->frame * 0.2), sin(ri->frame * 0.07) * 10 * sin(ri->frame * 0.2), -300};
         scene->camera_rotation = (RI_vector_4f){0, 1, 0, 0};
         scene->camera_rotation = (RI_vector_4f){0, 1, 0, 0};
 
 
         RI_euler_rotation_to_quaternion(&floor->transform.rotation, (RI_vector_3f){0, y_rotation, 0});
         RI_euler_rotation_to_quaternion(&floor->transform.rotation, (RI_vector_3f){0, y_rotation, 0});

+ 230 - 16
src/library/rasteriver.c

@@ -325,6 +325,8 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
         float horizontal_fov_factor = target_texture->resolution.x / tanf(0.5 * scene->FOV);
         float horizontal_fov_factor = target_texture->resolution.x / tanf(0.5 * scene->FOV);
         float vertical_fov_factor = target_texture->resolution.y / tanf(0.5 * scene->FOV);
         float vertical_fov_factor = target_texture->resolution.y / tanf(0.5 * scene->FOV);
 
 
+        scene->min_clip = scene->minimum_clip_distance;
+
         if (!scene->faces_to_render){
         if (!scene->faces_to_render){
             int total_faces = 0;
             int total_faces = 0;
             
             
@@ -336,7 +338,10 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
             scene->face_count = total_faces;
             scene->face_count = total_faces;
         }
         }
 
 
+        memset(scene->faces_to_render, 0, sizeof(RI_renderable_face) * scene->face_count * 2);
+
         int current_renderable_face_index = 0;
         int current_renderable_face_index = 0;
+        int current_split_renderable_face_index = 0;
 
 
         for (int actor_index = 0; actor_index < scene->actor_count; ++actor_index){
         for (int actor_index = 0; actor_index < scene->actor_count; ++actor_index){
             RI_actor *current_actor = scene->actors[actor_index];
             RI_actor *current_actor = scene->actors[actor_index];
@@ -402,6 +407,213 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
                 vector_3f_element_wise_subtract(&cur_r_face->position_1, scene->camera_position);
                 vector_3f_element_wise_subtract(&cur_r_face->position_1, scene->camera_position);
                 vector_3f_element_wise_subtract(&cur_r_face->position_2, scene->camera_position);
                 vector_3f_element_wise_subtract(&cur_r_face->position_2, scene->camera_position);
 
 
+                RI_vector_3f *pos_0 = &cur_r_face->position_0;
+                RI_vector_3f *pos_1 = &cur_r_face->position_1;
+                RI_vector_3f *pos_2 = &cur_r_face->position_2;
+
+                int is_0_clipped = pos_0->z < scene->min_clip;
+                int is_1_clipped = pos_1->z < scene->min_clip;
+                int is_2_clipped = pos_2->z < scene->min_clip;
+
+                int clip_count = is_0_clipped + is_1_clipped + is_2_clipped;
+
+                cur_r_face->should_render = 1;
+
+                switch(clip_count){
+                    case 3: // ignore polygon, it's behind the camera
+                        continue;
+                        break;
+                    
+                    case 2:{ // shrink poylgon
+                        RI_vector_3f *unclipped_point, *point_a, *point_b;
+                        RI_vector_3f *unclipped_normal, *normal_a, *normal_b;
+                        RI_vector_2f *unclipped_uv, *uv_a, *uv_b;
+
+                        if (!is_0_clipped){ 
+                            unclipped_point = &cur_r_face->position_0;
+                            point_a = &cur_r_face->position_1;
+                            point_b = &cur_r_face->position_2;
+                            
+                            unclipped_normal = &cur_r_face->normal_0;
+                            normal_a = &cur_r_face->normal_1;
+                            normal_b = &cur_r_face->normal_2;
+                        
+                            unclipped_uv = &cur_r_face->uv_0;
+                            uv_a = &cur_r_face->uv_1;
+                            uv_b = &cur_r_face->uv_2;
+                        }
+                        else if (!is_1_clipped){ 
+                            unclipped_point = &cur_r_face->position_1;
+                            point_a = &cur_r_face->position_2;
+                            point_b = &cur_r_face->position_0;
+                            
+                            unclipped_normal = &cur_r_face->normal_1;
+                            normal_a = &cur_r_face->normal_2;
+                            normal_b = &cur_r_face->normal_0;
+                        
+                            unclipped_uv = &cur_r_face->uv_1;
+                            uv_a = &cur_r_face->uv_2;
+                            uv_b = &cur_r_face->uv_0;
+                        }
+                        else if (!is_2_clipped){ 
+                            unclipped_point = &cur_r_face->position_2;
+                            point_a = &cur_r_face->position_0;
+                            point_b = &cur_r_face->position_1;
+                            
+                            unclipped_normal = &cur_r_face->normal_2;
+                            normal_a = &cur_r_face->normal_0;
+                            normal_b = &cur_r_face->normal_1;
+                        
+                            unclipped_uv = &cur_r_face->uv_2;
+                            uv_a = &cur_r_face->uv_0;
+                            uv_b = &cur_r_face->uv_1;
+                        }
+                    
+                        float fraction_a_to_unclip = (scene->min_clip - unclipped_point->z) / (point_a->z - unclipped_point->z);                          
+                        float fraction_b_to_unclip = (scene->min_clip - unclipped_point->z) / (point_b->z - unclipped_point->z);  
+
+                        vector_3f_lerp(*unclipped_point, *point_a, point_a, fraction_a_to_unclip);
+                        vector_3f_lerp(*unclipped_point, *point_b, point_b, fraction_b_to_unclip);
+
+                        vector_3f_lerp(*unclipped_normal, *normal_a, normal_a, fraction_a_to_unclip);
+                        vector_3f_lerp(*unclipped_normal, *normal_b, normal_b, fraction_b_to_unclip);
+
+                        vector_2f_lerp(*unclipped_uv, *uv_a, uv_a, fraction_a_to_unclip);
+                        vector_2f_lerp(*unclipped_uv, *uv_b, uv_b, fraction_b_to_unclip);
+
+                        break;}
+
+                    case 1: // split polygon
+                        RI_vector_3f clipped_point, point_a, point_b;
+                        RI_vector_3f clipped_normal, normal_a, normal_b;
+                        RI_vector_2f clipped_uv, uv_a, uv_b;
+
+                        if (is_0_clipped){ 
+                            clipped_point = cur_r_face->position_0;
+                            point_a = cur_r_face->position_1;
+                            point_b = cur_r_face->position_2;
+                            
+                            clipped_normal = cur_r_face->normal_0;
+                            normal_a = cur_r_face->normal_1;
+                            normal_b = cur_r_face->normal_2;
+                        
+                            clipped_uv = cur_r_face->uv_0;
+                            uv_a = cur_r_face->uv_1;
+                            uv_b = cur_r_face->uv_2;
+                        }
+                        else if (is_1_clipped){ 
+                            clipped_point = cur_r_face->position_1;
+                            point_a = cur_r_face->position_2;
+                            point_b = cur_r_face->position_0;
+                            
+                            clipped_normal = cur_r_face->normal_1;
+                            normal_a = cur_r_face->normal_2;
+                            normal_b = cur_r_face->normal_0;
+                        
+                            clipped_uv = cur_r_face->uv_1;
+                            uv_a = cur_r_face->uv_2;
+                            uv_b = cur_r_face->uv_0;
+                        }
+                        else if (is_2_clipped){ 
+                            clipped_point = cur_r_face->position_2;
+                            point_a = cur_r_face->position_0;
+                            point_b = cur_r_face->position_1;
+                            
+                            clipped_normal = cur_r_face->normal_2;
+                            normal_a = cur_r_face->normal_0;
+                            normal_b = cur_r_face->normal_1;
+                        
+                            clipped_uv = cur_r_face->uv_2;
+                            uv_a = cur_r_face->uv_0;
+                            uv_b = cur_r_face->uv_1;
+                        }
+
+                        float fraction_a_to_clip = (scene->min_clip - clipped_point.z) / (point_a.z - clipped_point.z);                        
+                        float fraction_b_to_clip = (scene->min_clip - clipped_point.z) / (point_b.z - clipped_point.z);                        
+
+                        RI_vector_3f new_point_a, new_point_b;  // the new points that move along the polygon's edge to match the z value of min_clip.
+                        RI_vector_3f new_normal_a, new_normal_b;  // they come from the clipped point which was originally only 1
+                        RI_vector_2f new_uv_a, new_uv_b;
+                        
+                        vector_3f_lerp(clipped_point, point_a, &new_point_a, fraction_a_to_clip);
+                        vector_3f_lerp(clipped_point, point_b, &new_point_b, fraction_b_to_clip);
+                        
+                        vector_3f_lerp(clipped_normal, normal_a, &new_normal_a, fraction_a_to_clip);
+                        vector_3f_lerp(clipped_normal, normal_b, &new_normal_b, fraction_b_to_clip);
+                        
+                        vector_2f_lerp(clipped_uv, uv_a, &new_uv_a, fraction_a_to_clip);
+                        vector_2f_lerp(clipped_uv, uv_b, &new_uv_b, fraction_b_to_clip);
+
+                        // okay, now we have a quad (in clockwise order, point a, point b, new point b, new point a)
+                        // quads are easy to turn into tris >w<
+
+                        RI_renderable_face *cur_r_split_face = &scene->faces_to_render[scene->face_count + current_split_renderable_face_index];
+
+                        cur_r_split_face->should_render = 1;
+
+                        cur_r_split_face->material_reference = cur_r_face->material_reference;
+
+                        cur_r_face->position_0 = point_a;
+                        cur_r_face->position_1 = point_b;
+                        cur_r_face->position_2 = new_point_a;
+
+                        cur_r_face->normal_0 = normal_a;
+                        cur_r_face->normal_1 = normal_b;
+                        cur_r_face->normal_2 = new_normal_a;
+
+                        cur_r_face->uv_0 = uv_a;
+                        cur_r_face->uv_1 = uv_b;
+                        cur_r_face->uv_2 = new_uv_a;
+
+                        cur_r_split_face->position_0 = point_b;
+                        cur_r_split_face->position_1 = new_point_b;
+                        cur_r_split_face->position_2 = new_point_a;
+
+                        cur_r_split_face->normal_0 = normal_b;
+                        cur_r_split_face->normal_1 = new_normal_b;
+                        cur_r_split_face->normal_2 = new_normal_a;
+
+                        cur_r_split_face->uv_0 = uv_b;
+                        cur_r_split_face->uv_1 = new_uv_b;
+                        cur_r_split_face->uv_2 = new_uv_a;
+
+                        cur_r_split_face->position_0.x = cur_r_split_face->position_0.x / cur_r_split_face->position_0.z * horizontal_fov_factor;
+                        cur_r_split_face->position_0.y = cur_r_split_face->position_0.y / cur_r_split_face->position_0.z * vertical_fov_factor;
+                        
+                        cur_r_split_face->position_1.x = cur_r_split_face->position_1.x / cur_r_split_face->position_1.z * horizontal_fov_factor;
+                        cur_r_split_face->position_1.y = cur_r_split_face->position_1.y / cur_r_split_face->position_1.z * vertical_fov_factor;
+
+                        cur_r_split_face->position_2.x = cur_r_split_face->position_2.x / cur_r_split_face->position_2.z * horizontal_fov_factor;
+                        cur_r_split_face->position_2.y = cur_r_split_face->position_2.y / cur_r_split_face->position_2.z * vertical_fov_factor;
+
+                        cur_r_split_face->min_screen_x = cur_r_split_face->position_0.x; 
+                        if (cur_r_split_face->position_1.x < cur_r_split_face->min_screen_x) cur_r_split_face->min_screen_x = cur_r_split_face->position_1.x;
+                        if (cur_r_split_face->position_2.x < cur_r_split_face->min_screen_x) cur_r_split_face->min_screen_x = cur_r_split_face->position_2.x;
+                        cur_r_split_face->min_screen_x = fmax(cur_r_split_face->min_screen_x, -target_texture->resolution.x / 2); 
+
+                        cur_r_split_face->max_screen_x = cur_r_split_face->position_0.x; 
+                        if (cur_r_split_face->position_1.x > cur_r_split_face->max_screen_x) cur_r_split_face->max_screen_x = cur_r_split_face->position_1.x;
+                        if (cur_r_split_face->position_2.x > cur_r_split_face->max_screen_x) cur_r_split_face->max_screen_x = cur_r_split_face->position_2.x;
+                        cur_r_split_face->max_screen_x = fmin(cur_r_split_face->max_screen_x, target_texture->resolution.x / 2); 
+
+                        cur_r_split_face->min_screen_y = cur_r_split_face->position_0.y; 
+                        if (cur_r_split_face->position_1.y < cur_r_split_face->min_screen_y) cur_r_split_face->min_screen_y = cur_r_split_face->position_1.y;
+                        if (cur_r_split_face->position_2.y < cur_r_split_face->min_screen_y) cur_r_split_face->min_screen_y = cur_r_split_face->position_2.y;
+                        cur_r_split_face->min_screen_y = fmax(cur_r_split_face->min_screen_y, -target_texture->resolution.y / 2); 
+
+                        cur_r_split_face->max_screen_y = cur_r_split_face->position_0.y; 
+                        if (cur_r_split_face->position_1.y > cur_r_split_face->max_screen_y) cur_r_split_face->max_screen_y = cur_r_split_face->position_1.y;
+                        if (cur_r_split_face->position_2.y > cur_r_split_face->max_screen_y) cur_r_split_face->max_screen_y = cur_r_split_face->position_2.y;
+                        cur_r_split_face->max_screen_y = fmin(cur_r_split_face->max_screen_y, target_texture->resolution.y / 2); 
+
+                        ++current_split_renderable_face_index;
+                        
+                        break;
+                    
+                    case 0: // no issues, ignore
+                        break;
+                }
+
                 cur_r_face->position_0.x = cur_r_face->position_0.x / cur_r_face->position_0.z * horizontal_fov_factor;
                 cur_r_face->position_0.x = cur_r_face->position_0.x / cur_r_face->position_0.z * horizontal_fov_factor;
                 cur_r_face->position_0.y = cur_r_face->position_0.y / cur_r_face->position_0.z * vertical_fov_factor;
                 cur_r_face->position_0.y = cur_r_face->position_0.y / cur_r_face->position_0.z * vertical_fov_factor;
                 
                 
@@ -411,33 +623,25 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
                 cur_r_face->position_2.x = cur_r_face->position_2.x / cur_r_face->position_2.z * horizontal_fov_factor;
                 cur_r_face->position_2.x = cur_r_face->position_2.x / cur_r_face->position_2.z * horizontal_fov_factor;
                 cur_r_face->position_2.y = cur_r_face->position_2.y / cur_r_face->position_2.z * vertical_fov_factor;
                 cur_r_face->position_2.y = cur_r_face->position_2.y / cur_r_face->position_2.z * vertical_fov_factor;
 
 
-                RI_vector_3f *pos_0 = &cur_r_face->position_0;
-                RI_vector_3f *pos_1 = &cur_r_face->position_1;
-                RI_vector_3f *pos_2 = &cur_r_face->position_2;
-
-                if (pos_0->z < scene->min_clip || pos_1->z < scene->min_clip || pos_2->z < scene->min_clip){
-                    if (pos_0->z < scene->min_clip && pos_1->z < scene->min_clip && pos_2->z < scene->min_clip){
-                        continue;
-                    }
-
-                    // triangle culling code
-                }            
-            
                 cur_r_face->min_screen_x = pos_0->x; 
                 cur_r_face->min_screen_x = pos_0->x; 
                 if (pos_1->x < cur_r_face->min_screen_x) cur_r_face->min_screen_x = pos_1->x;
                 if (pos_1->x < cur_r_face->min_screen_x) cur_r_face->min_screen_x = pos_1->x;
                 if (pos_2->x < cur_r_face->min_screen_x) cur_r_face->min_screen_x = pos_2->x;
                 if (pos_2->x < cur_r_face->min_screen_x) cur_r_face->min_screen_x = pos_2->x;
+                cur_r_face->min_screen_x = fmax(cur_r_face->min_screen_x, -target_texture->resolution.x / 2); 
 
 
                 cur_r_face->max_screen_x = pos_0->x; 
                 cur_r_face->max_screen_x = pos_0->x; 
                 if (pos_1->x > cur_r_face->max_screen_x) cur_r_face->max_screen_x = pos_1->x;
                 if (pos_1->x > cur_r_face->max_screen_x) cur_r_face->max_screen_x = pos_1->x;
                 if (pos_2->x > cur_r_face->max_screen_x) cur_r_face->max_screen_x = pos_2->x;
                 if (pos_2->x > cur_r_face->max_screen_x) cur_r_face->max_screen_x = pos_2->x;
+                cur_r_face->max_screen_x = fmin(cur_r_face->max_screen_x, target_texture->resolution.x / 2); 
 
 
                 cur_r_face->min_screen_y = pos_0->y; 
                 cur_r_face->min_screen_y = pos_0->y; 
                 if (pos_1->y < cur_r_face->min_screen_y) cur_r_face->min_screen_y = pos_1->y;
                 if (pos_1->y < cur_r_face->min_screen_y) cur_r_face->min_screen_y = pos_1->y;
                 if (pos_2->y < cur_r_face->min_screen_y) cur_r_face->min_screen_y = pos_2->y;
                 if (pos_2->y < cur_r_face->min_screen_y) cur_r_face->min_screen_y = pos_2->y;
+                cur_r_face->min_screen_y = fmax(cur_r_face->min_screen_y, -target_texture->resolution.y / 2); 
 
 
                 cur_r_face->max_screen_y = pos_0->y; 
                 cur_r_face->max_screen_y = pos_0->y; 
                 if (pos_1->y > cur_r_face->max_screen_y) cur_r_face->max_screen_y = pos_1->y;
                 if (pos_1->y > cur_r_face->max_screen_y) cur_r_face->max_screen_y = pos_1->y;
                 if (pos_2->y > cur_r_face->max_screen_y) cur_r_face->max_screen_y = pos_2->y;
                 if (pos_2->y > cur_r_face->max_screen_y) cur_r_face->max_screen_y = pos_2->y;
+                cur_r_face->max_screen_y = fmin(cur_r_face->max_screen_y, target_texture->resolution.y / 2); 
 
 
                 ++current_renderable_face_index;
                 ++current_renderable_face_index;
             }
             }
@@ -447,12 +651,14 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
 
 
         for (int pixel_index = 0; pixel_index < target_texture->resolution.x * target_texture->resolution.y; ++pixel_index){
         for (int pixel_index = 0; pixel_index < target_texture->resolution.x * target_texture->resolution.y; ++pixel_index){
             target_texture->image_buffer[pixel_index] = 0xFF333333;
             target_texture->image_buffer[pixel_index] = 0xFF333333;
-            ri.z_buffer[pixel_index] = 99999;
+            ri.z_buffer[pixel_index] = 999999999;
         }
         }
 
 
-        for (int face_index = 0; face_index < scene->face_count; ++face_index){
+        for (int face_index = 0; face_index < scene->face_count * 2; ++face_index){
             RI_renderable_face *current_face = &scene->faces_to_render[face_index];
             RI_renderable_face *current_face = &scene->faces_to_render[face_index];
             
             
+            if (!current_face->should_render) continue;
+
             RI_material *mat = current_face->material_reference;
             RI_material *mat = current_face->material_reference;
         
         
             RI_vector_2f *uv_0 = &current_face->uv_0;;
             RI_vector_2f *uv_0 = &current_face->uv_0;;
@@ -493,6 +699,10 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
                     w1 = ((pos_2->y - pos_0->y) * (pixel_x_index - pos_0->x) + (pos_0->x - pos_2->x) * (pixel_y_index - pos_0->y)) / denominator; 
                     w1 = ((pos_2->y - pos_0->y) * (pixel_x_index - pos_0->x) + (pos_0->x - pos_2->x) * (pixel_y_index - pos_0->y)) / denominator; 
                     w2 = 1.0 - w0 - w1; 
                     w2 = 1.0 - w0 - w1; 
                 
                 
+                    if (!(mat->flags & RI_MATERIAL_DOUBLE_SIDED) && denominator > 0){
+                        continue;
+                    }
+
                     float w_over_z = (w0 / pos_0->z + w1 / pos_1->z + w2 / pos_2->z); 
                     float w_over_z = (w0 / pos_0->z + w1 / pos_1->z + w2 / pos_2->z); 
                     float interpolated_z = 1.0 / w_over_z;
                     float interpolated_z = 1.0 / w_over_z;
                 
                 
@@ -510,7 +720,7 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
                     
                     
                     uint32_t pixel_color = 0xFF000000;
                     uint32_t pixel_color = 0xFF000000;
                     
                     
-                    if (mat->flags & RI_MATERIAL_HAS_TEXTURE || !uv_0 || !uv_1 || !uv_2){                
+                    if (mat->flags & RI_MATERIAL_HAS_TEXTURE && uv_0 && uv_1 && uv_2){                
                         double ux = (w0 * (uv_0->x / pos_0->z) + w1 * (uv_1->x / pos_1->z) + w2 * (uv_2->x / pos_2->z)) / w_over_z;
                         double ux = (w0 * (uv_0->x / pos_0->z) + w1 * (uv_1->x / pos_1->z) + w2 * (uv_2->x / pos_2->z)) / w_over_z;
                         double uy = (w0 * (uv_0->y / pos_0->z) + w1 * (uv_1->y / pos_1->z) + w2 * (uv_2->y / pos_2->z)) / w_over_z;                
                         double uy = (w0 * (uv_0->y / pos_0->z) + w1 * (uv_1->y / pos_1->z) + w2 * (uv_2->y / pos_2->z)) / w_over_z;                
                     
                     
@@ -525,13 +735,17 @@ int RI_render(RI_scene *scene, RI_texture *target_texture){
                         if (mat->albedo) pixel_color = mat->albedo;
                         if (mat->albedo) pixel_color = mat->albedo;
                         else pixel_color = 0xFFFF77FF;
                         else pixel_color = 0xFFFF77FF;
                     }
                     }
+
+                    // tri culling debug
+                    if (face_index >= scene->face_count) pixel_color = 0xFF7777FF;
+                    // if (face_index < scene->face_count) pixel_color = 0xFF77FF77;
                 
                 
                     // flip the texture
                     // flip the texture
                     // x = target_texture->resolution.x - 1 - x;
                     // x = target_texture->resolution.x - 1 - x;
                     // y = target_texture->resolution.y - 1 - y;
                     // y = target_texture->resolution.y - 1 - y;
                 
                 
                     if (x >= 0 && y >= 0 && x < target_texture->resolution.x && y < target_texture->resolution.y){
                     if (x >= 0 && y >= 0 && x < target_texture->resolution.x && y < target_texture->resolution.y){
-                        target_texture->image_buffer[y * target_texture->resolution.y + x] = pixel_color;
+                        target_texture->image_buffer[y * target_texture->resolution.x + x] = pixel_color;
                     }
                     }
                 }
                 }
             }
             }