From d34c04e157b2d0a0a32e01446b1eb32abb752776 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 18 Aug 2024 01:28:43 +0100 Subject: [PATCH 1/6] Start implementing shaders and move vector code to dedicated files --- src/main.c | 48 ++++++++++- src/obj.c | 235 ++++++----------------------------------------------- src/obj.h | 88 ++++---------------- src/vec.c | 57 +++++++++++++ src/vec.h | 163 +++++++++++++++++++++++++++++++++++++ 5 files changed, 305 insertions(+), 286 deletions(-) create mode 100644 src/vec.c create mode 100644 src/vec.h diff --git a/src/main.c b/src/main.c index d72ae92..1696294 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,9 @@ +#include "aliases.h" #include "img.h" #include "mem_arena.h" #include "mem_utils.h" #include "obj.h" +#include "vec.h" #include #include #include @@ -10,6 +12,11 @@ #define SIZE 1200 #define RESOURCE(NAME) "resources/" NAME +V3f g_eye = {0.2f, 0.1f, 0.75f}; +V3f g_target = {0}; +V3f g_up = {0.0f, 1.0f, 0.0f}; +M4x4f g_cam_matrix = mat4x4_identity; + enum { TINY_EXIT_SUCCESS, TINY_EXIT_ARENA_INIT_FAILED, @@ -17,6 +24,10 @@ enum { TINY_EXIT_MODEL_LOAD_FAILED, }; +internal M4x4f get_projection_matrix(ProjectionType projection_type); +internal V3f main_shader_vertex(const V3f *vertex, M4x4f *model_view, + M4x4f *projection, const Render *render); + int main(void) { Arena *arena = NULL; if (!wapp_mem_arena_init(&arena, 10ul * 1024ul * 1024ul * 1024ul, @@ -38,12 +49,45 @@ int main(void) { return TINY_EXIT_MODEL_LOAD_FAILED; } + M4x4f model_view = lookat(g_eye, g_target, g_up); + M4x4f perspective_projection = + get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE); + + Shader main_shader = { + .vertex = main_shader_vertex, + .model_view = &model_view, + .projection = &perspective_projection, + }; + clear_buffer(&(render.img), &bg); - render_model(&obj, &render, teal, RENDER_TYPE_SHADED, COLOUR_TYPE_FIXED, - PROJECTION_TYPE_PERSPECTIVE); + render_model(&obj, &render, &main_shader, RENDER_TYPE_SHADED, teal); save_image(&(render.img), "result.pam"); wapp_mem_arena_destroy(&arena); return TINY_EXIT_SUCCESS; } + +internal M4x4f get_projection_matrix(ProjectionType projection_type) { + if (projection_type == PROJECTION_TYPE_PERSPECTIVE) { + // Calculate projection matrix + V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y, + g_eye.z); + normalise_v3(cam); + f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f; + return projection(coeff); + } + + return mat4x4_identity; +} + +internal V3f main_shader_vertex(const V3f *vertex, M4x4f *model_view, + M4x4f *projection, const Render *render) { + V4f vh = {.x = vertex->x, .y = vertex->y, .z = vertex->z, .w = 1.0f}; + vh = mat4x4_mul_vec4((*projection), mat4x4_mul_vec4((*model_view), vh)); + vh.y = 0.0 - vh.y; + vh = mat4x4_mul_vec4( + viewport(vh.x, vh.y, render->img.width, render->img.height), vh); + + return project_vec4(vh); +} diff --git a/src/obj.c b/src/obj.c index a77a4d8..0094a9e 100644 --- a/src/obj.c +++ b/src/obj.c @@ -5,6 +5,7 @@ #include "pam.h" #include "typed_list.h" #include "utils.h" +#include "vec.h" #include #include #include @@ -12,84 +13,6 @@ #include #define TRIANGLE_VERTICES 3 -#define DEPTH_MAX 255 - -#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 magnitude_v3(V) (sqrtf(dot_v3(V, V))) -#define normalise_v3(V) \ - do { \ - f32 magnitude = magnitude_v3(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, \ - }) -#define mat4x4_identity \ - ((M4x4f){ \ - .row0 = {1.0f, 0.0f, 0.0f, 0.0f}, \ - .row1 = {0.0f, 1.0f, 0.0f, 0.0f}, \ - .row2 = {0.0f, 0.0f, 1.0f, 0.0f}, \ - .row3 = {0.0f, 0.0f, 0.0f, 1.0f}, \ - }) -#define mat4x4_mul(MAT1, MAT2) \ - ((M4x4f){ \ - .row0.x = MAT1.row0.x * MAT2.row0.x + MAT1.row0.y * MAT2.row1.x + \ - MAT1.row0.z * MAT2.row2.x + MAT1.row0.w * MAT2.row3.x, \ - .row0.y = MAT1.row0.x * MAT2.row0.y + MAT1.row0.y * MAT2.row1.y + \ - MAT1.row0.z * MAT2.row2.y + MAT1.row0.w * MAT2.row3.y, \ - .row0.z = MAT1.row0.x * MAT2.row0.z + MAT1.row0.y * MAT2.row1.z + \ - MAT1.row0.z * MAT2.row2.z + MAT1.row0.w * MAT2.row3.z, \ - .row0.w = MAT1.row0.x * MAT2.row0.w + MAT1.row0.y * MAT2.row1.w + \ - MAT1.row0.z * MAT2.row2.w + MAT1.row0.w * MAT2.row3.w, \ - .row1.x = MAT1.row1.x * MAT2.row0.x + MAT1.row1.y * MAT2.row1.x + \ - MAT1.row1.z * MAT2.row2.x + MAT1.row1.w * MAT2.row3.x, \ - .row1.y = MAT1.row1.x * MAT2.row0.y + MAT1.row1.y * MAT2.row1.y + \ - MAT1.row1.z * MAT2.row2.y + MAT1.row1.w * MAT2.row3.y, \ - .row1.z = MAT1.row1.x * MAT2.row0.z + MAT1.row1.y * MAT2.row1.z + \ - MAT1.row1.z * MAT2.row2.z + MAT1.row1.w * MAT2.row3.z, \ - .row1.w = MAT1.row1.x * MAT2.row0.w + MAT1.row1.y * MAT2.row1.w + \ - MAT1.row1.z * MAT2.row2.w + MAT1.row1.w * MAT2.row3.w, \ - .row2.x = MAT1.row2.x * MAT2.row0.x + MAT1.row2.y * MAT2.row1.x + \ - MAT1.row2.z * MAT2.row2.x + MAT1.row2.w * MAT2.row3.x, \ - .row2.y = MAT1.row2.x * MAT2.row0.y + MAT1.row2.y * MAT2.row1.y + \ - MAT1.row2.z * MAT2.row2.y + MAT1.row2.w * MAT2.row3.y, \ - .row2.z = MAT1.row2.x * MAT2.row0.z + MAT1.row2.y * MAT2.row1.z + \ - MAT1.row2.z * MAT2.row2.z + MAT1.row2.w * MAT2.row3.z, \ - .row2.w = MAT1.row2.x * MAT2.row0.w + MAT1.row2.y * MAT2.row1.w + \ - MAT1.row2.z * MAT2.row2.w + MAT1.row2.w * MAT2.row3.w, \ - .row3.x = MAT1.row3.x * MAT2.row0.x + MAT1.row3.y * MAT2.row1.x + \ - MAT1.row3.z * MAT2.row2.x + MAT1.row3.w * MAT2.row3.x, \ - .row3.y = MAT1.row3.x * MAT2.row0.y + MAT1.row3.y * MAT2.row1.y + \ - MAT1.row3.z * MAT2.row2.y + MAT1.row3.w * MAT2.row3.y, \ - .row3.z = MAT1.row3.x * MAT2.row0.z + MAT1.row3.y * MAT2.row1.z + \ - MAT1.row3.z * MAT2.row2.z + MAT1.row3.w * MAT2.row3.z, \ - .row3.w = MAT1.row3.x * MAT2.row0.w + MAT1.row3.y * MAT2.row1.w + \ - MAT1.row3.z * MAT2.row2.w + MAT1.row3.w * MAT2.row3.w, \ - }) -#define mat4x4_mul_vec4(MAT, V) \ - ((V4f){ \ - .x = MAT.row0.x * V.x + MAT.row0.y * V.y + MAT.row0.z * V.z + \ - MAT.row0.w * V.w, \ - .y = MAT.row1.x * V.x + MAT.row1.y * V.y + MAT.row1.z * V.z + \ - MAT.row1.w * V.w, \ - .z = MAT.row2.x * V.x + MAT.row2.y * V.y + MAT.row2.z * V.z + \ - MAT.row2.w * V.w, \ - .w = MAT.row3.x * V.x + MAT.row3.y * V.y + MAT.row3.z * V.z + \ - MAT.row3.w * V.w, \ - }) -#define project_vec4(V) ((V3f){.x = V.x / V.w, .y = V.y / V.w, .z = V.z / V.w}) typedef struct triangle_bbox TriangleBBox; struct triangle_bbox { @@ -100,15 +23,12 @@ struct triangle_bbox { }; internal void render_triangle(const Triangle *triangle, const Model *model, - Render *render, Colour colour, RenderType type, - ProjectionType projection, M4x4f mv); + const Shader *shader, Render *render, + RenderType render_type, Colour colour); internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], V3f normals[TRIANGLE_VERTICES], V2f coordinates[TRIANGLE_VERTICES], Colour colour, Image *texture, RenderType type); -internal M4x4f lookat(V3f eye, V3f target, V3f up); -internal M4x4f viewport(f32 x, f32 y, u64 w, u64 h); -internal M4x4f projection(f32 coeff); internal TriangleBBox get_triangle_bbox(const Image *img, V3f vertices[TRIANGLE_VERTICES]); internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, @@ -117,10 +37,6 @@ internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, internal V3f get_viewport_vertex(const V3f *vertex, const Image *img); V3f g_light_dir = {0.0f, 0.0f, 1.0f}; -V3f g_eye = {0.2f, 0.1f, 0.75f}; -V3f g_target = {0}; -V3f g_up = {0.0f, 1.0f, 0.0f}; -M4x4f g_cam_matrix = mat4x4_identity; Model load_obj_file(Arena *arena, const char *filename, const char *texture) { if (!arena) { @@ -215,35 +131,18 @@ bool init_render(Arena *arena, Render *render, u64 width, u64 height) { return true; } -void render_model(const Model *model, Render *render, Colour colour, - RenderType type, ColourType colour_type, - ProjectionType projection_type) { +void render_model(const Model *model, Render *render, const Shader *shader, + RenderType render_type, Colour colour) { Triangle triangle; - M4x4f model_view = lookat(g_eye, g_target, g_up); - - // Calculate projection matrix - V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y, - g_eye.z); - normalise_v3(cam); - f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f; - g_cam_matrix = projection(coeff); - for (u64 i = 0; i < model->triangles->count; ++i) { triangle = list_get(model->triangles, i); - if (colour_type == COLOUR_TYPE_RANDOM) { - colour = (Colour){.r = rand() % UINT8_MAX, - .g = rand() % UINT8_MAX, - .b = rand() % UINT8_MAX, - .a = 255}; - } - render_triangle(&triangle, model, render, colour, type, projection_type, - model_view); + render_triangle(&triangle, model, shader, render, render_type, colour); } } internal void render_triangle(const Triangle *triangle, const Model *model, - Render *render, Colour colour, RenderType type, - ProjectionType projection_type, M4x4f mv) { + const Shader *shader, Render *render, + RenderType render_type, Colour colour) { Image *img = &(render->img); V3f vertices[TRIANGLE_VERTICES] = { list_get(model->vertices, triangle->p0), @@ -261,51 +160,24 @@ internal void render_triangle(const Triangle *triangle, const Model *model, list_get(model->texture_coordinates, triangle->tx2), }; - // Camera for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { - V4f vertex; - vertex = (V4f){ - .x = vertices[i].x, - .y = vertices[i].y, - .z = vertices[i].z, - .w = 1.0f, - }; - vertex = mat4x4_mul_vec4(mv, vertex); - vertices[i] = project_vec4(vertex); + vertices[i] = shader->vertex(&vertices[i], shader->model_view, + shader->projection, render); } - // Basic perspective projection - if (projection_type == PROJECTION_TYPE_PERSPECTIVE) { - V4f vertex; - - for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { - vertex = (V4f){ - .x = vertices[i].x, - .y = vertices[i].y, - .z = vertices[i].z, - .w = 1.0f, - }; - vertex = mat4x4_mul_vec4(g_cam_matrix, vertex); - vertices[i] = project_vec4(vertex); - } - } - - if (type == RENDER_TYPE_WIREFRAME) { + if (render_type == RENDER_TYPE_WIREFRAME) { V3f v0, v1; u64 x0, y0, x1, y1; - V3f vp0, vp1; for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { v0 = vertices[i]; v1 = vertices[(i + 1) % TRIANGLE_VERTICES]; - vp0 = get_viewport_vertex(&v0, img); - vp1 = get_viewport_vertex(&v1, img); - - draw_line(img, (u64)vp0.x, (u64)vp0.y, (u64)vp1.x, (u64)vp1.y, colour); + draw_line(img, (u64)v0.x, (u64)v0.y, (u64)v1.x, (u64)v1.y, colour); } - } else if (type == RENDER_TYPE_FILLED || type == RENDER_TYPE_SHADED) { + } else if (render_type == RENDER_TYPE_FILLED || + render_type == RENDER_TYPE_SHADED) { fill_triangle(render, vertices, normals, coordinates, colour, - model->texture, type); + model->texture, render_type); } } @@ -317,9 +189,9 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], Depth *depth = &(render->depth); TriangleBBox bbox = get_triangle_bbox(img, vertices); - V3f v0 = get_viewport_vertex(&vertices[0], img); - V3f v1 = get_viewport_vertex(&vertices[1], img); - V3f v2 = get_viewport_vertex(&vertices[2], img); + V3f v0 = vertices[0]; + V3f v1 = vertices[1]; + V3f v2 = vertices[2]; V2i ab = V2(V2i, i64, v0.x, v0.y, v1.x, v1.y); V2i ac = V2(V2i, i64, v0.x, v0.y, v2.x, v2.y); @@ -388,77 +260,18 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], } } -internal M4x4f lookat(V3f eye, V3f target, V3f up) { - V3f z = V3(V3f, f32, target.x, target.y, target.z, eye.x, eye.y, eye.z); - normalise_v3(z); - V3f x = cross_product(up, z); - normalise_v3(x); - V3f y = cross_product(z, x); - normalise_v3(y); - - M4x4f rotation = mat4x4_identity; - rotation.row0.x = x.x; - rotation.row0.y = x.y; - rotation.row0.z = x.z; - rotation.row1.x = y.x; - rotation.row1.y = y.y; - rotation.row1.z = y.z; - rotation.row2.x = z.x; - rotation.row2.y = z.y; - rotation.row2.z = z.z; - - M4x4f translation = mat4x4_identity; - translation.row0.w = -(eye.x); - translation.row1.w = -(eye.y); - translation.row2.w = -(eye.z); - - return mat4x4_mul(rotation, translation); -} - -internal M4x4f viewport(f32 x, f32 y, u64 w, u64 h) { - M4x4f output = mat4x4_identity; - - f32 half_width = (f32)w * 0.5f; - f32 half_height = (f32)h * 0.5f; - f32 half_depth = (f32)DEPTH_MAX * 0.5f; - - output.row0.x = half_width; - output.row0.w = x + half_width; - output.row1.y = half_height; - output.row1.w = y + half_height; - output.row2.z = output.row2.w = half_depth; - - return output; -} - -internal M4x4f projection(f32 coeff) { - // clang-format off - return (M4x4f){ - .row0 = {1.0f, 0.0f, 0.0f, 0.0f}, - .row1 = {0.0f, 1.0f, 0.0f, 0.0f}, - .row2 = {0.0f, 0.0f, 1.0f, 0.0f}, - .row3 = {0.0f, 0.0f, coeff, 1.0f}, - }; - // clang-format on -} - internal TriangleBBox get_triangle_bbox(const Image *img, V3f vertices[TRIANGLE_VERTICES]) { f32 x0 = min(vertices[0].x, min(vertices[1].x, vertices[2].x)); f32 x1 = max(vertices[0].x, max(vertices[1].x, vertices[2].x)); - // NOTE (Abdelrahman): Because y is flipped, we use max for the minimum and - // min for the maximum - f32 y0 = max(vertices[0].y, max(vertices[1].y, vertices[2].y)); - f32 y1 = min(vertices[0].y, min(vertices[1].y, vertices[2].y)); - - V3f minimum = get_viewport_vertex(&(V3f){x0, y0, 0.0f}, img); - V3f maximum = get_viewport_vertex(&(V3f){x1, y1, 0.0f}, img); + f32 y0 = min(vertices[0].y, min(vertices[1].y, vertices[2].y)); + f32 y1 = max(vertices[0].y, max(vertices[1].y, vertices[2].y)); return (TriangleBBox){ - .x0 = minimum.x, - .y0 = minimum.y, - .x1 = maximum.x, - .y1 = maximum.y, + .x0 = x0, + .y0 = y0, + .x1 = x1, + .y1 = y1, }; } diff --git a/src/obj.h b/src/obj.h index d47580b..03ee5a0 100644 --- a/src/obj.h +++ b/src/obj.h @@ -5,6 +5,7 @@ #include "img.h" #include "mem_arena.h" #include "typed_list.h" +#include "vec.h" #define INVALID_MODEL ((Model){0}) #define IS_INVALID_MODEL(m) (m.vertices == NULL || m.triangles == NULL) @@ -22,67 +23,6 @@ struct triangle { u64 tx2; }; -typedef struct i64x2 V2i; -struct i64x2 { - i64 x; - i64 y; -}; - -typedef struct u64x2 V2u; -struct u64x2 { - u64 x; - u64 y; -}; - -typedef struct f32x2 V2f; -struct f32x2 { - union { - f32 x; - f32 u; - }; - union { - f32 y; - f32 v; - }; -}; - -typedef struct f32x3 V3f; -struct f32x3 { - f32 x; - f32 y; - f32 z; -}; - -typedef struct f32x4 V4f; -struct f32x4 { - f32 x; - f32 y; - f32 z; - f32 w; -}; - -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; -}; - -typedef struct f32_4x4 M4x4f; -struct f32_4x4 { - V4f row0; - V4f row1; - V4f row2; - V4f row3; -}; - typedef enum { RENDER_TYPE_WIREFRAME, RENDER_TYPE_FILLED, @@ -91,13 +31,6 @@ typedef enum { COUNT_RENDER_TYPES, } RenderType; -typedef enum { - COLOUR_TYPE_FIXED, - COLOUR_TYPE_RANDOM, - - COUNT_COLOUR_TYPE, -} ColourType; - typedef enum { PROJECTION_TYPE_ORTHOGRAPHIC, PROJECTION_TYPE_PERSPECTIVE, @@ -105,8 +38,6 @@ typedef enum { COUNT_PROJECTION_TYPE, } ProjectionType; -MAKE_LIST_TYPE(V3f); -MAKE_LIST_TYPE(V2f); MAKE_LIST_TYPE(Triangle); typedef struct model Model; @@ -124,10 +55,21 @@ struct render { Depth depth; }; +typedef V3f(VertexShader)(const V3f *vertex, M4x4f *model_view, + M4x4f *projection, const Render *render); +typedef bool(FragmentShader)(Colour colour); + +typedef struct shader Shader; +struct shader { + VertexShader *vertex; + FragmentShader *fragment; + M4x4f *model_view; + M4x4f *projection; +}; + Model load_obj_file(Arena *arena, const char *filename, const char *texture); bool init_render(Arena *arena, Render *render, u64 width, u64 height); -void render_model(const Model *model, Render *render, Colour colour, - RenderType type, ColourType colour_type, - ProjectionType projection); +void render_model(const Model *model, Render *render, const Shader *shader, + RenderType render_type, Colour colour); #endif // OBJ_H diff --git a/src/vec.c b/src/vec.c new file mode 100644 index 0000000..de689bc --- /dev/null +++ b/src/vec.c @@ -0,0 +1,57 @@ +#include "vec.h" + +#define DEPTH_MAX 255 + +M4x4f lookat(V3f eye, V3f target, V3f up) { + V3f z = V3(V3f, f32, target.x, target.y, target.z, eye.x, eye.y, eye.z); + normalise_v3(z); + V3f x = cross_product(up, z); + normalise_v3(x); + V3f y = cross_product(z, x); + normalise_v3(y); + + M4x4f rotation = mat4x4_identity; + rotation.row0.x = x.x; + rotation.row0.y = x.y; + rotation.row0.z = x.z; + rotation.row1.x = y.x; + rotation.row1.y = y.y; + rotation.row1.z = y.z; + rotation.row2.x = z.x; + rotation.row2.y = z.y; + rotation.row2.z = z.z; + + M4x4f translation = mat4x4_identity; + translation.row0.w = -(eye.x); + translation.row1.w = -(eye.y); + translation.row2.w = -(eye.z); + + return mat4x4_mul(rotation, translation); +} + +M4x4f projection(f32 coeff) { + // clang-format off + return (M4x4f){ + .row0 = {1.0f, 0.0f, 0.0f, 0.0f}, + .row1 = {0.0f, 1.0f, 0.0f, 0.0f}, + .row2 = {0.0f, 0.0f, 1.0f, 0.0f}, + .row3 = {0.0f, 0.0f, coeff, 1.0f}, + }; + // clang-format on +} + +M4x4f viewport(f32 x, f32 y, u64 w, u64 h) { + M4x4f output = mat4x4_identity; + + f32 half_width = (f32)w * 0.5f; + f32 half_height = (f32)h * 0.5f; + f32 half_depth = (f32)DEPTH_MAX * 0.5f; + + output.row0.x = half_width; + output.row0.w = x + half_width; + output.row1.y = half_height; + output.row1.w = y + half_height; + output.row2.z = output.row2.w = half_depth; + + return output; +} diff --git a/src/vec.h b/src/vec.h new file mode 100644 index 0000000..f6a56e7 --- /dev/null +++ b/src/vec.h @@ -0,0 +1,163 @@ +#ifndef VEC_H +#define VEC_H + +#include "aliases.h" +#include "typed_list.h" +#include + +typedef struct i64x2 V2i; +struct i64x2 { + i64 x; + i64 y; +}; + +typedef struct u64x2 V2u; +struct u64x2 { + u64 x; + u64 y; +}; + +typedef struct f32x2 V2f; +struct f32x2 { + union { + f32 x; + f32 u; + }; + union { + f32 y; + f32 v; + }; +}; + +typedef struct f32x3 V3f; +struct f32x3 { + f32 x; + f32 y; + f32 z; +}; + +typedef struct f32x4 V4f; +struct f32x4 { + f32 x; + f32 y; + f32 z; + f32 w; +}; + +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; +}; + +typedef struct f32_4x4 M4x4f; +struct f32_4x4 { + V4f row0; + V4f row1; + V4f row2; + V4f row3; +}; + +MAKE_LIST_TYPE(V3f); +MAKE_LIST_TYPE(V2f); + +#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 magnitude_v3(V) (sqrtf(dot_v3(V, V))) + +#define normalise_v3(V) \ + do { \ + f32 magnitude = magnitude_v3(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, \ + }) + +#define mat4x4_identity \ + ((M4x4f){ \ + .row0 = {1.0f, 0.0f, 0.0f, 0.0f}, \ + .row1 = {0.0f, 1.0f, 0.0f, 0.0f}, \ + .row2 = {0.0f, 0.0f, 1.0f, 0.0f}, \ + .row3 = {0.0f, 0.0f, 0.0f, 1.0f}, \ + }) + +#define mat4x4_mul(MAT1, MAT2) \ + ((M4x4f){ \ + .row0.x = MAT1.row0.x * MAT2.row0.x + MAT1.row0.y * MAT2.row1.x + \ + MAT1.row0.z * MAT2.row2.x + MAT1.row0.w * MAT2.row3.x, \ + .row0.y = MAT1.row0.x * MAT2.row0.y + MAT1.row0.y * MAT2.row1.y + \ + MAT1.row0.z * MAT2.row2.y + MAT1.row0.w * MAT2.row3.y, \ + .row0.z = MAT1.row0.x * MAT2.row0.z + MAT1.row0.y * MAT2.row1.z + \ + MAT1.row0.z * MAT2.row2.z + MAT1.row0.w * MAT2.row3.z, \ + .row0.w = MAT1.row0.x * MAT2.row0.w + MAT1.row0.y * MAT2.row1.w + \ + MAT1.row0.z * MAT2.row2.w + MAT1.row0.w * MAT2.row3.w, \ + .row1.x = MAT1.row1.x * MAT2.row0.x + MAT1.row1.y * MAT2.row1.x + \ + MAT1.row1.z * MAT2.row2.x + MAT1.row1.w * MAT2.row3.x, \ + .row1.y = MAT1.row1.x * MAT2.row0.y + MAT1.row1.y * MAT2.row1.y + \ + MAT1.row1.z * MAT2.row2.y + MAT1.row1.w * MAT2.row3.y, \ + .row1.z = MAT1.row1.x * MAT2.row0.z + MAT1.row1.y * MAT2.row1.z + \ + MAT1.row1.z * MAT2.row2.z + MAT1.row1.w * MAT2.row3.z, \ + .row1.w = MAT1.row1.x * MAT2.row0.w + MAT1.row1.y * MAT2.row1.w + \ + MAT1.row1.z * MAT2.row2.w + MAT1.row1.w * MAT2.row3.w, \ + .row2.x = MAT1.row2.x * MAT2.row0.x + MAT1.row2.y * MAT2.row1.x + \ + MAT1.row2.z * MAT2.row2.x + MAT1.row2.w * MAT2.row3.x, \ + .row2.y = MAT1.row2.x * MAT2.row0.y + MAT1.row2.y * MAT2.row1.y + \ + MAT1.row2.z * MAT2.row2.y + MAT1.row2.w * MAT2.row3.y, \ + .row2.z = MAT1.row2.x * MAT2.row0.z + MAT1.row2.y * MAT2.row1.z + \ + MAT1.row2.z * MAT2.row2.z + MAT1.row2.w * MAT2.row3.z, \ + .row2.w = MAT1.row2.x * MAT2.row0.w + MAT1.row2.y * MAT2.row1.w + \ + MAT1.row2.z * MAT2.row2.w + MAT1.row2.w * MAT2.row3.w, \ + .row3.x = MAT1.row3.x * MAT2.row0.x + MAT1.row3.y * MAT2.row1.x + \ + MAT1.row3.z * MAT2.row2.x + MAT1.row3.w * MAT2.row3.x, \ + .row3.y = MAT1.row3.x * MAT2.row0.y + MAT1.row3.y * MAT2.row1.y + \ + MAT1.row3.z * MAT2.row2.y + MAT1.row3.w * MAT2.row3.y, \ + .row3.z = MAT1.row3.x * MAT2.row0.z + MAT1.row3.y * MAT2.row1.z + \ + MAT1.row3.z * MAT2.row2.z + MAT1.row3.w * MAT2.row3.z, \ + .row3.w = MAT1.row3.x * MAT2.row0.w + MAT1.row3.y * MAT2.row1.w + \ + MAT1.row3.z * MAT2.row2.w + MAT1.row3.w * MAT2.row3.w, \ + }) + +#define mat4x4_mul_vec4(MAT, V) \ + ((V4f){ \ + .x = MAT.row0.x * V.x + MAT.row0.y * V.y + MAT.row0.z * V.z + \ + MAT.row0.w * V.w, \ + .y = MAT.row1.x * V.x + MAT.row1.y * V.y + MAT.row1.z * V.z + \ + MAT.row1.w * V.w, \ + .z = MAT.row2.x * V.x + MAT.row2.y * V.y + MAT.row2.z * V.z + \ + MAT.row2.w * V.w, \ + .w = MAT.row3.x * V.x + MAT.row3.y * V.y + MAT.row3.z * V.z + \ + MAT.row3.w * V.w, \ + }) + +#define project_vec4(V) ((V3f){.x = V.x / V.w, .y = V.y / V.w, .z = V.z / V.w}) + +M4x4f lookat(V3f eye, V3f target, V3f up); +M4x4f projection(f32 coeff); +M4x4f viewport(f32 x, f32 y, u64 w, u64 h); + +#endif // VEC_H -- 2.39.5 From 6d6d4781ff9d9049c346319bcb22fac9475c3a40 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 18 Aug 2024 01:53:49 +0100 Subject: [PATCH 2/6] Extract shader into its own header --- src/main.c | 7 +++---- src/obj.c | 2 +- src/obj.h | 14 +------------- src/shader.h | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 src/shader.h diff --git a/src/main.c b/src/main.c index 1696294..1d2fe9d 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,7 @@ enum { internal M4x4f get_projection_matrix(ProjectionType projection_type); internal V3f main_shader_vertex(const V3f *vertex, M4x4f *model_view, - M4x4f *projection, const Render *render); + M4x4f *projection, const Image *img); int main(void) { Arena *arena = NULL; @@ -82,12 +82,11 @@ internal M4x4f get_projection_matrix(ProjectionType projection_type) { } internal V3f main_shader_vertex(const V3f *vertex, M4x4f *model_view, - M4x4f *projection, const Render *render) { + M4x4f *projection, const Image *img) { V4f vh = {.x = vertex->x, .y = vertex->y, .z = vertex->z, .w = 1.0f}; vh = mat4x4_mul_vec4((*projection), mat4x4_mul_vec4((*model_view), vh)); vh.y = 0.0 - vh.y; - vh = mat4x4_mul_vec4( - viewport(vh.x, vh.y, render->img.width, render->img.height), vh); + vh = mat4x4_mul_vec4(viewport(vh.x, vh.y, img->width, img->height), vh); return project_vec4(vh); } diff --git a/src/obj.c b/src/obj.c index 0094a9e..d408f39 100644 --- a/src/obj.c +++ b/src/obj.c @@ -162,7 +162,7 @@ internal void render_triangle(const Triangle *triangle, const Model *model, for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { vertices[i] = shader->vertex(&vertices[i], shader->model_view, - shader->projection, render); + shader->projection, &render->img); } if (render_type == RENDER_TYPE_WIREFRAME) { diff --git a/src/obj.h b/src/obj.h index 03ee5a0..7ac49bf 100644 --- a/src/obj.h +++ b/src/obj.h @@ -4,8 +4,8 @@ #include "aliases.h" #include "img.h" #include "mem_arena.h" +#include "shader.h" #include "typed_list.h" -#include "vec.h" #define INVALID_MODEL ((Model){0}) #define IS_INVALID_MODEL(m) (m.vertices == NULL || m.triangles == NULL) @@ -55,18 +55,6 @@ struct render { Depth depth; }; -typedef V3f(VertexShader)(const V3f *vertex, M4x4f *model_view, - M4x4f *projection, const Render *render); -typedef bool(FragmentShader)(Colour colour); - -typedef struct shader Shader; -struct shader { - VertexShader *vertex; - FragmentShader *fragment; - M4x4f *model_view; - M4x4f *projection; -}; - Model load_obj_file(Arena *arena, const char *filename, const char *texture); bool init_render(Arena *arena, Render *render, u64 width, u64 height); void render_model(const Model *model, Render *render, const Shader *shader, diff --git a/src/shader.h b/src/shader.h new file mode 100644 index 0000000..42817d8 --- /dev/null +++ b/src/shader.h @@ -0,0 +1,19 @@ +#ifndef SHADER_H +#define SHADER_H + +#include "img.h" +#include "vec.h" + +typedef V3f(VertexShader)(const V3f *vertex, M4x4f *model_view, + M4x4f *projection, const Image *img); +typedef bool(FragmentShader)(Colour colour); + +typedef struct shader Shader; +struct shader { + VertexShader *vertex; + FragmentShader *fragment; + M4x4f *model_view; + M4x4f *projection; +}; + +#endif // SHADER_H -- 2.39.5 From 6c275baa20c6013f97b4442fecced8758d0ef3f7 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 18 Aug 2024 15:14:01 +0100 Subject: [PATCH 3/6] Ensure pixel coordinates are within bounds --- src/img.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/img.c b/src/img.c index 12dec1e..51a63f1 100644 --- a/src/img.c +++ b/src/img.c @@ -7,7 +7,7 @@ #include #include -internal u64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y, u64 base_size); +internal i64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y, u64 base_size); bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size) { if (!arena || !buffer || buffer->width == 0 || buffer->height == 0) { @@ -21,12 +21,20 @@ bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size) { } u8 *_get_pixel(Buffer *buffer, u64 x, u64 y, u64 base_size) { - u64 idx = calculate_pixel_index(buffer, x, y, base_size); + i64 idx = calculate_pixel_index(buffer, x, y, base_size); + if (idx == -1) { + idx = 0; + } + return ((u8 *)(buffer->buf)) + idx; } void _set_pixel(Buffer *buffer, u64 x, u64 y, void *value, u64 base_size) { - u64 idx = calculate_pixel_index(buffer, x, y, base_size); + i64 idx = calculate_pixel_index(buffer, x, y, base_size); + if (idx == -1) { + return; + } + memcpy(((u8 *)(buffer->buf)) + idx, value, base_size); return; } @@ -75,7 +83,11 @@ void save_image(const Image *img, const char *filename) { write_p7_image(img->width, img->height, (u8 *)(img->buf), filename); } -internal u64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y, +internal i64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y, u64 base_size) { + if (x < 0 || y < 0 || x >= buffer->width || y >= buffer->height) { + return -1; + } + return (y * buffer->width + x) * base_size; } -- 2.39.5 From 891a97739f63872d66a0678ac43d72bfa80bad22 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 18 Aug 2024 15:14:40 +0100 Subject: [PATCH 4/6] Refactor shader code and implement fragment shaders --- src/obj.c | 81 ++++++++++++++++++++++++---------------------------- src/obj.h | 2 +- src/shader.c | 62 ++++++++++++++++++++++++++++++++++++++++ src/shader.h | 38 +++++++++++++++++------- 4 files changed, 129 insertions(+), 54 deletions(-) create mode 100644 src/shader.c diff --git a/src/obj.c b/src/obj.c index d408f39..862f7b9 100644 --- a/src/obj.c +++ b/src/obj.c @@ -3,6 +3,7 @@ #include "img.h" #include "mem_arena.h" #include "pam.h" +#include "shader.h" #include "typed_list.h" #include "utils.h" #include "vec.h" @@ -23,9 +24,10 @@ struct triangle_bbox { }; internal void render_triangle(const Triangle *triangle, const Model *model, - const Shader *shader, Render *render, + ShaderID shader, Render *render, RenderType render_type, Colour colour); -internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], +internal void fill_triangle(Render *render, ShaderID shader, + V3f vertices[TRIANGLE_VERTICES], V3f normals[TRIANGLE_VERTICES], V2f coordinates[TRIANGLE_VERTICES], Colour colour, Image *texture, RenderType type); @@ -36,8 +38,6 @@ internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, const V2i *ap); internal V3f get_viewport_vertex(const V3f *vertex, const Image *img); -V3f g_light_dir = {0.0f, 0.0f, 1.0f}; - Model load_obj_file(Arena *arena, const char *filename, const char *texture) { if (!arena) { return INVALID_MODEL; @@ -131,7 +131,7 @@ bool init_render(Arena *arena, Render *render, u64 width, u64 height) { return true; } -void render_model(const Model *model, Render *render, const Shader *shader, +void render_model(const Model *model, Render *render, ShaderID shader, RenderType render_type, Colour colour) { Triangle triangle; for (u64 i = 0; i < model->triangles->count; ++i) { @@ -141,7 +141,7 @@ void render_model(const Model *model, Render *render, const Shader *shader, } internal void render_triangle(const Triangle *triangle, const Model *model, - const Shader *shader, Render *render, + ShaderID shader, Render *render, RenderType render_type, Colour colour) { Image *img = &(render->img); V3f vertices[TRIANGLE_VERTICES] = { @@ -161,8 +161,8 @@ internal void render_triangle(const Triangle *triangle, const Model *model, }; for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { - vertices[i] = shader->vertex(&vertices[i], shader->model_view, - shader->projection, &render->img); + vertices[i] = + run_vertex_shader(shader, &vertices[i], (Buffer *)&render->img); } if (render_type == RENDER_TYPE_WIREFRAME) { @@ -176,12 +176,13 @@ internal void render_triangle(const Triangle *triangle, const Model *model, } } else if (render_type == RENDER_TYPE_FILLED || render_type == RENDER_TYPE_SHADED) { - fill_triangle(render, vertices, normals, coordinates, colour, + fill_triangle(render, shader, vertices, normals, coordinates, colour, model->texture, render_type); } } -internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], +internal void fill_triangle(Render *render, ShaderID shader, + V3f vertices[TRIANGLE_VERTICES], V3f normals[TRIANGLE_VERTICES], V2f coordinates[TRIANGLE_VERTICES], Colour colour, Image *texture, RenderType type) { @@ -207,6 +208,8 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], V3f normal; f32 tx_u, tx_v; u64 tx_x, tx_y; + V2f tex_coords; + FragmentResult result; f32 intensity = 1.0f; @@ -222,40 +225,32 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], z += v0.z * coords.x + v1.z * coords.y + v2.z * coords.z; zbuf = get_pixel(f32, &(render->depth), x, y); - if (z > zbuf) { - if (type == RENDER_TYPE_SHADED) { - nx = normals[0].x * coords.x + normals[1].x * coords.y + - normals[2].x * coords.z; - ny = normals[0].y * coords.x + normals[1].y * coords.y + - normals[2].y * coords.z; - nz = normals[0].z * coords.x + normals[1].z * coords.y + - normals[2].z * coords.z; - normal = (V3f){nx, ny, nz}; - intensity = dot_v3(normal, g_light_dir); - } - - if (intensity < 0.0f) { - intensity = 0.01f; - } - - if (texture) { - tx_u = coordinates[0].u * coords.x + coordinates[1].u * coords.y + - coordinates[2].u * coords.z; - tx_v = coordinates[0].v * coords.x + coordinates[1].v * coords.y + - coordinates[2].v * coords.z; - tx_x = tx_u * texture->width; - tx_y = (1.0f - tx_v) * texture->height; - - colour = get_pixel(Colour, texture, tx_x, tx_y); - } - - colour.r *= intensity; - colour.g *= intensity; - colour.b *= intensity; - - set_pixel(depth, x, y, &z); - set_pixel(img, x, y, &colour); + if (z <= zbuf) { + continue; } + + nx = normals[0].x * coords.x + normals[1].x * coords.y + + normals[2].x * coords.z; + ny = normals[0].y * coords.x + normals[1].y * coords.y + + normals[2].y * coords.z; + nz = normals[0].z * coords.x + normals[1].z * coords.y + + normals[2].z * coords.z; + normal = (V3f){nx, ny, nz}; + + tx_u = coordinates[0].u * coords.x + coordinates[1].u * coords.y + + coordinates[2].u * coords.z; + tx_v = coordinates[0].v * coords.x + coordinates[1].v * coords.y + + coordinates[2].v * coords.z; + tex_coords = (V2f){tx_u, tx_v}; + + result = + run_fragment_shader(shader, normal, tex_coords, &colour, texture); + if (DISCARD_FRAGMENT(result)) { + continue; + } + + set_pixel(depth, x, y, &z); + set_pixel(img, x, y, &result.colour); } } } diff --git a/src/obj.h b/src/obj.h index 7ac49bf..23f8c94 100644 --- a/src/obj.h +++ b/src/obj.h @@ -57,7 +57,7 @@ struct render { Model load_obj_file(Arena *arena, const char *filename, const char *texture); bool init_render(Arena *arena, Render *render, u64 width, u64 height); -void render_model(const Model *model, Render *render, const Shader *shader, +void render_model(const Model *model, Render *render, ShaderID shader, RenderType render_type, Colour colour); #endif // OBJ_H diff --git a/src/shader.c b/src/shader.c new file mode 100644 index 0000000..312220f --- /dev/null +++ b/src/shader.c @@ -0,0 +1,62 @@ +#include "shader.h" +#include "aliases.h" +#include "vec.h" + +#define MAX_SHADER_COUNT 2048 + +typedef struct shader_repo ShaderRepo; +struct shader_repo { + void *shaders[MAX_SHADER_COUNT]; + VertexShader *vertex_funcs[MAX_SHADER_COUNT]; + FragmentShader *fragment_funcs[MAX_SHADER_COUNT]; + u64 count; +}; + +internal ShaderRepo g_repository = {0}; + +ShaderID create_shader(void *shader, VertexShader *vertex, + FragmentShader *fragment) { + if (g_repository.count + 1 >= MAX_SHADER_COUNT) { + return INVALID_SHADER; + } + + ++(g_repository.count); + g_repository.shaders[g_repository.count] = shader; + g_repository.vertex_funcs[g_repository.count] = vertex; + g_repository.fragment_funcs[g_repository.count] = fragment; + + return (ShaderID){g_repository.count}; +} + +V3f run_vertex_shader(ShaderID shader, const V3f *vertex, + const Buffer *out_buf) { + if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !vertex || + !out_buf) { + return (V3f){0}; + } + + void *shader_obj = g_repository.shaders[shader.id]; + VertexShader *vertex_func = g_repository.vertex_funcs[shader.id]; + + if (!shader_obj || !vertex_func) { + return (V3f){0}; + } + + return vertex_func(shader_obj, vertex, out_buf); +} + +FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, + const Colour *colour, const Image *texture) { + if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) { + return DISCARDED_FRAGMENT; + } + + void *shader_obj = g_repository.shaders[shader.id]; + FragmentShader *fragment_func = g_repository.fragment_funcs[shader.id]; + + if (!shader_obj || !fragment_func) { + return DISCARDED_FRAGMENT; + } + + return fragment_func(shader_obj, normal, tex_coords, colour, texture); +} diff --git a/src/shader.h b/src/shader.h index 42817d8..ca73f49 100644 --- a/src/shader.h +++ b/src/shader.h @@ -1,19 +1,37 @@ #ifndef SHADER_H #define SHADER_H +#include "aliases.h" #include "img.h" #include "vec.h" -typedef V3f(VertexShader)(const V3f *vertex, M4x4f *model_view, - M4x4f *projection, const Image *img); -typedef bool(FragmentShader)(Colour colour); - -typedef struct shader Shader; -struct shader { - VertexShader *vertex; - FragmentShader *fragment; - M4x4f *model_view; - M4x4f *projection; +typedef struct shader_id ShaderID; +struct shader_id { + u64 id; }; +typedef struct fragment_result FragmentResult; +struct fragment_result { + Colour colour; + bool discard; +}; + +#define INVALID_SHADER ((ShaderID){0}) +#define IS_INVALID_SHADER(ID) (ID.id == 0) +#define DISCARDED_FRAGMENT ((FragmentResult){.discard = true}) +#define DISCARD_FRAGMENT(RESULT) (RESULT.discard) + +typedef V3f(VertexShader)(void *shader, const V3f *vertex, + const Buffer *out_buf); +typedef FragmentResult(FragmentShader)(void *shader, V3f normal, V2f tex_coords, + const Colour *colour, + const Image *texture); + +ShaderID create_shader(void *shader, VertexShader *vertex, + FragmentShader *fragment); +V3f run_vertex_shader(ShaderID shader, const V3f *vertex, + const Buffer *out_buf); +FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, + const Colour *colour, const Image *texture); + #endif // SHADER_H -- 2.39.5 From ff207a458eaef905170d157e5344cfcbe855549e Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 18 Aug 2024 15:15:19 +0100 Subject: [PATCH 5/6] Create shaders --- src/main.c | 55 ++++--------------- src/shaders.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/shaders.h | 6 ++ 3 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 src/shaders.c create mode 100644 src/shaders.h diff --git a/src/main.c b/src/main.c index 1d2fe9d..f0895e6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,9 +1,10 @@ -#include "aliases.h" #include "img.h" #include "mem_arena.h" #include "mem_utils.h" #include "obj.h" -#include "vec.h" +#include "shader.h" +#include "shaders.h" +#include #include #include #include @@ -12,10 +13,12 @@ #define SIZE 1200 #define RESOURCE(NAME) "resources/" NAME -V3f g_eye = {0.2f, 0.1f, 0.75f}; -V3f g_target = {0}; -V3f g_up = {0.0f, 1.0f, 0.0f}; -M4x4f g_cam_matrix = mat4x4_identity; +extern ShaderID perspective_lit_textured_id; +extern ShaderID perspective_lit_coloured_id; +extern ShaderID perspective_albedo_id; +extern ShaderID orthographic_lit_textured_id; +extern ShaderID orthographic_lit_coloured_id; +extern ShaderID orthographic_albedo_id; enum { TINY_EXIT_SUCCESS, @@ -24,10 +27,6 @@ enum { TINY_EXIT_MODEL_LOAD_FAILED, }; -internal M4x4f get_projection_matrix(ProjectionType projection_type); -internal V3f main_shader_vertex(const V3f *vertex, M4x4f *model_view, - M4x4f *projection, const Image *img); - int main(void) { Arena *arena = NULL; if (!wapp_mem_arena_init(&arena, 10ul * 1024ul * 1024ul * 1024ul, @@ -49,44 +48,14 @@ int main(void) { return TINY_EXIT_MODEL_LOAD_FAILED; } - M4x4f model_view = lookat(g_eye, g_target, g_up); - M4x4f perspective_projection = - get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE); - - Shader main_shader = { - .vertex = main_shader_vertex, - .model_view = &model_view, - .projection = &perspective_projection, - }; + load_shaders(); clear_buffer(&(render.img), &bg); - render_model(&obj, &render, &main_shader, RENDER_TYPE_SHADED, teal); + render_model(&obj, &render, perspective_lit_textured_id, RENDER_TYPE_SHADED, + teal); save_image(&(render.img), "result.pam"); wapp_mem_arena_destroy(&arena); return TINY_EXIT_SUCCESS; } - -internal M4x4f get_projection_matrix(ProjectionType projection_type) { - if (projection_type == PROJECTION_TYPE_PERSPECTIVE) { - // Calculate projection matrix - V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y, - g_eye.z); - normalise_v3(cam); - f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f; - return projection(coeff); - } - - return mat4x4_identity; -} - -internal V3f main_shader_vertex(const V3f *vertex, M4x4f *model_view, - M4x4f *projection, const Image *img) { - V4f vh = {.x = vertex->x, .y = vertex->y, .z = vertex->z, .w = 1.0f}; - vh = mat4x4_mul_vec4((*projection), mat4x4_mul_vec4((*model_view), vh)); - vh.y = 0.0 - vh.y; - vh = mat4x4_mul_vec4(viewport(vh.x, vh.y, img->width, img->height), vh); - - return project_vec4(vh); -} diff --git a/src/shaders.c b/src/shaders.c new file mode 100644 index 0000000..34b7c9c --- /dev/null +++ b/src/shaders.c @@ -0,0 +1,148 @@ +#include "img.h" +#include "obj.h" +#include "shader.h" +#include "utils.h" +#include "vec.h" + +typedef struct shader Shader; +struct shader { + M4x4f model_view; + M4x4f projection; +}; + +Shader perspective = {0}; +Shader orthographic = {0}; + +ShaderID perspective_lit_textured_id = {0}; +ShaderID perspective_lit_coloured_id = {0}; +ShaderID perspective_albedo_id = {0}; +ShaderID orthographic_lit_textured_id = {0}; +ShaderID orthographic_lit_coloured_id = {0}; +ShaderID orthographic_albedo_id = {0}; + +V3f g_light_dir = {0.0f, 0.0f, 1.0f}; +V3f g_eye = {0.2f, 0.1f, 0.75f}; +V3f g_target = {0}; +V3f g_up = {0.0f, 1.0f, 0.0f}; +M4x4f g_cam_matrix = mat4x4_identity; + +internal V3f general_shader_vertex(void *shader, const V3f *vertex, + const Buffer *out_buf); +internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, + V2f tex_coords, + const Colour *colour, + const Image *texture); +internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, + V2f tex_coords, + const Colour *colour, + const Image *texture); +internal FragmentResult albedo_shader_fragment(void *shader, V3f normal, + V2f tex_coords, + const Colour *colour, + const Image *texture); +internal M4x4f get_projection_matrix(ProjectionType projection_type); +internal f32 get_intensity(const V3f *normal); + +void load_shaders(void) { + M4x4f model_view = lookat(g_eye, g_target, g_up); + M4x4f orthographic_projection = + get_projection_matrix(PROJECTION_TYPE_ORTHOGRAPHIC); + M4x4f perspective_projection = + get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE); + + perspective.model_view = orthographic.model_view = model_view; + perspective.projection = perspective_projection; + orthographic.projection = orthographic_projection; + + perspective_lit_textured_id = create_shader( + &perspective, general_shader_vertex, lit_textured_shader_fragment); + perspective_lit_coloured_id = create_shader( + &perspective, general_shader_vertex, lit_coloured_shader_fragment); + perspective_albedo_id = create_shader(&perspective, general_shader_vertex, + albedo_shader_fragment); + orthographic_lit_textured_id = create_shader( + &orthographic, general_shader_vertex, lit_textured_shader_fragment); + orthographic_lit_coloured_id = create_shader( + &orthographic, general_shader_vertex, lit_coloured_shader_fragment); + orthographic_albedo_id = create_shader(&orthographic, general_shader_vertex, + albedo_shader_fragment); +} + +internal V3f general_shader_vertex(void *shader, const V3f *vertex, + const Buffer *out_buf) { + Shader *shader_ptr = (Shader *)shader; + + V4f vh = {.x = vertex->x, .y = vertex->y, .z = vertex->z, .w = 1.0f}; + vh = mat4x4_mul_vec4(shader_ptr->projection, + mat4x4_mul_vec4(shader_ptr->model_view, vh)); + vh.y = 0.0 - vh.y; + vh = mat4x4_mul_vec4(viewport(vh.x, vh.y, out_buf->width, out_buf->height), + vh); + + return project_vec4(vh); +} + +internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, + V2f tex_coords, + const Colour *colour, + const Image *texture) { + if (!texture) { + return DISCARDED_FRAGMENT; + } + + f32 intensity = get_intensity(&normal); + + u64 tx_x = tex_coords.u * texture->width; + u64 tx_y = (1.0f - tex_coords.v) * texture->height; + + Colour output = get_pixel(Colour, texture, tx_x, tx_y); + + output.r *= intensity; + output.g *= intensity; + output.b *= intensity; + + return (FragmentResult){.colour = output}; +} + +internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, + V2f tex_coords, + const Colour *colour, + const Image *texture) { + f32 intensity = get_intensity(&normal); + Colour output = *colour; + + output.r *= intensity; + output.g *= intensity; + output.b *= intensity; + + return (FragmentResult){.colour = output}; +} + +internal FragmentResult albedo_shader_fragment(void *shader, V3f normal, + V2f tex_coords, + const Colour *colour, + const Image *texture) { + return (FragmentResult){.colour = *colour}; +} + +internal M4x4f get_projection_matrix(ProjectionType projection_type) { + if (projection_type == PROJECTION_TYPE_PERSPECTIVE) { + // Calculate projection matrix + V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y, + g_eye.z); + normalise_v3(cam); + f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f; + return projection(coeff); + } + + return mat4x4_identity; +} + +internal f32 get_intensity(const V3f *normal) { + f32 intensity = dot_v3((*normal), g_light_dir); + if (intensity < 0.0f) { + intensity = 0.01f; + } + + return intensity; +} diff --git a/src/shaders.h b/src/shaders.h new file mode 100644 index 0000000..2022243 --- /dev/null +++ b/src/shaders.h @@ -0,0 +1,6 @@ +#ifndef SHADERS_H +#define SHADERS_H + +void load_shaders(void); + +#endif // SHADERS_H -- 2.39.5 From fbf3f17b8f00d031f40525c526b8f32690d596d1 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 18 Aug 2024 15:23:21 +0100 Subject: [PATCH 6/6] Reorganise code --- compile | 6 ++++-- src/{ => img}/img.c | 0 src/{ => img}/img.h | 0 src/{ => list}/typed_list.c | 0 src/{ => list}/typed_list.h | 0 src/{ => obj}/obj.c | 0 src/{ => obj}/obj.h | 0 src/{ => pam}/pam.c | 0 src/{ => pam}/pam.h | 0 src/{ => shader}/shader.c | 0 src/{ => shader}/shader.h | 0 src/{ => shader}/shaders.c | 0 src/{ => shader}/shaders.h | 0 src/{ => utils}/utils.c | 0 src/{ => utils}/utils.h | 0 src/{ => vec}/vec.c | 0 src/{ => vec}/vec.h | 0 17 files changed, 4 insertions(+), 2 deletions(-) rename src/{ => img}/img.c (100%) rename src/{ => img}/img.h (100%) rename src/{ => list}/typed_list.c (100%) rename src/{ => list}/typed_list.h (100%) rename src/{ => obj}/obj.c (100%) rename src/{ => obj}/obj.h (100%) rename src/{ => pam}/pam.c (100%) rename src/{ => pam}/pam.h (100%) rename src/{ => shader}/shader.c (100%) rename src/{ => shader}/shader.h (100%) rename src/{ => shader}/shaders.c (100%) rename src/{ => shader}/shaders.h (100%) rename src/{ => utils}/utils.c (100%) rename src/{ => utils}/utils.h (100%) rename src/{ => vec}/vec.c (100%) rename src/{ => vec}/vec.h (100%) diff --git a/compile b/compile index e6bf2a4..23050bf 100755 --- a/compile +++ b/compile @@ -3,9 +3,11 @@ CC=clang WAPP_INCLUDE="$(find intern/wapp/src -type d | xargs -I{} echo -n "-I{} ")" WAPP_SRC="$(find intern/wapp/src -type f -name "*.c" | xargs -I{} echo -n "{} ")" -CFLAGS="-g -Isrc $WAPP_INCLUDE" +TINYRENDER_INCLUDE="$(find src -type d | xargs -I{} echo -n "-I{} ")" +TINYRENDER_SRC="$(find src -type f -name "*.c" | xargs -I{} echo -n "{} ")" +CFLAGS="-g $TINYRENDER_INCLUDE $WAPP_INCLUDE" LIBS="-lm" -SRC="src/*.c $WAPP_SRC" +SRC="$TINYRENDER_SRC $WAPP_SRC" OUT=tiny (set -x ; $CC $CFLAGS $LIBS $SRC -o $OUT) diff --git a/src/img.c b/src/img/img.c similarity index 100% rename from src/img.c rename to src/img/img.c diff --git a/src/img.h b/src/img/img.h similarity index 100% rename from src/img.h rename to src/img/img.h diff --git a/src/typed_list.c b/src/list/typed_list.c similarity index 100% rename from src/typed_list.c rename to src/list/typed_list.c diff --git a/src/typed_list.h b/src/list/typed_list.h similarity index 100% rename from src/typed_list.h rename to src/list/typed_list.h diff --git a/src/obj.c b/src/obj/obj.c similarity index 100% rename from src/obj.c rename to src/obj/obj.c diff --git a/src/obj.h b/src/obj/obj.h similarity index 100% rename from src/obj.h rename to src/obj/obj.h diff --git a/src/pam.c b/src/pam/pam.c similarity index 100% rename from src/pam.c rename to src/pam/pam.c diff --git a/src/pam.h b/src/pam/pam.h similarity index 100% rename from src/pam.h rename to src/pam/pam.h diff --git a/src/shader.c b/src/shader/shader.c similarity index 100% rename from src/shader.c rename to src/shader/shader.c diff --git a/src/shader.h b/src/shader/shader.h similarity index 100% rename from src/shader.h rename to src/shader/shader.h diff --git a/src/shaders.c b/src/shader/shaders.c similarity index 100% rename from src/shaders.c rename to src/shader/shaders.c diff --git a/src/shaders.h b/src/shader/shaders.h similarity index 100% rename from src/shaders.h rename to src/shader/shaders.h diff --git a/src/utils.c b/src/utils/utils.c similarity index 100% rename from src/utils.c rename to src/utils/utils.c diff --git a/src/utils.h b/src/utils/utils.h similarity index 100% rename from src/utils.h rename to src/utils/utils.h diff --git a/src/vec.c b/src/vec/vec.c similarity index 100% rename from src/vec.c rename to src/vec/vec.c diff --git a/src/vec.h b/src/vec/vec.h similarity index 100% rename from src/vec.h rename to src/vec/vec.h -- 2.39.5