This commit is contained in:
veclavtlica
2026-09-14 00:02:08 +03:00
parent 578c4a6d4f
commit c350d65592
5 changed files with 90 additions and 26 deletions
+54 -18
View File
@@ -5,6 +5,7 @@
#ifndef COM_GEM_H
#define COM_GEM_H
#include "fix.h"
#include "mat.h"
#include "pnt.h"
#include "vec.h"
@@ -60,38 +61,73 @@ static inline uint8_t com_gem_clip_vis_project(com_vec_t a, com_pnt_t *out) {
}
static inline void com_gem_draw_triangle(com_pnt_t v0, com_pnt_t v1,
com_pnt_t v2, uint8_t *buffer) {
// 1. Compute the bounding box of the triangle
com_pnt_t v2, uint8_t *out) {
int minX = com_vec_min(com_vec_from(v0.s.x, v1.s.x, v2.s.x));
int minY = com_vec_min(com_vec_from(v0.s.y, v1.s.y, v2.s.y));
int maxX = com_vec_max(com_vec_from(v0.s.x, v1.s.x, v2.s.x));
int maxY = com_vec_max(com_vec_from(v0.s.y, v1.s.y, v2.s.y));
// 2. Clip the bounding box against screen dimensions to avoid out-of-bounds
// errors
// minX = CLAMP(minX, 0, 480 - 1);
// minY = CLAMP(minY, 0, HEIGHT - 1);
// maxX = CLAMP(maxX, 0, 480 - 1);
// maxY = CLAMP(maxY, 0, HEIGHT - 1);
// 3. Loop over all pixels inside the bounding box
for (int y = minY; y <= maxY; y++) {
for (int x = minX; x <= maxX; x++) {
com_pnt_t p = {.s = {x, y}};
// Test the pixel center against all 3 edges
int w0 = com_pnt_edge_orient(v1, v2, p);
int w1 = com_pnt_edge_orient(v2, v0, p);
int w2 = com_pnt_edge_orient(v0, v1, p);
com_vec_t ws = com_pnt_edge_weight(v0, v1, v2, p);
// If the point is inside or on all edges, draw the pixel
// (Assumes Clockwise vertex ordering)
if (w0 >= 0 && w1 >= 0 && w2 >= 0) {
if (ws.a[0] >= 0 && ws.a[1] >= 0 && ws.a[2] >= 0) {
printf("%i, %i\n", y, x);
buffer[(y * 640 + x) * 4 + 0] = '#';
buffer[(y * 640 + x) * 4 + 1] = '#';
buffer[(y * 640 + x) * 4 + 2] = '#';
buffer[(y * 640 + x) * 4 + 3] = '#';
out[(y * 640 + x) * 4 + 0] = 125;
out[(y * 640 + x) * 4 + 1] = 125;
out[(y * 640 + x) * 4 + 2] = 125;
}
}
}
}
static inline void com_gem_draw_triangle_textured(com_pnt_t v0, com_pnt_t v1,
com_pnt_t v2, uint8_t *out,
com_pnt_t uv0, com_pnt_t uv1,
com_pnt_t uv2, uint8_t *tex) {
int minX = com_vec_min(com_vec_from(v0.s.x, v1.s.x, v2.s.x));
int minY = com_vec_min(com_vec_from(v0.s.y, v1.s.y, v2.s.y));
int maxX = com_vec_max(com_vec_from(v0.s.x, v1.s.x, v2.s.x));
int maxY = com_vec_max(com_vec_from(v0.s.y, v1.s.y, v2.s.y));
com_fix_t const area = com_pnt_area(v0, v1, v2);
for (int y = minY; y <= maxY; y++) {
for (int x = minX; x <= maxX; x++) {
com_pnt_t p = {.s = {x, y}};
/* TODO: Move to a separate weighting function over vec. */
// Test the pixel center against all 3 edges
com_vec_t ws = com_pnt_edge_weight(v0, v1, v2, p);
// If the point is inside or on all edges, draw the pixel
// (Assumes Clockwise vertex ordering)
if (ws.a[0] >= 0 && ws.a[1] >= 0 && ws.a[2] >= 0) {
// Barycentric weights
ws = com_vec_div(ws, com_vec_scalar(area));
// Affine interpolation of UVs.
com_fix_t const u =
(ws.a[0] * uv0.a[0] + ws.a[1] * uv1.a[0] + ws.a[2] * uv2.a[0]) >>
COM_FIX_FRACBITS;
com_fix_t const v =
(ws.a[0] * uv0.a[1] + ws.a[1] * uv1.a[1] + ws.a[2] * uv2.a[1]) >>
COM_FIX_FRACBITS;
// Nearest-neighbor texture lookup, in [0..32) range.
int32_t tx =
(int32_t)((u + (COM_FIX_FRACUNIT / 2)) / (COM_FIX_FRACUNIT / 16));
int32_t ty =
(int32_t)((v + (COM_FIX_FRACUNIT / 2)) / (COM_FIX_FRACUNIT / 16));
out[(y * 640 + x) * 4 + 0] = tex[(ty * 32 + tx) * 3 + 0];
out[(y * 640 + x) * 4 + 1] = tex[(ty * 32 + tx) * 3 + 1];
out[(y * 640 + x) * 4 + 2] = tex[(ty * 32 + tx) * 3 + 2];
}
}
}