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