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