Files
3drenderer/src/triangle.c

185 lines
5.6 KiB
C

#include "triangle.h"
#include "display.h"
#include "swap.h"
// Draw a filled triangle with a flat bottom
void fill_flat_bottom_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
// Find the two slopes (two triangle legs)
float inv_slope_1 = (float)(x1 - x0) / (y1 - y0);
float inv_slope_2 = (float)(x2 - x0) / (y2 - y0);
// Start x_start and x_end from the top vertex (x0, y0)
float x_start = x0;
float x_end = x0;
// Loop all the scanlines from top to bottom
for (int y = y0; y <= y2; y++) {
draw_line(x_start, y, x_end, y, color);
x_start += inv_slope_1;
x_end += inv_slope_2;
}
}
// Draw a filled triangle with a flat top
void fill_flat_top_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
// Find the two slopes (two triangle legs)
float inv_slope_1 = (float)(x2 - x0) / (y2 - y0);
float inv_slope_2 = (float)(x2 - x1) / (y2 - y1);
// Start x_start and x_end from the bottom vertex (x0, y0)
float x_start = x2;
float x_end = x2;
// Loop all the scanlines from bottom to top
for (int y = y2; y >= y0; y--) {
draw_line(x_start, y, x_end, y, color);
x_start -= inv_slope_1;
x_end -= inv_slope_2;
}
}
void draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
draw_line(x0, y0, x1, y1, color);
draw_line(x1, y1, x2, y2, color);
draw_line(x2, y2, x0, y0, color);
};
void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) {
// We need to sort the vertices by the y-coordinate ascending (y0 < y < y2)
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
}
if (y1 > y2) {
int_swap(&y1, &y2);
int_swap(&x1, &x2);
}
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
}
if (y1 == y2) {
fill_flat_bottom_triangle(x0, y0, x1, y1, x2, y2, color);
} else if (y0 == y1) {
fill_flat_top_triangle(x0, y0, x1, y1, x2, y2, color);
} else {
// Calculate the new vertex (Mx, My) using triangle similarity
int My = y1;
int Mx = ((float)((x2-x0) * (y1 - y0)) / (float)(y2 - y0)) + x0;
fill_flat_bottom_triangle(x0, y0, x1, y1, Mx, My, color);
fill_flat_top_triangle(x1, y1, Mx, My, x2, y2, color);
}
}
////////////////////////////////////////////////////////////////////////////////
// Draw a textured triangle with the flat-top/flat-bottom method
// We split the original triangle in two, half flat-bottom and half flat-top
////////////////////////////////////////////////////////////////////////////////
//
// v0
// /\
// / \
// / \
// / \
// v1-------v3
// \_ \
// \_ \
// \_ \
// \_ \
// \_ \
// \_ \
// \_ \
// \_ \
// \\
// \
// v2
////////////////////////////////////////////////////////////////////////////////
// TODO: use color_t type or uint32_t type?
void draw_textured_triangle(
int x0, int y0, float u0, float v0,
int x1, int y1, float u1, float v1,
int x2, int y2, float u2, float v2,
color_t* texture
) {
// We need to sort the vertices by y-coordinate asecnding (y0 < y1 < y2)
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
float_swap(&u0, &u1);
float_swap(&v0, &v1);
}
if (y1 > y2) {
int_swap(&y1, &y2);
int_swap(&x1, &x2);
float_swap(&u1, &u2);
float_swap(&v1, &v2);
}
if (y0 > y1) {
int_swap(&y0, &y1);
int_swap(&x0, &x1);
float_swap(&u0, &u1);
float_swap(&v0, &v1);
}
//////////////////////////////////////////////////////
// Render the upper part of the triangle (flat-bottom)
//////////////////////////////////////////////////////
float inv_slope_1 = 0;
float inv_slope_2 = 0;
// first and second slope of triangle legs
if (y1 - y0 != 0) inv_slope_1 = (float)(x1 - x0) / abs(y1 - y0);
if (y2 - y0 != 0) inv_slope_2 = (float)(x2 - x0) / abs(y2 - y0);
if (y1 - y0 != 0) {
for (int y = y0; y <= y1; y++) {
int x_start = x1 + (y - y1) * inv_slope_1;
int x_end = x0 + (y - y0) * inv_slope_2;
if (x_end < x_start) {
int_swap(&x_start, &x_end); // swap if x_start is to the right of x_end
}
for (int x = x_start; x < x_end; x++) {
// Draw our pixel with the color that comes from the texture
draw_pixel(x, y, 0xFFFF00FF);
}
}
}
//////////////////////////////////////////////////////
// Render the upper part of the triangle (flat-bottom)
//////////////////////////////////////////////////////
inv_slope_1 = 0;
inv_slope_2 = 0;
// first and second slope of triangle legs
if (y2 - y1 != 0) inv_slope_1 = (float)(x2 - x1) / abs(y2 - y1);
if (y2 - y0 != 0) inv_slope_2 = (float)(x2 - x0) / abs(y2 - y0);
if (y2 - y1 != 0) {
for (int y = y1; y <= y2; y++) {
int x_start = x1 + (y - y1) * inv_slope_1;
int x_end = x0 + (y - y0) * inv_slope_2;
if (x_end < x_start) {
int_swap(&x_start, &x_end); // swap if x_start is to the right of x_end
}
for (int x = x_start; x < x_end; x++) {
// Draw our pixel with the color that comes from the texture
draw_pixel(x, y, 0xFFFF00FF);
}
}
}
}