Ellipses!

This commit is contained in:
2024-02-25 22:10:21 -08:00
parent 30e4d544fd
commit be9c443c58
5 changed files with 155 additions and 17 deletions

View File

@ -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);
}
}

View File

@ -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.