From 5a24809935a2abcc293e10f7dad8b5fcc98c8f95 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 28 Jul 2024 22:43:00 +0100 Subject: [PATCH] Initial implementatin of barycentric coordinates --- src/main.c | 6 +++-- src/obj.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/main.c b/src/main.c index e27ab03..6a965aa 100644 --- a/src/main.c +++ b/src/main.c @@ -21,19 +21,21 @@ int main(void) { } Colour bg = {.r = 42, .g = 45, .b = 52, .a = 255}; + Colour teal = {.r = 14, .g = 156, .b = 208, .a = 255}; Colour orange = {.r = 242, .g = 100, .b = 48, .a = 255}; Image img = {.width = 1200, .height = 1200}; if (!init_image(arena, &img)) { return TINY_EXIT_IMAGE_INIT_FAILED; } - Model model = load_obj_file(arena, "resources/head.obj"); + Model model = load_obj_file(arena, "resources/triangle.obj"); if (IS_NULL_MODEL(model)) { return TINY_EXIT_MODEL_LOAD_FAILED; } clear_image(&img, bg); - render_model(&model, &img, orange, RENDER_TYPE_FILLED); + render_model(&model, &img, teal, RENDER_TYPE_FILLED); + render_model(&model, &img, orange, RENDER_TYPE_WIREFRAME); save_image(&img, "result.pam"); wapp_mem_arena_destroy(&arena); diff --git a/src/obj.c b/src/obj.c index e2ce4fb..594e3a8 100644 --- a/src/obj.c +++ b/src/obj.c @@ -16,10 +16,42 @@ struct triangle_bbox { u64 y1; }; +typedef struct i64x2 V2i; +struct i64x2 { + i64 x; + i64 y; +}; + +typedef struct f32x3 V3f; +struct f32x3 { + f32 x; + f32 y; + f32 z; +}; + +typedef struct u64x3 V3u; +struct u64x3 { + u64 x; + u64 y; + u64 z; +}; + +typedef struct f32_3x3 M3x3f; +struct f32_3x3 { + V3f row0; + V3f row1; + V3f row2; +}; + internal void render_triangle(const Triangle *triangle, const Model *model, Image *img, Colour colour, RenderType type); +internal void fill_triangle(Image *img, Vertex vertices[TRIANGLE_VERTICES], + Colour colour); internal TriangleBBox get_triangle_bbox(const Image *img, Vertex vertices[TRIANGLE_VERTICES]); +internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, + const V2i *ab, const V2i *ac, + const V2i *ap); 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); @@ -104,9 +136,36 @@ internal void render_triangle(const Triangle *triangle, const Model *model, draw_line(img, x0, y0, x1, y1, colour); } } else if (type == RENDER_TYPE_FILLED) { - TriangleBBox bbox = get_triangle_bbox(img, vertices); - for (u64 y = bbox.y0; y < bbox.y1; ++y) { - draw_line(img, bbox.x0, y, bbox.x1, y, colour); + fill_triangle(img, vertices, colour); + } +} + +internal void fill_triangle(Image *img, Vertex vertices[TRIANGLE_VERTICES], + Colour colour) { + TriangleBBox bbox = get_triangle_bbox(img, vertices); + + u64 v0x, v0y, v1x, v1y, v2x, v2y; + get_image_coordinates(&(vertices[0]), img, &v0x, &v0y); + get_image_coordinates(&(vertices[1]), img, &v1x, &v1y); + get_image_coordinates(&(vertices[2]), img, &v2x, &v2y); + + V2i ab = {.x = (i64)v1x - (i64)v0x, .y = (i64)v1y - (i64)v0y}; + V2i ac = {.x = (i64)v2x - (i64)v0x, .y = (i64)v2y - (i64)v0y}; + f32 d00 = (f32)ab.x * (f32)ab.x + (f32)ab.y + (f32)ab.y; + f32 d01 = (f32)ab.x * (f32)ac.x + (f32)ab.y + (f32)ac.y; + f32 d11 = (f32)ac.x * (f32)ac.x + (f32)ac.y + (f32)ac.y; + f32 denom = (f32)d00 * (f32)d11 - (f32)d01 * (f32)d01; + V2i ap; + V3f coords; + + for (u64 y = bbox.y0; y < bbox.y1; ++y) { + for (u64 x = bbox.x0; x < bbox.x1; ++x) { + ap = (V2i){.x = (i64)x - (i64)v0x, .y = (i64)y - (i64)v0y}; + coords = get_barycentric_coords(d00, d01, d11, denom, &ab, &ac, &ap); + if (coords.x < 0.0f || coords.y < 0.0f || coords.z < 0.0f) { + continue; + } + set_pixel(img, x, y, colour); } } } @@ -128,6 +187,19 @@ internal TriangleBBox get_triangle_bbox(const Image *img, }; } +internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, + const V2i *ab, const V2i *ac, + const V2i *ap) { + f32 d20 = (f32)ap->x * (f32)ab->x + (f32)ap->y + (f32)ab->y; + f32 d21 = (f32)ap->x * (f32)ac->x + (f32)ap->y + (f32)ac->y; + + f32 v = (d11 * d20 - d01 * d21) / denom; + f32 w = (d00 * d21 - d01 * d20) / denom; + f32 u = 1.0f - v - w; + + return (V3f){v, w, u}; +} + internal void get_image_coordinates(const Vertex *vertex, const Image *img, u64 *x, u64 *y) { *x = ndc_to_image_coordinate(vertex->x, img->width);