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