From dd5bf6cfc680451f7fc69f3251d103739ae6446b Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 15 Apr 2021 13:38:20 +0200 Subject: Implement Bresenham's line drawing algorithm --- src/main.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index ea43821..06fe7d9 100644 --- a/src/main.c +++ b/src/main.c @@ -84,7 +84,7 @@ put_char(int x, int y, Color clr, u8 chr) { } static inline void -put_line(int x, int y, Color clr, char *msg) { +put_text(int x, int y, Color clr, char *msg) { int count = 0; while (*msg) { put_char(x + count, y, clr, *msg++); @@ -92,6 +92,75 @@ put_line(int x, int y, Color clr, char *msg) { } } +// Draws a line with the given color between (x0,y0) and (x1,y1) using the +// Bresenham's line drawing algorithm using exclusively integer arithmetic. +static inline void +draw_line(int x0, int y0, int x1, int y1, Color clr) { + // Keep track of the coordinate for writing to the memory buffer. + int x = x0; + int y = y0; + + // Normalize the drawing direction to always draw from (x0, y0)->(x1, y1) + int x_step = 1; + int y_step = 1; + int dx = x1 - x0; + int dy = y1 - y0; + if (x0 > x1) { + x_step = -1; + dx = x0 - x1; + } + if (y0 > y1) { + y_step = -1; + dy = y0 - y1; + } + + // Precalculate line deltas. + int ddx = dx + dx; + int ddy = dy + dy; + + // These variables are dependant on the slope. We can avoid considering + // separate cases for positive and negative slopes by using pointers to + // update the step in x or y. + int diff; + int diff_inc_a; + int diff_inc_b; + int n_steps; + int *a; + int *b; + int a_step; + int b_step; + if (dx >= dy) { + diff = ddy - dx; + diff_inc_a = ddy; + diff_inc_b = ddx; + n_steps = dx; + a = &x; + b = &y; + a_step = x_step; + b_step = y_step; + } else { + diff = ddx - dy; + diff_inc_a = ddx; + diff_inc_b = ddy; + n_steps = dy; + a = &y; + b = &x; + a_step = y_step; + b_step = x_step; + } + + // Draw the line with Bresenham's algorithm. + for (size_t i = 0; i <= n_steps; ++i) { + FRAMEBUFFER[y][x] = clr; + *a += a_step; + diff += diff_inc_a; + if (diff > 0) { + *b += b_step; + diff -= diff_inc_b; + } + } +} + static inline void wait_vsync() { while(DISP_VCOUNT >= 160); @@ -105,11 +174,26 @@ wait_vsync() { int main(void) { set_display_mode(DISP_MODE_3 | DISP_BG2); + + put_text(0, 0, rgb15(18, 0, 0), "\n\n\n\n"); + + draw_line(0, 0, 3, 8,rgb15(0, 30, 0)); + draw_line(8, 0, 16, 8,rgb15(0, 0, 30)); + + draw_line(0, 0, 8, 3,rgb15(0, 0, 30)); + draw_line(8, 0, 16, 8,rgb15(0, 0, 30)); + + // Testing a "rectangle" + draw_line(0, 0, 0, 7,rgb15(0, 0, 30)); + draw_line(0, 0, 7, 0,rgb15(0, 30, 30)); + draw_line(0, 7, 7, 7,rgb15(30, 0, 0)); + draw_line(7, 0, 7, 7,rgb15(0, 30, 0)); + + draw_line(8, 7, 15, 0,rgb15(0, 0, 30)); + + char scanline_counter[16]; while(true) { wait_vsync(); - put_line(16, 20 + 16, rgb15(28, 0, 0), "Hello world from the GBA!"); - put_line(16, 20 + 32, rgb15(0, 28, 28), "Using my little 8x8 bd-font"); - put_line(16, 20 + 64, rgb15(16, 0, 28), "Isn't that neat? :D"); }; return 0; -- cgit v1.2.1