gfx.c 5.76 KB
Newer Older
1
2
#include "gfx.h"
#include "framebuffer.h"
3
#include <math.h>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stddef.h>
#include <stdlib.h>

const struct gfx_color_rgb gfx_colors_rgb[COLORS] = {
	{ 255, 255, 255 }, /* WHITE */
	{ 0, 0, 0 },       /* BLACK */
	{ 255, 0, 0 },     /* RED */
	{ 0, 255, 0 },     /* GREEN */
	{ 0, 0, 255 },     /* BLUE */
	{ 255, 255, 0 }    /* YELLOW */
};

void gfx_setpixel(struct gfx_region *r, int x, int y, Color c)
{
	if (x < 0 || y < 0)
		return;
	if (x >= r->width || y >= r->height)
		return;

	fb_setpixel(r->fb, r->x + x, r->y + y, c);
}

struct gfx_region gfx_screen(struct framebuffer *fb)
{
	struct gfx_region r = { .fb     = fb,
				.x      = 0,
				.y      = 0,
				.width  = fb->width,
				.height = fb->height };
	return r;
}

static inline int letter_bit(sFONT *font, char c, int x, int y)
{
	if (x < 0 || y < 0)
		return 0;
	if (x >= font->Width || y >= font->Height)
		return 0;
	if (c < ' ' || c > '~')
		return 0;

	size_t bytes_per_row      = font->Width / 8 + 1;
	size_t bytes_per_letter   = bytes_per_row * font->Height;
	int letter                = c - ' ';
	const uint8_t *letter_ptr = font->table + bytes_per_letter * letter;
	int horz_byte             = x / 8;
	int horz_bit              = 7 - x % 8;

	return (*(letter_ptr + y * bytes_per_row + horz_byte) >> horz_bit) & 1;
}

void gfx_putchar(
	sFONT *font,
	struct gfx_region *r,
	int x,
	int y,
	char ch,
	Color fg,
	Color bg
) {
	for (int yo = 0; yo < font->Height; yo++) {
		for (int xo = 0; xo < font->Width; xo++) {
			int lb = letter_bit(font, ch, xo, yo);

			if (fg != bg) {
				Color c = lb ? fg : bg;
				gfx_setpixel(r, x + xo, y + yo, c);
			} else {
				if (lb) {
					gfx_setpixel(r, x + xo, y + yo, fg);
				}
			}
		}
	}
}

void gfx_puts(
	sFONT *font,
	struct gfx_region *r,
	int x,
	int y,
	const char *str,
	Color fg,
	Color bg
) {
	while (*str) {
90
91
92
		gfx_putchar(font, r, x, y, *str, fg, bg);
		str++;

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
		x += font->Width;
		if (x >= r->width) {
			x = 0;
			y += font->Height;
		}
		if (y >= r->height)
			return;
	}
}

Color gfx_color_rgb_f(struct gfx_region *reg, float r, float g, float b)
{
	return fb_encode_color_rgb_f(reg->fb, r, g, b);
}

Color gfx_color_rgb(struct gfx_region *reg, uint8_t r, uint8_t g, uint8_t b)
{
	return fb_encode_color_rgb(reg->fb, r, g, b);
}

void gfx_update(struct gfx_region *reg)
{
	reg->fb->update(reg->fb);
}

void gfx_clear_to_color(struct gfx_region *reg, Color c)
{
	fb_clear_to_color(reg->fb, c);
}

void gfx_clear(struct gfx_region *reg)
{
	gfx_clear_to_color(reg, gfx_color(reg, BLACK));
}

void gfx_circle(struct gfx_region *reg, int x, int y, int r, int t, Color c)
{
	for (int y_ = y - r; y_ <= y + r; y_++) {
		for (int x_ = x - r; x_ <= x + r; x_++) {
			int dx    = (x_ - x) * (x_ - x);
			int dy    = (y_ - y) * (y_ - y);
			int outer = (r + t) * (r + t);
			int inner = r * r;
			int edge = ((dx + dy) >= inner) && ((dx + dy) <= outer);
			if (edge)
				gfx_setpixel(reg, x_, y_, c);
		}
	}
}

