From be9c443c58cbf32f0d83b6ba285ea81bec825300 Mon Sep 17 00:00:00 2001 From: Nyeogmi Date: Sun, 25 Feb 2024 22:10:21 -0800 Subject: [PATCH] Ellipses! --- .vscode/settings.json | 10 ++++- README.md | 16 ++++++- game/game.c | 23 ++++++++++ sys/sys_graphics.c | 100 +++++++++++++++++++++++++++++++++++++++++- sys/sys_graphics.h | 23 ++++------ 5 files changed, 155 insertions(+), 17 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 20d5904..050ef42 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,13 @@ { "files.associations": { - "stdbool.h": "c" + "*.h": "c", + "stdbool.h": "c", + "chrono": "c", + "cmath": "c", + "cstdlib": "c", + "format": "c", + "ratio": "c", + "xlocnum": "c", + "xutility": "c" } } \ No newline at end of file diff --git a/README.md b/README.md index 0da73f2..d3e8d98 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ # Croc Party! -A tiny platform game in C/SDL. \ No newline at end of file +A tiny platform game in C/SDL. + +# Commands + +## Run (release) + +``` +$ bazel run -c opt sdl_host.exe +``` + +## Run + +``` +$ bazel run sdl_host.exe +``` \ No newline at end of file diff --git a/game/game.c b/game/game.c index cc31113..7ad9fab 100644 --- a/game/game.c +++ b/game/game.c @@ -4,6 +4,16 @@ uint32_t game_frame; +int32_t ellipse_x0 = 32; +int32_t ellipse_y0 = 32; +int32_t ellipse_dx0 = 1; +int32_t ellipse_dy0 = 2; +int32_t ellipse_x1 = 96; +int32_t ellipse_y1 = 96; +int32_t ellipse_dx1 = 3; +int32_t ellipse_dy1 = 4; + + const char* game_title() { return "Croc Party!"; } @@ -35,6 +45,16 @@ void game_destroy() { void game_update() { game_frame += 4; + + ellipse_x0 += ellipse_dx0; + if (ellipse_x0 < 0 || ellipse_x0 > DEVICE_W) { ellipse_dx0 *= -1; } + ellipse_y0 += ellipse_dy0; + if (ellipse_y0 < 0 || ellipse_y0 > DEVICE_W) { ellipse_dy0 *= -1; } + + ellipse_x1 += ellipse_dx1; + if (ellipse_x1 < 0 || ellipse_x1 > DEVICE_H) { ellipse_dx1 *= -1; } + ellipse_y1 += ellipse_dy1; + if (ellipse_y1 < 0 || ellipse_y1 > DEVICE_H) { ellipse_dy1 *= -1; } } void game_draw() { @@ -58,4 +78,7 @@ void game_draw() { for (int i = 0; i < DEVICE_BUTTON_N; i++) { sys_pixel_set(i, 0, device_buttons[i] ? 0x00 : 0xff); } + + sys_oval_draw_ext(ellipse_x0, ellipse_y0, ellipse_x1, ellipse_y1, 10, true); + sys_oval_draw_ext(ellipse_x0, ellipse_y0, ellipse_x1, ellipse_y1, 245, false); } diff --git a/sys/sys_graphics.c b/sys/sys_graphics.c index 8d3239f..1a07501 100644 --- a/sys/sys_graphics.c +++ b/sys/sys_graphics.c @@ -8,6 +8,9 @@ sys_color sys_dpal[256]; // primitives (forward declare) void sys_pixel_internal_set(sys_i32 x, sys_i32 y, sys_color c); +void sys_scanline_internal_set( + sys_i32 x0, sys_i32 x1, sys_i32 y, sys_color c, bool fill +); // == public == void sys_clip_set(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1) { @@ -75,7 +78,89 @@ void sys_camera_reset() { sys_camera_set(0, 0); } -// TODO: Continue from sys_circ_draw_ext +// Based on bresenham implementations by alois zingl +// https://zingl.github.io/bresenham.html +void sys_circ_draw(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c) { + assert(sys_get_initialized()); + + sys_circ_draw_ext(x, y, r, c, false); +} + +void sys_circ_fill(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c) { + assert(sys_get_initialized()); + + sys_circ_draw_ext(x, y, r, c, true); +} + +void sys_circ_draw_ext( + sys_i32 x, sys_i32 y, sys_i32 r, sys_color c, bool fill +) { + assert(sys_get_initialized()); + + if (r < 0) { return; } + + sys_oval_draw_ext(x - r, y - r, x + r + 1, y + r + 1, c, fill); +} + +void sys_oval_draw( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c +) { + assert(sys_get_initialized()); + + sys_oval_draw_ext(x0, y0, x1, y1, c, false); +} + +void sys_oval_fill( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c +) { + assert(sys_get_initialized()); + + sys_oval_draw_ext(x0, y0, x1, y1, c, true); +} + +void sys_oval_draw_ext( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c, bool fill +) { + if (x0 == x1 || y0 == y1) { return; } + if (x0 > x1) { sys_i32 tmp = x0; x0 = x1; x1 = tmp; } + if (y0 > y1) { sys_i32 tmp = y0; y0 = y1; y1 = tmp; } + // alois' algorithm for this implies the bounds are inclusive + x1 -= 1; y1 -= 1; + + int64_t a = x1 - x0; + int64_t b = y1 - y0; + int64_t b1 = b & 1; + + int64_t dx = 4 * (1 - a) * b * b; + int64_t dy = 4 * (b1 + 1) * a * a; + int64_t err = dx + dy + b1 * a * a; + + y0 += (b + 1) / 2; + y1 = y0 - b1; + a *= 8 * a; + b1 = 8 * b * b; + + do { + // draw the points at the edge of the line + sys_scanline_internal_set(x0, x1, y0, c, false); + sys_scanline_internal_set(x0, x1, y1, c, false); + int64_t e2 = 2 * err; + if (e2 <= dy) { + if (fill) { + // draw the whole line + sys_scanline_internal_set(x0, x1, y0, c, true); + sys_scanline_internal_set(x0, x1, y1, c, true); + } + y0++; y1--; dy += a; err += dy; + } + if (e2 >= dx || 2 * err > dy) { x0++; x1--; dx += b1; err += dx; } + } while (x0 <= x1); + + while (y0 - y1 < b) { + sys_scanline_internal_set(x0 - 1, x1 + 1, y0, c, fill); y0++; + sys_scanline_internal_set(x0 - 1, x1 + 1, y1, c, fill); y1--; + } +} void sys_spal_set(sys_color c0, sys_screen_color rc1) { assert(sys_get_initialized()); @@ -123,4 +208,17 @@ void sys_pixel_internal_set(sys_i32 x, sys_i32 y, sys_color c) { assert(y < DEVICE_H); device_pixels[y][x] = realc; +} +void sys_scanline_internal_set( + sys_i32 x0, sys_i32 x1, sys_i32 y, sys_color c, + bool fill +) { + if (fill) { + for (sys_i32 x = x0; x <= x1; x++) { + sys_pixel_internal_set(x, y, c); + } + } else { + sys_pixel_internal_set(x0, y, c); + sys_pixel_internal_set(x1, y, c); + } } \ No newline at end of file diff --git a/sys/sys_graphics.h b/sys/sys_graphics.h index ccc0526..709f4e5 100644 --- a/sys/sys_graphics.h +++ b/sys/sys_graphics.h @@ -75,29 +75,25 @@ void sys_camera_reset(); /** * Draw or fill a circle at `(x, y)` with radius `r`. * - * The circle consists of a "stroke" region and a "fill" region which the user - * can decide individually on whether or not to fill. + * The circle is centered at the center of the pixel, not at the junction + * between pixels. * * If r is negative, the circle is not drawn. * * This is a special case of sys_circ_oval_draw_ext. */ -void sys_circ_draw_ext(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c, bool stroke, bool fill); void sys_circ_draw(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c); void sys_circ_fill(sys_i32 x, sys_i32 y, sys_i32 r); +void sys_circ_draw_ext(sys_i32 x, sys_i32 y, sys_i32 r, sys_color c, bool fill); /** * Draw or fill an oval in the rectangle from `(x0, y0)` to `(x1, y1)` - * - * The oval consists of a "stroke" region and a "fill" region which the user - * can decide individually on whether or not to fill. */ -void sys_oval_draw_ext( - sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c, - bool stroke, bool fill -); void sys_oval_draw(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); void sys_oval_fill(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); +void sys_oval_draw_ext( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c, bool fill +); /** * Draw a line from x0 to y0. @@ -107,12 +103,11 @@ void sys_line_draw(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); /** * Draw or fill a rectangle `(x, y, w, h)` */ -void sys_rect_draw_ext( - sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c, - bool stroke, bool fill -); void sys_rect_draw(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); void sys_rect_fill(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c); +void sys_rect_draw_ext( + sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, sys_color c, bool fill +); /** * Set screen palette.