test triangle rendered?

This commit is contained in:
veclavtlica
2026-09-13 22:30:19 +03:00
parent 4e1fa1ed1c
commit 578c4a6d4f
6 changed files with 193 additions and 3 deletions
+12
View File
@@ -139,4 +139,16 @@ static inline com_fix_t com_fix_tan(com_fix_t a) {
return com_fix_div(s, c);
}
/* Branchless min.
* https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax */
static inline com_fix_t com_fix_min(com_fix_t x, com_fix_t y) {
return y ^ ((x ^ y) & -(x < y));
}
/* Branchless max.
* https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax */
static inline com_fix_t com_fix_max(com_fix_t x, com_fix_t y) {
return x ^ ((x ^ y) & -(x < y));
}
#endif
+45 -3
View File
@@ -6,6 +6,8 @@
#define COM_GEM_H
#include "mat.h"
#include "pnt.h"
#include "vec.h"
#include <stdint.h>
/* Projects vertex position to a clip space via reordered row-major MVP matrix.
@@ -37,6 +39,8 @@ static inline com_vec_t com_gem_vec_project_clip(com_mat_t a, com_vec_t b) {
/* TODO: If we clip test bounding volume of a model first we can skip
* all clipping whatsoever, which might hold true more often, than the cost of
* testing the volume. */
/* TODO: It should be possible to have results in pixel position, not -1 to 1.
*/
#define COM_GEM_VERTEX_UNCLIPPED (0 << 0)
#define COM_GEM_VERTEX_CLIPPED_X (1 << 0)
@@ -44,15 +48,53 @@ static inline com_vec_t com_gem_vec_project_clip(com_mat_t a, com_vec_t b) {
/* Attempt to project clip space vertex to NDC, reporting which component lies
* outside of view. Bit test against those per component. This is needed for
* determining new view-lying clipped triangles. */
static inline uint8_t com_gem_clip_vis_project(com_vec_t a, com_vec_t *out) {
static inline uint8_t com_gem_clip_vis_project(com_vec_t a, com_pnt_t *out) {
uint8_t mask;
if (a.s.x < -a.s.z || a.s.x > a.s.z)
mask ^= COM_GEM_VERTEX_CLIPPED_X;
if (a.s.y < -a.s.z || a.s.y > a.s.z)
mask ^= COM_GEM_VERTEX_CLIPPED_Y;
out->a[0] = com_fix_div(a.a[0], a.a[2]);
out->a[1] = com_fix_div(a.a[1], a.a[2]);
out->a[0] = com_fix_div(a.a[0], a.a[2]) / 480 + 240;
out->a[1] = com_fix_div(a.a[1], a.a[2]) / 640 + 320;
return mask;
}
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
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);
// If the point is inside or on all edges, draw the pixel
// (Assumes Clockwise vertex ordering)
if (w0 >= 0 && w1 >= 0 && w2 >= 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] = '#';
}
}
}
}
#endif
+86
View File
@@ -0,0 +1,86 @@
/*
Fixed point implementation of 2 dimensional pnttors.
*/
#ifndef COM_PNT_H
#define COM_PNT_H
#include "def.h"
#include "fix.h"
#include "vec.h"
#include <stdint.h>
typedef union {
com_def_alignedas(16) com_def_vector(com_fix_t, a, 2);
com_def_alignedas(16) struct {
com_fix_t x;
com_fix_t y;
} s;
} com_pnt_t;
static inline com_pnt_t com_pnt_from(com_fix_t x, com_fix_t y) {
return (com_pnt_t){.s = {.x = x, .y = y}};
}
static inline com_pnt_t com_pnt_from_vec(com_vec_t a) {
return (com_pnt_t){.s = {.x = a.a[0], .y = a.a[1]}};
}
static inline com_pnt_t com_pnt_identity(void) {
return (com_pnt_t){.s = {
.x = COM_FIX_FRACUNIT,
.y = COM_FIX_FRACUNIT,
}};
}
static inline com_pnt_t com_pnt_add(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.s = {.x = com_fix_add(a.s.x, b.s.x), .y = com_fix_add(a.s.y, b.s.y)}};
}
static inline com_pnt_t com_pnt_sub(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.s = {.x = com_fix_sub(a.s.x, b.s.x), .y = com_fix_sub(a.s.y, b.s.y)}};
}
static inline com_pnt_t com_pnt_mul(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.s = {.x = com_fix_mul(a.s.x, b.s.x), .y = com_fix_mul(a.s.y, b.s.y)}};
}
/* Note: this does not clamp for over/underflow cases */
static inline com_pnt_t com_pnt_div(com_pnt_t a, com_pnt_t b) {
return (com_pnt_t){
.s = {.x = com_fix_div(a.s.x, b.s.x), .y = com_fix_div(a.s.y, b.s.y)}};
}
/* Scale pnttor by a fixed point number */
static inline com_pnt_t com_pnt_scl(com_pnt_t a, com_fix_t b) {
return (com_pnt_t){
.s = {.x = com_fix_mul(a.s.x, b), .y = com_fix_mul(a.s.y, b)}};
}
static inline com_fix_t com_pnt_min(com_pnt_t a) {
return com_fix_min(a.a[0], a.a[1]);
}
static inline com_fix_t com_pnt_max(com_pnt_t a) {
return com_fix_max(a.a[0], a.a[1]);
}
/* TODO: Safeguard by com_fix_mul()? */
/* Tests whether a point is lying right to a line produced by l0 and l1.
This assumes that l0 and l1 are in clockwise order.
Result is positive or zero if it holds true, otherwise it's negative. */
static inline com_fix_t com_pnt_edge_orient(com_pnt_t l0, com_pnt_t l1,
com_pnt_t p) {
return (l0.s.x - l1.s.x) * (p.s.y - l1.s.y) -
(l0.s.y - l1.s.y) * (p.s.x - l1.s.x);
}
static inline void com_pnt_print(com_pnt_t a) {
com_fix_print(a.a[0]);
com_fix_print(a.a[1]);
}
#endif
+18
View File
@@ -20,6 +20,10 @@ typedef union {
} s;
} com_vec_t;
static inline com_vec_t com_vec_from(com_fix_t x, com_fix_t y, com_fix_t z) {
return (com_vec_t){.s = {.x = x, .y = y, .z = z}};
}
static inline com_vec_t com_vec_identity(void) {
return (com_vec_t){.s = {.x = COM_FIX_FRACUNIT,
.y = COM_FIX_FRACUNIT,
@@ -88,4 +92,18 @@ static inline com_vec_t com_vec_nrm(com_vec_t a) {
.z = com_fix_div(a.s.z, n)}};
}
static inline com_fix_t com_vec_min(com_vec_t a) {
return com_fix_min(com_fix_min(a.a[0], a.a[1]), a.a[2]);
}
static inline com_fix_t com_vec_max(com_vec_t a) {
return com_fix_max(com_fix_max(a.a[0], a.a[1]), a.a[2]);
}
static inline void com_vec_print(com_vec_t a) {
com_fix_print(a.a[0]);
com_fix_print(a.a[1]);
com_fix_print(a.a[2]);
}
#endif