diff --git a/src/main.c b/src/main.c index 95aa221..4eac319 100644 --- a/src/main.c +++ b/src/main.c @@ -37,8 +37,9 @@ int main(void) { } clear_image(&img, bg); - render_model(&model, &img, teal, RENDER_TYPE_FILLED, COLOUR_TYPE_RANDOM); - render_model(&model, &img, orange, RENDER_TYPE_WIREFRAME, COLOUR_TYPE_FIXED); + render_model(&model, &img, teal, RENDER_TYPE_SHADED, COLOUR_TYPE_FIXED); + // render_model(&model, &img, orange, RENDER_TYPE_WIREFRAME, + // COLOUR_TYPE_FIXED); save_image(&img, "result.pam"); wapp_mem_arena_destroy(&arena); diff --git a/src/obj.c b/src/obj.c index 79e9554..3386b07 100644 --- a/src/obj.c +++ b/src/obj.c @@ -5,15 +5,33 @@ #include "typed_list.h" #include "utils.h" #include +#include #include #include #define TRIANGLE_VERTICES 3 + +#define V2(T, ELEM_T, X0, Y0, X1, Y1) \ + ((T){(ELEM_T)X1 - (ELEM_T)X0, (ELEM_T)Y1 - (ELEM_T)Y0}) +#define V3(T, ELEM_T, X0, Y0, Z0, X1, Y1, Z1) \ + ((T){(ELEM_T)X1 - (ELEM_T)X0, (ELEM_T)Y1 - (ELEM_T)Y0, \ + (ELEM_T)Z1 - (ELEM_T)Z0}) #define dot_v2(V1, V2) ((f32)V1.x * (f32)V2.x + (f32)V1.y * (f32)V2.y) #define dot_v3(V1, V2) \ ((f32)V1.x * (f32)V2.x + (f32)V1.y * (f32)V2.y + (f32)V1.z * (f32)V2.z) -#define V2(T, ELEM_T, X0, Y0, X1, Y1) \ - ((T){(ELEM_T)X1 - (ELEM_T)X0, (ELEM_T)Y1 - (ELEM_T)Y0}) +#define normalise_v3(V) \ + do { \ + f32 magnitude = sqrtf(dot_v3(V, V)); \ + V.x /= magnitude; \ + V.y /= magnitude; \ + V.z /= magnitude; \ + } while (0); +#define cross_product(V1, V2) \ + ((V3f){ \ + .x = V1.y * V2.z - V1.z * V2.y, \ + .y = V1.z * V2.x - V1.x * V2.z, \ + .z = V1.x * V2.y - V1.y * V2.x, \ + }) typedef struct triangle_bbox TriangleBBox; struct triangle_bbox { @@ -63,6 +81,8 @@ internal void get_image_coordinates(const Vertex *vertex, const Image *img, u64 *x, u64 *y); internal u64 ndc_to_image_coordinate(f32 value, u64 max); +V3f g_light_dir = {0.0f, 0.0f, -1.0f}; + Model load_obj_file(Arena *arena, const char *filename) { if (!arena) { return NULL_MODEL; @@ -148,8 +168,28 @@ internal void render_triangle(const Triangle *triangle, const Model *model, draw_line(img, x0, y0, x1, y1, colour); } - } else if (type == RENDER_TYPE_FILLED) { - fill_triangle(img, vertices, colour); + } else if (type == RENDER_TYPE_FILLED || type == RENDER_TYPE_SHADED) { + f32 intensity = 1.0f; + + if (type == RENDER_TYPE_SHADED) { + V3f ab = V3(V3f, f32, vertices[0].x, vertices[0].y, vertices[0].z, + vertices[1].x, vertices[1].y, vertices[1].z); + V3f ac = V3(V3f, f32, vertices[0].x, vertices[0].y, vertices[0].z, + vertices[2].x, vertices[2].y, vertices[2].z); + + V3f normal = cross_product(ac, ab); + normalise_v3(normal); + + intensity = dot_v3(normal, g_light_dir); + + colour.r *= intensity; + colour.g *= intensity; + colour.b *= intensity; + } + + if (intensity > 0.0f) { + fill_triangle(img, vertices, colour); + } } } diff --git a/src/obj.h b/src/obj.h index 9c320c0..6c70ef4 100644 --- a/src/obj.h +++ b/src/obj.h @@ -26,6 +26,7 @@ struct triangle { typedef enum { RENDER_TYPE_WIREFRAME, RENDER_TYPE_FILLED, + RENDER_TYPE_SHADED, COUNT_RENDER_TYPES, } RenderType;