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
479static void plot_char_fast(struct flanterm_context *_ctx, struct flanterm_fb_char *old, struct flanterm_fb_char *c, size_t x, size_t y) {
480 struct flanterm_fb_context *ctx = (void *)_ctx;
481
482 if (x >= _ctx->cols || y >= _ctx->rows) {
483 return;
484 }
485
486 x = ctx->offset_x + x * ctx->glyph_width;
487 y = ctx->offset_y + y * ctx->glyph_height;
488
489#ifdef FLANTERM_FB_DISABLE_CANVAS
490 uint32_t default_bg = ctx->default_bg;
491#endif
492
493 bool *new_glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
494 bool *old_glyph = &ctx->font_bool[old->c * ctx->font_height * ctx->font_width];
495 for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
496 uint8_t fy = gy / ctx->font_scale_y;
497 volatile uint32_t *fb_line = ctx->framebuffer + x + (y + gy) * (ctx->pitch / 4);
498#ifndef FLANTERM_FB_DISABLE_CANVAS
499 uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
500#endif
501 for (size_t fx = 0; fx < ctx->font_width; fx++) {
502 bool old_draw = old_glyph[fy * ctx->font_width + fx];
503 bool new_draw = new_glyph[fy * ctx->font_width + fx];
504 if (old_draw == new_draw)
505 continue;
506 for (size_t i = 0; i < ctx->font_scale_x; i++) {
507 size_t gx = ctx->font_scale_x * fx + i;
508#ifndef FLANTERM_FB_DISABLE_CANVAS
509 uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
510 uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
511#else
512 uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
513 uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
514#endif
515 fb_line[gx] = new_draw ? fg : bg;
516 }
517 }
518 }
519}
520
521static inline bool compare_char(struct flanterm_fb_char *a, struct flanterm_fb_char *b) {
522 return !(a->c != b->c || a->bg != b->bg || a->fg != b->fg);
523}
524
525static void push_to_queue(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
526 struct flanterm_fb_context *ctx = (void *)_ctx;
527
528 if (x >= _ctx->cols || y >= _ctx->rows) {
529 return;
530 }
531
532 size_t i = y * _ctx->cols + x;
533
534 struct flanterm_fb_queue_item *q = ctx->map[i];
535
536 if (q == NULL) {
537 if (compare_char(&ctx->grid[i], c)) {
538 return;
539 }
540 q = &ctx->queue[ctx->queue_i++];
541 q->x = x;
542 q->y = y;
543 ctx->map[i] = q;
544 }
545
546 q->c = *c;
547}
548
549static void flanterm_fb_revscroll(struct flanterm_context *_ctx) {
550 struct flanterm_fb_context *ctx = (void *)_ctx;
551
552 for (size_t i = (_ctx->scroll_bottom_margin - 1) * _ctx->cols - 1;
553 i >= _ctx->scroll_top_margin * _ctx->cols; i--) {
554 if (i == (size_t)-1) {
555 break;
556 }
557 struct flanterm_fb_char *c;
558 struct flanterm_fb_queue_item *q = ctx->map[i];
559 if (q != NULL) {
560 c = &q->c;
561 } else {
562 c = &ctx->grid[i];
563 }
564 push_to_queue(_ctx, c, (i + _ctx->cols) % _ctx->cols, (i + _ctx->cols) / _ctx->cols);
565 }
566
567 // Clear the first line of the screen.
568 struct flanterm_fb_char empty;
569 empty.c = ' ';
570 empty.fg = ctx->text_fg;
571 empty.bg = ctx->text_bg;
572 for (size_t i = 0; i < _ctx->cols; i++) {
573 push_to_queue(_ctx, &empty, i, _ctx->scroll_top_margin);
574 }
575}
576
577static void flanterm_fb_scroll(struct flanterm_context *_ctx) {
578 struct flanterm_fb_context *ctx = (void *)_ctx;
579
580 for (size_t i = (_ctx->scroll_top_margin + 1) * _ctx->cols;
581 i < _ctx->scroll_bottom_margin * _ctx->cols; i++) {
582 struct flanterm_fb_char *c;
583 struct flanterm_fb_queue_item *q = ctx->map[i];
584 if (q != NULL) {
585 c = &q->c;
586 } else {
587 c = &ctx->grid[i];
588 }
589 push_to_queue(_ctx, c, (i - _ctx->cols) % _ctx->cols, (i - _ctx->cols) / _ctx->cols);
590 }
591
592 // Clear the last line of the screen.
593 struct flanterm_fb_char empty;
594 empty.c = ' ';
595 empty.fg = ctx->text_fg;
596 empty.bg = ctx->text_bg;
597 for (size_t i = 0; i < _ctx->cols; i++) {
598 push_to_queue(_ctx, &empty, i, _ctx->scroll_bottom_margin - 1);
599 }
600}
601
602static void flanterm_fb_clear(struct flanterm_context *_ctx, bool move) {
603 struct flanterm_fb_context *ctx = (void *)_ctx;
604
605 struct flanterm_fb_char empty;
606 empty.c = ' ';
607 empty.fg = ctx->text_fg;
608 empty.bg = ctx->text_bg;
609 for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
610 push_to_queue(_ctx, &empty, i % _ctx->cols, i / _ctx->cols);
611 }
612
613 if (move) {
614 ctx->cursor_x = 0;
615 ctx->cursor_y = 0;
616 }
617}
618
619static void flanterm_fb_set_cursor_pos(struct flanterm_context *_ctx, size_t x, size_t y) {
620 struct flanterm_fb_context *ctx = (void *)_ctx;
621
622 if (x >= _ctx->cols) {
623 if ((int)x < 0) {
624 x = 0;
625 } else {
626 x = _ctx->cols - 1;
627 }
628 }
629 if (y >= _ctx->rows) {
630 if ((int)y < 0) {
631 y = 0;
632 } else {
633 y = _ctx->rows - 1;
634 }
635 }
636 ctx->cursor_x = x;
637 ctx->cursor_y = y;
638}
639
640static void flanterm_fb_get_cursor_pos(struct flanterm_context *_ctx, size_t *x, size_t *y) {
641 struct flanterm_fb_context *ctx = (void *)_ctx;
642
643 *x = ctx->cursor_x >= _ctx->cols ? _ctx->cols - 1 : ctx->cursor_x;
644 *y = ctx->cursor_y >= _ctx->rows ? _ctx->rows - 1 : ctx->cursor_y;
645}
646
647static 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) {
648 struct flanterm_fb_context *ctx = (void *)_ctx;
649
650 if (old_x >= _ctx->cols || old_y >= _ctx->rows
651 || new_x >= _ctx->cols || new_y >= _ctx->rows) {
652 return;
653 }
654
655 size_t i = old_x + old_y * _ctx->cols;
656
657 struct flanterm_fb_char *c;
658 struct flanterm_fb_queue_item *q = ctx->map[i];
659 if (q != NULL) {
660 c = &q->c;
661 } else {
662 c = &ctx->grid[i];
663 }
664
665 push_to_queue(_ctx, c, new_x, new_y);
666}
667
668static void flanterm_fb_set_text_fg(struct flanterm_context *_ctx, size_t fg) {
669 struct flanterm_fb_context *ctx = (void *)_ctx;
670
671 ctx->text_fg = ctx->ansi_colours[fg];
672}
673
674static void flanterm_fb_set_text_bg(struct flanterm_context *_ctx, size_t bg) {
675 struct flanterm_fb_context *ctx = (void *)_ctx;
676
677 ctx->text_bg = ctx->ansi_colours[bg];
678}
679
680static void flanterm_fb_set_text_fg_bright(struct flanterm_context *_ctx, size_t fg) {
681 struct flanterm_fb_context *ctx = (void *)_ctx;
682
683 ctx->text_fg = ctx->ansi_bright_colours[fg];
684}
685
686static void flanterm_fb_set_text_bg_bright(struct flanterm_context *_ctx, size_t bg) {
687 struct flanterm_fb_context *ctx = (void *)_ctx;
688
689 ctx->text_bg = ctx->ansi_bright_colours[bg];
690}
691
692static void flanterm_fb_set_text_fg_rgb(struct flanterm_context *_ctx, uint32_t fg) {
693 struct flanterm_fb_context *ctx = (void *)_ctx;
694
695 ctx->text_fg = convert_colour(_ctx, fg);
696}
697
698static void flanterm_fb_set_text_bg_rgb(struct flanterm_context *_ctx, uint32_t bg) {
699 struct flanterm_fb_context *ctx = (void *)_ctx;
700
701 ctx->text_bg = convert_colour(_ctx, bg);
702}
703
704static void flanterm_fb_set_text_fg_default(struct flanterm_context *_ctx) {
705 struct flanterm_fb_context *ctx = (void *)_ctx;
706
707 ctx->text_fg = ctx->default_fg;
708}
709
710static void flanterm_fb_set_text_bg_default(struct flanterm_context *_ctx) {
711 struct flanterm_fb_context *ctx = (void *)_ctx;
712
713 ctx->text_bg = 0xffffffff;
714}
715
716static void flanterm_fb_set_text_fg_default_bright(struct flanterm_context *_ctx) {
717 struct flanterm_fb_context *ctx = (void *)_ctx;
718
719 ctx->text_fg = ctx->default_fg_bright;
720}
721
722static void flanterm_fb_set_text_bg_default_bright(struct flanterm_context *_ctx) {
723 struct flanterm_fb_context *ctx = (void *)_ctx;
724
725 ctx->text_bg = ctx->default_bg_bright;
726}
727
728static void draw_cursor(struct flanterm_context *_ctx) {
729 struct flanterm_fb_context *ctx = (void *)_ctx;
730
731 if (ctx->cursor_x >= _ctx->cols || ctx->cursor_y >= _ctx->rows) {
732 return;
733 }
734
735 size_t i = ctx->cursor_x + ctx->cursor_y * _ctx->cols;
736
737 struct flanterm_fb_char c;
738 struct flanterm_fb_queue_item *q = ctx->map[i];
739 if (q != NULL) {
740 c = q->c;
741 } else {
742 c = ctx->grid[i];
743 }
744 uint32_t tmp = c.fg;
745 c.fg = c.bg;
746 c.bg = tmp;
747 plot_char(_ctx, &c, ctx->cursor_x, ctx->cursor_y);
748 if (q != NULL) {
749 ctx->grid[i] = q->c;
750 ctx->map[i] = NULL;
751 }
752}
753
754static void flanterm_fb_double_buffer_flush(struct flanterm_context *_ctx) {
755 struct flanterm_fb_context *ctx = (void *)_ctx;
756
757 if (_ctx->cursor_enabled) {
758 draw_cursor(_ctx);
759 }
760
761 for (size_t i = 0; i < ctx->queue_i; i++) {
762 struct flanterm_fb_queue_item *q = &ctx->queue[i];
763 size_t offset = q->y * _ctx->cols + q->x;
764 if (ctx->map[offset] == NULL) {
765 continue;
766 }
767 struct flanterm_fb_char *old = &ctx->grid[offset];
768 if (q->c.bg == old->bg && q->c.fg == old->fg) {
769 plot_char_fast(_ctx, old, &q->c, q->x, q->y);
770 } else {
771 plot_char(_ctx, &q->c, q->x, q->y);
772 }
773 ctx->grid[offset] = q->c;
774 ctx->map[offset] = NULL;
775 }
776
777 if ((ctx->old_cursor_x != ctx->cursor_x || ctx->old_cursor_y != ctx->cursor_y) || _ctx->cursor_enabled == false) {
778 if (ctx->old_cursor_x < _ctx->cols && ctx->old_cursor_y < _ctx->rows) {
779 plot_char(_ctx, &ctx->grid[ctx->old_cursor_x + ctx->old_cursor_y * _ctx->cols], ctx->old_cursor_x, ctx->old_cursor_y);
780 }
781 }
782
783 ctx->old_cursor_x = ctx->cursor_x;
784 ctx->old_cursor_y = ctx->cursor_y;
785
786 ctx->queue_i = 0;
787}
788
789static void flanterm_fb_raw_putchar(struct flanterm_context *_ctx, uint8_t c) {
790 struct flanterm_fb_context *ctx = (void *)_ctx;
791
792 if (ctx->cursor_x >= _ctx->cols && (ctx->cursor_y < _ctx->scroll_bottom_margin - 1 || _ctx->scroll_enabled)) {
793 ctx->cursor_x = 0;
794 ctx->cursor_y++;
795 if (ctx->cursor_y == _ctx->scroll_bottom_margin) {
796 ctx->cursor_y--;
797 flanterm_fb_scroll(_ctx);
798 }
799 if (ctx->cursor_y >= _ctx->cols) {
800 ctx->cursor_y = _ctx->cols - 1;
801 }
802 }
803
804 struct flanterm_fb_char ch;
805 ch.c = c;
806 ch.fg = ctx->text_fg;
807 ch.bg = ctx->text_bg;
808 push_to_queue(_ctx, &ch, ctx->cursor_x++, ctx->cursor_y);
809}
810
811static void flanterm_fb_full_refresh(struct flanterm_context *_ctx) {
812 struct flanterm_fb_context *ctx = (void *)_ctx;
813
814#ifdef FLANTERM_FB_DISABLE_CANVAS
815 uint32_t default_bg = ctx->default_bg;
816#endif
817
818 for (size_t y = 0; y < ctx->height; y++) {
819 for (size_t x = 0; x < ctx->width; x++) {
820#ifndef FLANTERM_FB_DISABLE_CANVAS
821 ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = ctx->canvas[y * ctx->width + x];
822#else
823 ctx->framebuffer[y * (ctx->pitch / sizeof(uint32_t)) + x] = default_bg;
824#endif
825 }
826 }
827
828 for (size_t i = 0; i < (size_t)_ctx->rows * _ctx->cols; i++) {
829 size_t x = i % _ctx->cols;
830 size_t y = i / _ctx->cols;
831
832 plot_char(_ctx, &ctx->grid[i], x, y);
833 }
834
835 if (_ctx->cursor_enabled) {
836 draw_cursor(_ctx);
837 }
838}
839
840static void flanterm_fb_deinit(struct flanterm_context *_ctx, void (*_free)(void *, size_t)) {
841 struct flanterm_fb_context *ctx = (void *)_ctx;
842
843 if (_free == NULL) {
844 return;
845 }
846
847 _free(ctx->font_bits, ctx->font_bits_size);
848 _free(ctx->font_bool, ctx->font_bool_size);
849 _free(ctx->grid, ctx->grid_size);
850 _free(ctx->queue, ctx->queue_size);
851 _free(ctx->map, ctx->map_size);
852
853#ifndef FLANTERM_FB_DISABLE_CANVAS
854 _free(ctx->canvas, ctx->canvas_size);
855#endif
856
857 _free(ctx, sizeof(struct flanterm_fb_context));
858}
859
860struct flanterm_context *flanterm_fb_init(
861 void *(*_malloc)(size_t),
862 void (*_free)(void *, size_t),
863 uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
864#ifdef FLANTERM_FB_SUPPORT_BPP
865 uint8_t red_mask_size, uint8_t red_mask_shift,
866 uint8_t green_mask_size, uint8_t green_mask_shift,
867 uint8_t blue_mask_size, uint8_t blue_mask_shift,
868#endif
869#ifndef FLANTERM_FB_DISABLE_CANVAS
870 uint32_t *canvas,
871#endif
872 uint32_t *ansi_colours, uint32_t *ansi_bright_colours,
873 uint32_t *default_bg, uint32_t *default_fg,
874 uint32_t *default_bg_bright, uint32_t *default_fg_bright,
875 void *font, size_t font_width, size_t font_height, size_t font_spacing,
876 size_t font_scale_x, size_t font_scale_y,
877 size_t margin
878) {
879#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
880 size_t orig_bump_alloc_ptr = bump_alloc_ptr;
881#endif
882
883#ifdef FLANTERM_FB_SUPPORT_BPP
884 if (red_mask_size < 8 || red_mask_size != green_mask_size || red_mask_size != blue_mask_size) {
885 return NULL;
886 }
887#endif
888
889 if (_malloc == NULL) {
890#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
891 _malloc = bump_alloc;
892#else
893 return NULL;
894#endif
895 }
896
897 struct flanterm_fb_context *ctx = NULL;
898 ctx = _malloc(sizeof(struct flanterm_fb_context));
899 if (ctx == NULL) {
900 goto fail;
901 }
902
903 struct flanterm_context *_ctx = (void *)ctx;
904 memset(ctx, 0, sizeof(struct flanterm_fb_context));
905
906#ifdef FLANTERM_FB_SUPPORT_BPP
907 ctx->red_mask_size = red_mask_size;
908 ctx->red_mask_shift = red_mask_shift + (red_mask_size - 8);
909 ctx->green_mask_size = green_mask_size;
910 ctx->green_mask_shift = green_mask_shift + (green_mask_size - 8);
911 ctx->blue_mask_size = blue_mask_size;
912 ctx->blue_mask_shift = blue_mask_shift + (blue_mask_size - 8);
913#endif
914
915 if (ansi_colours != NULL) {
916 for (size_t i = 0; i < 8; i++) {
917 ctx->ansi_colours[i] = convert_colour(_ctx, ansi_colours[i]);
918 }
919 } else {
920 ctx->ansi_colours[0] = convert_colour(_ctx, 0x00000000); // black
921 ctx->ansi_colours[1] = convert_colour(_ctx, 0x00aa0000); // red
922 ctx->ansi_colours[2] = convert_colour(_ctx, 0x0000aa00); // green
923 ctx->ansi_colours[3] = convert_colour(_ctx, 0x00aa5500); // brown
924 ctx->ansi_colours[4] = convert_colour(_ctx, 0x000000aa); // blue
925 ctx->ansi_colours[5] = convert_colour(_ctx, 0x00aa00aa); // magenta
926 ctx->ansi_colours[6] = convert_colour(_ctx, 0x0000aaaa); // cyan
927 ctx->ansi_colours[7] = convert_colour(_ctx, 0x00aaaaaa); // grey
928 }
929
930 if (ansi_bright_colours != NULL) {
931 for (size_t i = 0; i < 8; i++) {
932 ctx->ansi_bright_colours[i] = convert_colour(_ctx, ansi_bright_colours[i]);
933 }
934 } else {
935 ctx->ansi_bright_colours[0] = convert_colour(_ctx, 0x00555555); // black
936 ctx->ansi_bright_colours[1] = convert_colour(_ctx, 0x00ff5555); // red
937 ctx->ansi_bright_colours[2] = convert_colour(_ctx, 0x0055ff55); // green
938 ctx->ansi_bright_colours[3] = convert_colour(_ctx, 0x00ffff55); // brown
939 ctx->ansi_bright_colours[4] = convert_colour(_ctx, 0x005555ff); // blue
940 ctx->ansi_bright_colours[5] = convert_colour(_ctx, 0x00ff55ff); // magenta
941 ctx->ansi_bright_colours[6] = convert_colour(_ctx, 0x0055ffff); // cyan
942 ctx->ansi_bright_colours[7] = convert_colour(_ctx, 0x00ffffff); // grey
943 }
944
945 if (default_bg != NULL) {
946 ctx->default_bg = convert_colour(_ctx, *default_bg);
947 } else {
948 ctx->default_bg = 0x00000000; // background (black)
949 }
950
951 if (default_fg != NULL) {
952 ctx->default_fg = convert_colour(_ctx, *default_fg);
953 } else {
954 ctx->default_fg = convert_colour(_ctx, 0x00aaaaaa); // foreground (grey)
955 }
956
957 if (default_bg_bright != NULL) {
958 ctx->default_bg_bright = convert_colour(_ctx, *default_bg_bright);
959 } else {
960 ctx->default_bg_bright = convert_colour(_ctx, 0x00555555); // background (black)
961 }
962
963 if (default_fg_bright != NULL) {
964 ctx->default_fg_bright = convert_colour(_ctx, *default_fg_bright);
965 } else {
966 ctx->default_fg_bright = convert_colour(_ctx, 0x00ffffff); // foreground (grey)
967 }
968
969 ctx->text_fg = ctx->default_fg;
970 ctx->text_bg = 0xffffffff;
971
972 ctx->framebuffer = (void *)framebuffer;
973 ctx->width = width;
974 ctx->height = height;
975 ctx->pitch = pitch;
976
977#define FONT_BYTES ((font_width * font_height * FLANTERM_FB_FONT_GLYPHS) / 8)
978
979 if (font != NULL) {
980 ctx->font_width = font_width;
981 ctx->font_height = font_height;
982 ctx->font_bits_size = FONT_BYTES;
983 ctx->font_bits = _malloc(ctx->font_bits_size);
984 if (ctx->font_bits == NULL) {
985 goto fail;
986 }
987 memcpy(ctx->font_bits, font, ctx->font_bits_size);
988 } else {
989 ctx->font_width = font_width = 8;
990 ctx->font_height = font_height = 16;
991 ctx->font_bits_size = FONT_BYTES;
992 font_spacing = 1;
993 ctx->font_bits = _malloc(ctx->font_bits_size);
994 if (ctx->font_bits == NULL) {
995 goto fail;
996 }
997 memcpy(ctx->font_bits, builtin_font, ctx->font_bits_size);
998 }
999
1000#undef FONT_BYTES
1001
1002 ctx->font_width += font_spacing;
1003
1004 ctx->font_bool_size = FLANTERM_FB_FONT_GLYPHS * font_height * ctx->font_width * sizeof(bool);
1005 ctx->font_bool = _malloc(ctx->font_bool_size);
1006 if (ctx->font_bool == NULL) {
1007 goto fail;
1008 }
1009
1010 for (size_t i = 0; i < FLANTERM_FB_FONT_GLYPHS; i++) {
1011 uint8_t *glyph = &ctx->font_bits[i * font_height];
1012
1013 for (size_t y = 0; y < font_height; y++) {
1014 // NOTE: the characters in VGA fonts are always one byte wide.
1015 // 9 dot wide fonts have 8 dots and one empty column, except
1016 // characters 0xC0-0xDF replicate column 9.
1017 for (size_t x = 0; x < 8; x++) {
1018 size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
1019
1020 if ((glyph[y] & (0x80 >> x))) {
1021 ctx->font_bool[offset] = true;
1022 } else {
1023 ctx->font_bool[offset] = false;
1024 }
1025 }
1026 // fill columns above 8 like VGA Line Graphics Mode does
1027 for (size_t x = 8; x < ctx->font_width; x++) {
1028 size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
1029
1030 if (i >= 0xc0 && i <= 0xdf) {
1031 ctx->font_bool[offset] = (glyph[y] & 1);
1032 } else {
1033 ctx->font_bool[offset] = false;
1034 }
1035 }
1036 }
1037 }
1038
1039 ctx->font_scale_x = font_scale_x;
1040 ctx->font_scale_y = font_scale_y;
1041
1042 ctx->glyph_width = ctx->font_width * font_scale_x;
1043 ctx->glyph_height = font_height * font_scale_y;
1044
1045 _ctx->cols = (ctx->width - margin * 2) / ctx->glyph_width;
1046 _ctx->rows = (ctx->height - margin * 2) / ctx->glyph_height;
1047
1048 ctx->offset_x = margin + ((ctx->width - margin * 2) % ctx->glyph_width) / 2;
1049 ctx->offset_y = margin + ((ctx->height - margin * 2) % ctx->glyph_height) / 2;
1050
1051 ctx->grid_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_char);
1052 ctx->grid = _malloc(ctx->grid_size);
1053 if (ctx->grid == NULL) {
1054 goto fail;
1055 }
1056 for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
1057 ctx->grid[i].c = ' ';
1058 ctx->grid[i].fg = ctx->text_fg;
1059 ctx->grid[i].bg = ctx->text_bg;
1060 }
1061
1062 ctx->queue_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item);
1063 ctx->queue = _malloc(ctx->queue_size);
1064 if (ctx->queue == NULL) {
1065 goto fail;
1066 }
1067 ctx->queue_i = 0;
1068 memset(ctx->queue, 0, ctx->queue_size);
1069
1070 ctx->map_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item *);
1071 ctx->map = _malloc(ctx->map_size);
1072 if (ctx->map == NULL) {
1073 goto fail;
1074 }
1075 memset(ctx->map, 0, ctx->map_size);
1076
1077#ifndef FLANTERM_FB_DISABLE_CANVAS
1078 ctx->canvas_size = ctx->width * ctx->height * sizeof(uint32_t);
1079 ctx->canvas = _malloc(ctx->canvas_size);
1080 if (ctx->canvas == NULL) {
1081 goto fail;
1082 }
1083 if (canvas != NULL) {
1084 for (size_t i = 0; i < ctx->width * ctx->height; i++) {
1085 ctx->canvas[i] = convert_colour(_ctx, canvas[i]);
1086 }
1087 } else {
1088 for (size_t i = 0; i < ctx->width * ctx->height; i++) {
1089 ctx->canvas[i] = ctx->default_bg;
1090 }
1091 }
1092#endif
1093
1094 _ctx->raw_putchar = flanterm_fb_raw_putchar;
1095 _ctx->clear = flanterm_fb_clear;
1096 _ctx->set_cursor_pos = flanterm_fb_set_cursor_pos;
1097 _ctx->get_cursor_pos = flanterm_fb_get_cursor_pos;
1098 _ctx->set_text_fg = flanterm_fb_set_text_fg;
1099 _ctx->set_text_bg = flanterm_fb_set_text_bg;
1100 _ctx->set_text_fg_bright = flanterm_fb_set_text_fg_bright;
1101 _ctx->set_text_bg_bright = flanterm_fb_set_text_bg_bright;
1102 _ctx->set_text_fg_rgb = flanterm_fb_set_text_fg_rgb;
1103 _ctx->set_text_bg_rgb = flanterm_fb_set_text_bg_rgb;
1104 _ctx->set_text_fg_default = flanterm_fb_set_text_fg_default;
1105 _ctx->set_text_bg_default = flanterm_fb_set_text_bg_default;
1106 _ctx->set_text_fg_default_bright = flanterm_fb_set_text_fg_default_bright;
1107 _ctx->set_text_bg_default_bright = flanterm_fb_set_text_bg_default_bright;
1108 _ctx->move_character = flanterm_fb_move_character;
1109 _ctx->scroll = flanterm_fb_scroll;
1110 _ctx->revscroll = flanterm_fb_revscroll;
1111 _ctx->swap_palette = flanterm_fb_swap_palette;
1112 _ctx->save_state = flanterm_fb_save_state;
1113 _ctx->restore_state = flanterm_fb_restore_state;
1114 _ctx->double_buffer_flush = flanterm_fb_double_buffer_flush;
1115 _ctx->full_refresh = flanterm_fb_full_refresh;
1116 _ctx->deinit = flanterm_fb_deinit;
1117
1118 flanterm_context_reinit(_ctx);
1119 flanterm_fb_full_refresh(_ctx);
1120
1121 return _ctx;
1122
1123fail:
1124#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
1125 if (_malloc == bump_alloc) {
1126 bump_alloc_ptr = orig_bump_alloc_ptr;
1127 return NULL;
1128 }
1129#endif
1130
1131 if (_free == NULL) {
1132 return NULL;
1133 }
1134
1135#ifndef FLANTERM_FB_DISABLE_CANVAS
1136 if (ctx->canvas != NULL) {
1137 _free(ctx->canvas, ctx->canvas_size);
1138 }
1139#endif
1140 if (ctx->map != NULL) {
1141 _free(ctx->map, ctx->map_size);
1142 }
1143 if (ctx->queue != NULL) {
1144 _free(ctx->queue, ctx->queue_size);
1145 }
1146 if (ctx->grid != NULL) {
1147 _free(ctx->grid, ctx->grid_size);
1148 }
1149 if (ctx->font_bool != NULL) {
1150 _free(ctx->font_bool, ctx->font_bool_size);
1151 }
1152 if (ctx->font_bits != NULL) {
1153 _free(ctx->font_bits, ctx->font_bits_size);
1154 }
1155 if (ctx != NULL) {
1156 _free(ctx, sizeof(struct flanterm_fb_context));
1157 }
1158
1159 return NULL;
1160}