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