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