Implement shaders #1
							
								
								
									
										48
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								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 <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
							
								
								
									
										235
									
								
								src/obj.c
									
									
									
									
									
								
							
							
						
						
									
										235
									
								
								src/obj.c
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ | ||||
| #include "pam.h" | ||||
| #include "typed_list.h" | ||||
| #include "utils.h" | ||||
| #include "vec.h" | ||||
| #include <limits.h> | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| @@ -12,84 +13,6 @@ | ||||
| #include <string.h> | ||||
|  | ||||
| #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, | ||||
|   }; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										88
									
								
								src/obj.h
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								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 | ||||
|   | ||||
							
								
								
									
										57
									
								
								src/vec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/vec.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										163
									
								
								src/vec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/vec.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| #ifndef VEC_H | ||||
| #define VEC_H | ||||
|  | ||||
| #include "aliases.h" | ||||
| #include "typed_list.h" | ||||
| #include <math.h> | ||||
|  | ||||
| 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 | ||||
		Reference in New Issue
	
	Block a user