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