no libc, start on socket x11
This commit is contained in:
+126
-14
@@ -9,7 +9,9 @@
|
||||
#include "mat.h"
|
||||
#include "pnt.h"
|
||||
#include "vec.h"
|
||||
#include "zord.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Projects vertex position to a clip space via reordered row-major MVP matrix.
|
||||
It skips calculation of z depth component, as we assume to never use it.
|
||||
@@ -46,17 +48,29 @@ static inline com_vec_t com_gem_vec_project_clip(com_mat_t a, com_vec_t b) {
|
||||
#define COM_GEM_VERTEX_UNCLIPPED (0 << 0)
|
||||
#define COM_GEM_VERTEX_CLIPPED_X (1 << 0)
|
||||
#define COM_GEM_VERTEX_CLIPPED_Y (1 << 1)
|
||||
/* 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. */
|
||||
/* Attempt to project clip space vertex to render pixel space, 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_pnt_t *out) {
|
||||
uint8_t mask = 0;
|
||||
if (a.a[0] < -a.a[2] || a.a[0] > a.a[2])
|
||||
mask ^= COM_GEM_VERTEX_CLIPPED_X;
|
||||
if (a.a[1] < -a.a[2] || a.a[1] > a.a[2])
|
||||
mask ^= COM_GEM_VERTEX_CLIPPED_Y;
|
||||
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;
|
||||
// out->a[0] = com_fix_mul((com_fix_div(a.a[0], a.a[2]) + COM_FIX_FRACUNIT) >>
|
||||
// 1,
|
||||
// 640 * COM_FIX_FRACUNIT);
|
||||
// out->a[1] = com_fix_mul((com_fix_div(a.a[1], a.a[2]) + COM_FIX_FRACUNIT) >>
|
||||
// 1,
|
||||
// 480 * COM_FIX_FRACUNIT);
|
||||
out->a[0] =
|
||||
(com_fix_mul(com_fix_div(a.a[0], a.a[2]), 640 * COM_FIX_FRACUNIT) >>
|
||||
COM_FIX_FRACBITS) +
|
||||
320;
|
||||
out->a[1] =
|
||||
(com_fix_mul(com_fix_div(a.a[1], a.a[2]), 480 * COM_FIX_FRACUNIT) >>
|
||||
COM_FIX_FRACBITS) +
|
||||
240;
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -75,7 +89,7 @@ static inline void com_gem_draw_triangle(com_pnt_t v0, com_pnt_t v1,
|
||||
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)
|
||||
// (Assumes Counter Clockwise vertex ordering)
|
||||
if (ws.a[0] >= 0 && ws.a[1] >= 0 && ws.a[2] >= 0) {
|
||||
out[(y * 640 + x) * 4 + 0] = 125;
|
||||
out[(y * 640 + x) * 4 + 1] = 125;
|
||||
@@ -85,10 +99,15 @@ static inline void com_gem_draw_triangle(com_pnt_t v0, com_pnt_t v1,
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
/* TODO: Implement and compare:
|
||||
https://www.digipen.edu/sites/default/files/public/docs/theses/salem-haykal-digipen-master-of-science-in-computer-science-thesis-an-optimized-triangle-rasterizer.pdf
|
||||
|
||||
Tile-based variant fares even worse than this implementation.
|
||||
*/
|
||||
static inline void
|
||||
com_gem_draw_triangle_textured_edge(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.a[0], v1.a[0], v2.a[0]));
|
||||
int minY = com_vec_min(com_vec_from(v0.a[1], v1.a[1], v2.a[1]));
|
||||
int maxX = com_vec_max(com_vec_from(v0.a[0], v1.a[0], v2.a[0]));
|
||||
@@ -100,7 +119,6 @@ static inline void com_gem_draw_triangle_textured(com_pnt_t v0, com_pnt_t v1,
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
com_pnt_t p = {.a = {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);
|
||||
|
||||
@@ -124,12 +142,106 @@ static inline void com_gem_draw_triangle_textured(com_pnt_t v0, com_pnt_t v1,
|
||||
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];
|
||||
// uint32_t idx = com_zord_order(tx, ty);
|
||||
uint32_t idx = ty * 32 + tx;
|
||||
// uint32_t bidx = com_zord_order(x, y);
|
||||
uint32_t bidx = y * 640 + x;
|
||||
|
||||
out[bidx * 4 + 0] = tex[idx * 3 + 0];
|
||||
out[bidx * 4 + 1] = tex[idx * 3 + 1];
|
||||
out[bidx * 4 + 2] = tex[idx * 3 + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void draw_span(int32_t x_start_fp, int32_t x_end_fp, int y,
|
||||
uint8_t *out, uint8_t *tex) {
|
||||
int x1 = com_fix_int(
|
||||
x_start_fp + (1 << (COM_FIX_FRACBITS - 1))); // Rounding to nearest pixel
|
||||
int x2 = com_fix_int(x_end_fp + (1 << (COM_FIX_FRACBITS - 1)));
|
||||
|
||||
if (x1 > x2) {
|
||||
int tmp = x1;
|
||||
x1 = x2;
|
||||
x2 = tmp;
|
||||
}
|
||||
|
||||
for (int x = x1; x < x2; x++) {
|
||||
uint32_t idx = 0 * 32 + 0;
|
||||
uint32_t bidx = y * 640 + x;
|
||||
out[bidx * 4 + 0] = tex[idx * 3 + 0];
|
||||
out[bidx * 4 + 1] = tex[idx * 3 + 1];
|
||||
out[bidx * 4 + 2] = tex[idx * 3 + 2];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
com_gem_draw_triangle_textured_span(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) {
|
||||
// 1. Sort vertices by Y coordinate (v0.a[1] <= v1.a[1] <= v2.a[1])
|
||||
if (v0.a[1] > v1.a[1]) {
|
||||
com_pnt_t tmp = v0;
|
||||
v0 = v1;
|
||||
v1 = tmp;
|
||||
}
|
||||
if (v0.a[1] > v2.a[1]) {
|
||||
com_pnt_t tmp = v0;
|
||||
v0 = v2;
|
||||
v2 = tmp;
|
||||
}
|
||||
if (v1.a[1] > v2.a[1]) {
|
||||
com_pnt_t tmp = v1;
|
||||
v1 = v2;
|
||||
v2 = tmp;
|
||||
}
|
||||
|
||||
// Guard against zero-height triangles
|
||||
if ((int)v0.a[1] == (int)v2.a[1])
|
||||
return;
|
||||
|
||||
// 2. Compute overall inverse slopes (dX/dY) for all edges
|
||||
// Fixed-point division is performed using 64-bit integer casting to prevent
|
||||
// overflow
|
||||
com_fix_t dx02 = (v2.a[1] != v0.a[1])
|
||||
? (com_fix_t)((int64_t)(v2.a[0] - v0.a[0])
|
||||
<< COM_FIX_FRACBITS / (v2.a[1] - v0.a[1]))
|
||||
: 0;
|
||||
com_fix_t dx01 = (v1.a[1] != v0.a[1])
|
||||
? (com_fix_t)((int64_t)(v1.a[0] - v0.a[0])
|
||||
<< COM_FIX_FRACBITS / (v1.a[1] - v0.a[1]))
|
||||
: 0;
|
||||
com_fix_t dx12 = (v2.a[1] != v1.a[1])
|
||||
? (com_fix_t)((int64_t)(v2.a[0] - v1.a[0])
|
||||
<< COM_FIX_FRACBITS / (v2.a[1] - v1.a[1]))
|
||||
: 0;
|
||||
|
||||
// Determine the scanline limits (pixel discrete boundaries)
|
||||
int y_start = com_fix_int(v0.a[1]);
|
||||
int y_mid = com_fix_int(v1.a[1]);
|
||||
int y_end = com_fix_int(v2.a[1]);
|
||||
|
||||
// Initialize edge walkers starting at the top vertex (v0)
|
||||
com_fix_t edge1 = v0.a[0]; // Follows the long edge (v0 -> v2)
|
||||
com_fix_t edge2 = v0.a[0]; // Follows short edges (v0 -> v1, then v1 -> v2)
|
||||
|
||||
// 3. Top Half Scan: Walk from top vertex to middle vertex breakpoint
|
||||
for (int y = y_start; y < y_mid; y++) {
|
||||
draw_span(edge1, edge2, y, out, tex);
|
||||
edge1 += dx02;
|
||||
edge2 += dx01;
|
||||
}
|
||||
|
||||
// Adjust the short edge walker directly to the middle vertex position
|
||||
edge2 = v1.a[0];
|
||||
|
||||
// 4. Bottom Half Scan: Walk from middle vertex to bottom vertex
|
||||
for (int y = y_mid; y < y_end; y++) {
|
||||
draw_span(edge1, edge2, y, out, tex);
|
||||
edge1 += dx02;
|
||||
edge2 += dx12;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user