gfx.c 6.13 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
#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
) {
89
	// iterate over the string
Jannis Rieger's avatar
Jannis Rieger committed
90
	while (*str) {
91
92
		// if the current position plus the width of the next character
		// would bring us outside of the display ...
Jannis Rieger's avatar
Jannis Rieger committed
93
		if ((x + font->Width) > r->width) {
94
			// ... we move down a line before printing the character
95
96
97
			x = 0;
			y += font->Height;
		}
98
		// if the line is outside the display we return
Jannis Rieger's avatar
Jannis Rieger committed
99
		if (y >= r->height)
100
			return;
101
102
103
104
105
106
107

		// now print the character
		gfx_putchar(font, r, x, y, *str, fg, bg);
		str++;

		// move along on the x axis to get the position of the next character
		x += font->Width;
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
	}
}

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)
{
138
139
	for (int y_ = y - r - t; y_ <= y + r + t; y_++) {
		for (int x_ = x - r - t; x_ <= x + r + t; x_++) {
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
			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
) {
168
169
170
171
	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);
172
173
174
175
176
177
178
179
180
181
182
}

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

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
 * 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);
206
		}
207
208
209
210
211
212

		if (d > 0) {
			y += yi;
			d -= 2 * dx;
		}
		d += 2 * dy;
213
214
215
	}
}

216
217
218
219
220
221
/*
 * 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
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
255
256
257
258
259
260
261
262
	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);
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
298
299
300
301
302
303
304
305
		}
	}
}

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