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