void gfx_circle_fill(struct gfx_region *reg, int x, int y, int r, Color c)
{
	for (int y_ = y - r; y_ <= y + r; y_++) {
		for (int x_ = x - r; x_ <= x + r; x_++) {
			int dx   = (x_ - x) * (x_ - x);
			int dy   = (y_ - y) * (y_ - y);
			int edge = r * r;
			int fill = (dx + dy) <= edge;
			if (fill)
				gfx_setpixel(reg, x_, y_, c);
		}
	}
}

void gfx_rectangle(
	struct gfx_region *reg, int x, int y, int w, int h, int t, Color c
) {
160
161
162
163
	gfx_line(reg, x, y, x + w, y, t, c);
	gfx_line(reg, x, y + h, x + w, y + h, t, c);
	gfx_line(reg, x, y, x, y + h, t, c);
	gfx_line(reg, x + w, y, x + w, y + h, t, c);
164
165
166
167
168
169
170
171
172
173
174
}

void gfx_rectangle_fill(
	struct gfx_region *reg, int x, int y, int w, int h, Color c
) {
	for (int y_ = y; y_ < y + h; y_++) {
		for (int x_ = x; x_ < x + w; x_++)
			gfx_setpixel(reg, x_, y_, c);
	}
}

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * For derivation of the algorithm, see:
 * https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
 */
static void plot_line_low(
	struct gfx_region *reg, int x0, int y0, int x1, int y1, int t, Color c
) {
	int dx = x1 - x0;
	int dy = y1 - y0;
	int yi = 1;

	if (dy < 0) {
		yi = -1;
		dy = -dy;
	}

	int d = 2 * dy - dx;
	int y = y0;
	for (int x = x0; x < x1; x++) {
		if (t > 1) {
			gfx_circle_fill(reg, x, y, t, c);
		} else {
			gfx_setpixel(reg, x, y, c);
198
		}
199
200
201
202
203
204

		if (d > 0) {
			y += yi;
			d -= 2 * dx;
		}
		d += 2 * dy;
205
206
207
	}
}

208
209
210
211
212
213
/*
 * For derivation of the algorithm, see:
 * https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
 */
static void plot_line_high(
	struct gfx_region *reg, int x0, int y0, int x1, int y1, int t, Color c
214
) {
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	int dx = x1 - x0;
	int dy = y1 - y0;
	int xi = 1;

	if (dx < 0) {
		xi = -1;
		dx = -dx;
	}

	int d = 2 * dx - dy;
	int x = x0;
	for (int y = y0; y < y1; y++) {
		if (t > 1) {
			gfx_circle_fill(reg, x, y, t, c);
		} else {
			gfx_setpixel(reg, x, y, c);
		}

		if (d > 0) {
			x += xi;
			d -= 2 * dy;
		}
		d += 2 * dx;
	}
}

void gfx_line(
	struct gfx_region *reg, int x0, int y0, int x1, int y1, int t, Color c
) {
	if (abs(y1 - y0) < abs(x1 - x0)) {
		if (x0 > x1) {
			plot_line_low(reg, x1, y1, x0, y0, t, c);
		} else {
			plot_line_low(reg, x0, y0, x1, y1, t, c);
		}
	} else {
		if (y0 > y1) {
			plot_line_high(reg, x1, y1, x0, y0, t, c);
		} else {
			plot_line_high(reg, x0, y0, x1, y1, t, c);
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
		}
	}
}

Color gfx_color(struct gfx_region *reg, enum gfx_color color)
{
	if ((int)(color) >= COLORS)
		return 0;

	const struct gfx_color_rgb *c = &gfx_colors_rgb[color];
	return gfx_color_rgb(reg, c->r, c->g, c->b);
}

void gfx_copy_region_raw(
	struct gfx_region *reg,
	int x,
	int y,
	int w,
	int h,
	size_t bpp,
	const void *p
) {
	for (int y_ = 0; y_ < h; y_++) {
		for (int x_ = 0; x_ < w; x_++) {
			Color c;

			switch (bpp) {
			default:
			case 2:
				c = *(const uint16_t *)(p);
				break;
			}

			gfx_setpixel(reg, x + x_, y + y_, c);
			p += bpp;
		}
	}
}

void gfx_copy_raw(struct gfx_region *reg, const void *p, size_t size)
{
	fb_copy_raw(reg->fb, p, size);
}