Fast and reasonably complete (framebuffer) terminal emulator (Zig fork)
1/* Copyright (C) 2022-2024 mintsuki and contributors.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain the above copyright notice,
7 * this list of conditions and the following disclaimer.
8 *
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23 * POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <stdint.h>
27#include <stddef.h>
28
29#include "../flanterm.h"
30#include "fb.h"
31
32void *memset(void *, int, size_t);
33void *memcpy(void *, const void *, size_t);
34
35#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
36
37#ifndef FLANTERM_FB_BUMP_ALLOC_POOL_SIZE
38#define FLANTERM_FB_BUMP_ALLOC_POOL_SIZE 873000
39
40#define FLANTERM_FB_WIDTH_LIMIT 1920
41#define FLANTERM_FB_HEIGHT_LIMIT 1200
42#endif
43
44static uint8_t bump_alloc_pool[FLANTERM_FB_BUMP_ALLOC_POOL_SIZE];
45static size_t bump_alloc_ptr = 0;
46
47static void *bump_alloc(size_t s) {
48 size_t next_ptr = bump_alloc_ptr + s;
49 if (next_ptr > FLANTERM_FB_BUMP_ALLOC_POOL_SIZE) {
50 return NULL;
51 }
52 void *ret = &bump_alloc_pool[bump_alloc_ptr];
53 bump_alloc_ptr = next_ptr;
54 return ret;
55}
56
57#endif
58
59// Builtin font originally taken from:
60// https://github.com/viler-int10h/vga-text-mode-fonts/raw/master/FONTS/PC-OTHER/TOSH-SAT.F16
61static const uint8_t builtin_font[] = {
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x81, 0x81, 0xa5, 0xa5, 0x81,
64 0x81, 0xa5, 0x99, 0x81, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff,
65 0xff, 0xdb, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0x7e, 0x3c, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10,
67 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe,
68 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
69 0x3c, 0x3c, 0xdb, 0xff, 0xff, 0xdb, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0x66, 0x18, 0x18,
71 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
72 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
73 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x84, 0x84, 0xcc, 0x78, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
76 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1e,
77 0x0e, 0x1e, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x30, 0x30,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x1c, 0x1e, 0x16, 0x12,
80 0x10, 0x10, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, 0x2c,
81 0x26, 0x32, 0x3a, 0x2e, 0x26, 0x22, 0x62, 0xe2, 0xc6, 0x0e, 0x0c, 0x00,
82 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe,
84 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
85 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78,
87 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
88 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
89 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c,
91 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
93 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78, 0x30, 0xfc, 0x00, 0x00,
94 0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
95 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
96 0x30, 0x30, 0xfc, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x18, 0x0c, 0xfe, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0xfe, 0x60, 0x30, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
100 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
104 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x30, 0x30, 0x00, 0x30,
107 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
109 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
110 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc0, 0xc0, 0x7c, 0x06, 0x06, 0xc6, 0x7c,
111 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x0c, 0x0c, 0x18, 0x38,
112 0x30, 0x60, 0x60, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
113 0x6c, 0x38, 0x30, 0x76, 0xde, 0xcc, 0xcc, 0xde, 0x76, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, 0x60, 0x60,
116 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
117 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x38, 0xfe, 0x38, 0x6c, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
120 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
125 0x0c, 0x0c, 0x18, 0x38, 0x30, 0x60, 0x60, 0xc0, 0xc0, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6,
127 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
128 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
129 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0x06, 0xc6,
131 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc,
132 0xfe, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
133 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x3c, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
135 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
136 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
137 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c,
139 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
140 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
142 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c,
143 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00,
144 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60,
145 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x00, 0x30,
147 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
148 0xde, 0xde, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
149 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
151 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0,
152 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
153 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
155 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0,
156 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
157 0xc0, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6,
159 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
160 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
161 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0xc6, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6,
163 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
164 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
165 0xee, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
166 0x00, 0x00, 0xc6, 0xc6, 0xe6, 0xe6, 0xf6, 0xde, 0xce, 0xce, 0xc6, 0xc6,
167 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
168 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6,
169 0xc6, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xf6, 0xda,
171 0x6c, 0x06, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc,
172 0xd8, 0xcc, 0xcc, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
173 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
175 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
176 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
177 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c,
179 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x38,
180 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc,
181 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0xfe, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xc0,
183 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60,
184 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
185 0x60, 0x60, 0x30, 0x38, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00,
186 0x00, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
187 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
190 0x00, 0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x06, 0x06,
192 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
193 0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xdc, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
195 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x76, 0xce, 0xc6,
196 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
199 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xce, 0xc6,
200 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
201 0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
202 0x00, 0x00, 0x18, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
203 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1e, 0x06, 0x06,
204 0x06, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
205 0xc0, 0xc6, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc6, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
207 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6,
208 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
211 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc6,
212 0xc6, 0xc6, 0xe6, 0xdc, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
213 0x00, 0x76, 0xce, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x06, 0x06, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
215 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0,
216 0x70, 0x1c, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
217 0x30, 0xfe, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
219 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
220 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6,
223 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
224 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00, 0x00, 0x00,
226 0x00, 0x00, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x30, 0x30,
227 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00,
228 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x30,
229 0x30, 0x30, 0x30, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x6c,
232 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
233 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x18, 0xcc, 0x78, 0x00,
234 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
235 0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6,
236 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
237 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6,
239 0x7e, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x06, 0x06,
240 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
241 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
243 0x7c, 0x18, 0x0c, 0x38, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
244 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
245 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
246 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0,
247 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18,
248 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
249 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
250 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
251 0x3c, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6,
252 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
253 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
254 0x18, 0x30, 0x60, 0x00, 0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0,
255 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x36, 0x36,
256 0x76, 0xde, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3c,
257 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
258 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
259 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
260 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
261 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
262 0x00, 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
263 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xc6, 0xc6, 0xc6,
264 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
265 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00,
266 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
267 0x7c, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
268 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
269 0x30, 0x78, 0xcc, 0xc0, 0xc0, 0xcc, 0x78, 0x30, 0x30, 0x00, 0x00, 0x00,
270 0x00, 0x00, 0x38, 0x6c, 0x60, 0x60, 0x60, 0xf8, 0x60, 0x60, 0x60, 0xe6,
271 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
272 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
273 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
274 0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18,
275 0x18, 0xd8, 0x70, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x06, 0x06,
276 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
277 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
278 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
279 0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6,
280 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
281 0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
282 0x76, 0xdc, 0x00, 0xc6, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6,
283 0xc6, 0x00, 0x00, 0x00, 0x00, 0x78, 0xd8, 0xd8, 0x6c, 0x00, 0xfc, 0x00,
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
285 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xc6,
287 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c,
291 0x18, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30,
292 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
293 0x00, 0x30, 0x30, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
296 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x88, 0x22, 0x88,
297 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
298 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
299 0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
300 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
301 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
302 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
303 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
304 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
305 0x36, 0x36, 0x36, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x36, 0x36, 0x36,
307 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18,
308 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
309 0x36, 0xf6, 0xf6, 0x06, 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36,
310 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
311 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x06,
312 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
313 0x36, 0xf6, 0xf6, 0x06, 0x06, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0xfe, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
316 0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
318 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
320 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
322 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
323 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
324 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
325 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
326 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
327 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
328 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
329 0x36, 0x37, 0x37, 0x30, 0x30, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x37, 0x37, 0x36,
331 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0xf7, 0x00,
332 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 0x00, 0xff, 0xff, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
334 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x30, 0x30, 0x37, 0x37, 0x36,
335 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
336 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
337 0x36, 0xf7, 0xf7, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
338 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
340 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x36, 0x36, 0x36,
343 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
344 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
345 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
347 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
348 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
349 0x36, 0x36, 0x36, 0xff, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
350 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0xff, 0xff, 0x18,
351 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
352 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
354 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
355 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
357 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
358 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
359 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
360 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x76, 0xd6, 0xdc, 0xc8, 0xc8, 0xdc, 0xd6, 0x76, 0x00, 0x00, 0x00,
362 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
363 0xd8, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
364 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x7e, 0xfe, 0x24, 0x24, 0x24, 0x24, 0x66, 0xc6, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0xfe, 0xfe, 0xc2, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc2, 0xfe,
367 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc8, 0xcc,
368 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x6c, 0x60, 0xc0, 0x00,
370 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xfc, 0x98, 0x18, 0x18, 0x18, 0x18,
371 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x78, 0xcc, 0xcc,
372 0xcc, 0x78, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
373 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
374 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c,
375 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x60, 0x30, 0x78, 0xcc,
376 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 0x00, 0x76, 0xbb, 0x99, 0x99, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
378 0x00, 0x00, 0x02, 0x06, 0x3c, 0x6c, 0xce, 0xd6, 0xd6, 0xe6, 0x6c, 0x78,
379 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x60, 0xc0, 0xc0, 0xfe,
380 0xc0, 0xc0, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
381 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
382 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc,
384 0x30, 0x30, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
387 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x36, 0x30, 0x30, 0x30,
388 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18,
389 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
390 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
392 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc,
393 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
397 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c, 0x00, 0x00,
398 0x00, 0xd8, 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x0c, 0x18, 0x30, 0x60, 0x7c,
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
402 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 0x00, 0x00, 0x00, 0x00
404};
405
406#ifdef FLANTERM_FB_SUPPORT_BPP
407static inline __attribute__((always_inline)) uint32_t convert_colour(struct flanterm_context *_ctx, uint32_t colour) {
408 struct flanterm_fb_context *ctx = (void *)_ctx;
409 uint32_t r = (colour >> 16) & 0xff;
410 uint32_t g = (colour >> 8) & 0xff;
411 uint32_t b = colour & 0xff;
412 return (r << ctx->red_mask_shift) | (g << ctx->green_mask_shift) | (b << ctx->blue_mask_shift);
413}
414#else
415#define convert_colour(CTX, COLOUR) (COLOUR)
416#endif
417
418static void flanterm_fb_save_state(struct flanterm_context *_ctx) {
419 struct flanterm_fb_context *ctx = (void *)_ctx;
420 ctx->saved_state_text_fg = ctx->text_fg;
421 ctx->saved_state_text_bg = ctx->text_bg;
422 ctx->saved_state_cursor_x = ctx->cursor_x;
423 ctx->saved_state_cursor_y = ctx->cursor_y;
424}
425
426static void flanterm_fb_restore_state(struct flanterm_context *_ctx) {
427 struct flanterm_fb_context *ctx = (void *)_ctx;
428 ctx->text_fg = ctx->saved_state_text_fg;
429 ctx->text_bg = ctx->saved_state_text_bg;
430 ctx->cursor_x = ctx->saved_state_cursor_x;
431 ctx->cursor_y = ctx->saved_state_cursor_y;
432}
433
434static void flanterm_fb_swap_palette(struct flanterm_context *_ctx) {
435 struct flanterm_fb_context *ctx = (void *)_ctx;
436 uint32_t tmp = ctx->text_bg;
437 ctx->text_bg = ctx->text_fg;
438 ctx->text_fg = tmp;
439}
440
441static void plot_char(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
442 struct flanterm_fb_context *ctx = (void *)_ctx;
443
444 if (x >= _ctx->cols || y >= _ctx->rows) {
445 return;
446 }
447
448#ifdef FLANTERM_FB_DISABLE_CANVAS
449 uint32_t default_bg = ctx->default_bg;
450#endif
451
452 x = ctx->offset_x + x * ctx->glyph_width;
453 y = ctx->offset_y + y * ctx->glyph_height;
454
455 bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
456 // naming: fx,fy for font coordinates, gx,gy for glyph coordinates
457 for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
458 uint8_t fy = gy / ctx->font_scale_y;
459 volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
460
461#ifndef FLANTERM_FB_DISABLE_CANVAS
462 uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
463#endif
464
465 for (size_t fx = 0; fx < ctx->font_width; fx++) {
466 bool draw = glyph[fy * ctx->font_width + fx];
467 for (size_t i = 0; i < ctx->font_scale_x; i++) {
468 size_t gx = ctx->font_scale_x * fx + i;
469#ifndef FLANTERM_FB_DISABLE_CANVAS
470 uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
471 uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
472#else
473 uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
474 uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
475#endif
476 fb_line[gx] = draw ? fg : bg;
477 }
478 }
479 }
480}
481
482#ifdef FLANTERM_FB_ENABLE_MASKING
483static void plot_char_masked(struct flanterm_context *_ctx, struct flanterm_fb_char *old, struct flanterm_fb_char *c, size_t x, size_t y) {
484 struct flanterm_fb_context *ctx = (void *)_ctx;
485
486 if (x >= _ctx->cols || y >= _ctx->rows) {
487 return;
488 }
489
490 x = ctx->offset_x + x * ctx->glyph_width;
491 y = ctx->offset_y + y * ctx->glyph_height;
492
493#ifdef FLANTERM_FB_DISABLE_CANVAS
494 uint32_t default_bg = ctx->default_bg;
495#endif
496
497 bool *new_glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
498 bool *old_glyph = &ctx->font_bool[old->c * ctx->font_height * ctx->font_width];
499 for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
500 uint8_t fy = gy / ctx->font_scale_y;
501 volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
502#ifndef FLANTERM_FB_DISABLE_CANVAS
503 uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
504#endif
505 for (size_t fx = 0; fx < ctx->font_width; fx++) {
506 bool old_draw = old_glyph[fy * ctx->font_width + fx];
507 bool new_draw = new_glyph[fy * ctx->font_width + fx];
508 if (old_draw == new_draw)
509 continue;
510 for (size_t i = 0; i < ctx->font_scale_x; i++) {
511 size_t gx = ctx->font_scale_x * fx + i;
512#ifndef FLANTERM_FB_DISABLE_CANVAS
513 uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
514 uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
515#else
516 uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
517 uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
518#endif
519 fb_line[gx] = new_draw ? fg : bg;
520 }
521 }
522 }
523}
524#endif
525
526static inline bool compare_char(struct flanterm_fb_char *a, struct flanterm_fb_char *b) {
527 return !(a->c != b->c || a->bg != b->bg || a->fg != b->fg);
528}
529
530static void push_to_queue(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
531 struct flanterm_fb_context *ctx = (void *)_ctx;
532
533 if (x >= _ctx->cols || y >= _ctx->rows) {
534 return;
535 }
536
537 size_t i = y * _ctx->cols + x;
538
539 struct flanterm_fb_queue_item *q = ctx->map[i];
540
541 if (q == NULL) {
542 if (compare_char(&ctx->grid[i], c)) {
543 return;
544 }
545 q = &ctx->queue[ctx->queue_i++];
546 q->x = x;
547 q->y = y;
548 ctx->map[i] = q;
549 }
550
551 q->c = *c;
552}
553
554static void flanterm_fb_revscroll(struct flanterm_context *_ctx) {
555 struct flanterm_fb_context *ctx = (void *)_ctx;
556
557 for (size_t i = (_ctx->scroll_bottom_margin - 1) * _ctx->cols - 1;
558 i >= _ctx->scroll_top_margin * _ctx->cols; i--) {
559 if (i == (size_t)-1) {
560 break;
561 }
562 struct flanterm_fb_char *c;
563 struct flanterm_fb_queue_item *q = ctx->map[i];
564 if (q != NULL) {
565 c = &q->c;
566 } else {
567 c = &ctx->grid[i];
568 }
569 push_to_queue(_ctx, c, (i + _ctx->cols) % _ctx->cols, (i + _ctx->cols) / _ctx->cols);
570 }
571
572 // Clear the first line of the screen.
573 struct flanterm_fb_char empty;
574 empty.c = ' ';
575 empty.fg = ctx->text_fg;
576 empty.bg = ctx->text_bg;
577 for (size_t i = 0; i < _ctx->cols; i++) {
578 push_to_queue(_ctx, &empty, i, _ctx->scroll_top_margin);
579 }
580}
581
582static void flanterm_fb_scroll(struct flanterm_context *_ctx) {
583 struct flanterm_fb_context *ctx = (void *)_ctx;
584
585 for (size_t i = (_ctx->scroll_top_margin + 1) * _ctx->cols;
586 i < _ctx->scroll_bottom_margin * _ctx->cols; i++) {
587 struct flanterm_fb_char *c;
588 struct flanterm_fb_queue_item *q = ctx->map[i];
589 if (q != NULL) {
590 c = &q->c;
591 } else {
592 c = &ctx->grid[i];
593 }
594 push_to_queue(_ctx, c, (i - _ctx->cols) % _ctx->cols, (i - _ctx->cols) / _ctx->cols);
595 }
596
597 // Clear the last line of the screen.
598 struct flanterm_fb_char empty;
599 empty.c = ' ';
600 empty.fg = ctx->text_fg;
601 empty.bg = ctx->text_bg;
602 for (size_t i = 0; i < _ctx->cols; i++) {
603 push_to_queue(_ctx, &empty, i, _ctx->scroll_bottom_margin - 1);
604 }
605}
606
607static void flanterm_fb_clear(struct flanterm_context *_ctx, bool move) {
608 struct flanterm_fb_context *ctx = (void *)_ctx;
609
610 struct flanterm_fb_char empty;
611 empty.c = ' ';
612 empty.fg = ctx->text_fg;
613 empty.bg = ctx->text_bg;
614 for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
615 push_to_queue(_ctx, &empty, i % _ctx->cols, i / _ctx->cols);
616 }
617
618 if (move) {
619 ctx->cursor_x = 0;
620 ctx->cursor_y = 0;
621 }
622}
623
624static void flanterm_fb_set_cursor_pos(struct flanterm_context *_ctx, size_t x, size_t y) {
625 struct flanterm_fb_context *ctx = (void *)_ctx;
626
627 if (x >= _ctx->cols) {
628 if ((int)x < 0) {
629 x = 0;
630 } else {
631 x = _ctx->cols - 1;
632 }
633 }
634 if (y >= _ctx->rows) {
635 if ((int)y < 0) {
636 y = 0;
637 } else {
638 y = _ctx->rows - 1;
639 }
640 }
641 ctx->cursor_x = x;
642 ctx->cursor_y = y;
643}
644
645static void flanterm_fb_get_cursor_pos(struct flanterm_context *_ctx, size_t *x, size_t *y) {
646 struct flanterm_fb_context *ctx = (void *)_ctx;
647
648 *x = ctx->cursor_x >= _ctx->cols ? _ctx->cols - 1 : ctx->cursor_x;
649 *y = ctx->cursor_y >= _ctx->rows ? _ctx->rows - 1 : ctx->cursor_y;
650}
651
652static void flanterm_fb_move_character(struct flanterm_context *_ctx, size_t new_x, size_t new_y, size_t old_x, size_t old_y) {
653 struct flanterm_fb_context *ctx = (void *)_ctx;
654
655 if (old_x >= _ctx->cols || old_y >= _ctx->rows
656 || new_x >= _ctx->cols || new_y >= _ctx->rows) {
657 return;
658 }
659
660 size_t i = old_x + old_y * _ctx->cols;
661
662 struct flanterm_fb_char *c;
663 struct flanterm_fb_queue_item *q = ctx->map[i];
664 if (q != NULL) {
665 c = &q->c;
666 } else {
667 c = &ctx->grid[i];
668 }
669
670 push_to_queue(_ctx, c, new_x, new_y);
671}
672
673static void flanterm_fb_set_text_fg(struct flanterm_context *_ctx, size_t fg) {
674 struct flanterm_fb_context *ctx = (void *)_ctx;
675
676 ctx->text_fg = ctx->ansi_colours[fg];
677}
678
679static void flanterm_fb_set_text_bg(struct flanterm_context *_ctx, size_t bg) {
680 struct flanterm_fb_context *ctx = (void *)_ctx;
681
682 ctx->text_bg = ctx->ansi_colours[bg];
683}
684
685static void flanterm_fb_set_text_fg_bright(struct flanterm_context *_ctx, size_t fg) {
686 struct flanterm_fb_context *ctx = (void *)_ctx;
687
688 ctx->text_fg = ctx->ansi_bright_colours[fg];
689}
690
691static void flanterm_fb_set_text_bg_bright(struct flanterm_context *_ctx, size_t bg) {
692 struct flanterm_fb_context *ctx = (void *)_ctx;
693
694 ctx->text_bg = ctx->ansi_bright_colours[bg];
695}
696
697static void flanterm_fb_set_text_fg_rgb(struct flanterm_context *_ctx, uint32_t fg) {
698 struct flanterm_fb_context *ctx = (void *)_ctx;
699
700 ctx->text_fg = convert_colour(_ctx, fg);
701}
702
703static void flanterm_fb_set_text_bg_rgb(struct flanterm_context *_ctx, uint32_t bg) {
704 struct flanterm_fb_context *ctx = (void *)_ctx;
705
706 ctx->text_bg = convert_colour(_ctx, bg);
707}
708
709static void flanterm_fb_set_text_fg_default(struct flanterm_context *_ctx) {
710 struct flanterm_fb_context *ctx = (void *)_ctx;
711
712 ctx->text_fg = ctx->default_fg;
713}
714
715static void flanterm_fb_set_text_bg_default(struct flanterm_context *_ctx) {
716 struct flanterm_fb_context *ctx = (void *)_ctx;
717
718 ctx->text_bg = 0xffffffff;
719}
720
721static void flanterm_fb_set_text_fg_default_bright(struct flanterm_context *_ctx) {
722 struct flanterm_fb_context *ctx = (void *)_ctx;
723
724 ctx->text_fg = ctx->default_fg_bright;
725}
726
727static void flanterm_fb_set_text_bg_default_bright(struct flanterm_context *_ctx) {
728 struct flanterm_fb_context *ctx = (void *)_ctx;
729
730 ctx->text_bg = ctx->default_bg_bright;
731}
732
733static void draw_cursor(struct flanterm_context *_ctx) {
734 struct flanterm_fb_context *ctx = (void *)_ctx;
735
736 if (ctx->cursor_x >= _ctx->cols || ctx->cursor_y >= _ctx->rows) {
737 return;
738 }
739
740 size_t i = ctx->cursor_x + ctx->cursor_y * _ctx->cols;
741
742 struct flanterm_fb_char c;
743 struct flanterm_fb_queue_item *q = ctx->map[i];
744 if (q != NULL) {
745 c = q->c;
746 } else {
747 c = ctx->grid[i];
748 }
749 uint32_t tmp = c.fg;
750 c.fg = c.bg;
751 c.bg = tmp;
752 plot_char(_ctx, &c, ctx->cursor_x, ctx->cursor_y);
753 if (q != NULL) {
754 ctx->grid[i] = q->c;
755 ctx->map[i] = NULL;
756 }
757}
758
759static void flanterm_fb_double_buffer_flush(struct flanterm_context *_ctx) {
760 struct flanterm_fb_context *ctx = (void *)_ctx;
761
762 if (_ctx->cursor_enabled) {
763 draw_cursor(_ctx);
764 }
765
766 for (size_t i = 0; i < ctx->queue_i; i++) {
767 struct flanterm_fb_queue_item *q = &ctx->queue[i];
768 size_t offset = q->y * _ctx->cols + q->x;
769 if (ctx->map[offset] == NULL) {
770 continue;
771 }
772 #ifdef FLANTERM_FB_ENABLE_MASKING
773 struct flanterm_fb_char *old = &ctx->grid[offset];
774 if (q->c.bg == old->bg && q->c.fg == old->fg) {
775 plot_char_masked(_ctx, old, &q->c, q->x, q->y);
776 } else {
777 plot_char(_ctx, &q->c, q->x, q->y);
778 }
779 #else
780 plot_char(_ctx, &q->c, q->x, q->y);
781 #endif
782 ctx->grid[offset] = q->c;
783 ctx->map[offset] = NULL;
784 }
785
786 if ((ctx->old_cursor_x != ctx->cursor_x || ctx->old_cursor_y != ctx->cursor_y) || _ctx->cursor_enabled == false) {
787 if (ctx->old_cursor_x < _ctx->cols && ctx->old_cursor_y < _ctx->rows) {
788 plot_char(_ctx, &ctx->grid[ctx->old_cursor_x + ctx->old_cursor_y * _ctx->cols], ctx->old_cursor_x, ctx->old_cursor_y);
789 }
790 }
791
792 ctx->old_cursor_x = ctx->cursor_x;
793 ctx->old_cursor_y = ctx->cursor_y;
794
795 ctx->queue_i = 0;
796}
797
798static void flanterm_fb_raw_putchar(struct flanterm_context *_ctx, uint8_t c) {
799 struct flanterm_fb_context *ctx = (void *)_ctx;
800
801 if (ctx->cursor_x >= _ctx->cols && (ctx->cursor_y < _ctx->scroll_bottom_margin - 1 || _ctx->scroll_enabled)) {
802 ctx->cursor_x = 0;
803 ctx->cursor_y++;
804 if (ctx->cursor_y == _ctx->scroll_bottom_margin) {
805 ctx->cursor_y--;
806 flanterm_fb_scroll(_ctx);
807 }
808 if (ctx->cursor_y >= _ctx->cols) {
809 ctx->cursor_y = _ctx->cols - 1;
810 }
811 }
812
813 struct flanterm_fb_char ch;
814 ch.c = c;
815 ch.fg = ctx->text_fg;
816 ch.bg = ctx->text_bg;
817 push_to_queue(_ctx, &ch, ctx->cursor_x++, ctx->cursor_y);
818}
819
820static void flanterm_fb_full_refresh(struct flanterm_context *_ctx) {
821 struct flanterm_fb_context *ctx = (void *)_ctx;
822
823#ifdef FLANTERM_FB_DISABLE_CANVAS
824 uint32_t default_bg = ctx->default_bg;
825#endif
826
827 for (size_t y = 0; y < ctx->height; y++) {
828 for (size_t x = 0; x < ctx->width; x++) {
829#ifndef FLANTERM_FB_DISABLE_CANVAS
830 ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = ctx->canvas[y * ctx->width + x];
831#else
832 ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = default_bg;
833#endif
834 }
835 }
836
837 for (size_t i = 0; i < (size_t)_ctx->rows * _ctx->cols; i++) {
838 size_t x = i % _ctx->cols;
839 size_t y = i / _ctx->cols;
840
841 plot_char(_ctx, &ctx->grid[i], x, y);
842 }
843
844 if (_ctx->cursor_enabled) {
845 draw_cursor(_ctx);
846 }
847}
848
849static void flanterm_fb_deinit(struct flanterm_context *_ctx, void (*_free)(void *, size_t)) {
850 struct flanterm_fb_context *ctx = (void *)_ctx;
851
852 if (_free == NULL) {
853 return;
854 }
855
856 _free(ctx->font_bits, ctx->font_bits_size);
857 _free(ctx->font_bool, ctx->font_bool_size);
858 _free(ctx->grid, ctx->grid_size);
859 _free(ctx->queue, ctx->queue_size);
860 _free(ctx->map, ctx->map_size);
861
862#ifndef FLANTERM_FB_DISABLE_CANVAS
863 _free(ctx->canvas, ctx->canvas_size);
864#endif
865
866 _free(ctx, sizeof(struct flanterm_fb_context));
867}
868
869struct flanterm_context *flanterm_fb_init(
870 void *(*_malloc)(size_t),
871 void (*_free)(void *, size_t),
872 uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
873#ifdef FLANTERM_FB_SUPPORT_BPP
874 uint8_t red_mask_size, uint8_t red_mask_shift,
875 uint8_t green_mask_size, uint8_t green_mask_shift,
876 uint8_t blue_mask_size, uint8_t blue_mask_shift,
877#endif
878#ifndef FLANTERM_FB_DISABLE_CANVAS
879 uint32_t *canvas,
880#endif
881 uint32_t *ansi_colours, uint32_t *ansi_bright_colours,
882 uint32_t *default_bg, uint32_t *default_fg,
883 uint32_t *default_bg_bright, uint32_t *default_fg_bright,
884 void *font, size_t font_width, size_t font_height, size_t font_spacing,
885 size_t font_scale_x, size_t font_scale_y,
886 size_t margin
887) {
888#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
889 size_t orig_bump_alloc_ptr = bump_alloc_ptr;
890
891 // Limit terminal size if needed
892 if (width > FLANTERM_FB_WIDTH_LIMIT || height > FLANTERM_FB_HEIGHT_LIMIT) {
893 size_t width_limit = width > FLANTERM_FB_WIDTH_LIMIT ? FLANTERM_FB_WIDTH_LIMIT : width;
894 size_t height_limit = height > FLANTERM_FB_HEIGHT_LIMIT ? FLANTERM_FB_HEIGHT_LIMIT : height;
895
896 framebuffer = (uint32_t *)((uintptr_t)framebuffer + ((((height / 2) - (height_limit / 2)) * pitch) + (((width / 2) - (width_limit / 2)) * 4)));
897
898 width = width_limit;
899 height = height_limit;
900 }
901#endif
902
903#ifdef FLANTERM_FB_SUPPORT_BPP
904 if (red_mask_size < 8 || red_mask_size != green_mask_size || red_mask_size != blue_mask_size) {
905 return NULL;
906 }
907#endif
908
909 if (_malloc == NULL) {
910#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
911 _malloc = bump_alloc;
912#else
913 return NULL;
914#endif
915 }
916
917 struct flanterm_fb_context *ctx = NULL;
918 ctx = _malloc(sizeof(struct flanterm_fb_context));
919 if (ctx == NULL) {
920 goto fail;
921 }
922
923 struct flanterm_context *_ctx = (void *)ctx;
924 memset(ctx, 0, sizeof(struct flanterm_fb_context));
925
926#ifdef FLANTERM_FB_SUPPORT_BPP
927 ctx->red_mask_size = red_mask_size;
928 ctx->red_mask_shift = red_mask_shift + (red_mask_size - 8);
929 ctx->green_mask_size = green_mask_size;
930 ctx->green_mask_shift = green_mask_shift + (green_mask_size - 8);
931 ctx->blue_mask_size = blue_mask_size;
932 ctx->blue_mask_shift = blue_mask_shift + (blue_mask_size - 8);
933#endif
934
935 if (ansi_colours != NULL) {
936 for (size_t i = 0; i < 8; i++) {
937 ctx->ansi_colours[i] = convert_colour(_ctx, ansi_colours[i]);
938 }
939 } else {
940 ctx->ansi_colours[0] = convert_colour(_ctx, 0x00000000); // black
941 ctx->ansi_colours[1] = convert_colour(_ctx, 0x00aa0000); // red
942 ctx->ansi_colours[2] = convert_colour(_ctx, 0x0000aa00); // green
943 ctx->ansi_colours[3] = convert_colour(_ctx, 0x00aa5500); // brown
944 ctx->ansi_colours[4] = convert_colour(_ctx, 0x000000aa); // blue
945 ctx->ansi_colours[5] = convert_colour(_ctx, 0x00aa00aa); // magenta
946 ctx->ansi_colours[6] = convert_colour(_ctx, 0x0000aaaa); // cyan
947 ctx->ansi_colours[7] = convert_colour(_ctx, 0x00aaaaaa); // grey
948 }
949
950 if (ansi_bright_colours != NULL) {
951 for (size_t i = 0; i < 8; i++) {
952 ctx->ansi_bright_colours[i] = convert_colour(_ctx, ansi_bright_colours[i]);
953 }
954 } else {
955 ctx->ansi_bright_colours[0] = convert_colour(_ctx, 0x00555555); // black
956 ctx->ansi_bright_colours[1] = convert_colour(_ctx, 0x00ff5555); // red
957 ctx->ansi_bright_colours[2] = convert_colour(_ctx, 0x0055ff55); // green
958 ctx->ansi_bright_colours[3] = convert_colour(_ctx, 0x00ffff55); // brown
959 ctx->ansi_bright_colours[4] = convert_colour(_ctx, 0x005555ff); // blue
960 ctx->ansi_bright_colours[5] = convert_colour(_ctx, 0x00ff55ff); // magenta
961 ctx->ansi_bright_colours[6] = convert_colour(_ctx, 0x0055ffff); // cyan
962 ctx->ansi_bright_colours[7] = convert_colour(_ctx, 0x00ffffff); // grey
963 }
964
965 if (default_bg != NULL) {
966 ctx->default_bg = convert_colour(_ctx, *default_bg);
967 } else {
968 ctx->default_bg = 0x00000000; // background (black)
969 }
970
971 if (default_fg != NULL) {
972 ctx->default_fg = convert_colour(_ctx, *default_fg);
973 } else {
974 ctx->default_fg = convert_colour(_ctx, 0x00aaaaaa); // foreground (grey)
975 }
976
977 if (default_bg_bright != NULL) {
978 ctx->default_bg_bright = convert_colour(_ctx, *default_bg_bright);
979 } else {
980 ctx->default_bg_bright = convert_colour(_ctx, 0x00555555); // background (black)
981 }
982
983 if (default_fg_bright != NULL) {
984 ctx->default_fg_bright = convert_colour(_ctx, *default_fg_bright);
985 } else {
986 ctx->default_fg_bright = convert_colour(_ctx, 0x00ffffff); // foreground (grey)
987 }
988
989 ctx->text_fg = ctx->default_fg;
990 ctx->text_bg = 0xffffffff;
991
992 ctx->framebuffer = (void *)framebuffer;
993 ctx->width = width;
994 ctx->height = height;
995 ctx->pitch = pitch;
996
997#define FONT_BYTES ((font_width * font_height * FLANTERM_FB_FONT_GLYPHS) / 8)
998
999 if (font != NULL) {
1000 ctx->font_width = font_width;
1001 ctx->font_height = font_height;
1002 ctx->font_bits_size = FONT_BYTES;
1003 ctx->font_bits = _malloc(ctx->font_bits_size);
1004 if (ctx->font_bits == NULL) {
1005 goto fail;
1006 }
1007 memcpy(ctx->font_bits, font, ctx->font_bits_size);
1008 } else {
1009 ctx->font_width = font_width = 8;
1010 ctx->font_height = font_height = 16;
1011 ctx->font_bits_size = FONT_BYTES;
1012 font_spacing = 1;
1013 ctx->font_bits = _malloc(ctx->font_bits_size);
1014 if (ctx->font_bits == NULL) {
1015 goto fail;
1016 }
1017 memcpy(ctx->font_bits, builtin_font, ctx->font_bits_size);
1018 }
1019
1020#undef FONT_BYTES
1021
1022 ctx->font_width += font_spacing;
1023
1024 ctx->font_bool_size = FLANTERM_FB_FONT_GLYPHS * font_height * ctx->font_width * sizeof(bool);
1025 ctx->font_bool = _malloc(ctx->font_bool_size);
1026 if (ctx->font_bool == NULL) {
1027 goto fail;
1028 }
1029
1030 for (size_t i = 0; i < FLANTERM_FB_FONT_GLYPHS; i++) {
1031 uint8_t *glyph = &ctx->font_bits[i * font_height];
1032
1033 for (size_t y = 0; y < font_height; y++) {
1034 // NOTE: the characters in VGA fonts are always one byte wide.
1035 // 9 dot wide fonts have 8 dots and one empty column, except
1036 // characters 0xC0-0xDF replicate column 9.
1037 for (size_t x = 0; x < 8; x++) {
1038 size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
1039
1040 if ((glyph[y] & (0x80 >> x))) {
1041 ctx->font_bool[offset] = true;
1042 } else {
1043 ctx->font_bool[offset] = false;
1044 }
1045 }
1046 // fill columns above 8 like VGA Line Graphics Mode does
1047 for (size_t x = 8; x < ctx->font_width; x++) {
1048 size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
1049
1050 if (i >= 0xc0 && i <= 0xdf) {
1051 ctx->font_bool[offset] = (glyph[y] & 1);
1052 } else {
1053 ctx->font_bool[offset] = false;
1054 }
1055 }
1056 }
1057 }
1058
1059 ctx->font_scale_x = font_scale_x;
1060 ctx->font_scale_y = font_scale_y;
1061
1062 ctx->glyph_width = ctx->font_width * font_scale_x;
1063 ctx->glyph_height = font_height * font_scale_y;
1064
1065 _ctx->cols = (ctx->width - margin * 2) / ctx->glyph_width;
1066 _ctx->rows = (ctx->height - margin * 2) / ctx->glyph_height;
1067
1068 ctx->offset_x = margin + ((ctx->width - margin * 2) % ctx->glyph_width) / 2;
1069 ctx->offset_y = margin + ((ctx->height - margin * 2) % ctx->glyph_height) / 2;
1070
1071 ctx->grid_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_char);
1072 ctx->grid = _malloc(ctx->grid_size);
1073 if (ctx->grid == NULL) {
1074 goto fail;
1075 }
1076 for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
1077 ctx->grid[i].c = ' ';
1078 ctx->grid[i].fg = ctx->text_fg;
1079 ctx->grid[i].bg = ctx->text_bg;
1080 }
1081
1082 ctx->queue_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item);
1083 ctx->queue = _malloc(ctx->queue_size);
1084 if (ctx->queue == NULL) {
1085 goto fail;
1086 }
1087 ctx->queue_i = 0;
1088 memset(ctx->queue, 0, ctx->queue_size);
1089
1090 ctx->map_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item *);
1091 ctx->map = _malloc(ctx->map_size);
1092 if (ctx->map == NULL) {
1093 goto fail;
1094 }
1095 memset(ctx->map, 0, ctx->map_size);
1096
1097#ifndef FLANTERM_FB_DISABLE_CANVAS
1098 ctx->canvas_size = ctx->width * ctx->height * sizeof(uint32_t);
1099 ctx->canvas = _malloc(ctx->canvas_size);
1100 if (ctx->canvas == NULL) {
1101 goto fail;
1102 }
1103 if (canvas != NULL) {
1104 for (size_t i = 0; i < ctx->width * ctx->height; i++) {
1105 ctx->canvas[i] = convert_colour(_ctx, canvas[i]);
1106 }
1107 } else {
1108 for (size_t i = 0; i < ctx->width * ctx->height; i++) {
1109 ctx->canvas[i] = ctx->default_bg;
1110 }
1111 }
1112#endif
1113
1114 _ctx->raw_putchar = flanterm_fb_raw_putchar;
1115 _ctx->clear = flanterm_fb_clear;
1116 _ctx->set_cursor_pos = flanterm_fb_set_cursor_pos;
1117 _ctx->get_cursor_pos = flanterm_fb_get_cursor_pos;
1118 _ctx->set_text_fg = flanterm_fb_set_text_fg;
1119 _ctx->set_text_bg = flanterm_fb_set_text_bg;
1120 _ctx->set_text_fg_bright = flanterm_fb_set_text_fg_bright;
1121 _ctx->set_text_bg_bright = flanterm_fb_set_text_bg_bright;
1122 _ctx->set_text_fg_rgb = flanterm_fb_set_text_fg_rgb;
1123 _ctx->set_text_bg_rgb = flanterm_fb_set_text_bg_rgb;
1124 _ctx->set_text_fg_default = flanterm_fb_set_text_fg_default;
1125 _ctx->set_text_bg_default = flanterm_fb_set_text_bg_default;
1126 _ctx->set_text_fg_default_bright = flanterm_fb_set_text_fg_default_bright;
1127 _ctx->set_text_bg_default_bright = flanterm_fb_set_text_bg_default_bright;
1128 _ctx->move_character = flanterm_fb_move_character;
1129 _ctx->scroll = flanterm_fb_scroll;
1130 _ctx->revscroll = flanterm_fb_revscroll;
1131 _ctx->swap_palette = flanterm_fb_swap_palette;
1132 _ctx->save_state = flanterm_fb_save_state;
1133 _ctx->restore_state = flanterm_fb_restore_state;
1134 _ctx->double_buffer_flush = flanterm_fb_double_buffer_flush;
1135 _ctx->full_refresh = flanterm_fb_full_refresh;
1136 _ctx->deinit = flanterm_fb_deinit;
1137
1138 flanterm_context_reinit(_ctx);
1139 flanterm_fb_full_refresh(_ctx);
1140
1141 return _ctx;
1142
1143fail:
1144#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
1145 if (_malloc == bump_alloc) {
1146 bump_alloc_ptr = orig_bump_alloc_ptr;
1147 return NULL;
1148 }
1149#endif
1150
1151 if (_free == NULL) {
1152 return NULL;
1153 }
1154
1155#ifndef FLANTERM_FB_DISABLE_CANVAS
1156 if (ctx->canvas != NULL) {
1157 _free(ctx->canvas, ctx->canvas_size);
1158 }
1159#endif
1160 if (ctx->map != NULL) {
1161 _free(ctx->map, ctx->map_size);
1162 }
1163 if (ctx->queue != NULL) {
1164 _free(ctx->queue, ctx->queue_size);
1165 }
1166 if (ctx->grid != NULL) {
1167 _free(ctx->grid, ctx->grid_size);
1168 }
1169 if (ctx->font_bool != NULL) {
1170 _free(ctx->font_bool, ctx->font_bool_size);
1171 }
1172 if (ctx->font_bits != NULL) {
1173 _free(ctx->font_bits, ctx->font_bits_size);
1174 }
1175 if (ctx != NULL) {
1176 _free(ctx, sizeof(struct flanterm_fb_context));
1177 }
1178
1179 return NULL;
1180}