-
Notifications
You must be signed in to change notification settings - Fork 12
/
draw.h
106 lines (87 loc) · 3.37 KB
/
draw.h
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
/* See LICENSE for licence details. */
static inline void draw_sixel(struct framebuffer *fb, int line, int col, uint8_t *bitmap)
{
int h, w, src_offset, dst_offset;
uint32_t pixel, color = 0;
for (h = 0; h < CELL_HEIGHT; h++) {
for (w = 0; w < CELL_WIDTH; w++) {
src_offset = BYTES_PER_PIXEL * (h * CELL_WIDTH + w);
memcpy(&color, bitmap + src_offset, BYTES_PER_PIXEL);
dst_offset = (line * CELL_HEIGHT + h) * fb->line_length + (col * CELL_WIDTH + w) * fb->bytes_per_pixel;
pixel = color2pixel(&fb->vinfo, color);
memcpy(fb->buf + dst_offset, &pixel, fb->bytes_per_pixel);
}
}
}
static inline void draw_line(struct framebuffer *fb, struct terminal *term, int line)
{
int pos, size, bdf_padding, glyph_width, margin_right;
int col, w, h;
uint32_t pixel;
struct color_pair_t color_pair;
struct cell_t *cellp;
for (col = term->cols - 1; col >= 0; col--) {
margin_right = (term->cols - 1 - col) * CELL_WIDTH;
/* target cell */
cellp = &term->cells[col + line * term->cols];
/* draw sixel bitmap */
if (cellp->has_bitmap) {
draw_sixel(fb, line, col, cellp->bitmap);
continue;
}
/* copy current color_pair (maybe changed) */
color_pair = cellp->color_pair;
/* check wide character or not */
glyph_width = (cellp->width == HALF) ? CELL_WIDTH: CELL_WIDTH * 2;
bdf_padding = my_ceil(glyph_width, BITS_PER_BYTE) * BITS_PER_BYTE - glyph_width;
if (cellp->width == WIDE)
bdf_padding += CELL_WIDTH;
/* check cursor positon */
if ((term->mode & MODE_CURSOR && line == term->cursor.y)
&& (col == term->cursor.x
|| (cellp->width == WIDE && (col + 1) == term->cursor.x)
|| (cellp->width == NEXT_TO_WIDE && (col - 1) == term->cursor.x))) {
color_pair.fg = DEFAULT_BG;
color_pair.bg = (!tty.visible && BACKGROUND_DRAW) ? PASSIVE_CURSOR_COLOR: ACTIVE_CURSOR_COLOR;
}
for (h = 0; h < CELL_HEIGHT; h++) {
/* if UNDERLINE attribute on, swap bg/fg */
if ((h == (CELL_HEIGHT - 1)) && (cellp->attribute & attr_mask[ATTR_UNDERLINE]))
color_pair.bg = color_pair.fg;
for (w = 0; w < CELL_WIDTH; w++) {
pos = (term->width - 1 - margin_right - w) * fb->bytes_per_pixel
+ (line * CELL_HEIGHT + h) * fb->line_length;
/* set color palette */
if (cellp->glyphp->bitmap[h] & (0x01 << (bdf_padding + w)))
pixel = term->color_palette[color_pair.fg];
else if (fb->wall && color_pair.bg == DEFAULT_BG) /* wallpaper */
memcpy(&pixel, fb->wall + pos, fb->bytes_per_pixel);
else
pixel = term->color_palette[color_pair.bg];
/* update copy buffer only */
memcpy(fb->buf + pos, &pixel, fb->bytes_per_pixel);
}
}
}
/* actual display update (bit blit) */
pos = (line * CELL_HEIGHT) * fb->line_length;
size = CELL_HEIGHT * fb->line_length;
memcpy(fb->fp + pos, fb->buf + pos, size);
/* TODO: page flip
if fb_fix_screeninfo.ypanstep > 0, we can use hardware panning.
set fb_fix_screeninfo.{yres_virtual,yoffset} and call ioctl(FBIOPAN_DISPLAY)
but drivers of recent hardware (inteldrmfb, nouveaufb, radeonfb) don't support...
(we can use this by using libdrm)
*/
term->line_dirty[line] = ((term->mode & MODE_CURSOR) && term->cursor.y == line) ? true: false;
}
void refresh(struct framebuffer *fb, struct terminal *term)
{
int line;
if (term->mode & MODE_CURSOR)
term->line_dirty[term->cursor.y] = true;
for (line = 0; line < term->lines; line++) {
if (term->line_dirty[line])
draw_line(fb, term, line);
}
}