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