libdraw

Minimal window and drawing library
git clone http://git.omkov.net/libdraw
Log | Tree | Refs | Download

libdraw/src/draw.c (96 lines, 3.1 KiB) -rw-r--r-- blame download

01234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
// Copyright (C) 2024, Jakob Wakeling
// All rights reserved.

#include "draw.h"
#include "util/util.h"

#include <stdlib.h>

#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; }
	}
}