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