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