Switch to using a viewport matrix

This commit is contained in:
Abdelrahman Said 2024-08-17 16:27:45 +01:00
parent 3e414881d9
commit f77fa5694b

View File

@ -13,6 +13,7 @@
#define TRIANGLE_VERTICES 3 #define TRIANGLE_VERTICES 3
#define CAMERA_DISTANCE 5.0f #define CAMERA_DISTANCE 5.0f
#define DEPTH_MAX 255
#define V2(T, ELEM_T, X0, Y0, X1, Y1) \ #define V2(T, ELEM_T, X0, Y0, X1, Y1) \
((T){(ELEM_T)X1 - (ELEM_T)X0, (ELEM_T)Y1 - (ELEM_T)Y0}) ((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, V2f coordinates[TRIANGLE_VERTICES], Colour colour,
Image *texture, RenderType type); Image *texture, RenderType type);
internal M4x4f lookat(V3f eye, V3f target, V3f up); 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, internal TriangleBBox get_triangle_bbox(const Image *img,
V3f vertices[TRIANGLE_VERTICES]); V3f vertices[TRIANGLE_VERTICES]);
internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom,
const V2i *ab, const V2i *ac, const V2i *ab, const V2i *ac,
const V2i *ap); const V2i *ap);
internal void get_image_coordinates(f32 norm_x, f32 norm_y, const Image *img, internal V3f get_viewport_vertex(V3f vertex, const Image *img);
u64 *x, u64 *y);
internal u64 ndc_to_image_coordinate(f32 value, u64 max);
V3f g_light_dir = {0.0f, 0.0f, 1.0f}; 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) { if (type == RENDER_TYPE_WIREFRAME) {
V3f v0, v1; V3f v0, v1;
u64 x0, y0, x1, y1; u64 x0, y0, x1, y1;
V3f vp0, vp1;
for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
v0 = vertices[i]; v0 = vertices[i];
v1 = vertices[(i + 1) % TRIANGLE_VERTICES]; v1 = vertices[(i + 1) % TRIANGLE_VERTICES];
get_image_coordinates(v0.x, v0.y, img, &x0, &y0); vp0 = get_viewport_vertex(v0, img);
get_image_coordinates(v1.x, v1.y, img, &x1, &y1); 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) { } else if (type == RENDER_TYPE_FILLED || type == RENDER_TYPE_SHADED) {
fill_triangle(render, vertices, normals, coordinates, colour, 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); Depth *depth = &(render->depth);
TriangleBBox bbox = get_triangle_bbox(img, vertices); TriangleBBox bbox = get_triangle_bbox(img, vertices);
V2u v0, v1, v2; V3f v0 = get_viewport_vertex(vertices[0], img);
get_image_coordinates(vertices[0].x, vertices[0].y, img, &(v0.x), &(v0.y)); V3f v1 = get_viewport_vertex(vertices[1], img);
get_image_coordinates(vertices[1].x, vertices[1].y, img, &(v1.x), &(v1.y)); V3f v2 = get_viewport_vertex(vertices[2], img);
get_image_coordinates(vertices[2].x, vertices[2].y, img, &(v2.x), &(v2.y));
V2i ab = V2(V2i, i64, v0.x, v0.y, v1.x, v1.y); 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); 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); 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, internal TriangleBBox get_triangle_bbox(const Image *img,
V3f vertices[TRIANGLE_VERTICES]) { V3f vertices[TRIANGLE_VERTICES]) {
f32 x0 = min(vertices[0].x, min(vertices[1].x, vertices[2].x)); 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 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)); f32 y1 = min(vertices[0].y, min(vertices[1].y, vertices[2].y));
TriangleBBox bbox = {0}; V3f minimum = get_viewport_vertex((V3f){x0, y0, 0.0f}, img);
get_image_coordinates(x0, y0, img, &(bbox.x0), &(bbox.y0)); V3f maximum = get_viewport_vertex((V3f){x1, y1, 0.0f}, img);
get_image_coordinates(x1, y1, img, &(bbox.x1), &(bbox.y1));
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, 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}; return (V3f){v, w, u};
} }
internal void get_image_coordinates(f32 norm_x, f32 norm_y, const Image *img, internal V3f get_viewport_vertex(V3f vertex, const Image *img) {
u64 *x, u64 *y) { V4f vh = {.x = vertex.x, .y = 0.0f - vertex.y, .z = vertex.z, .w = 1.0f};
*x = ndc_to_image_coordinate(norm_x, img->width); vh = mat4x4_mul_vec4(viewport(vh.x, vh.y, img->width, img->height), vh);
*y = ndc_to_image_coordinate(0.0f - norm_y, img->height); return project_vec4(vh);
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);
} }