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