diff --git a/src/obj.c b/src/obj.c index 110b422..66581c4 100644 --- a/src/obj.c +++ b/src/obj.c @@ -13,6 +13,7 @@ #define TRIANGLE_VERTICES 3 #define CAMERA_DISTANCE 5.0f +#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}) @@ -106,14 +107,13 @@ internal void fill_triangle(Render *render, V3f vertices[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 TriangleBBox get_triangle_bbox(const Image *img, V3f 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(f32 norm_x, f32 norm_y, const Image *img, - u64 *x, u64 *y); -internal u64 ndc_to_image_coordinate(f32 value, u64 max); +internal V3f get_viewport_vertex(V3f vertex, const Image *img); V3f g_light_dir = {0.0f, 0.0f, 1.0f}; @@ -293,14 +293,15 @@ internal void render_triangle(const Triangle *triangle, const Model *model, if (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]; - get_image_coordinates(v0.x, v0.y, img, &x0, &y0); - get_image_coordinates(v1.x, v1.y, img, &x1, &y1); + vp0 = get_viewport_vertex(v0, img); + vp1 = get_viewport_vertex(v1, img); - draw_line(img, x0, y0, x1, y1, colour); + draw_line(img, (u64)vp0.x, (u64)vp0.y, (u64)vp1.x, (u64)vp1.y, colour); } } else if (type == RENDER_TYPE_FILLED || type == RENDER_TYPE_SHADED) { fill_triangle(render, vertices, normals, coordinates, colour, @@ -316,10 +317,9 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], Depth *depth = &(render->depth); TriangleBBox bbox = get_triangle_bbox(img, vertices); - V2u v0, v1, v2; - get_image_coordinates(vertices[0].x, vertices[0].y, img, &(v0.x), &(v0.y)); - get_image_coordinates(vertices[1].x, vertices[1].y, img, &(v1.x), &(v1.y)); - get_image_coordinates(vertices[2].x, vertices[2].y, img, &(v2.x), &(v2.y)); + V3f v0 = get_viewport_vertex(vertices[0], img); + V3f v1 = get_viewport_vertex(vertices[1], img); + V3f v2 = get_viewport_vertex(vertices[2], img); 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); @@ -416,6 +416,22 @@ internal M4x4f lookat(V3f eye, V3f target, V3f up) { 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 TriangleBBox get_triangle_bbox(const Image *img, V3f vertices[TRIANGLE_VERTICES]) { f32 x0 = min(vertices[0].x, min(vertices[1].x, vertices[2].x)); @@ -425,11 +441,15 @@ internal TriangleBBox get_triangle_bbox(const Image *img, 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)); - TriangleBBox bbox = {0}; - get_image_coordinates(x0, y0, img, &(bbox.x0), &(bbox.y0)); - get_image_coordinates(x1, y1, img, &(bbox.x1), &(bbox.y1)); + V3f minimum = get_viewport_vertex((V3f){x0, y0, 0.0f}, img); + V3f maximum = get_viewport_vertex((V3f){x1, y1, 0.0f}, img); - return bbox; + return (TriangleBBox){ + .x0 = minimum.x, + .y0 = minimum.y, + .x1 = maximum.x, + .y1 = maximum.y, + }; } internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, @@ -449,20 +469,8 @@ internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, return (V3f){v, w, u}; } -internal void get_image_coordinates(f32 norm_x, f32 norm_y, const Image *img, - u64 *x, u64 *y) { - *x = ndc_to_image_coordinate(norm_x, img->width); - *y = ndc_to_image_coordinate(0.0f - norm_y, img->height); - - if (*x >= img->width) { - *x = img->width - 1; - } - if (*y >= img->height) { - *y = img->height - 1; - } -} - -internal u64 ndc_to_image_coordinate(f32 value, u64 max) { - f32 result = (value + 1.0f) * max * 0.5f; - return clamp((u64)result, 0, max); +internal V3f get_viewport_vertex(V3f vertex, const Image *img) { + V4f vh = {.x = vertex.x, .y = 0.0f - vertex.y, .z = vertex.z, .w = 1.0f}; + vh = mat4x4_mul_vec4(viewport(vh.x, vh.y, img->width, img->height), vh); + return project_vec4(vh); }