From 8feaf2dc269dd0cb81de87be90d2b2c7f28bcbea Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Fri, 4 Jun 2021 15:36:18 +0200 Subject: Add line drawing func for horz/vert lines --- src/main.c | 1 + src/renderer.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 178 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 8df466f..048824e 100644 --- a/src/main.c +++ b/src/main.c @@ -55,6 +55,7 @@ test_rects() { for (size_t i = 0; i < 100; i++) { draw_rect(30, 30, 45, 45, 1); draw_rect(35, 35, 60, 40, 2); + draw_rect(10, 10, 200, 130, 2); draw_rect(1, 1, 6, 6, 3); } } diff --git a/src/renderer.c b/src/renderer.c index c66b87b..d247d06 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -44,6 +44,145 @@ draw_pixel(size_t x, size_t y, u8 color) { dirty_tiles[tile_y] |= 1 << tile_x; } +IWRAM_CODE +void +draw_line(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { + // Pointer to the initial position of the screen buffer where we will start + // writing our data. + // vu16 *destination = (u16*)(SCREEN_BUFFER + y0 * SCREEN_WIDTH + x0); + +// // Adjust the step direction and calculate deltas. +// size_t x_step; +// size_t y_step; +// size_t dx; +// size_t dy; +// if (x0 > x1) { +// x_step = -1; +// dx = x0 - x1; +// } else { +// x_step = 1; +// dx = x1 - x0; +// } +// if (y0 > y1) { +// y_step = -SCREEN_WIDTH; +// dy = y0 - y1; +// } else { +// y_step = +SCREEN_WIDTH; +// dy = y1 - y0; +// } + +// if(dy == 0) { +// // Horizontal line. +// for(int i = 0; i <= dx; i++) { +// draw_pixel(x0 + i, y0, clr); +// } +// } else if(dx == 0) { +// // Vertical line. +// for(int i = 0; i <= dy; i++) { +// draw_pixel(x0, y0 + i, clr); +// } +// } else if (dx >= dy){ +// // Positive slope. +// int diff = 2 * dy - dx; +// for (int i = 0; i <= dx; ++i) { +// // *destination = clr; +// if (diff >= 0) { +// // destination += y_step; +// diff -= 2 * dx; +// } +// // destination += x_step; +// diff += 2 * dy; +// } +// } else { +// // Negative slope. +// int diff = 2 * dx - dy; +// for (int i = 0; i <= dy; ++i) { +// // *destination = clr; +// if (diff >= 0) { +// // destination += x_step; +// diff -= 2 * dy; +// } +// // destination += y_step; +// diff += 2 * dx; +// } +// } + BOUNDCHECK_SCREEN(x0, y0); + BOUNDCHECK_SCREEN(x1, y1); + + // Find row positions for the given x/y coordinates. + size_t tile_x0 = x0 / 8; + size_t tile_y0 = y0 / 8; + size_t tile_x1 = x1 / 8; + size_t tile_y1 = y1 / 8; + size_t start_col0 = x0 % 8; + size_t start_col1 = x1 % 8; + size_t start_row0 = y0 % 8; + size_t start_row1 = y1 % 8; + + // Get a pointer to the backbuffer and the tile row. + u32 *backbuffer = &BACKBUF[start_row0 + (tile_x0 + tile_y0 * 32) * 8]; + + size_t dx = tile_x1 - tile_x0; + size_t dy = tile_y1 - tile_y0; + + if (y0 == y1) { + // There are 3 cases: + // 1. Lines fit on a single tile. + // 2. Lines go through 2 tiles, both require partial row updates. + // 3. Lines go through 3 or more tiles, first and last tiles use + // partial row updates, rows in the middle can write the. + if (dx < 1) { + u32 row_mask = 0xFFFFFFFF; + row_mask >>= (7 - start_col1 - dx) * 4; + row_mask &= 0xFFFFFFFF << start_col0 * 4; + u32 row = (0x11111111 * clr) & row_mask; + backbuffer[0] = (backbuffer[0] & ~row_mask) | row; + dirty_tiles[tile_y0] |= 1 << tile_x0; + } else { + size_t shift_left = start_col0 * 4; + size_t shift_right = (7 - start_col1) * 4; + u32 row_mask = 0xFFFFFFFF; + u32 row = 0x11111111 * clr; + backbuffer[0] = backbuffer[0] & ~(row_mask << shift_left); + backbuffer[0] |= row << shift_left; + dirty_tiles[tile_y0] |= 1 << tile_x0; + for (size_t i = 1; i < dx; i++) { + backbuffer[i * 8] = row; + dirty_tiles[tile_y0] |= 1 << (tile_x0 + i); + } + backbuffer[dx * 8] = backbuffer[dx * 8] & ~(row_mask >> shift_right); + backbuffer[dx * 8] |= row >> shift_right; + dirty_tiles[tile_y0] |= 1 << (tile_x0 + dx); + } + } else if (x0 == x1) { + //The vertical line cases are analogous to the horizontal ones. + u32 row_mask = 0xF << start_col0 * 4; + u32 row_left = (0x11111111 * clr) & row_mask; + if (dy < 1) { + for (size_t i = 0; i <= y1 - y0; i++, backbuffer++) { + backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left; + } + } else { + for (size_t i = 0; i < (8 - start_row0); i++, backbuffer++) { + backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left; + } + backbuffer += 8 * 31; + for (size_t j = 1; j < dy; j++) { + for (size_t i = 0; i < 8; i++, backbuffer++) { + backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left; + } + backbuffer += 8 * 31; + dirty_tiles[tile_y0 + j] |= 1 << tile_x0; + } + for (size_t i = 0; i <= start_row1; i++, backbuffer++) { + backbuffer[0] = (backbuffer[0] & ~row_mask) | row_left; + } + } + } + + // TODO: Add slope line drawing. +} + IWRAM_CODE void draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { @@ -61,24 +200,21 @@ draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { size_t start_row1 = y1 % 8; // Get a pointer to the backbuffer and the tile row. - u32 *backbuffer0 = &BACKBUF[start_row0 + (tile_x0 + tile_y0 * 32) * 8]; - u32 *backbuffer1 = &BACKBUF[start_row1 + (tile_x0 + tile_y1 * 32) * 8]; + u32 *buf_top = &BACKBUF[start_row0 + (tile_x0 + tile_y0 * 32) * 8]; + u32 *buf_bot = &BACKBUF[start_row1 + (tile_x0 + tile_y1 * 32) * 8]; size_t dx = tile_x1 - tile_x0; size_t dy = tile_y1 - tile_y0; - // There are 3 cases: - // 1. Lines fit on a single tile. - // 2. Lines go through 2 tiles, both require partial row updates. - // 3. Lines go through 3 or more tiles, first and last tiles use partial - // row updates, rows in the middle can write the. + // We can update two lines at a time, which is faster than calling draw_line + // four times. if (dx < 1) { u32 row_mask = 0xFFFFFFFF; row_mask >>= (7 - start_col1 - dx) * 4; row_mask &= 0xFFFFFFFF << start_col0 * 4; u32 row = (0x11111111 * clr) & row_mask; - backbuffer0[0] = (backbuffer0[0] & ~row_mask) | row; - backbuffer1[0] = (backbuffer1[0] & ~row_mask) | row; + buf_top[0] = (buf_top[0] & ~row_mask) | row; + buf_bot[0] = (buf_bot[0] & ~row_mask) | row; dirty_tiles[tile_y0] |= 1 << tile_x0; dirty_tiles[tile_y1] |= 1 << tile_x0; } else { @@ -86,49 +222,60 @@ draw_rect(size_t x0, size_t y0, size_t x1, size_t y1, u8 clr) { size_t shift_right = (7 - start_col1) * 4; u32 row_mask = 0xFFFFFFFF; u32 row = 0x11111111 * clr; - backbuffer0[0] = (backbuffer0[0] & ~(row_mask << shift_left)) | (row << shift_left); - backbuffer1[0] = (backbuffer1[0] & ~(row_mask << shift_left)) | (row << shift_left); + buf_top[0] = buf_top[0] & ~(row_mask << shift_left); + buf_top[0] |= row << shift_left; + buf_bot[0] = buf_bot[0] & ~(row_mask << shift_left); + buf_bot[0] |= row << shift_left; dirty_tiles[tile_y0] |= 1 << tile_x0; dirty_tiles[tile_y1] |= 1 << tile_x0; for (size_t i = 1; i < dx; i++) { - backbuffer0[i * 8] = row; - backbuffer1[i * 8] = row; + buf_top[i * 8] = row; + buf_bot[i * 8] = row; dirty_tiles[tile_y0] |= 1 << (tile_x0 + i); dirty_tiles[tile_y1] |= 1 << (tile_x0 + i); } - backbuffer0[dx * 8] = (backbuffer0[dx * 8] & ~(row_mask >> shift_right)) | (row >> shift_right); - backbuffer1[dx * 8] = (backbuffer1[dx * 8] & ~(row_mask >> shift_right)) | (row >> shift_right); + buf_top[dx * 8] = buf_top[dx * 8] & ~(row_mask >> shift_right); + buf_top[dx * 8] |= row >> shift_right; + buf_bot[dx * 8] = buf_bot[dx * 8] & ~(row_mask >> shift_right); + buf_bot[dx * 8] |= row >> shift_right; dirty_tiles[tile_y0] |= 1 << (tile_x0 + dx); dirty_tiles[tile_y1] |= 1 << (tile_x0 + dx); } - // The vertical line cases are analogous to the horizontal ones. u32 row_mask_left = 0xF << start_col0 * 4; u32 row_mask_right = 0xF << start_col1 * 4; u32 row_left = (0x11111111 * clr) & row_mask_left; u32 row_right = (0x11111111 * clr) & row_mask_right; if (dy < 1) { - for (size_t i = 1; i < y1 - y0; i++, backbuffer0++) { - backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; - backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; + for (size_t i = 1; i < y1 - y0; i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; } } else { - for (size_t i = 1; i < (8 - start_row0); i++, backbuffer0++) { - backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; - backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; + for (size_t i = 1; i < (8 - start_row0); i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; } - backbuffer0 += 8 * 31; + buf_top += 8 * 31; for (size_t j = 1; j < dy; j++) { - for (size_t i = 0; i < 8; i++, backbuffer0++) { - backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; - backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; + for (size_t i = 0; i < 8; i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; } - backbuffer0 += 8 * 31; + buf_top += 8 * 31; dirty_tiles[tile_y0 + j] |= 1 << tile_x0; dirty_tiles[tile_y0 + j] |= 1 << (tile_x0 + dx); } - for (size_t i = 0; i < start_row1; i++, backbuffer0++) { - backbuffer0[1] = (backbuffer0[1] & ~row_mask_left) | row_left; - backbuffer0[1 + 8 * dx] = (backbuffer0[1 + 8 * dx] & ~row_mask_right) | row_right; + for (size_t i = 0; i < start_row1; i++, buf_top++) { + buf_top[1] = buf_top[1] & ~row_mask_left; + buf_top[1] |= row_left; + buf_top[1 + 8 * dx] = buf_top[1 + 8 * dx] & ~row_mask_right; + buf_top[1 + 8 * dx] |= row_right; } } } -- cgit v1.2.1