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