From 3844c87cf1266a26e0b7277164894380aa3c8098 Mon Sep 17 00:00:00 2001 From: matthewmeeks Date: Sat, 15 Apr 2023 08:49:23 -0400 Subject: [PATCH 1/3] Backface culling, basic lighting, double terminal resolution with half block character --- demos/model3d.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++- demos/teapot3d.c | 2 ++ demos/vc.c | 16 +++++++++++--- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/demos/model3d.c b/demos/model3d.c index 01e5fbc..9bcd9c9 100644 --- a/demos/model3d.c +++ b/demos/model3d.c @@ -61,6 +61,35 @@ static Vector3 rotate_y(Vector3 p, float delta_angle) return make_vector3(cosf(angle)*mag, p.y, sinf(angle)*mag); } +static Vector3 cross(Vector3 a, Vector3 b) { + return make_vector3( + a.y * b.z - a.z * b.y, + a.z * b.x - a.x * b.z, + a.x * b.y - a.y * b.x); +} + +static Vector3 subtract3(Vector3 l, Vector3 r) { + return make_vector3(l.x - r.x, l.y - r.y, l.z - r.z); +} + +static void normalize3(Vector3 *v) { + float mag_sqr = v->x * v->x + v->y * v->y + v->z * v->z; + if (mag_sqr < EPSILON*EPSILON) { + v->x = 0; + v->y = 0; + v->z = 0; + return; + } + float mag = sqrtf(mag_sqr); + v->x /= mag; + v->y /= mag; + v->z /= mag; +} + +static float dot3(Vector3 a, Vector3 b) { + return a.x * b.x + a.y * b.y + a.z * b.z; +} + Olivec_Canvas vc_render(float dt) { angle += 0.25*PI*dt; @@ -69,6 +98,11 @@ Olivec_Canvas vc_render(float dt) olivec_fill(oc, BACKGROUND_COLOR); for (size_t i = 0; i < WIDTH*HEIGHT; ++i) zbuffer[i] = 0; +#ifdef LIGHTING + Vector3 sun = make_vector3(1, 3, -2); + normalize3(&sun); +#endif + for (size_t i = 0; i < faces_count; ++i) { int a = faces[i][0]; int b = faces[i][1]; @@ -81,6 +115,21 @@ Olivec_Canvas vc_render(float dt) Vector2 p2 = project_2d_scr(project_3d_2d(v2)); Vector2 p3 = project_2d_scr(project_3d_2d(v3)); +#ifdef LIGHTING + Vector3 normal = cross(subtract3(v2, v1), subtract3(v3, v1)); + normalize3(&normal); + + float diff = (dot3(normal, sun) + 1.0f) / 2.0f; + int dq = (int)(diff * 255); +#endif + +#ifdef BACKFACE_CULLING + if ((p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x) <= 0) continue; +#endif +#ifdef FRONTFACE_CULLING + if ((p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x) >= 0) continue; +#endif + int x1 = p1.x; int x2 = p2.x; int x3 = p3.x; @@ -90,9 +139,12 @@ Olivec_Canvas vc_render(float dt) int lx, hx, ly, hy; if (olivec_normalize_triangle(oc.width, oc.height, x1, y1, x2, y2, x3, y3, &lx, &hx, &ly, &hy)) { for (int y = ly; y <= hy; ++y) { + bool has_entered = false; + for (int x = lx; x <= hx; ++x) { int u1, u2, det; if (olivec_barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det)) { + has_entered = true; int u3 = det - u1 - u2; float z = 1/v1.z*u1/det + 1/v2.z*u2/det + 1/v3.z*u3/det; float near = 0.1f; @@ -100,6 +152,9 @@ Olivec_Canvas vc_render(float dt) if (1.0f/far < z && z < 1.0f/near && z > zbuffer[y*WIDTH + x]) { zbuffer[y*WIDTH + x] = z; OLIVEC_PIXEL(oc, x, y) = mix_colors3(0xFF1818FF, 0xFF18FF18, 0xFFFF1818, u1, u2, det); +#ifdef LIGHTING + olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), ((255 - dq)<<(3*8))); +#endif z = 1.0f/z; if (z >= 1.0) { @@ -109,7 +164,7 @@ Olivec_Canvas vc_render(float dt) olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), (v<<(3*8))); } } - } + } else if (has_entered) break; } } } diff --git a/demos/teapot3d.c b/demos/teapot3d.c index fc38731..3b87c56 100644 --- a/demos/teapot3d.c +++ b/demos/teapot3d.c @@ -1,3 +1,5 @@ #include "assets/utahTeapot.c" #define VC_TERM_SCALE_DOWN_FACTOR 10 +#define BACKFACE_CULLING +#define LIGHTING #include "model3d.c" diff --git a/demos/vc.c b/demos/vc.c index 405ec9e..6d48f2b 100644 --- a/demos/vc.c +++ b/demos/vc.c @@ -541,20 +541,30 @@ static void vc_term_compress_pixels(Olivec_Canvas oc) } } +void sig_handler(int signo) +{ + if (signo == SIGINT) { + printf("\033[?25h"); + exit(0); + } +} + int main(void) { + signal(SIGINT, sig_handler); + printf("\033[?25l"); for (;;) { vc_term_compress_pixels(vc_render(1.f/60.f)); - for (size_t y = 0; y < vc_term_scaled_down_height; ++y) { + for (size_t y = 0; y < vc_term_scaled_down_height - 1; y = y + 2) { for (size_t x = 0; x < vc_term_scaled_down_width; ++x) { // TODO: explore the idea of figuring out aspect ratio of the character using escape ANSI codes of the terminal and rendering the image accordingly - printf("\033[48;5;%dm ", vc_term_char_canvas[y*vc_term_scaled_down_width + x]); + printf("\033[48;5;%dm\033[38;5;%dm%s", vc_term_char_canvas[y*vc_term_scaled_down_width + x], vc_term_char_canvas[y*vc_term_scaled_down_width + vc_term_scaled_down_width + x], "\u2584"); } printf("\033[0m\n"); } usleep(1000*1000/60); - printf("\033[%zuA", vc_term_scaled_down_height); + printf("\033[%zuA", vc_term_scaled_down_height / 2); printf("\033[%zuD", vc_term_scaled_down_width); } return 0; From 1c951e3c54ae7ed531090391876fd51aebf5b09d Mon Sep 17 00:00:00 2001 From: matthewmeeks Date: Sat, 15 Apr 2023 08:54:52 -0400 Subject: [PATCH 2/3] cull before normal calc --- demos/model3d.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/demos/model3d.c b/demos/model3d.c index 9bcd9c9..b93e3d5 100644 --- a/demos/model3d.c +++ b/demos/model3d.c @@ -115,14 +115,6 @@ Olivec_Canvas vc_render(float dt) Vector2 p2 = project_2d_scr(project_3d_2d(v2)); Vector2 p3 = project_2d_scr(project_3d_2d(v3)); -#ifdef LIGHTING - Vector3 normal = cross(subtract3(v2, v1), subtract3(v3, v1)); - normalize3(&normal); - - float diff = (dot3(normal, sun) + 1.0f) / 2.0f; - int dq = (int)(diff * 255); -#endif - #ifdef BACKFACE_CULLING if ((p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x) <= 0) continue; #endif @@ -130,6 +122,14 @@ Olivec_Canvas vc_render(float dt) if ((p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x) >= 0) continue; #endif +#ifdef LIGHTING + Vector3 normal = cross(subtract3(v2, v1), subtract3(v3, v1)); + normalize3(&normal); + + float diffuse = (dot3(normal, sun) + 1.0f) / 2.0f; + int diffuse_byte_val = (int)(diffuse * 255); +#endif + int x1 = p1.x; int x2 = p2.x; int x3 = p3.x; @@ -153,7 +153,7 @@ Olivec_Canvas vc_render(float dt) zbuffer[y*WIDTH + x] = z; OLIVEC_PIXEL(oc, x, y) = mix_colors3(0xFF1818FF, 0xFF18FF18, 0xFFFF1818, u1, u2, det); #ifdef LIGHTING - olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), ((255 - dq)<<(3*8))); + olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), (255 - diffuse_byte_val)<<(3*8)); #endif z = 1.0f/z; From 5e30097c5a3ac9e9d5320ac6d477d04a49fbf0a4 Mon Sep 17 00:00:00 2001 From: matthewmeeks Date: Sat, 15 Apr 2023 09:09:48 -0400 Subject: [PATCH 3/3] merge half block character into format string --- demos/vc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/vc.c b/demos/vc.c index 6d48f2b..f4e1c79 100644 --- a/demos/vc.c +++ b/demos/vc.c @@ -558,7 +558,7 @@ int main(void) for (size_t y = 0; y < vc_term_scaled_down_height - 1; y = y + 2) { for (size_t x = 0; x < vc_term_scaled_down_width; ++x) { // TODO: explore the idea of figuring out aspect ratio of the character using escape ANSI codes of the terminal and rendering the image accordingly - printf("\033[48;5;%dm\033[38;5;%dm%s", vc_term_char_canvas[y*vc_term_scaled_down_width + x], vc_term_char_canvas[y*vc_term_scaled_down_width + vc_term_scaled_down_width + x], "\u2584"); + printf("\033[48;5;%dm\033[38;5;%dm\u2584", vc_term_char_canvas[y*vc_term_scaled_down_width + x], vc_term_char_canvas[y*vc_term_scaled_down_width + vc_term_scaled_down_width + x]); } printf("\033[0m\n"); }