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