#include #include "sys.h" #include "device/device.h" sys_i32 sys_cam_dx, sys_cam_dy; sys_i32 sys_clip_x0, sys_clip_y0, sys_clip_x1, sys_clip_y1; 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) { assert(sys_get_initialized()); sys_clip_set_ext(x0, y0, x1, y1, false); } void sys_clip_reset() { assert(sys_get_initialized()); sys_clip_set(0, 0, DEVICE_W, DEVICE_H); } void sys_clip_set_ext(sys_i32 x0, sys_i32 y0, sys_i32 x1, sys_i32 y1, bool clip_previous) { assert(sys_get_initialized()); sys_clip_x0 = sys_max_i32(x0, clip_previous ? sys_clip_x0 : 0); sys_clip_y0 = sys_max_i32(y0, clip_previous ? sys_clip_y0 : 0); sys_clip_x1 = sys_min_i32(x1, clip_previous ? sys_clip_x1 : DEVICE_W); sys_clip_y1 = sys_min_i32(y1, clip_previous ? sys_clip_y1 : DEVICE_H); } void sys_pixel_set(sys_i32 x, sys_i32 y, sys_color c) { assert(sys_get_initialized()); x += sys_cam_dx; y += sys_cam_dy; sys_pixel_internal_set(x, y, c); } sys_color sys_pixel_get(sys_i32 x, sys_i32 y) { assert(sys_get_initialized()); x += sys_cam_dx; y += sys_cam_dy; if (x < 0 || y < 0 || x >= DEVICE_W || y >= DEVICE_H) { return SYS_COLOR_TRANSPARENT; } return device_pixels[y][x]; } void sys_cls(sys_color c) { assert(sys_get_initialized()); for (int x = 0; x < DEVICE_W; x++) { for (int y = 0; y < DEVICE_W; y++) { sys_pixel_internal_set(x, y, c); } } } void sys_camera_set(sys_i32 x, sys_i32 y) { assert(sys_get_initialized()); sys_cam_dx = -x; sys_cam_dy = -y; } void sys_camera_reset() { assert(sys_get_initialized()); sys_camera_set(0, 0); } // 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()); device_palette[c0] = rc1; } void sys_spal_reset() { assert(sys_get_initialized()); for (int i = 0; i < SYS_COLOR_N; i++) { sys_spal_set(i, 0x000000ff); } } void sys_dpal_set(sys_color c0, sys_color c1) { assert(sys_get_initialized()); sys_dpal[c0] = c1; } void sys_dpal_reset() { assert(sys_get_initialized()); for (int i = 0; i < SYS_COLOR_N; i++) { sys_dpal_set(i, i); } } // == internal primitives == void sys_pixel_internal_set(sys_i32 x, sys_i32 y, sys_color c) { sys_color realc = sys_dpal[c]; if (realc == SYS_COLOR_TRANSPARENT) { return; } if ( x < sys_clip_x0 || y < sys_clip_y0 || x >= sys_clip_x1 || y >= sys_clip_y1 ) { return; } assert(x >= 0); assert(y >= 0); assert(x < DEVICE_W); 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); } }