1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/* Copyright (C) 2022-2026 Mintsuki and contributors.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifdef __cplusplus
29#error "Please do not compile Flanterm as C++ code! Flanterm should be compiled as C99 or newer."
30#endif
31
32#ifndef __STDC_VERSION__
33#error "Flanterm must be compiled as C99 or newer."
34#endif
35
36#if defined(_MSC_VER)
37#define ALWAYS_INLINE __forceinline
38#elif defined(__GNUC__) || defined(__clang__)
39#define ALWAYS_INLINE __attribute__((always_inline)) inline
40#else
41#define ALWAYS_INLINE inline
42#endif
43
44#include <stdint.h>
45#include <stddef.h>
46#include <stdbool.h>
47
48#ifndef FLANTERM_IN_FLANTERM
49#define FLANTERM_IN_FLANTERM
50#endif
51
52#include "../flanterm.h"
53#include "fb.h"
54
55void *memset(void *, int, size_t);
56void *memcpy(void *, const void *, size_t);
57
58#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
59
60#ifndef FLANTERM_FB_BUMP_ALLOC_POOL_SIZE
61#define FLANTERM_FB_BUMP_ALLOC_POOL_SIZE 873000
62
63#define FLANTERM_FB_WIDTH_LIMIT 1920
64#define FLANTERM_FB_HEIGHT_LIMIT 1200
65#endif
66
67static uint8_t bump_alloc_pool[FLANTERM_FB_BUMP_ALLOC_POOL_SIZE];
68static size_t bump_alloc_ptr = 0;
69static bool bump_alloc_base_offset_added = false;
70
71static void *bump_alloc(size_t s) {
72 if (!bump_alloc_base_offset_added) {
73 if ((uintptr_t)bump_alloc_pool & 0xf) {
74 bump_alloc_ptr += 0x10 - ((uintptr_t)bump_alloc_pool & 0xf);
75 }
76 bump_alloc_base_offset_added = true;
77 }
78
79 if ((s & 0xf) != 0) {
80 s += 0x10;
81 s &= ~(size_t)0xf;
82 }
83
84 size_t next_ptr = bump_alloc_ptr + s;
85 if (next_ptr > FLANTERM_FB_BUMP_ALLOC_POOL_SIZE) {
86 return NULL;
87 }
88 void *ret = &bump_alloc_pool[bump_alloc_ptr];
89 bump_alloc_ptr = next_ptr;
90 return ret;
91}
92
93static bool bump_allocated_instance = false;
94
95#endif
96
97// Builtin font originally taken from:
98// https://github.com/viler-int10h/vga-text-mode-fonts/raw/master/FONTS/PC-OTHER/TOSH-SAT.F16
99static const uint8_t builtin_font[] = {
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x81, 0x81, 0xa5, 0xa5, 0x81,
102 0x81, 0xa5, 0x99, 0x81, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0xff,
103 0xff, 0xdb, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0x7e, 0x3c, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10,
105 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe,
106 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
107 0x3c, 0x3c, 0xdb, 0xff, 0xff, 0xdb, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0xff, 0x66, 0x18, 0x18,
109 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
110 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
111 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x84, 0x84, 0xcc, 0x78, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
114 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1e,
115 0x0e, 0x1e, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x30, 0x30,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x1c, 0x1e, 0x16, 0x12,
118 0x10, 0x10, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, 0x2c,
119 0x26, 0x32, 0x3a, 0x2e, 0x26, 0x22, 0x62, 0xe2, 0xc6, 0x0e, 0x0c, 0x00,
120 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe,
122 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
123 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78,
125 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
126 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
127 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c,
129 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78,
131 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x78, 0x30, 0xfc, 0x00, 0x00,
132 0x00, 0x00, 0x30, 0x78, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
133 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
134 0x30, 0x30, 0xfc, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x00, 0x18, 0x0c, 0xfe, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0xfe, 0x60, 0x30, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
138 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
142 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x30, 0x30, 0x00, 0x30,
145 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
147 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
148 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc0, 0xc0, 0x7c, 0x06, 0x06, 0xc6, 0x7c,
149 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x0c, 0x0c, 0x18, 0x38,
150 0x30, 0x60, 0x60, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
151 0x6c, 0x38, 0x30, 0x76, 0xde, 0xcc, 0xcc, 0xde, 0x76, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, 0x60, 0x60,
154 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
155 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x38, 0xfe, 0x38, 0x6c, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
158 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
163 0x0c, 0x0c, 0x18, 0x38, 0x30, 0x60, 0x60, 0xc0, 0xc0, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6,
165 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
166 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
167 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0x06, 0xc6,
169 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc,
170 0xfe, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
171 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x3c, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
173 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
174 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
175 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c,
177 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
178 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
180 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c,
181 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00,
182 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60,
183 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 0x00, 0x00,
184 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x00, 0x30,
185 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
186 0xde, 0xde, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
187 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
189 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0,
190 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
191 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
193 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0,
194 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
195 0xc0, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6,
197 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
198 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
199 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0xc6, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6,
201 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
202 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
203 0xee, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
204 0x00, 0x00, 0xc6, 0xc6, 0xe6, 0xe6, 0xf6, 0xde, 0xce, 0xce, 0xc6, 0xc6,
205 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
206 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6,
207 0xc6, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xf6, 0xda,
209 0x6c, 0x06, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc,
210 0xd8, 0xcc, 0xcc, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
211 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
212 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
213 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
214 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
215 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
216 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c,
217 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x38,
218 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc,
219 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0xfe, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc0, 0xc0,
221 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60,
222 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
223 0x60, 0x60, 0x30, 0x38, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
225 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00,
226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
228 0x00, 0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x06, 0x06,
230 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
231 0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xdc, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
233 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x76, 0xce, 0xc6,
234 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x30,
237 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xce, 0xc6,
238 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
239 0xc0, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x18, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
241 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x1e, 0x06, 0x06,
242 0x06, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xc0,
243 0xc0, 0xc6, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc6, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
245 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6,
246 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
249 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc6,
250 0xc6, 0xc6, 0xe6, 0xdc, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x76, 0xce, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x06, 0x06, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xe6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
253 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0,
254 0x70, 0x1c, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
255 0x30, 0xfe, 0x30, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
257 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
258 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6,
261 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
262 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x30, 0x30,
265 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00,
266 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x30,
267 0x30, 0x30, 0x30, 0x1c, 0x30, 0x30, 0x30, 0x30, 0xe0, 0x00, 0x00, 0x00,
268 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x38, 0x38, 0x6c,
270 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
271 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x18, 0xcc, 0x78, 0x00,
272 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
273 0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6,
274 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
275 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
276 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6,
277 0x7e, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x06, 0x06,
278 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
279 0x00, 0x7c, 0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00,
280 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc6,
281 0x7c, 0x18, 0x0c, 0x38, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
282 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
283 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0, 0x7e, 0x00, 0x00, 0x00,
284 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc0, 0xc0, 0xc0,
285 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18,
286 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
287 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
288 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
289 0x3c, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6,
290 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
291 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
292 0x18, 0x30, 0x60, 0x00, 0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0,
293 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x36, 0x36,
294 0x76, 0xde, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3c,
295 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
296 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
297 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6,
298 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
299 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
300 0x00, 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
301 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xc6, 0xc6, 0xc6,
302 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c,
303 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00,
304 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
305 0x7c, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
306 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
307 0x30, 0x78, 0xcc, 0xc0, 0xc0, 0xcc, 0x78, 0x30, 0x30, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x38, 0x6c, 0x60, 0x60, 0x60, 0xf8, 0x60, 0x60, 0x60, 0xe6,
309 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
310 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc,
311 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18,
313 0x18, 0xd8, 0x70, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x06, 0x06,
314 0x7e, 0xc6, 0xc6, 0xc6, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
315 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
316 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
317 0x7c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6,
318 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
319 0x00, 0xdc, 0xe6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
320 0x76, 0xdc, 0x00, 0xc6, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6,
321 0xc6, 0x00, 0x00, 0x00, 0x00, 0x78, 0xd8, 0xd8, 0x6c, 0x00, 0xfc, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
323 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xc6,
325 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c,
329 0x18, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc2, 0xc6, 0xcc, 0xd8, 0x30,
330 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
331 0x00, 0x30, 0x30, 0x30, 0x78, 0x78, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00,
332 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
334 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x88, 0x22, 0x88,
335 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
336 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
337 0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
338 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
339 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
340 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18,
341 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
342 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
343 0x36, 0x36, 0x36, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x36, 0x36, 0x36,
345 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18,
346 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
347 0x36, 0xf6, 0xf6, 0x06, 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36,
348 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
349 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x06,
350 0x06, 0xf6, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
351 0x36, 0xf6, 0xf6, 0x06, 0x06, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0xfe, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18,
354 0x18, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
356 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
358 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
360 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18,
361 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
362 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
363 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
364 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
365 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
366 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
367 0x36, 0x37, 0x37, 0x30, 0x30, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x30, 0x30, 0x37, 0x37, 0x36,
369 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0xf7, 0x00,
370 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 0x00, 0xff, 0xff, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
372 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x30, 0x30, 0x37, 0x37, 0x36,
373 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
374 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
375 0x36, 0xf7, 0xf7, 0x00, 0x00, 0xf7, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36,
376 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
377 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
378 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18,
380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x36, 0x36, 0x36,
381 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
382 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
383 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x1f, 0x1f, 0x18,
385 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
386 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
387 0x36, 0x36, 0x36, 0xff, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
388 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0xff, 0xff, 0x18,
389 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
390 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
392 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
393 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
395 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
396 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
397 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x76, 0xd6, 0xdc, 0xc8, 0xc8, 0xdc, 0xd6, 0x76, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
401 0xd8, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
402 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 0x00, 0x7e, 0xfe, 0x24, 0x24, 0x24, 0x24, 0x66, 0xc6, 0x00, 0x00, 0x00,
404 0x00, 0x00, 0xfe, 0xfe, 0xc2, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc2, 0xfe,
405 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc8, 0xcc,
406 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
407 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x6c, 0x60, 0xc0, 0x00,
408 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xfc, 0x98, 0x18, 0x18, 0x18, 0x18,
409 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x30, 0x30, 0x78, 0xcc, 0xcc,
410 0xcc, 0x78, 0x30, 0x30, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
411 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
412 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c,
413 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0x60, 0x30, 0x78, 0xcc,
414 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
415 0x00, 0x76, 0xbb, 0x99, 0x99, 0xdd, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
416 0x00, 0x00, 0x02, 0x06, 0x3c, 0x6c, 0xce, 0xd6, 0xd6, 0xe6, 0x6c, 0x78,
417 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x60, 0xc0, 0xc0, 0xfe,
418 0xc0, 0xc0, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
419 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
420 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc,
422 0x30, 0x30, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
423 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x00, 0x00,
424 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
425 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x36, 0x30, 0x30, 0x30,
426 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18,
427 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
428 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
430 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc,
431 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
432 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
433 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
434 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
435 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c, 0x00, 0x00,
436 0x00, 0xd8, 0xec, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x00,
437 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x0c, 0x18, 0x30, 0x60, 0x7c,
438 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
439 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
440 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
441 0x00, 0x00, 0x00, 0x00
442};
443
444static ALWAYS_INLINE uint32_t convert_colour(struct flanterm_context *_ctx, uint32_t colour) {
445 struct flanterm_fb_context *ctx = (void *)_ctx;
446 uint32_t r = (colour >> 16) & 0xff;
447 uint32_t g = (colour >> 8) & 0xff;
448 uint32_t b = colour & 0xff;
449 uint32_t ret = (r << ctx->red_mask_shift) | (g << ctx->green_mask_shift) | (b << ctx->blue_mask_shift);
450 if (ctx->red_mask_size > 8) {
451 ret |= (r >> (16 - ctx->red_mask_size)) << (ctx->red_mask_shift - ctx->red_mask_size + 8);
452 }
453 if (ctx->green_mask_size > 8) {
454 ret |= (g >> (16 - ctx->green_mask_size)) << (ctx->green_mask_shift - ctx->green_mask_size + 8);
455 }
456 if (ctx->blue_mask_size > 8) {
457 ret |= (b >> (16 - ctx->blue_mask_size)) << (ctx->blue_mask_shift - ctx->blue_mask_size + 8);
458 }
459 return ret;
460}
461
462static void flanterm_fb_save_state(struct flanterm_context *_ctx) {
463 struct flanterm_fb_context *ctx = (void *)_ctx;
464 ctx->saved_state_text_fg = ctx->text_fg;
465 ctx->saved_state_text_bg = ctx->text_bg;
466 ctx->saved_state_cursor_x = ctx->cursor_x;
467 ctx->saved_state_cursor_y = ctx->cursor_y;
468}
469
470static void flanterm_fb_restore_state(struct flanterm_context *_ctx) {
471 struct flanterm_fb_context *ctx = (void *)_ctx;
472 ctx->text_fg = ctx->saved_state_text_fg;
473 ctx->text_bg = ctx->saved_state_text_bg;
474 ctx->cursor_x = ctx->saved_state_cursor_x;
475 ctx->cursor_y = ctx->saved_state_cursor_y;
476}
477
478static void flanterm_fb_swap_palette(struct flanterm_context *_ctx) {
479 struct flanterm_fb_context *ctx = (void *)_ctx;
480 uint32_t tmp = ctx->text_bg;
481 ctx->text_bg = ctx->text_fg;
482 ctx->text_fg = tmp;
483}
484
485static void plot_char_scaled_canvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
486 struct flanterm_fb_context *ctx = (void *)_ctx;
487
488 if (x >= _ctx->cols || y >= _ctx->rows) {
489 return;
490 }
491
492 x = ctx->offset_x + x * ctx->glyph_width;
493 y = ctx->offset_y + y * ctx->glyph_height;
494
495 bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
496
497 volatile uint32_t *dest;
498 int outer_stride, inner_stride;
499
500 switch (ctx->rotation) {
501 default:
502 case FLANTERM_FB_ROTATE_0:
503 dest = ctx->framebuffer + x + y * (ctx->pitch / 4);
504 outer_stride = ctx->pitch / 4;
505 inner_stride = 1;
506 break;
507 case FLANTERM_FB_ROTATE_90:
508 dest = ctx->framebuffer + (ctx->height - 1 - y) + x * (ctx->pitch / 4);
509 outer_stride = -1;
510 inner_stride = ctx->pitch / 4;
511 break;
512 case FLANTERM_FB_ROTATE_180:
513 dest = ctx->framebuffer + (ctx->width - 1 - x) + (ctx->height - 1 - y) * (ctx->pitch / 4);
514 outer_stride = -(ctx->pitch / 4);
515 inner_stride = -1;
516 break;
517 case FLANTERM_FB_ROTATE_270:
518 dest = ctx->framebuffer + y + (ctx->width - 1 - x) * (ctx->pitch / 4);
519 outer_stride = 1;
520 inner_stride = -(ctx->pitch / 4);
521 break;
522 }
523
524 // naming: fx,fy for font coordinates, gx,gy for glyph coordinates
525 for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
526 uint8_t fy = gy / ctx->font_scale_y;
527 volatile uint32_t *fb_line = dest;
528 uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
529 bool *glyph_pointer = glyph + (fy * ctx->font_width);
530 for (size_t fx = 0; fx < ctx->font_width; fx++) {
531 for (size_t i = 0; i < ctx->font_scale_x; i++) {
532 size_t gx = ctx->font_scale_x * fx + i;
533 uint32_t bg = c->bg == 0xffffffff ? canvas_line[gx] : c->bg;
534 uint32_t fg = c->fg == 0xffffffff ? canvas_line[gx] : c->fg;
535 *fb_line = *glyph_pointer ? fg : bg;
536 fb_line += inner_stride;
537 }
538 glyph_pointer++;
539 }
540 dest += outer_stride;
541 }
542}
543
544static void plot_char_scaled_uncanvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
545 struct flanterm_fb_context *ctx = (void *)_ctx;
546
547 if (x >= _ctx->cols || y >= _ctx->rows) {
548 return;
549 }
550
551 uint32_t default_bg = ctx->default_bg;
552
553 uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
554 uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
555
556 x = ctx->offset_x + x * ctx->glyph_width;
557 y = ctx->offset_y + y * ctx->glyph_height;
558
559 bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
560
561 volatile uint32_t *dest;
562 int outer_stride, inner_stride;
563
564 switch (ctx->rotation) {
565 default:
566 case FLANTERM_FB_ROTATE_0:
567 dest = ctx->framebuffer + x + y * (ctx->pitch / 4);
568 outer_stride = ctx->pitch / 4;
569 inner_stride = 1;
570 break;
571 case FLANTERM_FB_ROTATE_90:
572 dest = ctx->framebuffer + (ctx->height - 1 - y) + x * (ctx->pitch / 4);
573 outer_stride = -1;
574 inner_stride = ctx->pitch / 4;
575 break;
576 case FLANTERM_FB_ROTATE_180:
577 dest = ctx->framebuffer + (ctx->width - 1 - x) + (ctx->height - 1 - y) * (ctx->pitch / 4);
578 outer_stride = -(ctx->pitch / 4);
579 inner_stride = -1;
580 break;
581 case FLANTERM_FB_ROTATE_270:
582 dest = ctx->framebuffer + y + (ctx->width - 1 - x) * (ctx->pitch / 4);
583 outer_stride = 1;
584 inner_stride = -(ctx->pitch / 4);
585 break;
586 }
587
588 // naming: fx,fy for font coordinates, gx,gy for glyph coordinates
589 for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
590 uint8_t fy = gy / ctx->font_scale_y;
591 volatile uint32_t *fb_line = dest;
592 bool *glyph_pointer = glyph + (fy * ctx->font_width);
593 for (size_t fx = 0; fx < ctx->font_width; fx++) {
594 for (size_t i = 0; i < ctx->font_scale_x; i++) {
595 *fb_line = *glyph_pointer ? fg : bg;
596 fb_line += inner_stride;
597 }
598 glyph_pointer++;
599 }
600 dest += outer_stride;
601 }
602}
603
604static void plot_char_unscaled_canvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
605 struct flanterm_fb_context *ctx = (void *)_ctx;
606
607 if (x >= _ctx->cols || y >= _ctx->rows) {
608 return;
609 }
610
611 x = ctx->offset_x + x * ctx->glyph_width;
612 y = ctx->offset_y + y * ctx->glyph_height;
613
614 bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
615
616 volatile uint32_t *dest;
617 int outer_stride, inner_stride;
618
619 switch (ctx->rotation) {
620 default:
621 case FLANTERM_FB_ROTATE_0:
622 dest = ctx->framebuffer + x + y * (ctx->pitch / 4);
623 outer_stride = ctx->pitch / 4;
624 inner_stride = 1;
625 break;
626 case FLANTERM_FB_ROTATE_90:
627 dest = ctx->framebuffer + (ctx->height - 1 - y) + x * (ctx->pitch / 4);
628 outer_stride = -1;
629 inner_stride = ctx->pitch / 4;
630 break;
631 case FLANTERM_FB_ROTATE_180:
632 dest = ctx->framebuffer + (ctx->width - 1 - x) + (ctx->height - 1 - y) * (ctx->pitch / 4);
633 outer_stride = -(ctx->pitch / 4);
634 inner_stride = -1;
635 break;
636 case FLANTERM_FB_ROTATE_270:
637 dest = ctx->framebuffer + y + (ctx->width - 1 - x) * (ctx->pitch / 4);
638 outer_stride = 1;
639 inner_stride = -(ctx->pitch / 4);
640 break;
641 }
642
643 // naming: fx,fy for font coordinates, gx,gy for glyph coordinates
644 for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
645 volatile uint32_t *fb_line = dest;
646 uint32_t *canvas_line = ctx->canvas + x + (y + gy) * ctx->width;
647 bool *glyph_pointer = glyph + (gy * ctx->font_width);
648 for (size_t fx = 0; fx < ctx->font_width; fx++) {
649 uint32_t bg = c->bg == 0xffffffff ? canvas_line[fx] : c->bg;
650 uint32_t fg = c->fg == 0xffffffff ? canvas_line[fx] : c->fg;
651 *fb_line = *(glyph_pointer++) ? fg : bg;
652 fb_line += inner_stride;
653 }
654 dest += outer_stride;
655 }
656}
657
658static void plot_char_unscaled_uncanvas(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
659 struct flanterm_fb_context *ctx = (void *)_ctx;
660
661 if (x >= _ctx->cols || y >= _ctx->rows) {
662 return;
663 }
664
665 uint32_t default_bg = ctx->default_bg;
666
667 uint32_t bg = c->bg == 0xffffffff ? default_bg : c->bg;
668 uint32_t fg = c->fg == 0xffffffff ? default_bg : c->fg;
669
670 x = ctx->offset_x + x * ctx->glyph_width;
671 y = ctx->offset_y + y * ctx->glyph_height;
672
673 bool *glyph = &ctx->font_bool[c->c * ctx->font_height * ctx->font_width];
674
675 volatile uint32_t *dest;
676 int outer_stride, inner_stride;
677
678 switch (ctx->rotation) {
679 default:
680 case FLANTERM_FB_ROTATE_0:
681 dest = ctx->framebuffer + x + y * (ctx->pitch / 4);
682 outer_stride = ctx->pitch / 4;
683 inner_stride = 1;
684 break;
685 case FLANTERM_FB_ROTATE_90:
686 dest = ctx->framebuffer + (ctx->height - 1 - y) + x * (ctx->pitch / 4);
687 outer_stride = -1;
688 inner_stride = ctx->pitch / 4;
689 break;
690 case FLANTERM_FB_ROTATE_180:
691 dest = ctx->framebuffer + (ctx->width - 1 - x) + (ctx->height - 1 - y) * (ctx->pitch / 4);
692 outer_stride = -(ctx->pitch / 4);
693 inner_stride = -1;
694 break;
695 case FLANTERM_FB_ROTATE_270:
696 dest = ctx->framebuffer + y + (ctx->width - 1 - x) * (ctx->pitch / 4);
697 outer_stride = 1;
698 inner_stride = -(ctx->pitch / 4);
699 break;
700 }
701
702 // naming: fx,fy for font coordinates, gx,gy for glyph coordinates
703 for (size_t gy = 0; gy < ctx->glyph_height; gy++) {
704 volatile uint32_t *fb_line = dest;
705 bool *glyph_pointer = glyph + (gy * ctx->font_width);
706 for (size_t fx = 0; fx < ctx->font_width; fx++) {
707 *fb_line = *(glyph_pointer++) ? fg : bg;
708 fb_line += inner_stride;
709 }
710 dest += outer_stride;
711 }
712}
713
714static inline bool compare_char(struct flanterm_fb_char *a, struct flanterm_fb_char *b) {
715 return !(a->c != b->c || a->bg != b->bg || a->fg != b->fg);
716}
717
718static void push_to_queue(struct flanterm_context *_ctx, struct flanterm_fb_char *c, size_t x, size_t y) {
719 struct flanterm_fb_context *ctx = (void *)_ctx;
720
721 if (x >= _ctx->cols || y >= _ctx->rows) {
722 return;
723 }
724
725 size_t i = y * _ctx->cols + x;
726
727 struct flanterm_fb_queue_item *q = ctx->map[i];
728
729 if (q == NULL) {
730 if (compare_char(a: &ctx->grid[i], b: c)) {
731 return;
732 }
733 if (ctx->queue_i == _ctx->rows * _ctx->cols) {
734 return;
735 }
736 q = &ctx->queue[ctx->queue_i++];
737 q->x = x;
738 q->y = y;
739 ctx->map[i] = q;
740 }
741
742 q->c = *c;
743}
744
745static void flanterm_fb_revscroll(struct flanterm_context *_ctx) {
746 struct flanterm_fb_context *ctx = (void *)_ctx;
747
748 size_t start = _ctx->scroll_top_margin * _ctx->cols;
749 size_t end = (_ctx->scroll_bottom_margin - 1) * _ctx->cols;
750 for (size_t i = end; i > start; ) {
751 i--;
752 struct flanterm_fb_char *c;
753 struct flanterm_fb_queue_item *q = ctx->map[i];
754 if (q != NULL) {
755 c = &q->c;
756 } else {
757 c = &ctx->grid[i];
758 }
759 push_to_queue(_ctx, c, x: (i + _ctx->cols) % _ctx->cols, y: (i + _ctx->cols) / _ctx->cols);
760 }
761
762 // Clear the first line of the screen.
763 struct flanterm_fb_char empty;
764 empty.c = ' ';
765 empty.fg = ctx->text_fg;
766 empty.bg = ctx->text_bg;
767 for (size_t i = 0; i < _ctx->cols; i++) {
768 push_to_queue(_ctx, c: &empty, x: i, y: _ctx->scroll_top_margin);
769 }
770}
771
772static void flanterm_fb_scroll(struct flanterm_context *_ctx) {
773 struct flanterm_fb_context *ctx = (void *)_ctx;
774
775 for (size_t i = (_ctx->scroll_top_margin + 1) * _ctx->cols;
776 i < _ctx->scroll_bottom_margin * _ctx->cols; i++) {
777 struct flanterm_fb_char *c;
778 struct flanterm_fb_queue_item *q = ctx->map[i];
779 if (q != NULL) {
780 c = &q->c;
781 } else {
782 c = &ctx->grid[i];
783 }
784 push_to_queue(_ctx, c, x: (i - _ctx->cols) % _ctx->cols, y: (i - _ctx->cols) / _ctx->cols);
785 }
786
787 // Clear the last line of the screen.
788 struct flanterm_fb_char empty;
789 empty.c = ' ';
790 empty.fg = ctx->text_fg;
791 empty.bg = ctx->text_bg;
792 for (size_t i = 0; i < _ctx->cols; i++) {
793 push_to_queue(_ctx, c: &empty, x: i, y: _ctx->scroll_bottom_margin - 1);
794 }
795}
796
797static void flanterm_fb_clear(struct flanterm_context *_ctx, bool move) {
798 struct flanterm_fb_context *ctx = (void *)_ctx;
799
800 struct flanterm_fb_char empty;
801 empty.c = ' ';
802 empty.fg = ctx->text_fg;
803 empty.bg = ctx->text_bg;
804 for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
805 push_to_queue(_ctx, c: &empty, x: i % _ctx->cols, y: i / _ctx->cols);
806 }
807
808 if (move) {
809 ctx->cursor_x = 0;
810 ctx->cursor_y = 0;
811 }
812}
813
814static void flanterm_fb_set_cursor_pos(struct flanterm_context *_ctx, size_t x, size_t y) {
815 struct flanterm_fb_context *ctx = (void *)_ctx;
816
817 if (x >= _ctx->cols) {
818 if (x > SIZE_MAX / 2) {
819 x = 0;
820 } else {
821 x = _ctx->cols - 1;
822 }
823 }
824 if (y >= _ctx->rows) {
825 if (y > SIZE_MAX / 2) {
826 y = 0;
827 } else {
828 y = _ctx->rows - 1;
829 }
830 }
831 ctx->cursor_x = x;
832 ctx->cursor_y = y;
833}
834
835static void flanterm_fb_get_cursor_pos(struct flanterm_context *_ctx, size_t *x, size_t *y) {
836 struct flanterm_fb_context *ctx = (void *)_ctx;
837
838 *x = ctx->cursor_x >= _ctx->cols ? _ctx->cols - 1 : ctx->cursor_x;
839 *y = ctx->cursor_y >= _ctx->rows ? _ctx->rows - 1 : ctx->cursor_y;
840}
841
842static 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) {
843 struct flanterm_fb_context *ctx = (void *)_ctx;
844
845 if (old_x >= _ctx->cols || old_y >= _ctx->rows
846 || new_x >= _ctx->cols || new_y >= _ctx->rows) {
847 return;
848 }
849
850 size_t i = old_x + old_y * _ctx->cols;
851
852 struct flanterm_fb_char *c;
853 struct flanterm_fb_queue_item *q = ctx->map[i];
854 if (q != NULL) {
855 c = &q->c;
856 } else {
857 c = &ctx->grid[i];
858 }
859
860 push_to_queue(_ctx, c, x: new_x, y: new_y);
861}
862
863static void flanterm_fb_set_text_fg(struct flanterm_context *_ctx, size_t fg) {
864 struct flanterm_fb_context *ctx = (void *)_ctx;
865
866 ctx->text_fg = ctx->ansi_colours[fg];
867}
868
869static void flanterm_fb_set_text_bg(struct flanterm_context *_ctx, size_t bg) {
870 struct flanterm_fb_context *ctx = (void *)_ctx;
871
872 ctx->text_bg = ctx->ansi_colours[bg];
873}
874
875static void flanterm_fb_set_text_fg_bright(struct flanterm_context *_ctx, size_t fg) {
876 struct flanterm_fb_context *ctx = (void *)_ctx;
877
878 ctx->text_fg = ctx->ansi_bright_colours[fg];
879}
880
881static void flanterm_fb_set_text_bg_bright(struct flanterm_context *_ctx, size_t bg) {
882 struct flanterm_fb_context *ctx = (void *)_ctx;
883
884 ctx->text_bg = ctx->ansi_bright_colours[bg];
885}
886
887static void flanterm_fb_set_text_fg_rgb(struct flanterm_context *_ctx, uint32_t fg) {
888 struct flanterm_fb_context *ctx = (void *)_ctx;
889
890 ctx->text_fg = convert_colour(_ctx, colour: fg);
891}
892
893static void flanterm_fb_set_text_bg_rgb(struct flanterm_context *_ctx, uint32_t bg) {
894 struct flanterm_fb_context *ctx = (void *)_ctx;
895
896 ctx->text_bg = convert_colour(_ctx, colour: bg);
897}
898
899static void flanterm_fb_set_text_fg_default(struct flanterm_context *_ctx) {
900 struct flanterm_fb_context *ctx = (void *)_ctx;
901
902 ctx->text_fg = ctx->default_fg;
903}
904
905static void flanterm_fb_set_text_bg_default(struct flanterm_context *_ctx) {
906 struct flanterm_fb_context *ctx = (void *)_ctx;
907
908 ctx->text_bg = 0xffffffff;
909}
910
911static void flanterm_fb_set_text_fg_default_bright(struct flanterm_context *_ctx) {
912 struct flanterm_fb_context *ctx = (void *)_ctx;
913
914 ctx->text_fg = ctx->default_fg_bright;
915}
916
917static void flanterm_fb_set_text_bg_default_bright(struct flanterm_context *_ctx) {
918 struct flanterm_fb_context *ctx = (void *)_ctx;
919
920 ctx->text_bg = ctx->default_bg_bright;
921}
922
923static void draw_cursor(struct flanterm_context *_ctx) {
924 struct flanterm_fb_context *ctx = (void *)_ctx;
925
926 if (ctx->cursor_x >= _ctx->cols || ctx->cursor_y >= _ctx->rows) {
927 return;
928 }
929
930 size_t i = ctx->cursor_x + ctx->cursor_y * _ctx->cols;
931
932 struct flanterm_fb_char c;
933 struct flanterm_fb_queue_item *q = ctx->map[i];
934 if (q != NULL) {
935 c = q->c;
936 } else {
937 c = ctx->grid[i];
938 }
939 uint32_t tmp = c.fg;
940 c.fg = c.bg;
941 c.bg = tmp;
942 ctx->plot_char(_ctx, &c, ctx->cursor_x, ctx->cursor_y);
943 if (q != NULL) {
944 ctx->grid[i] = q->c;
945 ctx->map[i] = NULL;
946 }
947}
948
949static void flanterm_fb_double_buffer_flush(struct flanterm_context *_ctx) {
950 struct flanterm_fb_context *ctx = (void *)_ctx;
951
952 if (_ctx->cursor_enabled) {
953 draw_cursor(_ctx);
954 }
955
956 for (size_t i = 0; i < ctx->queue_i; i++) {
957 struct flanterm_fb_queue_item *q = &ctx->queue[i];
958 size_t offset = q->y * _ctx->cols + q->x;
959 if (ctx->map[offset] == NULL) {
960 continue;
961 }
962 ctx->plot_char(_ctx, &q->c, q->x, q->y);
963 ctx->grid[offset] = q->c;
964 ctx->map[offset] = NULL;
965 }
966
967 if ((ctx->old_cursor_x != ctx->cursor_x || ctx->old_cursor_y != ctx->cursor_y) || _ctx->cursor_enabled == false) {
968 if (ctx->old_cursor_x < _ctx->cols && ctx->old_cursor_y < _ctx->rows) {
969 ctx->plot_char(_ctx, &ctx->grid[ctx->old_cursor_x + ctx->old_cursor_y * _ctx->cols], ctx->old_cursor_x, ctx->old_cursor_y);
970 }
971 }
972
973 ctx->old_cursor_x = ctx->cursor_x;
974 ctx->old_cursor_y = ctx->cursor_y;
975
976 ctx->queue_i = 0;
977
978 if (ctx->flush_callback) {
979 ctx->flush_callback(ctx->framebuffer, ctx->pitch * ctx->phys_height);
980 }
981}
982
983static void flanterm_fb_raw_putchar(struct flanterm_context *_ctx, uint8_t c) {
984 struct flanterm_fb_context *ctx = (void *)_ctx;
985
986 if (ctx->cursor_x >= _ctx->cols) {
987 if (_ctx->wrap_enabled && (ctx->cursor_y < _ctx->scroll_bottom_margin - 1 || _ctx->scroll_enabled)) {
988 ctx->cursor_x = 0;
989 ctx->cursor_y++;
990 if (ctx->cursor_y == _ctx->scroll_bottom_margin) {
991 ctx->cursor_y--;
992 flanterm_fb_scroll(_ctx);
993 }
994 if (ctx->cursor_y >= _ctx->rows) {
995 ctx->cursor_y = _ctx->rows - 1;
996 }
997 } else {
998 ctx->cursor_x = _ctx->cols - 1;
999 }
1000 }
1001
1002 struct flanterm_fb_char ch;
1003 ch.c = c;
1004 ch.fg = ctx->text_fg;
1005 ch.bg = ctx->text_bg;
1006 push_to_queue(_ctx, c: &ch, x: ctx->cursor_x++, y: ctx->cursor_y);
1007}
1008
1009static void flanterm_fb_full_refresh(struct flanterm_context *_ctx) {
1010 struct flanterm_fb_context *ctx = (void *)_ctx;
1011
1012 uint32_t default_bg = ctx->default_bg;
1013
1014 for (size_t y = 0; y < ctx->height; y++) {
1015 for (size_t x = 0; x < ctx->width; x++) {
1016 size_t px, py;
1017 switch (ctx->rotation) {
1018 default:
1019 case FLANTERM_FB_ROTATE_0:
1020 px = x; py = y;
1021 break;
1022 case FLANTERM_FB_ROTATE_90:
1023 px = ctx->height - 1 - y; py = x;
1024 break;
1025 case FLANTERM_FB_ROTATE_180:
1026 px = ctx->width - 1 - x; py = ctx->height - 1 - y;
1027 break;
1028 case FLANTERM_FB_ROTATE_270:
1029 px = y; py = ctx->width - 1 - x;
1030 break;
1031 }
1032
1033 if (ctx->canvas != NULL) {
1034 ctx->framebuffer[py * (ctx->pitch / sizeof(uint32_t)) + px] = ctx->canvas[y * ctx->width + x];
1035 } else {
1036 ctx->framebuffer[py * (ctx->pitch / sizeof(uint32_t)) + px] = default_bg;
1037 }
1038 }
1039 }
1040
1041 for (size_t i = 0; i < (size_t)_ctx->rows * _ctx->cols; i++) {
1042 size_t x = i % _ctx->cols;
1043 size_t y = i / _ctx->cols;
1044
1045 ctx->plot_char(_ctx, &ctx->grid[i], x, y);
1046 }
1047
1048 if (_ctx->cursor_enabled) {
1049 draw_cursor(_ctx);
1050 }
1051
1052 if (ctx->flush_callback) {
1053 ctx->flush_callback(ctx->framebuffer, ctx->pitch * ctx->phys_height);
1054 }
1055}
1056
1057static void flanterm_fb_deinit(struct flanterm_context *_ctx, void (*_free)(void *, size_t)) {
1058 struct flanterm_fb_context *ctx = (void *)_ctx;
1059
1060 if (_free == NULL) {
1061#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
1062 if (bump_allocated_instance == true) {
1063 bump_alloc_ptr = 0;
1064 bump_alloc_base_offset_added = false;
1065 bump_allocated_instance = false;
1066 }
1067#endif
1068 return;
1069 }
1070
1071 _free(ctx->font_bits, ctx->font_bits_size);
1072 _free(ctx->font_bool, ctx->font_bool_size);
1073 _free(ctx->grid, ctx->grid_size);
1074 _free(ctx->queue, ctx->queue_size);
1075 _free(ctx->map, ctx->map_size);
1076
1077 if (ctx->canvas != NULL) {
1078 _free(ctx->canvas, ctx->canvas_size);
1079 }
1080
1081 _free(ctx, sizeof(struct flanterm_fb_context));
1082}
1083
1084struct flanterm_context *flanterm_fb_init(
1085 void *(*_malloc)(size_t),
1086 void (*_free)(void *, size_t),
1087 uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
1088 uint8_t red_mask_size, uint8_t red_mask_shift,
1089 uint8_t green_mask_size, uint8_t green_mask_shift,
1090 uint8_t blue_mask_size, uint8_t blue_mask_shift,
1091 uint32_t *canvas,
1092 uint32_t *ansi_colours, uint32_t *ansi_bright_colours,
1093 uint32_t *default_bg, uint32_t *default_fg,
1094 uint32_t *default_bg_bright, uint32_t *default_fg_bright,
1095 void *font, size_t font_width, size_t font_height, size_t font_spacing,
1096 size_t font_scale_x, size_t font_scale_y,
1097 size_t margin,
1098 int rotation
1099) {
1100 size_t phys_height = height;
1101
1102 if (rotation == FLANTERM_FB_ROTATE_90 || rotation == FLANTERM_FB_ROTATE_270) {
1103 size_t tmp = width;
1104 width = height;
1105 height = tmp;
1106 }
1107
1108 if (font_scale_x == 0 || font_scale_y == 0) {
1109 font_scale_x = 1;
1110 font_scale_y = 1;
1111 if (width >= (1920 + 1920 / 3) && height >= (1080 + 1080 / 3)) {
1112 font_scale_x = 2;
1113 font_scale_y = 2;
1114 }
1115 if (width >= (3840 + 3840 / 3) && height >= (2160 + 2160 / 3)) {
1116 font_scale_x = 4;
1117 font_scale_y = 4;
1118 }
1119 }
1120
1121 if (red_mask_size < 8 || red_mask_size != green_mask_size || red_mask_size != blue_mask_size) {
1122 return NULL;
1123 }
1124
1125 if (_malloc == NULL) {
1126#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
1127 if (bump_allocated_instance == true) {
1128 return NULL;
1129 }
1130 _malloc = bump_alloc;
1131 // Limit terminal size if needed
1132 if (width > FLANTERM_FB_WIDTH_LIMIT || height > FLANTERM_FB_HEIGHT_LIMIT) {
1133 size_t width_limit = width > FLANTERM_FB_WIDTH_LIMIT ? FLANTERM_FB_WIDTH_LIMIT : width;
1134 size_t height_limit = height > FLANTERM_FB_HEIGHT_LIMIT ? FLANTERM_FB_HEIGHT_LIMIT : height;
1135
1136 // width/height are logical (post-rotation) dimensions. For the
1137 // centering offset, we need to map back to the physical layout.
1138 // For ROTATE_0/180: logical height = physical rows (pitch stride),
1139 // logical width = physical cols (4-byte stride).
1140 // For ROTATE_90/270: logical height = physical cols (4-byte stride),
1141 // logical width = physical rows (pitch stride).
1142 if (rotation == FLANTERM_FB_ROTATE_90 || rotation == FLANTERM_FB_ROTATE_270) {
1143 framebuffer = (uint32_t *)((uintptr_t)framebuffer + ((((height / 2) - (height_limit / 2)) * 4) + (((width / 2) - (width_limit / 2)) * pitch)));
1144 } else {
1145 framebuffer = (uint32_t *)((uintptr_t)framebuffer + ((((height / 2) - (height_limit / 2)) * pitch) + (((width / 2) - (width_limit / 2)) * 4)));
1146 }
1147
1148 width = width_limit;
1149 height = height_limit;
1150
1151 // phys_height must reflect the physical row count for flush_callback.
1152 // For ROTATE_0/180, logical height = physical rows.
1153 // For ROTATE_90/270, logical width = physical rows.
1154 if (rotation == FLANTERM_FB_ROTATE_90 || rotation == FLANTERM_FB_ROTATE_270) {
1155 phys_height = width;
1156 } else {
1157 phys_height = height;
1158 }
1159 }
1160
1161 // Force disable canvas
1162 canvas = NULL;
1163#else
1164 return NULL;
1165#endif
1166 }
1167
1168 struct flanterm_fb_context *ctx = NULL;
1169 ctx = _malloc(sizeof(struct flanterm_fb_context));
1170 if (ctx == NULL) {
1171 goto fail;
1172 }
1173
1174 struct flanterm_context *_ctx = (void *)ctx;
1175 memset(ctx, 0, sizeof(struct flanterm_fb_context));
1176
1177 ctx->red_mask_size = red_mask_size;
1178 ctx->red_mask_shift = red_mask_shift + (red_mask_size - 8);
1179 ctx->green_mask_size = green_mask_size;
1180 ctx->green_mask_shift = green_mask_shift + (green_mask_size - 8);
1181 ctx->blue_mask_size = blue_mask_size;
1182 ctx->blue_mask_shift = blue_mask_shift + (blue_mask_size - 8);
1183
1184 if (ansi_colours != NULL) {
1185 for (size_t i = 0; i < 8; i++) {
1186 ctx->ansi_colours[i] = convert_colour(_ctx, colour: ansi_colours[i]);
1187 }
1188 } else {
1189 ctx->ansi_colours[0] = convert_colour(_ctx, colour: 0x00000000); // black
1190 ctx->ansi_colours[1] = convert_colour(_ctx, colour: 0x00aa0000); // red
1191 ctx->ansi_colours[2] = convert_colour(_ctx, colour: 0x0000aa00); // green
1192 ctx->ansi_colours[3] = convert_colour(_ctx, colour: 0x00aa5500); // brown
1193 ctx->ansi_colours[4] = convert_colour(_ctx, colour: 0x000000aa); // blue
1194 ctx->ansi_colours[5] = convert_colour(_ctx, colour: 0x00aa00aa); // magenta
1195 ctx->ansi_colours[6] = convert_colour(_ctx, colour: 0x0000aaaa); // cyan
1196 ctx->ansi_colours[7] = convert_colour(_ctx, colour: 0x00aaaaaa); // grey
1197 }
1198
1199 if (ansi_bright_colours != NULL) {
1200 for (size_t i = 0; i < 8; i++) {
1201 ctx->ansi_bright_colours[i] = convert_colour(_ctx, colour: ansi_bright_colours[i]);
1202 }
1203 } else {
1204 ctx->ansi_bright_colours[0] = convert_colour(_ctx, colour: 0x00555555); // black
1205 ctx->ansi_bright_colours[1] = convert_colour(_ctx, colour: 0x00ff5555); // red
1206 ctx->ansi_bright_colours[2] = convert_colour(_ctx, colour: 0x0055ff55); // green
1207 ctx->ansi_bright_colours[3] = convert_colour(_ctx, colour: 0x00ffff55); // brown
1208 ctx->ansi_bright_colours[4] = convert_colour(_ctx, colour: 0x005555ff); // blue
1209 ctx->ansi_bright_colours[5] = convert_colour(_ctx, colour: 0x00ff55ff); // magenta
1210 ctx->ansi_bright_colours[6] = convert_colour(_ctx, colour: 0x0055ffff); // cyan
1211 ctx->ansi_bright_colours[7] = convert_colour(_ctx, colour: 0x00ffffff); // grey
1212 }
1213
1214 if (default_bg != NULL) {
1215 ctx->default_bg = convert_colour(_ctx, colour: *default_bg);
1216 } else {
1217 ctx->default_bg = 0x00000000; // background (black)
1218 }
1219
1220 if (default_fg != NULL) {
1221 ctx->default_fg = convert_colour(_ctx, colour: *default_fg);
1222 } else {
1223 ctx->default_fg = convert_colour(_ctx, colour: 0x00aaaaaa); // foreground (grey)
1224 }
1225
1226 if (default_bg_bright != NULL) {
1227 ctx->default_bg_bright = convert_colour(_ctx, colour: *default_bg_bright);
1228 } else {
1229 ctx->default_bg_bright = convert_colour(_ctx, colour: 0x00555555); // background (black)
1230 }
1231
1232 if (default_fg_bright != NULL) {
1233 ctx->default_fg_bright = convert_colour(_ctx, colour: *default_fg_bright);
1234 } else {
1235 ctx->default_fg_bright = convert_colour(_ctx, colour: 0x00ffffff); // foreground (grey)
1236 }
1237
1238 ctx->text_fg = ctx->default_fg;
1239 ctx->text_bg = 0xffffffff;
1240 ctx->saved_state_text_fg = ctx->text_fg;
1241 ctx->saved_state_text_bg = ctx->text_bg;
1242
1243 ctx->rotation = rotation;
1244
1245 ctx->framebuffer = (void *)framebuffer;
1246 ctx->width = width;
1247 ctx->height = height;
1248 ctx->phys_height = phys_height;
1249 ctx->pitch = pitch;
1250
1251 // VGA fonts are always one byte per scanline regardless of font_width
1252#define FONT_BYTES (font_height * FLANTERM_FB_FONT_GLYPHS)
1253
1254 if (font != NULL) {
1255 ctx->font_width = font_width;
1256 ctx->font_height = font_height;
1257 ctx->font_bits_size = FONT_BYTES;
1258 ctx->font_bits = _malloc(ctx->font_bits_size);
1259 if (ctx->font_bits == NULL) {
1260 goto fail;
1261 }
1262 memcpy(ctx->font_bits, font, ctx->font_bits_size);
1263 } else {
1264 ctx->font_width = font_width = 8;
1265 ctx->font_height = font_height = 16;
1266 ctx->font_bits_size = FONT_BYTES;
1267 font_spacing = 1;
1268 ctx->font_bits = _malloc(ctx->font_bits_size);
1269 if (ctx->font_bits == NULL) {
1270 goto fail;
1271 }
1272 memcpy(ctx->font_bits, builtin_font, ctx->font_bits_size);
1273 }
1274
1275#undef FONT_BYTES
1276
1277 ctx->font_width += font_spacing;
1278
1279 ctx->font_bool_size = FLANTERM_FB_FONT_GLYPHS * font_height * ctx->font_width * sizeof(bool);
1280 ctx->font_bool = _malloc(ctx->font_bool_size);
1281 if (ctx->font_bool == NULL) {
1282 goto fail;
1283 }
1284
1285 for (size_t i = 0; i < FLANTERM_FB_FONT_GLYPHS; i++) {
1286 uint8_t *glyph = &ctx->font_bits[i * font_height];
1287
1288 for (size_t y = 0; y < font_height; y++) {
1289 // NOTE: the characters in VGA fonts are always one byte wide.
1290 // 9 dot wide fonts have 8 dots and one empty column, except
1291 // characters 0xC0-0xDF replicate column 9.
1292 for (size_t x = 0; x < 8; x++) {
1293 size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
1294
1295 if ((glyph[y] & (0x80 >> x))) {
1296 ctx->font_bool[offset] = true;
1297 } else {
1298 ctx->font_bool[offset] = false;
1299 }
1300 }
1301 // fill columns above 8 like VGA Line Graphics Mode does
1302 for (size_t x = 8; x < ctx->font_width; x++) {
1303 size_t offset = i * font_height * ctx->font_width + y * ctx->font_width + x;
1304
1305 if (i >= 0xc0 && i <= 0xdf) {
1306 ctx->font_bool[offset] = (glyph[y] & 1);
1307 } else {
1308 ctx->font_bool[offset] = false;
1309 }
1310 }
1311 }
1312 }
1313
1314 ctx->font_scale_x = font_scale_x;
1315 ctx->font_scale_y = font_scale_y;
1316
1317 ctx->glyph_width = ctx->font_width * font_scale_x;
1318 ctx->glyph_height = font_height * font_scale_y;
1319
1320 _ctx->cols = (ctx->width - margin * 2) / ctx->glyph_width;
1321 _ctx->rows = (ctx->height - margin * 2) / ctx->glyph_height;
1322
1323 ctx->offset_x = margin + ((ctx->width - margin * 2) % ctx->glyph_width) / 2;
1324 ctx->offset_y = margin + ((ctx->height - margin * 2) % ctx->glyph_height) / 2;
1325
1326 ctx->grid_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_char);
1327 ctx->grid = _malloc(ctx->grid_size);
1328 if (ctx->grid == NULL) {
1329 goto fail;
1330 }
1331 for (size_t i = 0; i < _ctx->rows * _ctx->cols; i++) {
1332 ctx->grid[i].c = ' ';
1333 ctx->grid[i].fg = ctx->text_fg;
1334 ctx->grid[i].bg = ctx->text_bg;
1335 }
1336
1337 ctx->queue_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item);
1338 ctx->queue = _malloc(ctx->queue_size);
1339 if (ctx->queue == NULL) {
1340 goto fail;
1341 }
1342 ctx->queue_i = 0;
1343 memset(ctx->queue, 0, ctx->queue_size);
1344
1345 ctx->map_size = _ctx->rows * _ctx->cols * sizeof(struct flanterm_fb_queue_item *);
1346 ctx->map = _malloc(ctx->map_size);
1347 if (ctx->map == NULL) {
1348 goto fail;
1349 }
1350 memset(ctx->map, 0, ctx->map_size);
1351
1352 if (canvas != NULL) {
1353 ctx->canvas_size = ctx->width * ctx->height * sizeof(uint32_t);
1354 ctx->canvas = _malloc(ctx->canvas_size);
1355 if (ctx->canvas == NULL) {
1356 goto fail;
1357 }
1358 for (size_t i = 0; i < ctx->width * ctx->height; i++) {
1359 ctx->canvas[i] = convert_colour(_ctx, colour: canvas[i]);
1360 }
1361 }
1362
1363 if (font_scale_x == 1 && font_scale_y == 1) {
1364 if (canvas == NULL) {
1365 ctx->plot_char = plot_char_unscaled_uncanvas;
1366 } else {
1367 ctx->plot_char = plot_char_unscaled_canvas;
1368 }
1369 } else {
1370 if (canvas == NULL) {
1371 ctx->plot_char = plot_char_scaled_uncanvas;
1372 } else {
1373 ctx->plot_char = plot_char_scaled_canvas;
1374 }
1375 }
1376
1377 _ctx->raw_putchar = flanterm_fb_raw_putchar;
1378 _ctx->clear = flanterm_fb_clear;
1379 _ctx->set_cursor_pos = flanterm_fb_set_cursor_pos;
1380 _ctx->get_cursor_pos = flanterm_fb_get_cursor_pos;
1381 _ctx->set_text_fg = flanterm_fb_set_text_fg;
1382 _ctx->set_text_bg = flanterm_fb_set_text_bg;
1383 _ctx->set_text_fg_bright = flanterm_fb_set_text_fg_bright;
1384 _ctx->set_text_bg_bright = flanterm_fb_set_text_bg_bright;
1385 _ctx->set_text_fg_rgb = flanterm_fb_set_text_fg_rgb;
1386 _ctx->set_text_bg_rgb = flanterm_fb_set_text_bg_rgb;
1387 _ctx->set_text_fg_default = flanterm_fb_set_text_fg_default;
1388 _ctx->set_text_bg_default = flanterm_fb_set_text_bg_default;
1389 _ctx->set_text_fg_default_bright = flanterm_fb_set_text_fg_default_bright;
1390 _ctx->set_text_bg_default_bright = flanterm_fb_set_text_bg_default_bright;
1391 _ctx->move_character = flanterm_fb_move_character;
1392 _ctx->scroll = flanterm_fb_scroll;
1393 _ctx->revscroll = flanterm_fb_revscroll;
1394 _ctx->swap_palette = flanterm_fb_swap_palette;
1395 _ctx->save_state = flanterm_fb_save_state;
1396 _ctx->restore_state = flanterm_fb_restore_state;
1397 _ctx->double_buffer_flush = flanterm_fb_double_buffer_flush;
1398 _ctx->full_refresh = flanterm_fb_full_refresh;
1399 _ctx->deinit = flanterm_fb_deinit;
1400
1401 flanterm_context_reinit(ctx: _ctx);
1402 flanterm_fb_full_refresh(_ctx);
1403
1404#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
1405 if (_malloc == bump_alloc) {
1406 bump_allocated_instance = true;
1407 }
1408#endif
1409
1410 return _ctx;
1411
1412fail:
1413 if (ctx == NULL) {
1414 return NULL;
1415 }
1416
1417#ifndef FLANTERM_FB_DISABLE_BUMP_ALLOC
1418 if (_malloc == bump_alloc) {
1419 bump_alloc_ptr = 0;
1420 bump_alloc_base_offset_added = false;
1421 return NULL;
1422 }
1423#endif
1424
1425 if (_free == NULL) {
1426 return NULL;
1427 }
1428
1429 if (ctx->canvas != NULL) {
1430 _free(ctx->canvas, ctx->canvas_size);
1431 }
1432 if (ctx->map != NULL) {
1433 _free(ctx->map, ctx->map_size);
1434 }
1435 if (ctx->queue != NULL) {
1436 _free(ctx->queue, ctx->queue_size);
1437 }
1438 if (ctx->grid != NULL) {
1439 _free(ctx->grid, ctx->grid_size);
1440 }
1441 if (ctx->font_bool != NULL) {
1442 _free(ctx->font_bool, ctx->font_bool_size);
1443 }
1444 if (ctx->font_bits != NULL) {
1445 _free(ctx->font_bits, ctx->font_bits_size);
1446 }
1447 if (ctx != NULL) {
1448 _free(ctx, sizeof(struct flanterm_fb_context));
1449 }
1450
1451 return NULL;
1452}
1453
1454void flanterm_fb_set_flush_callback(struct flanterm_context *_ctx, void (*flush_callback)(volatile void *address, size_t length)) {
1455 struct flanterm_fb_context *ctx = (void *)_ctx;
1456 ctx->flush_callback = flush_callback;
1457}
1458