// Copyright (C) 2024, Jakob Wakeling // All rights reserved. #include "draw.h" #include "util/util.h" #include #define PIXEL(B, X, Y) (B->buf[((Y) * B->bounds.w) + (X)]) #define SET(B, X, Y, C) (PIXEL(B, X, Y) = C) #define IS_BOUND(B, X, Y) ((X) >= (B)->bounds.x && (X) < (B)->bounds.w && (Y) >= (B)->bounds.y && (Y) < (B)->bounds.h) #define SET_BOUND(B, X, Y, C) (IS_BOUND(B, X, Y) ? SET(B, X, Y, C) : 0) bool draw_debug = false, draw_debug_verbose = false; draw_buffer *draw_buffer_init(int32_t w, int32_t h) { draw_buffer *buf = calloc(1, sizeof(draw_buffer)); if (buf == NULL) { return NULL; } *buf = (draw_buffer){ .bounds = {0, 0, w, h}, .buf = malloc((w * h) * sizeof(uint32_t)) }; if (buf->buf == NULL) { free(buf); return NULL; } return buf; } void draw_buffer_free(draw_buffer **buf) { free((*buf)->buf); free(*buf); *buf = NULL; } void draw_buffer_copy(draw_buffer *dst, draw_buffer *src, point dp, rect sr) { for (int32_t x = 0; x < dst->bounds.w && x < (src->bounds.w - src->bounds.x); x += 1) { for (int32_t y = 0; y < dst->bounds.h && y < (src->bounds.h - src->bounds.y); y += 1) { PIXEL(dst, x + dp.x, y + dp.y) = PIXEL(src, x + sr.x, y + sr.y); } } } void draw_buffer_clear(draw_buffer *buf, uint32_t colour) { for (int64_t i = 0; i < buf->bounds.w * buf->bounds.h; i += 1) { buf->buf[i] = colour; } } void draw_buffer_rect(draw_buffer *buf, point p, rect r, uint32_t colour) { int32_t x0 = CLAMP(p.x + r.x, buf->bounds.x, buf->bounds.w), y0 = CLAMP(p.y + r.y, buf->bounds.y, buf->bounds.h); int32_t x1 = CLAMP(p.x + r.w, buf->bounds.x, buf->bounds.w), y1 = CLAMP(p.y + r.h, buf->bounds.y, buf->bounds.h); for (int32_t x = x0; x < x1; x += 1) for (int32_t y = y0; y < y1; y += 1) { SET(buf, x, y, colour); } } void draw_buffer_line(draw_buffer *buf, point p0, point p1, uint32_t colour) { int32_t dx = abs(p1.x - p0.x); int32_t dy = abs(p1.y - p0.y); int32_t sx = p0.x < p1.x ? 1 : -1; int32_t sy = p0.y < p1.y ? 1 : -1; int32_t e = dx - dy; for (;;) { SET_BOUND(buf, p0.x, p0.y, colour); if (p0.x == p1.x && p0.y == p1.y) { break; } int32_t e2 = 2 * e; if (e2 > -dy) { e -= dy; p0.x += sx; } if (e2 < dx) { e += dx; p0.y += sy; } } SET_BOUND(buf, p0.x, p0.y, colour); } void draw_buffer_circle(draw_buffer *buf, point p, int32_t r, uint32_t colour, bool fill) { int32_t x = 0, y = r, d = 3 - (2 * r); while (x <= y) { if (fill) { for (int32_t i = -x; i <= x; i++) { SET_BOUND(buf, p.x + i, p.y + y, colour); SET_BOUND(buf, p.x + i, p.y - y, colour); } for (int32_t i = -y; i <= y; i++) { SET_BOUND(buf, p.x + i, p.y + x, colour); SET_BOUND(buf, p.x + i, p.y - x, colour); } } else { SET_BOUND(buf, p.x + x, p.y + y, colour); SET_BOUND(buf, p.x + x, p.y - y, colour); SET_BOUND(buf, p.x - x, p.y + y, colour); SET_BOUND(buf, p.x - x, p.y - y, colour); SET_BOUND(buf, p.x + y, p.y + x, colour); SET_BOUND(buf, p.x + y, p.y - x, colour); SET_BOUND(buf, p.x - y, p.y + x, colour); SET_BOUND(buf, p.x - y, p.y - x, colour); } x += 1; if (d < 0) { d += (4 * x) + 6; } else { d += (4 * (x - y)) + 10; y -= 1; } } }