summaryrefslogtreecommitdiff
path: root/src/os/object/framebuffer.cc
blob: 1a22320acfa51b67cc5da611dfebb597d13f94ef (plain)
1
2
3
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
90
91
92
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
#include "object/framebuffer.h"

#ifdef MULTIPASS_ARCH_arduino_nano
#include <avr/pgmspace.h>
#endif

#ifdef CONFIG_framebuffer_in_text_segment
__attribute__ ((section(".text")))
#endif
static unsigned char framebuffer[(unsigned long int)CONFIG_framebuffer_width * (unsigned long int)CONFIG_framebuffer_height / 8];

void Framebuffer::clear()
{
	for (unsigned int i = 0; i < width * (height / 8); i++) {
		data[i] = 0;
	}
}

void Framebuffer::fillBox(unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
	if (w == 0 || h == 0) {
		return;
	}
	w -= 1;
	h -= 1;
	if ((x+w) >= width || (y+h) >= height) {
		return;
	}

	unsigned int x1 = (height/8)*x;
	unsigned int x2 = (height/8)*(x+w);
	unsigned int y2 = height-1-y;
	unsigned int y1 = y2-h;
	unsigned char y2_mask = 0xff << (8 - (y2 % 8)); // bits from 0 to y2%8 must be filled
	unsigned char y1_mask = 0xff >> (y1 % 8); // bits from y1%8 to 7 must be filled
	y1 = y1/8;
	y2 = y2/8;

	if (y1 == y2) {
		// y1_mask and y2_mask overlap
		for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) {
			data[pos_x + y1] |= y1_mask & y2_mask;
		}
	} else {
		if (y1_mask != 0xff) {
			for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) {
				data[pos_x + y1] |= y1_mask;
			}
			y1++;
		}
		for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) {
			for (unsigned int pos_y = y1; pos_y < y2; pos_y++) {
				data[pos_x + pos_y] = 0xff;
			}
		}
		if (y2_mask) {
			for (unsigned int pos_x = x1; pos_x < x2; pos_x += height/8) {
				data[pos_x + y2] |= y2_mask;
			}
		}
	}
}

void Framebuffer::drawAt(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned char *image)
{
	y /= 8;
	for (unsigned int pos_x = 0; pos_x < w; pos_x++) {
		for (unsigned int pos_y = 0; pos_y < h/8; pos_y++) {
			data[(x + pos_x) * (height/8) + y + pos_y] = image[pos_x * (h/8) + pos_y];
		}
	}
}

void Framebuffer::drawBattery(unsigned int x, unsigned int y, unsigned char percent, bool charging)
{
	for (unsigned char i = 0; i < 13; i++) {
		data[(x+i) * (height/8) + y] = 0x81 | (0xff * (percent*2 >= i*15));
	}
	data[(x+11) * (height/8) + y/8] |= 0xe7;
	data[(x+12) * (height/8) + y/8] &= ~0x81;
	data[(x+12) * (height/8) + y/8] |= 0x24;
	data[(x+13) * (height/8) + y/8] = 0x3c;

	if (charging) {
		data[(x+2) * (height/8) + y/8] ^= 0x7e;
		data[(x+3) * (height/8) + y/8] ^= 0x3c;
		data[(x+4) * (height/8) + y/8] ^= 0x18;
		data[(x+7) * (height/8) + y/8] ^= 0x7e;
		data[(x+8) * (height/8) + y/8] ^= 0x3c;
		data[(x+9) * (height/8) + y/8] ^= 0x18;
	}
}

void Framebuffer::scroll()
{
	for (unsigned int pos_x = 0; pos_x < width; pos_x++) {
		for (unsigned int pos_y = 1; pos_y < height/8; pos_y++) {
			data[pos_x * (height/8) + pos_y - 1] = data[pos_x * (height/8) + pos_y];
		}
		data[pos_x * (height/8) + height/8 - 1] = 0;
	}
	if (fontY >= 8) {
		fontY -= 8;
	}
}

void Framebuffer::put(char c)
{
	if (font == 0) {
		return;
	}
	if (c == '\n') {
		fontX = 0;
		fontY += 8;
		return;
	}
	if ((c < 32) || (c > 126)) {
		c = '?';
	}
#ifdef MULTIPASS_ARCH_arduino_nano
	uint8_t *glyph_addr = (uint8_t *)pgm_read_ptr(&font[c - 32]);
	const unsigned char glyph_w = pgm_read_byte(&glyph_addr[0]);
#else
	glyph_t glyph = font[c - 32];
	const unsigned char glyph_w = glyph[0];
#endif

	if (fontX + glyph_w + 1 >= width) {
		put('\n');
	}
	if (fontY >= height) {
		scroll();
	}
	for (unsigned char i = 0; i < glyph_w; i++) {
#ifdef MULTIPASS_ARCH_arduino_nano
		data[(height/8) * (fontX + i) + fontY/8] = pgm_read_byte(&glyph_addr[i+1]);
#else
		data[(height/8) * (fontX + i) + fontY/8] = glyph[i+1];
#endif
	}
	data[(height/8) * (fontX + glyph_w + 1) + fontY/8] = 0;
	fontX += glyph_w + 2;
}

Framebuffer fb(framebuffer);