/************************************************************************ * * SDL layer * * Copyright (C) 2007, Juergen Buchmueller * * Partially based on ShrinkTo5, Copyright (C) 2004-2005 * Ocrana and Andrei Grecu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ************************************************************************/ #include #include #include #include #include #include #include "util.h" #include "debug.h" #include "sdl.h" /** @brief structure to keep the informations about a PPM image */ typedef struct { /** @brief mode from the header */ int mode; /** @brief width in pixels */ int width; /** @brief height in pixels */ int height; /** @brief pixel mask */ int mask; /** @brief raw data */ uint8_t *data; } ppm_t; static int sdl_alloc_pane(sdl_t *sdl, sdl_pane_t pane, rect_t *prc); static int sdl_realloc_pane(sdl_t *sdl, sdl_pane_t pane, rect_t *prc); static int sdl_make_cursor(uint8_t *pix, uint8_t *msk, int w, int h, const char *src); static int sdl_putch(sdl_t *sdl, sdl_pane_t pane, int x, int y, int ch, int col); static uint32_t sdl_timer_callback(uint32_t interval); /** @brief hardcoded 6x10 character generator */ static const uint8_t chargen_6x10[] = { 0x00, 0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x21, 0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, 0x22, 0x00,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00, 0x23, 0x00,0x50,0x50,0xf8,0x50,0xf8,0x50,0x50,0x00,0x00, 0x24, 0x00,0x20,0x70,0xa0,0x70,0x28,0x70,0x20,0x00,0x00, 0x25, 0x00,0x48,0xa8,0x50,0x20,0x50,0xa8,0x90,0x00,0x00, 0x26, 0x00,0x40,0xa0,0xa0,0x40,0xa8,0x90,0x68,0x00,0x00, 0x27, 0x00,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00, 0x28, 0x00,0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00,0x00, 0x29, 0x00,0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00,0x00, 0x2a, 0x00,0x00,0x88,0x50,0xf8,0x50,0x88,0x00,0x00,0x00, 0x2b, 0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00,0x00, 0x2c, 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x20,0x40,0x00, 0x2d, 0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x00, 0x2e, 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x70,0x20,0x00, 0x2f, 0x00,0x08,0x08,0x10,0x20,0x40,0x80,0x80,0x00,0x00, 0x30, 0x00,0x20,0x50,0x88,0x88,0x88,0x50,0x20,0x00,0x00, 0x31, 0x00,0x20,0x60,0xa0,0x20,0x20,0x20,0xf8,0x00,0x00, 0x32, 0x00,0x70,0x88,0x08,0x30,0x40,0x80,0xf8,0x00,0x00, 0x33, 0x00,0xf8,0x08,0x10,0x30,0x08,0x88,0x70,0x00,0x00, 0x34, 0x00,0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,0x00, 0x35, 0x00,0xf8,0x80,0xb0,0xc8,0x08,0x88,0x70,0x00,0x00, 0x36, 0x00,0x30,0x40,0x80,0xb0,0xc8,0x88,0x70,0x00,0x00, 0x37, 0x00,0xf8,0x08,0x10,0x10,0x20,0x40,0x40,0x00,0x00, 0x38, 0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x00, 0x39, 0x00,0x70,0x88,0x98,0x68,0x08,0x10,0x60,0x00,0x00, 0x3a, 0x00,0x00,0x20,0x70,0x20,0x00,0x20,0x70,0x20,0x00, 0x3b, 0x00,0x00,0x20,0x70,0x20,0x00,0x30,0x20,0x40,0x00, 0x3c, 0x00,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00,0x00, 0x3d, 0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00, 0x3e, 0x00,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x00, 0x3f, 0x00,0x70,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, 0x40, 0x00,0x70,0x88,0x98,0xa8,0xb0,0x80,0x70,0x00,0x00, 0x41, 0x00,0x20,0x50,0x88,0x88,0xf8,0x88,0x88,0x00,0x00, 0x42, 0x00,0xf0,0x48,0x48,0x70,0x48,0x48,0xf0,0x00,0x00, 0x43, 0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,0x00, 0x44, 0x00,0xf0,0x48,0x48,0x48,0x48,0x48,0xf0,0x00,0x00, 0x45, 0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0x46, 0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00,0x00, 0x47, 0x00,0x70,0x88,0x80,0x80,0x98,0x88,0x70,0x00,0x00, 0x48, 0x00,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0x49, 0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x4a, 0x00,0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00,0x00, 0x4b, 0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00,0x00, 0x4c, 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x00, 0x4d, 0x00,0x88,0x88,0xd8,0xa8,0x88,0x88,0x88,0x00,0x00, 0x4e, 0x00,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88,0x00,0x00, 0x4f, 0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0x50, 0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x00, 0x51, 0x00,0x70,0x88,0x88,0x88,0x88,0xa8,0x70,0x08,0x00, 0x52, 0x00,0xf0,0x88,0x88,0xf0,0xa0,0x90,0x88,0x00,0x00, 0x53, 0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,0x00, 0x54, 0x00,0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, 0x55, 0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0x56, 0x00,0x88,0x88,0x88,0x50,0x50,0x50,0x20,0x00,0x00, 0x57, 0x00,0x88,0x88,0x88,0xa8,0xa8,0xd8,0x88,0x00,0x00, 0x58, 0x00,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x00, 0x59, 0x00,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00, 0x5a, 0x00,0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x00, 0x5b, 0x00,0x70,0x40,0x40,0x40,0x40,0x40,0x70,0x00,0x00, 0x5c, 0x00,0x80,0x80,0x40,0x20,0x10,0x08,0x08,0x00,0x00, 0x5d, 0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x70,0x00,0x00, 0x5e, 0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00, 0x5f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00, 0x60, 0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x61, 0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0x62, 0x00,0x80,0x80,0xb0,0xc8,0x88,0xc8,0xb0,0x00,0x00, 0x63, 0x00,0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00,0x00, 0x64, 0x00,0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00,0x00, 0x65, 0x00,0x00,0x00,0x70,0x88,0xf8,0x80,0x70,0x00,0x00, 0x66, 0x00,0x30,0x48,0x40,0xf0,0x40,0x40,0x40,0x00,0x00, 0x67, 0x00,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x88,0x70, 0x68, 0x00,0x80,0x80,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00, 0x69, 0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0x6a, 0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x48,0x48,0x30, 0x6b, 0x00,0x80,0x80,0x88,0x90,0xe0,0x90,0x88,0x00,0x00, 0x6c, 0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x6d, 0x00,0x00,0x00,0xd0,0xa8,0xa8,0xa8,0x88,0x00,0x00, 0x6e, 0x00,0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00, 0x6f, 0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0x70, 0x00,0x00,0x00,0xb0,0xc8,0x88,0xc8,0xb0,0x80,0x80, 0x71, 0x00,0x00,0x00,0x68,0x98,0x88,0x98,0x68,0x08,0x08, 0x72, 0x00,0x00,0x00,0xb0,0xc8,0x80,0x80,0x80,0x00,0x00, 0x73, 0x00,0x00,0x00,0x70,0x80,0x70,0x08,0xf0,0x00,0x00, 0x74, 0x00,0x40,0x40,0xf0,0x40,0x40,0x48,0x30,0x00,0x00, 0x75, 0x00,0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00, 0x76, 0x00,0x00,0x00,0x88,0x88,0x50,0x50,0x20,0x00,0x00, 0x77, 0x00,0x00,0x00,0x88,0x88,0xa8,0xa8,0x50,0x00,0x00, 0x78, 0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00, 0x79, 0x00,0x00,0x00,0x88,0x88,0x98,0x68,0x08,0x88,0x70, 0x7a, 0x00,0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00,0x00, 0x7b, 0x00,0x18,0x20,0x10,0x60,0x10,0x20,0x18,0x00,0x00, 0x7c, 0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, 0x7d, 0x00,0x60,0x10,0x20,0x18,0x20,0x10,0x60,0x00,0x00, 0x7e, 0x00,0x48,0xa8,0x90,0x00,0x00,0x00,0x00,0x00,0x00, 0xa0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa1, 0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x00, 0xa2, 0x00,0x00,0x20,0x78,0xa0,0xa0,0xa0,0x78,0x20,0x00, 0xa3, 0x00,0x30,0x48,0x40,0xe0,0x40,0x48,0xb0,0x00,0x00, 0xa4, 0x00,0x00,0x00,0x88,0x70,0x50,0x70,0x88,0x00,0x00, 0xa5, 0x00,0x88,0x88,0x50,0x20,0xf8,0x20,0x20,0x20,0x00, 0xa6, 0x00,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00,0x00, 0xa7, 0x00,0x70,0x80,0xe0,0x90,0x48,0x38,0x08,0x70,0x00, 0xa8, 0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa9, 0x00,0x70,0x88,0xa8,0xc8,0xa8,0x88,0x70,0x00,0x00, 0xaa, 0x00,0x38,0x48,0x58,0x28,0x00,0x78,0x00,0x00,0x00, 0xab, 0x00,0x00,0x00,0x24,0x48,0x90,0x48,0x24,0x00,0x00, 0xac, 0x00,0x00,0x00,0x00,0x78,0x08,0x00,0x00,0x00,0x00, 0xad, 0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00, 0xae, 0x00,0x70,0x88,0xe8,0xc8,0xc8,0x88,0x70,0x00,0x00, 0xaf, 0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb0, 0x00,0x20,0x50,0x20,0x00,0x00,0x00,0x00,0x00,0x00, 0xb1, 0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0xf8,0x00,0x00, 0xb2, 0x30,0x48,0x10,0x20,0x78,0x00,0x00,0x00,0x00,0x00, 0xb3, 0x70,0x08,0x30,0x08,0x70,0x00,0x00,0x00,0x00,0x00, 0xb4, 0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb5, 0x00,0x00,0x00,0x88,0x88,0x88,0xc8,0xb0,0x80,0x00, 0xb6, 0x00,0x78,0xe8,0xe8,0x68,0x28,0x28,0x28,0x00,0x00, 0xb7, 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00, 0xb8, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20, 0xb9, 0x20,0x60,0x20,0x20,0x70,0x00,0x00,0x00,0x00,0x00, 0xba, 0x00,0x30,0x48,0x48,0x30,0x00,0x78,0x00,0x00,0x00, 0xbb, 0x00,0x00,0x00,0x90,0x48,0x24,0x48,0x90,0x00,0x00, 0xbc, 0x40,0xc0,0x40,0x40,0xe4,0x0c,0x14,0x3c,0x04,0x00, 0xbd, 0x40,0xc0,0x40,0x40,0xe8,0x14,0x04,0x08,0x1c,0x00, 0xbe, 0xc0,0x20,0x40,0x20,0xc8,0x18,0x28,0x78,0x08,0x00, 0xbf, 0x00,0x20,0x00,0x20,0x20,0x40,0x88,0x70,0x00,0x00, 0xc0, 0x40,0x20,0x70,0x88,0x88,0xf8,0x88,0x88,0x00,0x00, 0xc1, 0x10,0x20,0x70,0x88,0x88,0xf8,0x88,0x88,0x00,0x00, 0xc2, 0x20,0x50,0x70,0x88,0x88,0xf8,0x88,0x88,0x00,0x00, 0xc3, 0x48,0xb0,0x70,0x88,0x88,0xf8,0x88,0x88,0x00,0x00, 0xc4, 0x50,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x00,0x00, 0xc5, 0x20,0x50,0x70,0x88,0x88,0xf8,0x88,0x88,0x00,0x00, 0xc6, 0x00,0x3c,0x50,0x90,0x9c,0xf0,0x90,0x9c,0x00,0x00, 0xc7, 0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x20,0x40, 0xc8, 0x40,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xc9, 0x10,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xca, 0x20,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xcb, 0x50,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xcc, 0x40,0x20,0x70,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xcd, 0x10,0x20,0x70,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xce, 0x20,0x50,0x70,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xcf, 0x50,0x00,0x70,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xd0, 0x00,0xf0,0x48,0x48,0xe8,0x48,0x48,0xf0,0x00,0x00, 0xd1, 0x28,0x50,0x88,0xc8,0xa8,0x98,0x88,0x88,0x00,0x00, 0xd2, 0x40,0x20,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd3, 0x10,0x20,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd4, 0x20,0x50,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd5, 0x28,0x50,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd6, 0x50,0x00,0x70,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd7, 0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00, 0xd8, 0x00,0x70,0x98,0x98,0xa8,0xc8,0xc8,0x70,0x00,0x00, 0xd9, 0x40,0x20,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xda, 0x10,0x20,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xdb, 0x20,0x50,0x00,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xdc, 0x50,0x00,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xdd, 0x10,0x20,0x88,0x88,0x50,0x20,0x20,0x20,0x00,0x00, 0xde, 0x00,0x80,0xf0,0x88,0xf0,0x80,0x80,0x80,0x00,0x00, 0xdf, 0x00,0x70,0x88,0x90,0xa0,0x90,0x88,0xb0,0x00,0x00, 0xe0, 0x40,0x20,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe1, 0x10,0x20,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe2, 0x20,0x50,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe3, 0x28,0x50,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe4, 0x00,0x50,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe5, 0x20,0x50,0x20,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe6, 0x00,0x00,0x00,0x78,0x14,0x7c,0x90,0x7c,0x00,0x00, 0xe7, 0x00,0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x20,0x40, 0xe8, 0x40,0x20,0x00,0x70,0x88,0xf8,0x80,0x70,0x00,0x00, 0xe9, 0x10,0x20,0x00,0x70,0x88,0xf8,0x80,0x70,0x00,0x00, 0xea, 0x20,0x50,0x00,0x70,0x88,0xf8,0x80,0x70,0x00,0x00, 0xeb, 0x00,0x50,0x00,0x70,0x88,0xf8,0x80,0x70,0x00,0x00, 0xec, 0x40,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xed, 0x20,0x40,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xee, 0x20,0x50,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xef, 0x00,0x50,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xf0, 0x00,0xc0,0x30,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf1, 0x28,0x50,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00, 0xf2, 0x40,0x20,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf3, 0x10,0x20,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf4, 0x20,0x50,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf5, 0x28,0x50,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf6, 0x00,0x50,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf7, 0x00,0x00,0x20,0x00,0xf8,0x00,0x20,0x00,0x00,0x00, 0xf8, 0x00,0x00,0x00,0x78,0x98,0xa8,0xc8,0xf0,0x00,0x00, 0xf9, 0x40,0x20,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00, 0xfa, 0x10,0x20,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00, 0xfb, 0x20,0x50,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00, 0xfc, 0x00,0x50,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00, 0xfd, 0x00,0x10,0x20,0x88,0x88,0x98,0x68,0x08,0x88,0x70, 0xfe, 0x00,0x00,0x80,0xf0,0x88,0x88,0x88,0xf0,0x80,0x80, 0xff, 0x00,0x50,0x00,0x88,0x88,0x98,0x68,0x08,0x88,0x70 }; /** @brief hardcoded 6x12 character generator */ static const uint8_t chargen_6x12[] = { 0x00, 0x00,0x00,0x00,0xa8,0x00,0x88,0x00,0x88,0x00,0xa8,0x00,0x00, 0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x21, 0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, 0x22, 0x00,0x00,0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x23, 0x00,0x00,0x00,0x00,0x50,0xf8,0x50,0x50,0xf8,0x50,0x00,0x00, 0x24, 0x00,0x00,0x20,0x70,0xa8,0xa0,0x70,0x28,0xa8,0x70,0x20,0x00, 0x25, 0x00,0x00,0x00,0xc8,0xc8,0x10,0x20,0x40,0x98,0x98,0x00,0x00, 0x26, 0x00,0x00,0x00,0x40,0xa0,0xa0,0x40,0xa8,0x90,0x68,0x00,0x00, 0x27, 0x00,0x00,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x28, 0x00,0x00,0x10,0x20,0x20,0x40,0x40,0x40,0x20,0x20,0x10,0x00, 0x29, 0x00,0x00,0x40,0x20,0x20,0x10,0x10,0x10,0x20,0x20,0x40,0x00, 0x2a, 0x00,0x00,0x00,0x20,0xa8,0x70,0x20,0x70,0xa8,0x20,0x00,0x00, 0x2b, 0x00,0x00,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00,0x00, 0x2c, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xc0,0x00, 0x2d, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x00, 0x2e, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00, 0x2f, 0x00,0x00,0x00,0x08,0x10,0x10,0x20,0x40,0x40,0x80,0x00,0x00, 0x30, 0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00, 0x31, 0x00,0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x32, 0x00,0x00,0x00,0x70,0x88,0x08,0x10,0x20,0x40,0xf8,0x00,0x00, 0x33, 0x00,0x00,0x00,0xf8,0x08,0x10,0x30,0x08,0x88,0x70,0x00,0x00, 0x34, 0x00,0x00,0x00,0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,0x00, 0x35, 0x00,0x00,0x00,0xf8,0x80,0xf0,0x08,0x08,0x88,0x70,0x00,0x00, 0x36, 0x00,0x00,0x00,0x30,0x40,0x80,0xf0,0x88,0x88,0x70,0x00,0x00, 0x37, 0x00,0x00,0x00,0xf8,0x08,0x10,0x10,0x20,0x20,0x20,0x00,0x00, 0x38, 0x00,0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x00, 0x39, 0x00,0x00,0x00,0x70,0x88,0x88,0x78,0x08,0x10,0x60,0x00,0x00, 0x3a, 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0x00,0x00, 0x3b, 0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x60,0x60,0xc0,0x00, 0x3c, 0x00,0x00,0x00,0x00,0x10,0x20,0x40,0x20,0x10,0x00,0x00,0x00, 0x3d, 0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00, 0x3e, 0x00,0x00,0x00,0x00,0x40,0x20,0x10,0x20,0x40,0x00,0x00,0x00, 0x3f, 0x00,0x00,0x00,0x70,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, 0x40, 0x00,0x00,0x00,0x70,0x88,0xb8,0xa8,0xb8,0x80,0x70,0x00,0x00, 0x41, 0x00,0x00,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0x42, 0x00,0x00,0x00,0xf0,0x48,0x48,0x70,0x48,0x48,0xf0,0x00,0x00, 0x43, 0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,0x00, 0x44, 0x00,0x00,0x00,0xf0,0x48,0x48,0x48,0x48,0x48,0xf0,0x00,0x00, 0x45, 0x00,0x00,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0x46, 0x00,0x00,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00,0x00, 0x47, 0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x98,0x88,0x70,0x00,0x00, 0x48, 0x00,0x00,0x00,0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0x49, 0x00,0x00,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x4a, 0x00,0x00,0x00,0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00,0x00, 0x4b, 0x00,0x00,0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00,0x00, 0x4c, 0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x00, 0x4d, 0x00,0x00,0x00,0x88,0xd8,0xa8,0x88,0x88,0x88,0x88,0x00,0x00, 0x4e, 0x00,0x00,0x00,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88,0x00,0x00, 0x4f, 0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0x50, 0x00,0x00,0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x00, 0x51, 0x00,0x00,0x00,0x70,0x88,0x88,0x88,0xa8,0x90,0x68,0x00,0x00, 0x52, 0x00,0x00,0x00,0xf0,0x88,0x88,0xf0,0xa0,0x90,0x88,0x00,0x00, 0x53, 0x00,0x00,0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,0x00, 0x54, 0x00,0x00,0x00,0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00, 0x55, 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0x56, 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x50,0x50,0x20,0x00,0x00, 0x57, 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0xa8,0xa8,0x50,0x00,0x00, 0x58, 0x00,0x00,0x00,0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x00, 0x59, 0x00,0x00,0x00,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00, 0x5a, 0x00,0x00,0x00,0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x00, 0x5b, 0x00,0x00,0x70,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x70,0x00, 0x5c, 0x00,0x00,0x00,0x80,0x40,0x40,0x20,0x10,0x10,0x08,0x00,0x00, 0x5d, 0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, 0x5e, 0x00,0x00,0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x5f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8, 0x60, 0x00,0x00,0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x61, 0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0x62, 0x00,0x00,0x00,0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x00,0x00, 0x63, 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00,0x00, 0x64, 0x00,0x00,0x00,0x08,0x08,0x78,0x88,0x88,0x88,0x78,0x00,0x00, 0x65, 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0xf0,0x80,0x70,0x00,0x00, 0x66, 0x00,0x00,0x00,0x30,0x48,0x40,0xe0,0x40,0x40,0x40,0x00,0x00, 0x67, 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x70, 0x68, 0x00,0x00,0x00,0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00,0x00, 0x69, 0x00,0x00,0x00,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0x6a, 0x00,0x00,0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x48,0x30, 0x6b, 0x00,0x00,0x00,0x80,0x80,0x88,0x90,0xe0,0x90,0x88,0x00,0x00, 0x6c, 0x00,0x00,0x00,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0x6d, 0x00,0x00,0x00,0x00,0x00,0xd0,0xa8,0xa8,0xa8,0xa8,0x00,0x00, 0x6e, 0x00,0x00,0x00,0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00, 0x6f, 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0x70, 0x00,0x00,0x00,0x00,0x00,0xf0,0x88,0x88,0x88,0xf0,0x80,0x80, 0x71, 0x00,0x00,0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x78,0x08,0x08, 0x72, 0x00,0x00,0x00,0x00,0x00,0xb0,0xc8,0x80,0x80,0x80,0x00,0x00, 0x73, 0x00,0x00,0x00,0x00,0x00,0x78,0x80,0x70,0x08,0xf0,0x00,0x00, 0x74, 0x00,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x20,0x18,0x00,0x00, 0x75, 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00,0x00, 0x76, 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,0x00, 0x77, 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0xa8,0xa8,0x50,0x00,0x00, 0x78, 0x00,0x00,0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00, 0x79, 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x40,0x80, 0x7a, 0x00,0x00,0x00,0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00,0x00, 0x7b, 0x00,0x00,0x10,0x20,0x20,0x20,0x40,0x20,0x20,0x20,0x10,0x00, 0x7c, 0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, 0x7d, 0x00,0x00,0x40,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x40,0x00, 0x7e, 0x00,0x00,0x00,0x00,0x00,0x48,0xa8,0x90,0x00,0x00,0x00,0x00, 0xa0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa1, 0x00,0x00,0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x00, 0xa2, 0x00,0x00,0x00,0x00,0x20,0x70,0xa8,0xa0,0xa8,0x70,0x20,0x00, 0xa3, 0x00,0x00,0x00,0x30,0x48,0x40,0xe0,0x40,0x48,0xb0,0x00,0x00, 0xa4, 0x00,0x00,0x00,0x00,0x00,0xa8,0x50,0x88,0x50,0xa8,0x00,0x00, 0xa5, 0x00,0x00,0x00,0x88,0x50,0xf8,0x20,0xf8,0x20,0x20,0x00,0x00, 0xa6, 0x00,0x00,0x00,0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00,0x00, 0xa7, 0x00,0x00,0x38,0x40,0x30,0x48,0x48,0x30,0x08,0x70,0x00,0x00, 0xa8, 0x00,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa9, 0x00,0x00,0x00,0x78,0x84,0x94,0xa4,0x94,0x84,0x78,0x00,0x00, 0xaa, 0x00,0x30,0x50,0x30,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00, 0xab, 0x00,0x00,0x00,0x00,0x00,0x28,0x50,0xa0,0x50,0x28,0x00,0x00, 0xac, 0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x08,0x08,0x00,0x00,0x00, 0xad, 0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00, 0xae, 0x00,0x00,0x00,0x78,0x84,0xb4,0xa4,0xa4,0x84,0x78,0x00,0x00, 0xaf, 0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb0, 0x00,0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb1, 0x00,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0xf8,0x00,0x00, 0xb2, 0x20,0x50,0x10,0x20,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb3, 0x60,0x10,0x20,0x10,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb4, 0x00,0x00,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb5, 0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x98,0xe8,0x80,0x80, 0xb6, 0x00,0x00,0x78,0xe8,0xe8,0xe8,0x68,0x28,0x28,0x28,0x00,0x00, 0xb7, 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00, 0xb8, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60, 0xb9, 0x20,0x60,0x20,0x20,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xba, 0x20,0x50,0x20,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xbb, 0x00,0x00,0x00,0x00,0x00,0xa0,0x50,0x28,0x50,0xa0,0x00,0x00, 0xbc, 0x40,0xc0,0x40,0x40,0x50,0x30,0x50,0x78,0x10,0x10,0x00,0x00, 0xbd, 0x40,0xc0,0x40,0x40,0x50,0x28,0x08,0x10,0x20,0x38,0x00,0x00, 0xbe, 0xc0,0x20,0x40,0x20,0xd0,0x30,0x50,0x78,0x10,0x10,0x00,0x00, 0xbf, 0x00,0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x88,0x70,0x00,0x00, 0xc0, 0x40,0x20,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0xc1, 0x10,0x20,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0xc2, 0x20,0x50,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0xc3, 0x68,0xb0,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0xc4, 0x00,0x50,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0xc5, 0x20,0x50,0x20,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x00, 0xc6, 0x00,0x00,0x00,0x78,0xa0,0xa0,0xf0,0xa0,0xa0,0xb8,0x00,0x00, 0xc7, 0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x10,0x60, 0xc8, 0x40,0x20,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xc9, 0x10,0x20,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xca, 0x20,0x50,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xcb, 0x00,0x50,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00,0x00, 0xcc, 0x40,0x20,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xcd, 0x10,0x20,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xce, 0x20,0x50,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xcf, 0x00,0x50,0x00,0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, 0xd0, 0x00,0x00,0x00,0x70,0x48,0x48,0xe8,0x48,0x48,0x70,0x00,0x00, 0xd1, 0x68,0xb0,0x00,0x88,0x88,0xc8,0xa8,0x98,0x88,0x88,0x00,0x00, 0xd2, 0x40,0x20,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd3, 0x10,0x20,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd4, 0x20,0x50,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd5, 0x68,0xb0,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd6, 0x00,0x50,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xd7, 0x00,0x00,0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00, 0xd8, 0x00,0x00,0x08,0x70,0x98,0xa8,0xa8,0xa8,0xc8,0x70,0x80,0x00, 0xd9, 0x40,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xda, 0x10,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xdb, 0x20,0x50,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xdc, 0x00,0x50,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xdd, 0x10,0x20,0x00,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00, 0xde, 0x00,0x00,0x00,0x40,0x70,0x48,0x48,0x48,0x70,0x40,0x00,0x00, 0xdf, 0x00,0x00,0x00,0x70,0x88,0x90,0xa0,0x90,0x88,0xb0,0x00,0x00, 0xe0, 0x00,0x00,0x40,0x20,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe1, 0x00,0x00,0x10,0x20,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe2, 0x00,0x00,0x20,0x50,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe3, 0x00,0x00,0x68,0xb0,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe4, 0x00,0x00,0x00,0x50,0x00,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe5, 0x00,0x00,0x20,0x50,0x20,0x70,0x08,0x78,0x88,0x78,0x00,0x00, 0xe6, 0x00,0x00,0x00,0x00,0x00,0x70,0x28,0x70,0xa0,0x78,0x00,0x00, 0xe7, 0x00,0x00,0x00,0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x10,0x60, 0xe8, 0x00,0x00,0x40,0x20,0x00,0x70,0x88,0xf0,0x80,0x70,0x00,0x00, 0xe9, 0x00,0x00,0x10,0x20,0x00,0x70,0x88,0xf0,0x80,0x70,0x00,0x00, 0xea, 0x00,0x00,0x20,0x50,0x00,0x70,0x88,0xf0,0x80,0x70,0x00,0x00, 0xeb, 0x00,0x00,0x00,0x50,0x00,0x70,0x88,0xf0,0x80,0x70,0x00,0x00, 0xec, 0x00,0x00,0x40,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xed, 0x00,0x00,0x10,0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xee, 0x00,0x00,0x20,0x50,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xef, 0x00,0x00,0x00,0x50,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, 0xf0, 0x00,0x50,0x20,0x50,0x08,0x78,0x88,0x88,0x88,0x70,0x00,0x00, 0xf1, 0x00,0x00,0x68,0xb0,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00, 0xf2, 0x00,0x00,0x40,0x20,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf3, 0x00,0x00,0x10,0x20,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf4, 0x00,0x00,0x20,0x50,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf5, 0x00,0x00,0x68,0xb0,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf6, 0x00,0x00,0x00,0x50,0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00, 0xf7, 0x00,0x00,0x00,0x00,0x20,0x00,0xf8,0x00,0x20,0x00,0x00,0x00, 0xf8, 0x00,0x00,0x00,0x00,0x00,0x78,0x98,0xa8,0xc8,0xf0,0x00,0x00, 0xf9, 0x00,0x00,0x40,0x20,0x00,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xfa, 0x00,0x00,0x10,0x20,0x00,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xfb, 0x00,0x00,0x20,0x50,0x00,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xfc, 0x00,0x00,0x00,0x50,0x00,0x88,0x88,0x88,0x88,0x70,0x00,0x00, 0xfd, 0x00,0x00,0x10,0x20,0x00,0x88,0x88,0x88,0x50,0x20,0x40,0x80, 0xfe, 0x00,0x00,0x00,0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x80,0x80, 0xff, 0x00,0x00,0x00,0x50,0x00,0x88,0x88,0x88,0x50,0x20,0x40,0x80 }; /** @brief hardcoded 7x13 character generator */ static const uint8_t chargen_7x13[] = { 0x00, 0x00,0x00,0xac,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0xd4,0x00,0x00, 0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x21, 0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00, 0x22, 0x00,0x00,0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x23, 0x00,0x00,0x00,0x28,0x28,0x7c,0x28,0x7c,0x28,0x28,0x00,0x00,0x00, 0x24, 0x00,0x00,0x00,0x10,0x3c,0x50,0x38,0x14,0x78,0x10,0x00,0x00,0x00, 0x25, 0x00,0x00,0x44,0xa4,0x48,0x10,0x10,0x20,0x48,0x94,0x88,0x00,0x00, 0x26, 0x00,0x00,0x00,0x00,0x60,0x90,0x90,0x60,0x94,0x88,0x74,0x00,0x00, 0x27, 0x00,0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x28, 0x00,0x00,0x08,0x10,0x10,0x20,0x20,0x20,0x10,0x10,0x08,0x00,0x00, 0x29, 0x00,0x00,0x20,0x10,0x10,0x08,0x08,0x08,0x10,0x10,0x20,0x00,0x00, 0x2a, 0x00,0x00,0x00,0x00,0x48,0x30,0xfc,0x30,0x48,0x00,0x00,0x00,0x00, 0x2b, 0x00,0x00,0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00,0x00, 0x2c, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x30,0x40,0x00, 0x2d, 0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00, 0x2e, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x10,0x00, 0x2f, 0x00,0x00,0x04,0x04,0x08,0x08,0x10,0x20,0x20,0x40,0x40,0x00,0x00, 0x30, 0x00,0x00,0x30,0x48,0x84,0x84,0x84,0x84,0x84,0x48,0x30,0x00,0x00, 0x31, 0x00,0x00,0x10,0x30,0x50,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x32, 0x00,0x00,0x78,0x84,0x84,0x04,0x08,0x30,0x40,0x80,0xfc,0x00,0x00, 0x33, 0x00,0x00,0xfc,0x04,0x08,0x10,0x38,0x04,0x04,0x84,0x78,0x00,0x00, 0x34, 0x00,0x00,0x08,0x18,0x28,0x48,0x88,0x88,0xfc,0x08,0x08,0x00,0x00, 0x35, 0x00,0x00,0xfc,0x80,0x80,0xb8,0xc4,0x04,0x04,0x84,0x78,0x00,0x00, 0x36, 0x00,0x00,0x38,0x40,0x80,0x80,0xb8,0xc4,0x84,0x84,0x78,0x00,0x00, 0x37, 0x00,0x00,0xfc,0x04,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00, 0x38, 0x00,0x00,0x78,0x84,0x84,0x84,0x78,0x84,0x84,0x84,0x78,0x00,0x00, 0x39, 0x00,0x00,0x78,0x84,0x84,0x8c,0x74,0x04,0x04,0x08,0x70,0x00,0x00, 0x3a, 0x00,0x00,0x00,0x00,0x10,0x38,0x10,0x00,0x00,0x10,0x38,0x10,0x00, 0x3b, 0x00,0x00,0x00,0x00,0x10,0x38,0x10,0x00,0x00,0x38,0x30,0x40,0x00, 0x3c, 0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, 0x3d, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xfc,0x00,0x00,0x00,0x00, 0x3e, 0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, 0x3f, 0x00,0x00,0x78,0x84,0x84,0x04,0x08,0x10,0x10,0x00,0x10,0x00,0x00, 0x40, 0x00,0x00,0x78,0x84,0x84,0x9c,0xa4,0xac,0x94,0x80,0x78,0x00,0x00, 0x41, 0x00,0x00,0x30,0x48,0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x00,0x00, 0x42, 0x00,0x00,0xf8,0x44,0x44,0x44,0x78,0x44,0x44,0x44,0xf8,0x00,0x00, 0x43, 0x00,0x00,0x78,0x84,0x80,0x80,0x80,0x80,0x80,0x84,0x78,0x00,0x00, 0x44, 0x00,0x00,0xf8,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0xf8,0x00,0x00, 0x45, 0x00,0x00,0xfc,0x80,0x80,0x80,0xf0,0x80,0x80,0x80,0xfc,0x00,0x00, 0x46, 0x00,0x00,0xfc,0x80,0x80,0x80,0xf0,0x80,0x80,0x80,0x80,0x00,0x00, 0x47, 0x00,0x00,0x78,0x84,0x80,0x80,0x80,0x9c,0x84,0x8c,0x74,0x00,0x00, 0x48, 0x00,0x00,0x84,0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0x49, 0x00,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x4a, 0x00,0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x08,0x88,0x70,0x00,0x00, 0x4b, 0x00,0x00,0x84,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x84,0x00,0x00, 0x4c, 0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xfc,0x00,0x00, 0x4d, 0x00,0x00,0x84,0xcc,0xcc,0xb4,0xb4,0x84,0x84,0x84,0x84,0x00,0x00, 0x4e, 0x00,0x00,0x84,0x84,0xc4,0xa4,0x94,0x8c,0x84,0x84,0x84,0x00,0x00, 0x4f, 0x00,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0x50, 0x00,0x00,0xf8,0x84,0x84,0x84,0xf8,0x80,0x80,0x80,0x80,0x00,0x00, 0x51, 0x00,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0xa4,0x94,0x78,0x04,0x00, 0x52, 0x00,0x00,0xf8,0x84,0x84,0x84,0xf8,0xa0,0x90,0x88,0x84,0x00,0x00, 0x53, 0x00,0x00,0x78,0x84,0x80,0x80,0x78,0x04,0x04,0x84,0x78,0x00,0x00, 0x54, 0x00,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0x55, 0x00,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0x56, 0x00,0x00,0x84,0x84,0x84,0x48,0x48,0x48,0x30,0x30,0x30,0x00,0x00, 0x57, 0x00,0x00,0x84,0x84,0x84,0x84,0xb4,0xb4,0xcc,0xcc,0x84,0x00,0x00, 0x58, 0x00,0x00,0x84,0x84,0x48,0x48,0x30,0x48,0x48,0x84,0x84,0x00,0x00, 0x59, 0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0x5a, 0x00,0x00,0xfc,0x04,0x08,0x10,0x30,0x20,0x40,0x80,0xfc,0x00,0x00, 0x5b, 0x00,0x78,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x78,0x00, 0x5c, 0x00,0x00,0x40,0x40,0x20,0x20,0x10,0x08,0x08,0x04,0x04,0x00,0x00, 0x5d, 0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78,0x00, 0x5e, 0x00,0x00,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x5f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00, 0x60, 0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x61, 0x00,0x00,0x00,0x00,0x00,0x78,0x04,0x7c,0x84,0x8c,0x74,0x00,0x00, 0x62, 0x00,0x00,0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0xc4,0xb8,0x00,0x00, 0x63, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x80,0x80,0x84,0x78,0x00,0x00, 0x64, 0x00,0x00,0x04,0x04,0x04,0x74,0x8c,0x84,0x84,0x8c,0x74,0x00,0x00, 0x65, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0x66, 0x00,0x00,0x38,0x44,0x40,0x40,0xf0,0x40,0x40,0x40,0x40,0x00,0x00, 0x67, 0x00,0x00,0x00,0x00,0x00,0x74,0x88,0x88,0x70,0x80,0x78,0x84,0x78, 0x68, 0x00,0x00,0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84,0x84,0x00,0x00, 0x69, 0x00,0x00,0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x6a, 0x00,0x00,0x00,0x04,0x00,0x0c,0x04,0x04,0x04,0x04,0x44,0x44,0x38, 0x6b, 0x00,0x00,0x80,0x80,0x80,0x88,0x90,0xe0,0x90,0x88,0x84,0x00,0x00, 0x6c, 0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x6d, 0x00,0x00,0x00,0x00,0x00,0x68,0x54,0x54,0x54,0x54,0x44,0x00,0x00, 0x6e, 0x00,0x00,0x00,0x00,0x00,0xb8,0xc4,0x84,0x84,0x84,0x84,0x00,0x00, 0x6f, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0x70, 0x00,0x00,0x00,0x00,0x00,0xb8,0xc4,0x84,0xc4,0xb8,0x80,0x80,0x80, 0x71, 0x00,0x00,0x00,0x00,0x00,0x74,0x8c,0x84,0x8c,0x74,0x04,0x04,0x04, 0x72, 0x00,0x00,0x00,0x00,0x00,0xb8,0x44,0x40,0x40,0x40,0x40,0x00,0x00, 0x73, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x60,0x18,0x84,0x78,0x00,0x00, 0x74, 0x00,0x00,0x00,0x40,0x40,0xf0,0x40,0x40,0x40,0x44,0x38,0x00,0x00, 0x75, 0x00,0x00,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0x76, 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x00,0x00, 0x77, 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x54,0x54,0x54,0x28,0x00,0x00, 0x78, 0x00,0x00,0x00,0x00,0x00,0x84,0x48,0x30,0x30,0x48,0x84,0x00,0x00, 0x79, 0x00,0x00,0x00,0x00,0x00,0x84,0x84,0x84,0x8c,0x74,0x04,0x84,0x78, 0x7a, 0x00,0x00,0x00,0x00,0x00,0xfc,0x08,0x10,0x20,0x40,0xfc,0x00,0x00, 0x7b, 0x00,0x1c,0x20,0x20,0x20,0x10,0x60,0x10,0x20,0x20,0x20,0x1c,0x00, 0x7c, 0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0x7d, 0x00,0x70,0x08,0x08,0x08,0x10,0x0c,0x10,0x08,0x08,0x08,0x70,0x00, 0x7e, 0x00,0x00,0x24,0x54,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa1, 0x00,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0xa2, 0x00,0x00,0x10,0x38,0x54,0x50,0x50,0x54,0x38,0x10,0x00,0x00,0x00, 0xa3, 0x00,0x00,0x38,0x44,0x40,0x40,0xe0,0x40,0x40,0x44,0xb8,0x00,0x00, 0xa4, 0x00,0x00,0x00,0x00,0x84,0x78,0x48,0x48,0x78,0x84,0x00,0x00,0x00, 0xa5, 0x00,0x00,0x88,0x88,0x50,0x50,0xf8,0x20,0xf8,0x20,0x20,0x00,0x00, 0xa6, 0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x00,0x00, 0xa7, 0x00,0x30,0x48,0x40,0x30,0x48,0x48,0x30,0x08,0x48,0x30,0x00,0x00, 0xa8, 0x00,0x00,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa9, 0x00,0x00,0x78,0x84,0xb4,0xa4,0xa4,0xa4,0xb4,0x84,0x78,0x00,0x00, 0xaa, 0x00,0x00,0x38,0x04,0x3c,0x44,0x3c,0x00,0x7c,0x00,0x00,0x00,0x00, 0xab, 0x00,0x00,0x00,0x14,0x28,0x50,0xa0,0x50,0x28,0x14,0x00,0x00,0x00, 0xac, 0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x04,0x04,0x00,0x00,0x00,0x00, 0xad, 0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00, 0xae, 0x00,0x00,0x78,0x84,0xb4,0xac,0xac,0xb4,0xac,0x84,0x78,0x00,0x00, 0xaf, 0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb0, 0x00,0x00,0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb1, 0x00,0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00,0x00, 0xb2, 0x00,0x20,0x50,0x10,0x20,0x40,0x70,0x00,0x00,0x00,0x00,0x00,0x00, 0xb3, 0x00,0x70,0x10,0x20,0x10,0x50,0x20,0x00,0x00,0x00,0x00,0x00,0x00, 0xb4, 0x00,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb5, 0x00,0x00,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0xcc,0xb4,0x80,0x00, 0xb6, 0x00,0x00,0x7c,0xe8,0xe8,0xe8,0x68,0x28,0x28,0x28,0x28,0x00,0x00, 0xb7, 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00, 0xb8, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20, 0xb9, 0x00,0x20,0x60,0x20,0x20,0x20,0x70,0x00,0x00,0x00,0x00,0x00,0x00, 0xba, 0x00,0x00,0x30,0x48,0x48,0x30,0x00,0x78,0x00,0x00,0x00,0x00,0x00, 0xbb, 0x00,0x00,0x00,0xa0,0x50,0x28,0x14,0x28,0x50,0xa0,0x00,0x00,0x00, 0xbc, 0x00,0x40,0xc0,0x40,0x40,0x44,0xec,0x14,0x14,0x1c,0x04,0x00,0x00, 0xbd, 0x00,0x40,0xc0,0x40,0x40,0x48,0xf4,0x04,0x08,0x10,0x1c,0x00,0x00, 0xbe, 0x00,0xe0,0x20,0x40,0x20,0xa4,0x4c,0x14,0x14,0x1c,0x04,0x00,0x00, 0xbf, 0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x80,0x84,0x84,0x78,0x00,0x00, 0xc0, 0x00,0x20,0x10,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00, 0xc1, 0x00,0x10,0x20,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00, 0xc2, 0x00,0x30,0x48,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00, 0xc3, 0x00,0x64,0x98,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00, 0xc4, 0x00,0x48,0x48,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00, 0xc5, 0x00,0x30,0x48,0x30,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x00,0x00, 0xc6, 0x00,0x00,0x5c,0xa0,0xa0,0xa0,0xb8,0xe0,0xa0,0xa0,0xbc,0x00,0x00, 0xc7, 0x00,0x00,0x78,0x84,0x80,0x80,0x80,0x80,0x80,0x84,0x78,0x10,0x20, 0xc8, 0x00,0x20,0x10,0x00,0xfc,0x80,0x80,0xf0,0x80,0x80,0xfc,0x00,0x00, 0xc9, 0x00,0x10,0x20,0x00,0xfc,0x80,0x80,0xf0,0x80,0x80,0xfc,0x00,0x00, 0xca, 0x00,0x30,0x48,0x00,0xfc,0x80,0x80,0xf0,0x80,0x80,0xfc,0x00,0x00, 0xcb, 0x00,0x48,0x48,0x00,0xfc,0x80,0x80,0xf0,0x80,0x80,0xfc,0x00,0x00, 0xcc, 0x00,0x20,0x10,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xcd, 0x00,0x10,0x20,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xce, 0x00,0x10,0x28,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xcf, 0x00,0x44,0x44,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xd0, 0x00,0x00,0xf8,0x44,0x44,0x44,0xe4,0x44,0x44,0x44,0xf8,0x00,0x00, 0xd1, 0x00,0x64,0x98,0x00,0x84,0xc4,0xa4,0xa4,0x94,0x8c,0x84,0x00,0x00, 0xd2, 0x00,0x20,0x10,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd3, 0x00,0x10,0x20,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd4, 0x00,0x30,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd5, 0x00,0x64,0x98,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd6, 0x00,0x48,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd7, 0x00,0x00,0x00,0x00,0x84,0x48,0x30,0x30,0x48,0x84,0x00,0x00,0x00, 0xd8, 0x00,0x04,0x78,0x8c,0x94,0x94,0xa4,0xa4,0xa4,0xc4,0x78,0x80,0x00, 0xd9, 0x00,0x20,0x10,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xda, 0x00,0x10,0x20,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xdb, 0x00,0x30,0x48,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xdc, 0x00,0x48,0x48,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xdd, 0x00,0x08,0x10,0x00,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00,0x00, 0xde, 0x00,0x00,0x80,0xf8,0x84,0x84,0x84,0xf8,0x80,0x80,0x80,0x00,0x00, 0xdf, 0x00,0x00,0x30,0x48,0x48,0x50,0x50,0x48,0x44,0x44,0x58,0x00,0x00, 0xe0, 0x00,0x00,0x20,0x10,0x00,0x78,0x04,0x7c,0x84,0x8c,0x74,0x00,0x00, 0xe1, 0x00,0x00,0x10,0x20,0x00,0x78,0x04,0x7c,0x84,0x8c,0x74,0x00,0x00, 0xe2, 0x00,0x00,0x30,0x48,0x00,0x78,0x04,0x7c,0x84,0x8c,0x74,0x00,0x00, 0xe3, 0x00,0x00,0x64,0x98,0x00,0x78,0x04,0x7c,0x84,0x8c,0x74,0x00,0x00, 0xe4, 0x00,0x00,0x48,0x48,0x00,0x78,0x04,0x7c,0x84,0x8c,0x74,0x00,0x00, 0xe5, 0x00,0x30,0x48,0x30,0x00,0x78,0x04,0x7c,0x84,0x8c,0x74,0x00,0x00, 0xe6, 0x00,0x00,0x00,0x00,0x00,0x68,0x14,0x7c,0x90,0x94,0x68,0x00,0x00, 0xe7, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x80,0x80,0x84,0x78,0x10,0x20, 0xe8, 0x00,0x00,0x20,0x10,0x00,0x78,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xe9, 0x00,0x00,0x10,0x20,0x00,0x78,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xea, 0x00,0x00,0x30,0x48,0x00,0x78,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xeb, 0x00,0x00,0x48,0x48,0x00,0x78,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xec, 0x00,0x00,0x20,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xed, 0x00,0x00,0x10,0x20,0x00,0x30,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xee, 0x00,0x00,0x30,0x48,0x00,0x30,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xef, 0x00,0x00,0x48,0x48,0x00,0x30,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xf0, 0x00,0x48,0x30,0x50,0x08,0x78,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf1, 0x00,0x00,0x64,0x98,0x00,0xb8,0xc4,0x84,0x84,0x84,0x84,0x00,0x00, 0xf2, 0x00,0x00,0x20,0x10,0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf3, 0x00,0x00,0x10,0x20,0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf4, 0x00,0x00,0x30,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf5, 0x00,0x00,0x64,0x98,0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf6, 0x00,0x00,0x48,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf7, 0x00,0x00,0x00,0x10,0x10,0x00,0x7c,0x00,0x10,0x10,0x00,0x00,0x00, 0xf8, 0x00,0x00,0x00,0x00,0x04,0x78,0x8c,0x94,0xa4,0xc4,0x78,0x80,0x00, 0xf9, 0x00,0x00,0x20,0x10,0x00,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfa, 0x00,0x00,0x10,0x20,0x00,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfb, 0x00,0x00,0x30,0x48,0x00,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfc, 0x00,0x00,0x48,0x48,0x00,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfd, 0x00,0x00,0x10,0x20,0x00,0x84,0x84,0x84,0x8c,0x74,0x04,0x84,0x78, 0xfe, 0x00,0x00,0x00,0x80,0x80,0xb8,0xc4,0x84,0x84,0xc4,0xb8,0x80,0x80, 0xff, 0x00,0x00,0x48,0x48,0x00,0x84,0x84,0x84,0x8c,0x74,0x04,0x84,0x78 }; /** @brief hardcoded character generator */ static const uint8_t chargen_7x14[] = { 0x00, 0x00,0xb4,0x84,0x00,0x84,0x84,0x00,0x84,0x84,0x00,0x84,0xb4,0x00,0x00, 0x20, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x21, 0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x10,0x00,0x00, 0x22, 0x00,0x28,0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x23, 0x00,0x00,0x28,0x28,0x28,0x7c,0x28,0x28,0x7c,0x28,0x28,0x28,0x00,0x00, 0x24, 0x00,0x00,0x10,0x78,0x94,0x94,0x50,0x38,0x14,0x94,0x94,0x78,0x10,0x00, 0x25, 0x00,0x00,0x64,0x94,0x98,0x70,0x10,0x20,0x38,0x64,0xa4,0x98,0x00,0x00, 0x26, 0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x64,0x94,0x88,0x98,0x64,0x00,0x00, 0x27, 0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x28, 0x00,0x04,0x08,0x10,0x10,0x20,0x20,0x20,0x20,0x20,0x10,0x10,0x08,0x04, 0x29, 0x00,0x40,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x40, 0x2a, 0x00,0x00,0x00,0x00,0x10,0x54,0x38,0x10,0x38,0x54,0x10,0x00,0x00,0x00, 0x2b, 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x00,0x00,0x00, 0x2c, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x10,0x10,0x20, 0x2d, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00, 0x2e, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,0x10,0x00, 0x2f, 0x00,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80, 0x30, 0x00,0x00,0x30,0x48,0x84,0x84,0x84,0x84,0x84,0x84,0x48,0x30,0x00,0x00, 0x31, 0x00,0x00,0x10,0x30,0x50,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x32, 0x00,0x00,0x78,0x84,0x84,0x04,0x08,0x08,0x10,0x20,0x40,0xfc,0x00,0x00, 0x33, 0x00,0x00,0xfc,0x04,0x08,0x10,0x38,0x04,0x04,0x84,0x84,0x78,0x00,0x00, 0x34, 0x00,0x00,0x08,0x18,0x28,0x28,0x48,0x48,0x88,0xfc,0x08,0x08,0x00,0x00, 0x35, 0x00,0x00,0xfc,0x80,0x80,0xf8,0x84,0x04,0x04,0x84,0x84,0x78,0x00,0x00, 0x36, 0x00,0x00,0x38,0x40,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84,0x78,0x00,0x00, 0x37, 0x00,0x00,0xfc,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x00,0x00, 0x38, 0x00,0x00,0x78,0x84,0x84,0x48,0x30,0x48,0x84,0x84,0x84,0x78,0x00,0x00, 0x39, 0x00,0x00,0x78,0x84,0x84,0x84,0x8c,0x74,0x04,0x84,0x88,0x70,0x00,0x00, 0x3a, 0x00,0x00,0x00,0x00,0x10,0x38,0x10,0x00,0x00,0x10,0x38,0x10,0x00,0x00, 0x3b, 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x30,0x10,0x10,0x20,0x00, 0x3c, 0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, 0x3d, 0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00, 0x3e, 0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, 0x3f, 0x00,0x00,0x78,0x84,0x84,0x08,0x10,0x10,0x10,0x00,0x10,0x10,0x00,0x00, 0x40, 0x00,0x00,0x38,0x44,0x9c,0xa4,0xa4,0xa4,0xa4,0x9c,0x40,0x3c,0x00,0x00, 0x41, 0x00,0x00,0x30,0x48,0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0x42, 0x00,0x00,0xf0,0x88,0x84,0x88,0xf0,0x88,0x84,0x84,0x88,0xf0,0x00,0x00, 0x43, 0x00,0x00,0x78,0x84,0x84,0x80,0x80,0x80,0x80,0x84,0x84,0x78,0x00,0x00, 0x44, 0x00,0x00,0xf0,0x88,0x84,0x84,0x84,0x84,0x84,0x84,0x88,0xf0,0x00,0x00, 0x45, 0x00,0x00,0xfc,0x80,0x80,0x80,0xf0,0x80,0x80,0x80,0x80,0xfc,0x00,0x00, 0x46, 0x00,0x00,0xfc,0x80,0x80,0x80,0xf0,0x80,0x80,0x80,0x80,0x80,0x00,0x00, 0x47, 0x00,0x00,0x78,0x84,0x84,0x80,0x80,0x9c,0x84,0x84,0x8c,0x74,0x00,0x00, 0x48, 0x00,0x00,0x84,0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x84,0x00,0x00, 0x49, 0x00,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x4a, 0x00,0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x08,0x88,0x88,0x70,0x00,0x00, 0x4b, 0x00,0x00,0x84,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x84,0x84,0x00,0x00, 0x4c, 0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xfc,0x00,0x00, 0x4d, 0x00,0x00,0x84,0xcc,0xcc,0xb4,0xb4,0x84,0x84,0x84,0x84,0x84,0x00,0x00, 0x4e, 0x00,0x00,0x84,0x84,0xc4,0xc4,0xa4,0x94,0x8c,0x8c,0x84,0x84,0x00,0x00, 0x4f, 0x00,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0x50, 0x00,0x00,0xf8,0x84,0x84,0x84,0x84,0xf8,0x80,0x80,0x80,0x80,0x00,0x00, 0x51, 0x00,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0xe4,0x94,0x8c,0x78,0x08,0x04, 0x52, 0x00,0x00,0xf8,0x84,0x84,0x84,0x84,0xf8,0x90,0x88,0x84,0x84,0x00,0x00, 0x53, 0x00,0x00,0x78,0x84,0x84,0x80,0x60,0x18,0x04,0x84,0x84,0x78,0x00,0x00, 0x54, 0x00,0x00,0xfe,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0x55, 0x00,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0x56, 0x00,0x00,0x84,0x84,0x84,0x84,0x48,0x48,0x48,0x30,0x30,0x30,0x00,0x00, 0x57, 0x00,0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x54,0x54,0x54,0x28,0x00,0x00, 0x58, 0x00,0x00,0x84,0x84,0x48,0x48,0x30,0x30,0x48,0x48,0x84,0x84,0x00,0x00, 0x59, 0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0x5a, 0x00,0x00,0xfc,0x04,0x08,0x10,0x10,0x20,0x40,0x40,0x80,0xfc,0x00,0x00, 0x5b, 0x00,0x3c,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c, 0x5c, 0x00,0x80,0x80,0x40,0x40,0x20,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04, 0x5d, 0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x78, 0x5e, 0x00,0x30,0x48,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x5f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, 0x60, 0x00,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x61, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x04,0x7c,0x84,0x84,0x7c,0x00,0x00, 0x62, 0x00,0x00,0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84,0xc4,0xb8,0x00,0x00, 0x63, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x80,0x80,0x80,0x84,0x78,0x00,0x00, 0x64, 0x00,0x00,0x04,0x04,0x04,0x74,0x8c,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0x65, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0x66, 0x00,0x00,0x18,0x24,0x20,0x20,0xf8,0x20,0x20,0x20,0x20,0x20,0x00,0x00, 0x67, 0x00,0x00,0x00,0x00,0x00,0x74,0x88,0x88,0x88,0x70,0x40,0xb8,0x84,0x78, 0x68, 0x00,0x00,0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84,0x84,0x84,0x00,0x00, 0x69, 0x00,0x00,0x10,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x6a, 0x00,0x00,0x04,0x04,0x00,0x0c,0x04,0x04,0x04,0x04,0x04,0x44,0x44,0x38, 0x6b, 0x00,0x00,0x80,0x80,0x80,0x88,0x90,0xa0,0xe0,0x90,0x88,0x84,0x00,0x00, 0x6c, 0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0x6d, 0x00,0x00,0x00,0x00,0x00,0x68,0x54,0x54,0x54,0x54,0x54,0x44,0x00,0x00, 0x6e, 0x00,0x00,0x00,0x00,0x00,0xb8,0xc4,0x84,0x84,0x84,0x84,0x84,0x00,0x00, 0x6f, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0x70, 0x00,0x00,0x00,0x00,0x00,0xb8,0xc4,0x84,0x84,0x84,0xc4,0xb8,0x80,0x80, 0x71, 0x00,0x00,0x00,0x00,0x00,0x74,0x8c,0x84,0x84,0x84,0x8c,0x74,0x04,0x04, 0x72, 0x00,0x00,0x00,0x00,0x00,0xb8,0xc4,0x84,0x80,0x80,0x80,0x80,0x00,0x00, 0x73, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x40,0x30,0x08,0x84,0x78,0x00,0x00, 0x74, 0x00,0x00,0x20,0x20,0x20,0xf8,0x20,0x20,0x20,0x20,0x24,0x18,0x00,0x00, 0x75, 0x00,0x00,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0x76, 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00, 0x77, 0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x54,0x54,0x54,0x54,0x28,0x00,0x00, 0x78, 0x00,0x00,0x00,0x00,0x00,0x84,0x84,0x48,0x30,0x48,0x84,0x84,0x00,0x00, 0x79, 0x00,0x00,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x8c,0x74,0x04,0x84,0x78, 0x7a, 0x00,0x00,0x00,0x00,0x00,0xfc,0x08,0x10,0x20,0x20,0x40,0xfc,0x00,0x00, 0x7b, 0x00,0x0c,0x10,0x10,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x10,0x0c, 0x7c, 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x7d, 0x00,0x60,0x10,0x10,0x10,0x10,0x10,0x08,0x10,0x10,0x10,0x10,0x10,0x60, 0x7e, 0x00,0x40,0xa4,0x94,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa1, 0x00,0x00,0x10,0x10,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0xa2, 0x00,0x00,0x00,0x00,0x20,0x78,0xa4,0xa0,0xa0,0xa0,0xa4,0x78,0x20,0x00, 0xa3, 0x00,0x00,0x00,0x18,0x24,0x20,0x20,0x78,0x20,0x20,0x78,0x24,0x00,0x00, 0xa4, 0x00,0x00,0x00,0x00,0x84,0x78,0x48,0x48,0x78,0x84,0x00,0x00,0x00,0x00, 0xa5, 0x00,0x00,0x44,0x28,0x28,0x10,0x7c,0x10,0x7c,0x10,0x10,0x10,0x00,0x00, 0xa6, 0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00, 0xa7, 0x00,0x78,0x84,0x40,0x30,0x48,0x84,0x48,0x30,0x08,0x84,0x78,0x00,0x00, 0xa8, 0x00,0x48,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xa9, 0x00,0x78,0x84,0xb4,0xcc,0xc4,0xc4,0xc4,0xcc,0xb4,0x84,0x78,0x00,0x00, 0xaa, 0x00,0x38,0x44,0x3c,0x44,0x4c,0x34,0x00,0x7c,0x00,0x00,0x00,0x00,0x00, 0xab, 0x00,0x00,0x00,0x00,0x00,0x14,0x28,0x50,0xa0,0x50,0x28,0x14,0x00,0x00, 0xac, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x04,0x04,0x04,0x00,0x00, 0xad, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00, 0xae, 0x00,0x78,0x84,0xf4,0xcc,0xcc,0xf4,0xcc,0xcc,0xcc,0x84,0x78,0x00,0x00, 0xaf, 0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb0, 0x00,0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb1, 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x7c,0x00,0x00, 0xb2, 0x00,0x30,0x48,0x08,0x10,0x20,0x40,0x78,0x00,0x00,0x00,0x00,0x00,0x00, 0xb3, 0x00,0x30,0x48,0x08,0x30,0x08,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00, 0xb4, 0x00,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb5, 0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x6c,0x54,0x40,0x40, 0xb6, 0x00,0x00,0x3c,0x54,0x54,0x54,0x54,0x34,0x14,0x14,0x14,0x14,0x14,0x1c, 0xb7, 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xb8, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x20, 0xb9, 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x38,0x00,0x00,0x00,0x00,0x00,0x00, 0xba, 0x00,0x00,0x30,0x48,0x48,0x30,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00, 0xbb, 0x00,0x00,0x00,0x00,0x00,0xa0,0x50,0x28,0x14,0x28,0x50,0xa0,0x00,0x00, 0xbc, 0x00,0x00,0x40,0xc4,0x48,0x48,0x50,0x24,0x2c,0x54,0x9c,0x84,0x00,0x00, 0xbd, 0x00,0x00,0x40,0xc4,0x48,0x48,0x50,0x28,0x34,0x44,0x88,0x9c,0x00,0x00, 0xbe, 0x00,0x00,0xc4,0x24,0x48,0x30,0xd0,0x24,0x4c,0x54,0x9c,0x04,0x00,0x00, 0xbf, 0x00,0x00,0x00,0x20,0x20,0x00,0x20,0x20,0x20,0x20,0x40,0x84,0x84,0x78, 0xc0, 0x20,0x10,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0xc1, 0x10,0x20,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0xc2, 0x30,0x48,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0xc3, 0x64,0x98,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0xc4, 0x00,0x48,0x00,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0xc5, 0x00,0x30,0x48,0x30,0x48,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x00,0x00, 0xc6, 0x00,0x00,0x3c,0x50,0x90,0x90,0xfc,0x90,0x90,0x90,0x90,0x9c,0x00,0x00, 0xc7, 0x00,0x00,0x78,0x84,0x84,0x80,0x80,0x80,0x80,0x84,0x84,0x78,0x10,0x20, 0xc8, 0x20,0x10,0x00,0xfc,0x80,0x80,0x80,0xf8,0x80,0x80,0x80,0xfc,0x00,0x00, 0xc9, 0x10,0x20,0x00,0xfc,0x80,0x80,0x80,0xf8,0x80,0x80,0x80,0xfc,0x00,0x00, 0xca, 0x30,0x48,0x00,0xfc,0x80,0x80,0x80,0xf8,0x80,0x80,0x80,0xfc,0x00,0x00, 0xcb, 0x00,0x48,0x00,0xfc,0x80,0x80,0x80,0xf8,0x80,0x80,0x80,0xfc,0x00,0x00, 0xcc, 0x20,0x10,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xcd, 0x08,0x10,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xce, 0x10,0x28,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xcf, 0x00,0x28,0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xd0, 0x00,0x00,0x78,0x44,0x42,0x42,0xf2,0x42,0x42,0x42,0x44,0x78,0x00,0x00, 0xd1, 0x64,0x98,0x00,0xc4,0xc4,0xa4,0xa4,0x94,0x94,0x94,0x8c,0x8c,0x00,0x00, 0xd2, 0x20,0x10,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd3, 0x10,0x20,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd4, 0x30,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd5, 0x64,0x98,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd6, 0x00,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xd7, 0x00,0x00,0x00,0x00,0x00,0x82,0x44,0x28,0x10,0x28,0x44,0x82,0x00,0x00, 0xd8, 0x04,0x04,0x78,0x8c,0x94,0x94,0x94,0xa4,0xa4,0xa4,0xc4,0x78,0x80,0x80, 0xd9, 0x20,0x10,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xda, 0x10,0x20,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xdb, 0x30,0x48,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xdc, 0x00,0x48,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xdd, 0x08,0x10,0x00,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0xde, 0x00,0x00,0x80,0x80,0xf8,0x84,0x84,0x84,0x84,0xf8,0x80,0x80,0x00,0x00, 0xdf, 0x00,0x00,0x30,0x48,0x48,0x48,0x70,0x48,0x44,0x44,0x44,0xf8,0x00,0x00, 0xe0, 0x00,0x00,0x20,0x10,0x00,0x78,0x84,0x1c,0x64,0x84,0x8c,0x74,0x00,0x00, 0xe1, 0x00,0x00,0x08,0x10,0x00,0x78,0x84,0x1c,0x64,0x84,0x8c,0x74,0x00,0x00, 0xe2, 0x00,0x00,0x30,0x48,0x00,0x78,0x84,0x1c,0x64,0x84,0x8c,0x74,0x00,0x00, 0xe3, 0x00,0x00,0x64,0x98,0x00,0x78,0x84,0x1c,0x64,0x84,0x8c,0x74,0x00,0x00, 0xe4, 0x00,0x00,0x00,0x48,0x00,0x78,0x84,0x1c,0x64,0x84,0x8c,0x74,0x00,0x00, 0xe5, 0x00,0x30,0x48,0x30,0x00,0x78,0x84,0x1c,0x64,0x84,0x8c,0x74,0x00,0x00, 0xe6, 0x00,0x00,0x00,0x00,0x00,0x7c,0x92,0x32,0x5e,0x90,0x92,0x7c,0x00,0x00, 0xe7, 0x00,0x00,0x00,0x00,0x00,0x78,0x84,0x80,0x80,0x80,0x84,0x78,0x10,0x20, 0xe8, 0x00,0x00,0x20,0x10,0x00,0x78,0x84,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xe9, 0x00,0x00,0x10,0x20,0x00,0x78,0x84,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xea, 0x00,0x00,0x30,0x48,0x00,0x78,0x84,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xeb, 0x00,0x00,0x00,0x48,0x00,0x78,0x84,0x84,0xfc,0x80,0x84,0x78,0x00,0x00, 0xec, 0x00,0x00,0x20,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xed, 0x00,0x00,0x08,0x10,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xee, 0x00,0x00,0x30,0x48,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xef, 0x00,0x00,0x00,0x28,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00, 0xf0, 0x00,0x28,0x10,0x28,0x04,0x3c,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00, 0xf1, 0x00,0x00,0x64,0x98,0x00,0xb8,0xc4,0x84,0x84,0x84,0x84,0x84,0x00,0x00, 0xf2, 0x00,0x00,0x20,0x10,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf3, 0x00,0x00,0x10,0x20,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf4, 0x00,0x00,0x30,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf5, 0x00,0x00,0x64,0x98,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf6, 0x00,0x00,0x00,0x48,0x00,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x00,0x00, 0xf7, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0xfc,0x00,0x30,0x00,0x00, 0xf8, 0x00,0x00,0x00,0x04,0x08,0x78,0x94,0x94,0xa4,0xa4,0xc4,0x78,0x80,0x80, 0xf9, 0x00,0x00,0x20,0x10,0x00,0x84,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfa, 0x00,0x00,0x10,0x20,0x00,0x84,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfb, 0x00,0x00,0x30,0x48,0x00,0x84,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfc, 0x00,0x00,0x00,0x48,0x00,0x84,0x84,0x84,0x84,0x84,0x8c,0x74,0x00,0x00, 0xfd, 0x00,0x00,0x10,0x20,0x00,0x84,0x84,0x44,0x48,0x28,0x38,0x10,0x90,0x60, 0xfe, 0x00,0x00,0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84,0xc4,0xb8,0x80,0x80, 0xff, 0x00,0x00,0x00,0x48,0x00,0x84,0x84,0x44,0x48,0x28,0x38,0x10,0x90,0x60 }; /** @brief maximum number of simultaneously running timers */ #define SDL_MAX_TIMER 8 /** @brief timer callbacks */ static void (*timer_callback[SDL_MAX_TIMER])(void *); /** @brief timer callback cookies */ static void *timer_cookie[SDL_MAX_TIMER]; /** @brief timer intervals */ static uint32_t timer_interval[SDL_MAX_TIMER]; /** @brief currently there are 4 fonts hardcoded in the source */ #define SDL_FONTS 4 /** @brief built-in character generators */ static const chargen_t chargen[SDL_FONTS] = { { 6, 10, chargen_6x10, sizeof(chargen_6x10) }, { 6, 12, chargen_6x12, sizeof(chargen_6x12) }, { 7, 13, chargen_7x13, sizeof(chargen_7x13) }, { 7, 14, chargen_7x14, sizeof(chargen_7x14) } }; /** @brief TEXT_COLORS default color ramps for the text colors */ static const uint32_t text_colors[TEXT_COLORS] = { /* normal colors */ sdl_rgb( 0, 0, 0), sdl_rgb( 0, 0, 96), sdl_rgb( 0, 96, 0), sdl_rgb( 0, 96, 96), sdl_rgb( 96, 0, 0), sdl_rgb( 96, 0, 96), sdl_rgb( 96, 96, 0), sdl_rgb( 96, 96, 96), /* brighter colors (selected) */ sdl_rgb( 64, 64, 64), sdl_rgb( 0, 0,144), sdl_rgb( 0,144, 0), sdl_rgb( 0,144,144), sdl_rgb(144, 0, 0), sdl_rgb(144, 0,144), sdl_rgb(144,144, 0), sdl_rgb(144,144,144), /* normal colors (button) */ sdl_rgb( 0, 0, 0), sdl_rgb( 0, 0, 96), sdl_rgb( 0, 96, 0), sdl_rgb( 0, 96, 96), sdl_rgb( 96, 0, 0), sdl_rgb( 96, 0, 96), sdl_rgb( 96, 96, 0), sdl_rgb( 96, 96, 96), /* brighter colors (button, selected) */ sdl_rgb( 64, 64, 64), sdl_rgb( 0, 0,144), sdl_rgb( 0,144, 0), sdl_rgb( 0,144,144), sdl_rgb(144, 0, 0), sdl_rgb(144, 0,144), sdl_rgb(144,144, 0), sdl_rgb(144,144,144) }; /** * @brief allocate a new picture * * @result new sdl_t on success, NULL on error */ sdl_t *sdl_alloc(void) { FUN("sdl_alloc"); sdl_t *sdl = xmalloc(sizeof(sdl_t)); if (sdl_init(sdl, 640, 480, 0, 0)) { LOG(ERROR,(_fun,"sdl_init(%p) failed\n", sdl)); xfree(sdl); return NULL; } return sdl; } /** * @brief free a picture * * @param sdl pointer to a SDL context * @result 0 on sucess, -1 on error */ int sdl_free(sdl_t *sdl) { FUN("sdl_free"); if (sdl_zap(sdl)) { LOG(ERROR,(_fun,"sdl_zap failed %p\n", sdl)); errno = EINVAL; return -1; } xfree(sdl); return 0; } /** * @brief initialize a sdl_t context * * @param sdl pointer to a SDL context * @result 0 on sucess, -1 on error */ int sdl_init(sdl_t *sdl, int width, int height, int bwidth, int bheight) { FUN("sdl_init"); char buff[256]; uint8_t cursor[256]; uint32_t rmask, gmask, bmask, amask; uint32_t flags; SDL_Rect rc; rect_t rt; int h1, h2, h3; memset(sdl, 0, sizeof(*sdl)); SETTAG(sdl,SDL_TAG); /* width and height of target */ sdl->width = MAX(width, bwidth); sdl->height = height; sdl->border = bheight; sdl->bpp = 32; SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); SDL_EventState(SDL_KEYDOWN, SDL_ENABLE); SDL_EventState(SDL_KEYUP, SDL_ENABLE); SDL_EventState(SDL_QUIT, SDL_ENABLE); SDL_EnableKeyRepeat(250, 25); flags = SDL_HWSURFACE | SDL_RESIZABLE /* | SDL_FULLSCREEN */; sdl->scr = SDL_SetVideoMode(sdl->width, sdl->height + sdl->border, sdl->bpp, flags); if (NULL == sdl->scr) { LOG(FATAL,(_fun,"SDL_SetVideoMode(%d,%d,%d,%#x) failed\n", sdl->width, sdl->height + sdl->border, sdl->bpp, flags)); return -1; } sdl->bpp = sdl->scr->format->BitsPerPixel; rmask = sdl->scr->format->Rmask; gmask = sdl->scr->format->Gmask; bmask = sdl->scr->format->Bmask; amask = sdl->scr->format->Amask; LOG(INFO,(_fun,"SDL_SetVideoMode(%d,%d,%d,%#x) ok\n", sdl->scr->w, sdl->scr->h, sdl->bpp, flags)); flags = SDL_HWSURFACE | SDL_ASYNCBLIT; if (sdl->bpp <= 8) { sdl->bmap = SDL_CreateRGBSurface(flags, width, height, sdl->bpp, 0, 0, 0, 0); } else { sdl->bmap = SDL_CreateRGBSurface(flags, width, height, sdl->bpp, rmask, gmask, bmask, amask); } if (NULL == sdl->bmap) { LOG(FATAL,(_fun,"SDL_CreateSurface(%#x,%d,%d,%d,%#x,%#x,%#x,%#x) failed\n", flags, sdl->width, sdl->height, sdl->bpp, rmask, gmask, bmask, amask)); return -1; } /* fill preview rect */ rc.x = 0; rc.y = 0; rc.w = sdl->bmap->w; rc.h = sdl->bmap->h; SDL_FillRect(sdl->scr, &rc, SDL_MapRGB(sdl->scr->format, 0, 0, 0)); /* fill border rect */ rc.y = sdl->height; rc.w = sdl->width; rc.h = sdl->border; SDL_FillRect(sdl->scr, &rc, SDL_MapRGB(sdl->scr->format, 255, 255, 255)); sdl_chargen(sdl, BUILTIN_FONT); h1 = MIN(3 * sdl->font_h + 2, sdl->border - 2); h3 = MIN(3 * sdl->font_h + 2, sdl->border - 2 - h1); h2 = sdl->border - 2 - h1 - h3; rt.x = 1; rt.w = sdl->width - 2; rt.y = sdl->height + 1; rt.h = h1; sdl_alloc_pane(sdl, SDL_MENUE_PANE, &rt); rt.y = sdl->height + 1 + h1; rt.h = h2; sdl_alloc_pane(sdl, SDL_MAIN_PANE, &rt); rt.y = sdl->height + 1 + h1 + h2; rt.h = h3; sdl_alloc_pane(sdl, SDL_STATUS_PANE, &rt); snprintf(buff, sizeof(buff), "%s", APPTITLE); SDL_WM_SetCaption(buff, buff); sdl_make_cursor(&cursor[0x00], &cursor[0x80], 10, 16, "xx........" \ "x#x......." \ "x##x......" \ "x###x....." \ "x####x...." \ "x#####x..." \ "x######x.." \ "x#######x." \ "x########x" \ "x#####xxxx" \ "x##x##x..." \ "x#x.x##x.." \ "xx..x##x.." \ ".....x##x." \ ".....x##x." \ "......xx.."); sdl->cur = SDL_CreateCursor(&cursor[0x00], &cursor[0x80], 10, 16, 0, 0); SDL_SetCursor(sdl->cur); SDL_UpdateRect(sdl->scr, 0, 0, sdl->width, sdl->height + sdl->border); return 0; } /** * @brief resize a sdl_t context * * @param sdl pointer to a SDL context * @result 0 on sucess, -1 on error */ int sdl_resize(sdl_t *sdl, int width, int height) { FUN("sdl_resize"); uint32_t rmask, gmask, bmask, amask; uint32_t flags; SDL_Rect rc; rect_t rt; int h1, h2, h3; /* width and height of target */ if (width < sdl->bmap->w) width = sdl->bmap->w; sdl->width = width; if (height < sdl->bmap->h) height = sdl->bmap->h; sdl->border = height - sdl->bmap->h; if (sdl->scr) { SDL_FreeSurface(sdl->scr); sdl->scr = NULL; } flags = SDL_HWSURFACE | SDL_RESIZABLE /* | SDL_FULLSCREEN */; sdl->scr = SDL_SetVideoMode(sdl->width, sdl->height + sdl->border, sdl->bpp, flags); if (NULL == sdl->scr) { LOG(FATAL,(_fun,"SDL_SetVideoMode(%d,%d,%d,%#x) failed\n", sdl->width, sdl->height + sdl->border, sdl->bpp, flags)); return -1; } sdl->bpp = sdl->scr->format->BitsPerPixel; rmask = sdl->scr->format->Rmask; gmask = sdl->scr->format->Gmask; bmask = sdl->scr->format->Bmask; amask = sdl->scr->format->Amask; LOG(INFO,(_fun,"SDL_SetVideoMode(%d,%d,%d,%#x) ok\n", sdl->scr->w, sdl->scr->h, sdl->bpp, flags)); /* fill border rect */ rc.x = 0; rc.y = sdl->height; rc.w = sdl->width; rc.h = sdl->border; SDL_FillRect(sdl->scr, &rc, SDL_MapRGB(sdl->scr->format, 255, 255, 255)); h1 = MIN(3 * sdl->font_h + 2, sdl->border - 2); h3 = MIN(3 * sdl->font_h + 2, sdl->border - 2 - h1); h2 = sdl->border - 2 - h1 - h3; rt.x = 1; rt.w = sdl->width - 2; rt.y = sdl->height + 1; rt.h = h1; sdl_realloc_pane(sdl, SDL_MENUE_PANE, &rt); rt.y = sdl->height + 1 + h1; rt.h = h2; sdl_realloc_pane(sdl, SDL_MAIN_PANE, &rt); rt.y = sdl->height + 1 + h1 + h2; rt.h = h3; sdl_realloc_pane(sdl, SDL_STATUS_PANE, &rt); SDL_UpdateRect(sdl->scr, 0, 0, sdl->width, sdl->height + sdl->border); return 0; } /** * @brief zap a sdl_t context, i.e. make it invalid * * @param sdl pointer to a SDL context * @result 0 on sucess, -1 on error */ int sdl_zap(sdl_t *sdl) { FUN("sdl_zap"); int i; if (!SDL_VALID(sdl)) { /* refuse to free NULL and non-bitstream pointers */ LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } for (i = 0; i < SDL_PANES; i++) { sdl_text_t *p = &sdl->pane[i]; if (NULL != p->text) { xfree(p->text); p->text = NULL; } if (NULL != p->cmap) { xfree(p->cmap); p->cmap = NULL; } } if (NULL != sdl->scr) { SDL_FreeSurface(sdl->scr); sdl->scr = NULL; } if (NULL != sdl->bmap) { SDL_FreeSurface(sdl->bmap); sdl->bmap = NULL; } if (NULL != sdl->font) { SDL_FreeSurface(sdl->font); sdl->font = NULL; } if (NULL != sdl->cur) { SDL_FreeCursor(sdl->cur); sdl->cur = NULL; } SETTAG(sdl,INVALID_TAG); SDL_Quit(); return 0; } /** * @brief allocate buffers for a text pane * * @param sdl pointer to a SDL context * @param pane pane number * @param prc pointer to a rectangle (pixel coordinates) defining where to place the pane * @result 0 on sucess, -1 on error */ static int sdl_alloc_pane(sdl_t *sdl, sdl_pane_t pane, rect_t *prc) { FUN("sdl_alloc_pane"); sdl_text_t *t; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %t\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; memset(t, 0, sizeof(*t)); /* allocate text buffers for the border area */ if (prc->w <= 0 || prc->h <= 0) return 0; t->xorg = prc->x; t->yorg = prc->y; t->width = prc->w; t->height = prc->h; t->cw = t->tw = (prc->w - 2) / sdl->font_w; t->ch = t->th = (prc->h - 2) / sdl->font_h; t->tx = prc->x + 1 + (prc->w - 2 - t->tw * sdl->font_w) / 2; t->ty = prc->y + 1 + (prc->h - 2 - t->th * sdl->font_h) / 2; t->text = xcalloc(t->tw * t->th, sizeof(char)); if (NULL == t->text) { LOG(INFO,(_fun,"out of memory; text(%d)\n", t->tw * t->th)); errno = ENOMEM; return -1; } t->cmap = xcalloc(t->tw * t->th, sizeof(char)); if (NULL == t->cmap) { LOG(INFO,(_fun,"out of memory; cmap(%d)\n", t->tw * t->th)); errno = ENOMEM; return -1; } t->rgb_bg[0] = sdl_rgb(255,255,255); t->rgb_bg[1] = sdl_rgb(224,224,255); t->rgb_bg[2] = sdl_rgb(208,208,208); t->rgb_bg[3] = sdl_rgb(208,208,240); t->rgb_tl = sdl_rgb(224,224,224); t->rgb_br = sdl_rgb( 96, 96, 96); return sdl_frame_pane(sdl, pane, -1); } /** * @brief reallocate buffers for a text pane, keeping the text intact * * @param sdl pointer to a SDL context * @param pane pane number * @param prc pointer to a rectangle (pixel coordinates) defining where to place the pane * @result 0 on sucess, -1 on error */ static int sdl_realloc_pane(sdl_t *sdl, sdl_pane_t pane, rect_t *prc) { FUN("sdl_realloc_pane"); sdl_text_t *t; int x, y, w, h; char *text, *cmap; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; if (NULL == t->text) return 0; w = t->tw; h = t->th; text = t->text; cmap = t->cmap; if (prc->w <= 0 || prc->h <= 0) { /* empty pane */ xfree(text); xfree(cmap); memset(t, 0, sizeof(*t)); return 0; } /* allocate a text buffer for the text area (border) */ t->xorg = prc->x; t->yorg = prc->y; t->width = prc->w; t->height = prc->h; t->cw = t->tw = (prc->w - 2) / sdl->font_w; t->ch = t->th = (prc->h - 2) / sdl->font_h; t->tx = prc->x + 1 + (prc->w - 2 - t->tw * sdl->font_w) / 2; t->ty = prc->y + 1 + (prc->h - 2 - t->th * sdl->font_h) / 2; t->text = xcalloc(t->tw * t->th, sizeof(char)); if (NULL == t->text) { LOG(INFO,(_fun,"out of memory; text(%d)\n", t->tw * t->th)); errno = ENOMEM; return -1; } t->cmap = xcalloc(t->tw * t->th, sizeof(char)); if (NULL == t->cmap) { LOG(INFO,(_fun,"out of memory; text(%d)\n", t->tw * t->th)); errno = ENOMEM; return -1; } /* copy text to new buffer */ for (y = 0; y < MIN(h, t->th); y++) { for (x = 0; x < MIN(w, t->tw); x++) { sdl_putch(sdl, pane, x, y, text[y * w + x], cmap[y * w + x]); } } /* now free the old buffers */ xfree(text); xfree(cmap); return sdl_frame_pane(sdl, pane, -1); } /** * @brief switch the character generator * * @param sdl pointer to a SDL context * @param which which font to render (0 to 3) * @result 0 on sucess, -1 on error */ int sdl_chargen(sdl_t *sdl, int which) { FUN("sdl_chargen"); const chargen_t *cg = &chargen[which]; uint32_t rmask, gmask, bmask, amask; int flags; int i; if (NULL != sdl->font) { SDL_FreeSurface(sdl->font); sdl->font = NULL; } if (which < 0 || which >= SDL_FONTS) { fatal(1, "font index out of range (%d)\n", which); } sdl->font_w = cg->width; sdl->font_h = cg->height; #if SDL_BYTEORDER == SDL_MSB_FIRST rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_SRCALPHA; sdl->font = SDL_CreateRGBSurface(flags, sdl->font_w * 257, sdl->font_h * TEXT_COLORS, 32, rmask, gmask, bmask, amask); if (NULL == sdl->font) { LOG(FATAL,(_fun,"SDL_CreateSurface(%#x,%d,%d,%d,%#x,%#x,%#x,%#x) failed\n", flags, sdl->font_w * 257, sdl->font_h * TEXT_COLORS, sdl->bpp, rmask, gmask, bmask, amask)); return -1; } for (i = 0; i < TEXT_COLORS; i++) sdl_chargen_alpha(sdl, cg, i, text_colors[i]); return 0; } /** * @brief count the bits at and around a bit at a charmap * * @param cg pointer to the character generator * @param x pixel column * @param y pixel row * @result matrix weighted value for pixel, 0 if outside char */ static int bitcount(const chargen_t *cg, int i, int x, int y) { int shift; int tl, t, tr, l, c, r, bl, b, br; const uint8_t *p = &cg->data[i + y]; if (x < 0 || x >= cg->width || y < 0 || y >= cg->height) return 0; if (x > 0) { shift = 8 - x; l = (p[0] >> shift) & 1; tl = (y > 0) ? (p[-1] >> shift) & 1 : 0; bl = (y + 1 < cg->height) ? (p[+1] >> shift) & 1 : 0; } else { l = tl = bl = 0; } if (x + 1 < cg->width) { shift = 6 - x; r = (p[0] >> shift) & 1; tr = (y > 0) ? (p[-1] >> shift) & 1 : 0; br = (y + 1 < cg->height) ? (p[+1] >> shift) & 1 : 0; } else { r = tr = br = 0; } shift = 7 - x; t = (y > 0) ? (p[-1] >> shift) & 1 : 0; b = (y + 1 < cg->height) ? (p[+1] >> shift) & 1 : 0; c = (p[0] >> shift) & 1; return tl * c * 2 + t * 3 + tr * c * 2 + l * 3 + c *10 + r * 3 + bl * c * 2 + b * 3 + br * c * 2; } /** * @brief render one font on a color ramp from rgb0 to rgb1 * * @param sdl pointer to a SDL context * @param idx font index (0 to 7) * @param rgb values for red, green, blue * @result 0 on sucess, -1 on error */ int sdl_chargen_alpha(sdl_t *sdl, const chargen_t *cg, int col, uint32_t rgb) { FUN("sdl_chargen_ramp"); SDL_PixelFormat *fmt; SDL_Rect rc; uint32_t ramp[8]; int r = sdl_get_r(rgb); int g = sdl_get_g(rgb); int b = sdl_get_b(rgb); int i, ch, x, y; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (NULL == sdl->font) { LOG(ERROR,(_fun,"invalid font %p\n", sdl->font)); errno = EINVAL; return -1; } /* convert chargen to font */ fmt = sdl->font->format; ramp[0] = SDL_MapRGBA(fmt, r, g, b, 0); ramp[1] = SDL_MapRGBA(fmt, r, g, b, 15); ramp[2] = SDL_MapRGBA(fmt, r, g, b, 31); ramp[3] = SDL_MapRGBA(fmt, r, g, b, 63); ramp[4] = SDL_MapRGBA(fmt, r, g, b,127); ramp[5] = SDL_MapRGBA(fmt, r, g, b,159); ramp[6] = SDL_MapRGBA(fmt, r, g, b,191); ramp[7] = SDL_MapRGBA(fmt, r, g, b,255); rc.w = 1; rc.h = 1; for (i = 0; i < cg->size; i += cg->height + 1) { /* first byte is character code */ ch = cg->data[i]; rc.y = col * sdl->font_h; for (y = 0; y < sdl->font_h; y++, rc.y++) { rc.x = ch * sdl->font_w; for (x = 0; x < cg->width; x++, rc.x++) { switch (bitcount(cg, i + 1, x, y)) { case 0: case 1: case 2: SDL_FillRect(sdl->font, &rc, ramp[0]); break; case 3: SDL_FillRect(sdl->font, &rc, ramp[1]); break; case 4: SDL_FillRect(sdl->font, &rc, ramp[2]); break; case 5: case 6: SDL_FillRect(sdl->font, &rc, ramp[3]); break; case 7: case 8: SDL_FillRect(sdl->font, &rc, ramp[4]); break; case 9: case 10: SDL_FillRect(sdl->font, &rc, ramp[5]); break; case 11: case 12: case 13: SDL_FillRect(sdl->font, &rc, ramp[6]); break; default: SDL_FillRect(sdl->font, &rc, ramp[7]); break; } } } } return 0; } /** * @brief get (and lock) the screen surface pixels address for coordinates x, y * * @param sdl pointer to a SDL context * @param x x coordinate (scan column) * @param y y coordinate (scan line) * @result the memory address of the bitmap, or NULL on error */ uint8_t *sdl_lock_bitmap(sdl_t *sdl, int x, int y) { FUN("sdl_lock_bitmap"); uint8_t *p; SDL_Surface *s; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return NULL; } s = sdl->bmap; if (NULL == s) { LOG(ERROR,(_fun,"no surface %p\n", s)); errno = EINVAL; return NULL; } if (y < 0 || y >= s->h) { return NULL; } if (x < 0 || x >= s->w) { return NULL; } if (SDL_MUSTLOCK(s)) { if (SDL_LockSurface(s) <= 0) { LOG(ERROR,(_fun,"SDL_LockSurface(%p) failed\n", s)); return NULL; } } p = s->pixels; return p + y * s->pitch + x * s->format->BytesPerPixel; } /** * @brief unlock screen surface pixels * * @param sdl pointer to a SDL context */ int sdl_unlock_bitmap(sdl_t *sdl) { FUN("sdl_lock_bitmap"); SDL_Surface *s; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } s = sdl->bmap; if (NULL == s) { LOG(ERROR,(_fun,"no surface %p\n", s)); errno = EINVAL; return -1; } if (SDL_MUSTLOCK(s)) { SDL_UnlockSurface(s); } return 0; } /** @brief clear the screen surface bitmap */ int sdl_clear_bitmap(sdl_t *sdl, uint32_t rgb) { FUN("sdl_lock_bitmap"); SDL_Surface *s; uint8_t r, g, b; SDL_Rect rc; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } s = sdl->bmap; if (NULL == s) { LOG(ERROR,(_fun,"no surface %p\n", s)); errno = EINVAL; return -1; } r = sdl_get_r(rgb); g = sdl_get_g(rgb); b = sdl_get_b(rgb); rc.x = 0; rc.y = 0; rc.w = s->w; rc.h = s->h; SDL_FillRect(s, &rc, SDL_MapRGB(s->format, r, g, b)); return 0; } /** @brief load a PPM file and create a surface from it */ SDL_Surface *sdl_load_ppm(sdl_t *sdl, const char *filename) { FUN("sdl_load_ppm"); char w_h_line[32]; char mask_line[32]; int state = 0; int offs = 0; int size = 0; int ch; ppm_t *ppm = NULL; uint32_t rmask; uint32_t gmask; uint32_t bmask; uint32_t amask; SDL_Surface *surface = NULL; FILE *fp = NULL; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %ppm\n", sdl)); errno = EINVAL; return NULL; } fp = fopen(filename, "rb"); if (NULL == fp) { LOG(ERROR,(_fun,"fopen(\"%s\",\"rb\") failed (%s)\n", filename, strerror(errno))); return NULL; } ppm = xcalloc(1, sizeof(ppm_t)); state = 0; while ((ch = fgetc(fp)) != -1) { switch (state) { case 0: /* first char must be P */ if (ch != 'P') { LOG(ERROR,(_fun, "no PPM file (first char isn't 'P') '%s'\n", filename)); goto failed; } state++; break; case 1: /* second char is mode; we support only P6 for now */ if (ch != '6') { LOG(ERROR,(_fun, "unsupported PPM format (second char isn't '6') '%s'\n", filename)); goto failed; } /* 3 bytes R,G,B data */ ppm->mode = 3; state++; break; case 2: /* wait for end of line */ if (ch != '\n') break; state++; break; case 3: /* ignore comments */ if (ch == '#') { state = 2; break; } ppm->width = 0; ppm->height = 0; offs = 0; size = sizeof(w_h_line); state++; /* FALLTHRU */ case 4: /* read width and height line */ if (ch == '\n') { w_h_line[offs] = '\0'; if (w_h_line[0] == '#') break; if (2 != sscanf(w_h_line, "%d %d", &ppm->width, &ppm->height)) { LOG(FATAL,(_fun, "fatal: PPM width height line format (%s) '%s'\n", w_h_line, filename)); goto failed; } offs = 0; size = sizeof(mask_line); state++; break; } w_h_line[offs++] = ch; if (offs >= size) { w_h_line[--offs] = '\0'; LOG(FATAL,(_fun, "fatal: PPM width height line too long (%s) '%s'\n", w_h_line, filename)); goto failed; } break; case 5: /* read mask line */ if (ch == '\n') { mask_line[offs] = '\0'; if (mask_line[0] == '#') break; if (1 != sscanf(mask_line, "%d", &ppm->mask)) { LOG(FATAL,(_fun, "fatal: PPM mask line format (%s) '%s'\n", mask_line, filename)); goto failed; } offs = 0; size = ppm->width * ppm->height * ppm->mode; ppm->data = xmalloc(size * ppm->mode); state++; break; } mask_line[offs++] = ch; if (offs >= size) { mask_line[--offs] = '\0'; LOG(FATAL,(_fun, "fatal: PPM mask line too long (%s) '%s'\n", mask_line, filename)); goto failed; } break; case 6: /* read R,G,B data */ ppm->data[offs++] = ch & ppm->mask; if (offs >= size) state++; break; default: /* ignoring data beyond image */ break; } } fclose(fp); fp = NULL; #if SDL_BYTEORDER == SDL_MSB_FIRST rmask = ppm->mask << 16; gmask = ppm->mask << 8; bmask = ppm->mask << 0; amask = 0x00000000; #else rmask = ppm->mask << 0; gmask = ppm->mask << 8; bmask = ppm->mask << 16; amask = 0x00000000; #endif surface = SDL_CreateRGBSurfaceFrom(ppm->data, ppm->width, ppm->height, 24, ppm->width * ppm->mode, rmask, gmask, bmask, amask); if (NULL == surface) { LOG(ERROR,(_fun,"SDL_CreateRGBSurfaceFrom(%p,%d,%d,%d,%d,%#x,%#x,%#x,%#x) failed\n", ppm->data, ppm->width, ppm->height, sdl->bpp, ppm->width * ppm->mode, rmask, gmask, bmask, amask)); goto failed; } xfree(ppm); ppm = NULL; return surface; failed: if (surface) { SDL_FreeSurface(surface); ppm = NULL; } if (ppm) { xfree(ppm); ppm = NULL; } if (fp) { fclose(fp); fp = NULL; } return NULL; } /** @brief blit a surface to the screen (to preview area width, height) */ int sdl_blit(sdl_t *sdl, SDL_Surface *src) { FUN("sdl_blit"); SDL_Rect dstrect; SDL_Rect srcrect; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (NULL == src) { LOG(ERROR,(_fun,"invalid SDL_Surface* %p\n", src)); errno = EINVAL; return -1; } /* fill black background */ dstrect.x = 0; dstrect.y = 0; dstrect.w = sdl->width; dstrect.h = sdl->height; SDL_SetClipRect(sdl->scr, &dstrect); SDL_FillRect(sdl->scr, &dstrect, SDL_MapRGB(sdl->scr->format, 0, 0, 0)); /* center the source surface */ srcrect.x = 0; srcrect.y = 0; srcrect.w = src->w; srcrect.h = src->h; if (sdl->width > src->w) { dstrect.x = (sdl->width - src->w) / 2; dstrect.w = src->w; } else { dstrect.x = (src->w - sdl->width) / 2; dstrect.w = sdl->width; } if (sdl->height > src->h) { dstrect.y = (sdl->height - src->h) / 2; dstrect.h = src->h; } else { dstrect.y = (src->h - sdl->height) / 2; dstrect.h = sdl->height; } SDL_BlitSurface(src, &srcrect, sdl->scr, &dstrect); return 0; } /** * @brief get the screen surface stride, i.e. the scanline pitch * * @param sdl pointer to a SDL context * @result the stride, or -1 on error */ ssize_t sdl_get_stride(sdl_t *sdl) { FUN("sdl_get_stride"); SDL_Surface *s; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } s = sdl->bmap; if (NULL == s) { LOG(ERROR,(_fun,"no surface %p\n", s)); errno = EINVAL; return -1; } return s->pitch; } /** * @brief get the screen surface Alpha, Red, Green, and Blue losses and shifts * @param sdl pointer to a SDL context * @param format pointer to a sdl_format_t * @result 0 on sucess, -1 on error */ int sdl_get_format(sdl_t *sdl, sdl_format_t *format) { FUN("sdl_get_format"); SDL_Surface *s; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (NULL == format) { LOG(ERROR,(_fun,"invalid sdl_format_t* %p\n", format)); errno = EINVAL; return -1; } s = sdl->bmap; if (NULL == s) { LOG(ERROR,(_fun,"no surface %p\n", s)); errno = EINVAL; return -1; } if (sdl->bpp == 8) { format->bpp = 8; format->pb = 1; format->rl = 5; format->gl = 5; format->bl = 6; format->al = 8; format->rs = 5; format->gs = 2; format->bs = 0; format->as = 0; format->rm = (7 << 5); format->gm = (7 << 2); format->bm = (3 << 0); format->ck = 0; format->alpha = 0; } else { format->bpp = s->format->BitsPerPixel; format->pb = s->format->BytesPerPixel; format->rl = s->format->Rloss; format->gl = s->format->Gloss; format->bl = s->format->Bloss; format->al = s->format->Aloss; format->rs = s->format->Rshift; format->gs = s->format->Gshift; format->bs = s->format->Bshift; format->as = s->format->Ashift; format->rm = s->format->Rmask; format->gm = s->format->Gmask; format->bm = s->format->Bmask; format->am = s->format->Amask; format->ck = s->format->colorkey; format->alpha = s->format->alpha; } return 0; } /** @brief get the mouse cursor text area x and y coordinates and button status */ int sdl_get_mouse(sdl_t *sdl, sdl_pane_t *pane, int *x, int *y, int *b) { FUN("sdl_get_mouse"); sdl_pane_t i; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } for (i = 0; i < SDL_PANES; i++) { sdl_text_t *t = &sdl->pane[i]; if (sdl->mousex < t->tx) continue; if (sdl->mousey < t->ty) continue; if (sdl->mousex >= t->tx + t->width) continue; if (sdl->mousey >= t->ty + t->height) continue; *pane = i; *x = (sdl->mousex - t->tx) / sdl->font_w; *y = (sdl->mousey - t->ty) / sdl->font_h; *b = sdl->mouseb; return 0; } return -1; } /** * @brief print a string on the border area * * @param sdl pointer to a SDL context * @param pane text pane to print to * @param prc pointer to a text rectangle to update (may be NULL) * @param x column where printing starts (may be -1 to use current cursor x) * @param y row where printing starts (may be -1 to use current cursor y) * @param col color of the text (0 to 7) * @param fmt format string * @param ap variable argument list * @result the length of the output string */ ssize_t sdl_vprintf(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, int x, int y, int col, const char *fmt, va_list ap) { FUN("sdl_vprintf"); char buff[256]; sdl_text_t *t; SDL_Rect rc; int len; int width; int x0; int i, j; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); if (-1 != x) t->cx = x; if (-1 != y) t->cy = y; x0 = t->cx; if (prc) { /* update caller's rectangle */ prc->x = t->cx; prc->y = t->cy; prc->w = 0; prc->h = 0; } len = vsnprintf(buff, sizeof(buff), fmt, ap); for (i = 0, width = 0; i < len; i++) { switch (buff[i]) { case '\r': if (prc) { /* update caller's rectangle */ if (t->cx - prc->x > prc->w) prc->w = t->cx - prc->x; } t->cx = x0; break; case '\n': if (prc) { /* update caller's rectangle */ if (t->cx - prc->x > prc->w) prc->w = t->cx - prc->x; prc->h++; } t->cx = x0; t->cy++; break; /* dirty hack to change the color from the text string */ case '\020': case '\021': case '\022': case '\023': case '\024': case '\025': case '\026': case '\027': col = (col & 8) | (buff[i] & 7); break; case '\037': /* erase to end of line */ for (j = t->cx; j < t->tw; j++) sdl_putch(sdl, pane, j, t->cy, ' ', 0); break; default: sdl_putch(sdl, pane, t->cx, t->cy, buff[i], col); t->cx++; width++; } } if (prc) { /* caller want's the output rectangle */ if (t->cx - prc->x > prc->w) prc->w = t->cx - prc->x; if (0 == prc->h) prc->h = 1; } return width; } /** * @brief print a string on the border area * * @param sdl pointer to a SDL context * @param pane text pane to print to * @param prc pointer to a text rectangle to update (may be NULL) * @param x column where printing starts * @param y row where printing starts * @param col color of the text (0 to 7) * @param fmt format string and optional arguments * @result the width of the printed string in characters */ ssize_t sdl_printf(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, int x, int y, int col, const char *fmt, ...) { FUN("sdl_printf"); va_list ap; int width; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } va_start(ap, fmt); width = sdl_vprintf(sdl, pane, prc, x, y, col, fmt, ap); va_end(ap); return width; } /** * @brief draw a frame around a pane * * @param sdl pointer to a SDL context * @param n thickness of the frame * @param rgb0 color to use for the top and left edges of the frame * @param rgb1 color to use for the top and left edges of the frame * @result 0 on sucess, -1 on error */ int sdl_frame_pane(sdl_t *sdl, sdl_pane_t pane, int n) { FUN("sdl_frame_rect"); sdl_text_t *t; SDL_Rect rc; uint32_t col0, col1; uint8_t r, g, b; int x0, y0, x1, y1; int i; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = MIN(t->xorg - 2, 0); rc.y = MIN(t->yorg - 2, sdl->height); rc.w = MAX(t->width + 4, sdl->width); rc.h = MAX(t->height + 4, sdl->border); SDL_SetClipRect(sdl->scr, &rc); r = sdl_get_r(t->rgb_tl); g = sdl_get_g(t->rgb_tl); b = sdl_get_b(t->rgb_tl); col0 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(t->rgb_br); g = sdl_get_g(t->rgb_br); b = sdl_get_b(t->rgb_br); col1 = SDL_MapRGB(sdl->scr->format, r, g, b); x0 = t->xorg; y0 = t->yorg; x1 = t->xorg + t->width - 1; y1 = t->yorg + t->height - 1; if (n < 0) { /* frame outside */ for (i = n; i < 0; i++) { x0--; y0--; x1++; y1++; /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); } } else { /* frame inside */ for (i = 0; i < n; i++) { /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); x0++; y0++; x1--; y1--; } } SDL_UpdateRect(sdl->scr, rc.x, rc.y, rc.w, rc.h); return 0; } /** * @brief draw a frame around a rectangle * * @param sdl pointer to a SDL context * @param prc pointer to a rectangle (text coordinates) * @param n thickness of the frame * @param rgb0 color to use for the top and left edges of the frame * @param rgb1 color to use for the top and left edges of the frame * @result 0 on sucess, -1 on error */ int sdl_frame_rect(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, int n, uint32_t rgb0, uint32_t rgb1) { FUN("sdl_frame_rect"); sdl_text_t *t; SDL_Rect rc; uint32_t col0, col1; uint8_t r, g, b; int x0, y0, x1, y1; int i; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); r = sdl_get_r(rgb0) & 0xff; g = sdl_get_g(rgb0) & 0xff; b = sdl_get_b(rgb0) & 0xff; col0 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb1) & 0xff; g = sdl_get_g(rgb1) & 0xff; b = sdl_get_b(rgb1) & 0xff; col1 = SDL_MapRGB(sdl->scr->format, r, g, b); x0 = t->tx + prc->x * sdl->font_w; y0 = t->ty + prc->y * sdl->font_h; x1 = x0 + prc->w * sdl->font_w - 1; y1 = y0 + prc->h * sdl->font_h - 1; if (n < 0) { /* frame outside */ for (i = n; i < 0; i++) { x0--; y0--; x1++; y1++; /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); } } else { /* frame inside */ for (i = 0; i < n; i++) { /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); x0++; y0++; x1--; y1--; } } return 0; } /** * @brief fill a text rectangle with a solid color * * @param sdl pointer to a SDL context * @param pane pane number * @param prc pointer to a rectangle (text coordinates) * @param rgb color to use to fill * @result 0 on sucess, -1 on error */ int sdl_fill_rect(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, uint32_t rgb) { FUN("sdl_fill_rect"); sdl_text_t *t; SDL_Rect rc; uint32_t col; uint8_t r, g, b; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); r = sdl_get_r(rgb) & 0xff; g = sdl_get_g(rgb) & 0xff; b = sdl_get_b(rgb) & 0xff; col = SDL_MapRGB(sdl->scr->format, r, g, b); rc.x = t->tx + prc->x * sdl->font_w; rc.y = t->ty + prc->y * sdl->font_h; rc.w = prc->w * sdl->font_w; rc.h = prc->h * sdl->font_h; SDL_FillRect(sdl->scr, &rc, col); return 0; } /** * @brief underline a text rectangle with a solid color * * @param sdl pointer to a SDL context * @param pane pane number * @param prc pointer to a rectangle (text coordinates) * @param rgb color to use to fill * @result 0 on sucess, -1 on error */ int sdl_underline(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, uint32_t rgb) { FUN("sdl_underline"); sdl_text_t *t; SDL_Rect rc; uint32_t col; uint8_t r, g, b; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); r = sdl_get_r(rgb) & 0xff; g = sdl_get_g(rgb) & 0xff; b = sdl_get_b(rgb) & 0xff; col = SDL_MapRGB(sdl->scr->format, r, g, b); rc.x = t->tx + prc->x * sdl->font_w; rc.y = t->ty + prc->y * sdl->font_h + sdl->font_h - 1; rc.w = prc->w * sdl->font_w; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col); return 0; } /** * @brief draw a button * * The button types and their appearance: * * SDL_BTYPE_SELECT small box [-] or [+] * SDL_BTYPE_CHECKBOX small box with or without a mark inside * SDL_BTYPE_DEC button with a "<" sign inside * SDL_BTYPE_INC button with a ">" sign inside * SDL_BTYPE_DEC2 button with a "<<" sign inside * SDL_BTYPE_INC2 button with a ">>" sign inside * SDL_BTYPE_LEFT button with a left arrow inside * SDL_BTYPE_RIGHT button with a right arrow inside * SDL_BTYPE_UP button with a up arrow inside * SDL_BTYPE_DOWN button with a down arrow inside * * @param sdl pointer to a SDL context * @param pane pane number * @param prc pointer to a rectangle (text coordinates) * @param type the type of button or box to draw * @param on draw the + mark, if this is non zero * @param rgb0 color to use for the top and left edges of the frame * @param rgb1 color to use for the bottom and right edges of the frame * @param rgb2 color to use for the interior of the box * @param rgb3 color to use for the - or + mark */ int sdl_draw_button(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, sdl_button_type_t type, int on, uint32_t rgb0, uint32_t rgb1, uint32_t rgb2, uint32_t rgb3) { FUN("sdl_draw_button"); sdl_text_t *t; SDL_Rect rc; uint32_t col0, col1, col2, col3; uint8_t r, g, b; int x0, y0, x1, y1, xc, yc, wh; int i; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; x0 = t->tx + prc->x * sdl->font_w; y0 = t->ty + prc->y * sdl->font_h; x1 = x0 + prc->w * sdl->font_w - 1; y1 = y0 + prc->h * sdl->font_h - 1; /* empty rectangle? */ if (x1 <= x0 || y1 <= y0) return 0; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); r = sdl_get_r(rgb0); g = sdl_get_g(rgb0); b = sdl_get_b(rgb0); col0 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb1); g = sdl_get_g(rgb1); b = sdl_get_b(rgb1); col1 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb2); g = sdl_get_g(rgb2); b = sdl_get_b(rgb2); col2 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb3); g = sdl_get_g(rgb3); b = sdl_get_b(rgb3); col3 = SDL_MapRGB(sdl->scr->format, r, g, b); switch (type) { case SDL_BTYPE_SELECT: x1--; y1--; x0 += sdl->font_w / 2; x1 -= sdl->font_w / 2; /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); /* fill interior */ x0++; y0++; x1--; y1--; rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col2); /* make sure we have an even width */ if ((x1 + 1 - x0) & 1) x1++; /* make sure we have an even height */ if ((y1 + 1 - y0) & 1) y1++; /* draw horizontal line (minus, dash) */ rc.x = x0 + (x1 - x0) / 4; rc.y = y0 + (y1 - y0) / 2; rc.w = (x1 + 1 - x0) / 2; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col3); if (0 == on) { /* draw vertical line (plus) */ rc.x = x0 + (x1 - x0) / 2; rc.y = y0 + (y1 - y0) / 4; rc.w = 1; rc.h = (y1 + 1 - y0) / 2; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_CHECKBOX: x0++; y0++; x1--; y1--; for (i = 0; i < 2; i++) { /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, i ? col0 : col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, i ? col0 : col1); x0++; y0++; x1--; y1--; } /* fill interior */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col2); if (on) { /* shrink by one pixel */ x0++; y0++; x1--; y1--; /* fill box with rgb3 */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_DEC: case SDL_BTYPE_INC: case SDL_BTYPE_DEC2: case SDL_BTYPE_INC2: x1--; y1--; /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); /* fill interior */ x0++; y0++; x1--; y1--; rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col2); /* make sure we have an even width */ if ((x1 + 1 - x0) & 1) x1++; /* make sure we have an even height */ if ((y1 + 1 - y0) & 1) y1++; rc.w = 1; rc.h = 1; xc = (x1 - x0) / 2; yc = (y1 - y0) / 2; wh = MIN(xc,yc); switch (type) { case SDL_BTYPE_DEC: /* draw < symbol */ for (i = 0; i < wh; i++) { rc.x = x0 + xc/2 + i + wh/2; rc.y = y0 + yc - i; SDL_FillRect(sdl->scr, &rc, col3); rc.y = y0 + yc + i; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_INC: /* draw > symbol */ for (i = 0; i < wh; i++) { rc.x = x1 - xc/2 - wh/2 - i - 2; rc.y = y0 + yc - i; SDL_FillRect(sdl->scr, &rc, col3); rc.y = y0 + yc + i; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_DEC2: /* draw << symbol */ for (i = 0; i < wh; i++) { rc.x = x0 + xc/2 + i + wh/2; rc.y = y0 + yc - i; SDL_FillRect(sdl->scr, &rc, col3); rc.y = y0 + yc + i; SDL_FillRect(sdl->scr, &rc, col3); rc.x = x0 + xc/2 + i + wh/2 + 2; rc.y = y0 + yc - i; SDL_FillRect(sdl->scr, &rc, col3); rc.y = y0 + yc + i; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_INC2: /* draw >> symbol */ for (i = 0; i < wh; i++) { rc.x = x1 - xc/2 - wh/2 - i - 1; rc.y = y0 + yc - i; SDL_FillRect(sdl->scr, &rc, col3); rc.y = y0 + yc + i; SDL_FillRect(sdl->scr, &rc, col3); rc.x = x1 - xc/2 - wh/2 - i - 3; rc.y = y0 + yc - i; SDL_FillRect(sdl->scr, &rc, col3); rc.y = y0 + yc + i; SDL_FillRect(sdl->scr, &rc, col3); } break; default: /* pacify GCC */ break; } break; default: /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col3); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col3); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col3); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col3); /* 3D frame */ x0++; y0++; x1--; y1--; /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); /* fill interior */ x0++; y0++; x1--; y1--; rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col2); rc.w = 1; rc.h = 1; xc = (x1 - x0) / 2; yc = (y1 - y0) / 2; wh = MIN(xc,yc); switch (type) { case SDL_BTYPE_LEFT: /* draw left arrow symbol */ for (i = 0; i < wh; i++) { rc.x = x0 + xc/2 + i + wh/2; rc.y = y0 + yc - i; rc.h = 2 * i + 1; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_RIGHT: /* draw right arrow symbol */ for (i = 0; i < wh; i++) { rc.x = x1 - xc/2 - wh/2 - i - 2; rc.y = y0 + yc - i; rc.h = 2 * i + 1; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_UP: /* draw up arrow symbol */ for (i = 0; i < wh; i++) { rc.x = x0 + xc - i; rc.y = y0 + wh/2 + i; rc.w = 2 * i + 1; SDL_FillRect(sdl->scr, &rc, col3); } break; case SDL_BTYPE_DOWN: /* draw down arrow symbol */ for (i = 0; i < wh; i++) { rc.x = x0 + xc - i; rc.y = y1 - wh/2 - i - 2; rc.w = 2 * i + 1; SDL_FillRect(sdl->scr, &rc, col3); } break; default: /* pacify GCC */ break; } break; } return 0; } /** * @brief draw a slider * * @param sdl pointer to a SDL context * @param pane pane number * @param prc pointer to a rectangle (text coordinates) * @param sl pointer to the slider data * @param rgb0 color to use for the top and left edges of the frame * @param rgb1 color to use for the bottom and right edges of the frame * @param rgb2 color to use for the interior of the box * @param rgb3 color to use for the - or + mark */ int sdl_draw_slider(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, sdl_slider_t *sl, int border, uint32_t rgb0, uint32_t rgb1, uint32_t rgb2, uint32_t rgb3) { FUN("sdl_draw_slider"); sdl_text_t *t; SDL_Rect rc; uint32_t col0, col1, col2, col3; uint8_t r, g, b; int x0, y0, x1, y1, xc, yc, wh, i; double scale; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } if (NULL == sl) { LOG(ERROR,(_fun,"invalid slider %p\n", sl)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); r = sdl_get_r(rgb0); g = sdl_get_g(rgb0); b = sdl_get_b(rgb0); col0 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb1); g = sdl_get_g(rgb1); b = sdl_get_b(rgb1); col1 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb2); g = sdl_get_g(rgb2); b = sdl_get_b(rgb2); col2 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb3); g = sdl_get_g(rgb3); b = sdl_get_b(rgb3); col3 = SDL_MapRGB(sdl->scr->format, r, g, b); x0 = t->tx + prc->x * sdl->font_w; y0 = t->ty + prc->y * sdl->font_h; x1 = x0 + prc->w * sdl->font_w - 1; y1 = y0 + prc->h * sdl->font_h - 1; /* empty rectangle? */ if (x1 <= x0 || y1 <= y0) return 0; if (sl->type == 0) { x0--; x1++; } else { y0--; y1++; } /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col3); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col3); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col3); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col3); /* fill interior */ x0++; y0++; x1--; y1--; rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col2); switch (sl->type) { case 0: wh = x1 + 1 - x0; scale = (double)wh / (sl->max - sl->min); sl->pos0 = (int)((sl->cur - sl->min) * scale); sl->pos1 = sl->pos0 + (int)(sl->range * scale); x1 = x0 + sl->pos1; x0 = x0 + sl->pos0; break; case 1: wh = y1 + 1 - y0; scale = (double)wh / (sl->max - sl->min); sl->pos0 = (int)((sl->cur - sl->min) * scale); sl->pos1 = sl->pos0 + (int)(sl->range * scale); y1 = y0 + sl->pos1; y0 = y0 + sl->pos0; break; default: LOG(ERROR,(_fun,"invalid slider type (%d)\n", sl->type)); return -1; } #if 0 printf("scale:%5.3f min:%lld max:%lld cur:%lld range:%lld pos0:%d pos1:%d\n", scale, sl->min, sl->max, sl->cur, sl->range, sl->pos0, sl->pos1); #endif /* top line */ rc.x = x0; rc.y = y0; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col0); /* left line */ rc.x = x0; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col0); /* bottom line */ rc.x = x0; rc.y = y1; rc.w = x1 + 1 - x0; rc.h = 1; SDL_FillRect(sdl->scr, &rc, col1); /* right line */ rc.x = x1; rc.y = y0 + 1; rc.w = 1; rc.h = y1 + 1 - y0 - 2; SDL_FillRect(sdl->scr, &rc, col1); /* ripples */ xc = (x1 - x0) / 2; yc = (y1 - y0) / 2; switch (sl->type) { case 0: for (i = -6; i <= 6; i += 2) { rc.x = x0 + xc + i; rc.y = y0 + yc/2; rc.w = 1; rc.h = yc; if (rc.y > x0 && rc.y < x1) SDL_FillRect(sdl->scr, &rc, col3); } case 1: for (i = -6; i <= 6; i += 2) { rc.x = x0 + xc/2; rc.y = y0 + yc + i; rc.w = xc; rc.h = 1; if (rc.y > y0 && rc.y < y1) SDL_FillRect(sdl->scr, &rc, col3); } } return 0; } /** * @brief plot a pixel on a pane * * @param sdl pointer to a SDL context * @param pane pane number * @param x x coordinate in pixels relative to the left of the pane * @param y y coordinate in pixels relative to the top of the pane * @param rgb RGB color value * @result return 0 on success, -1 on error */ int sdl_plot(sdl_t *sdl, sdl_pane_t pane, int x, int y, uint32_t rgb) { FUN("sdl_plot"); sdl_text_t *t; SDL_Rect rc; uint32_t col; uint8_t r, g, b; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); rc.x += x; rc.y += y; rc.w = 1; rc.h = 1; r = sdl_get_r(rgb); g = sdl_get_g(rgb); b = sdl_get_b(rgb); col = SDL_MapRGB(sdl->scr->format, r, g, b); SDL_FillRect(sdl->scr, &rc, col); return 0; } /** * @brief draw a graph onto a rectangular canvas * * @param sdl pointer to a SDL context * @param pane pane number * @param prc pointer to a (text coordinates) rectangle * @param graph pointer to a sdl_graph_t context */ int sdl_draw_graph(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, sdl_graph_t *graph) { FUN("sdl_draw_graph"); sdl_text_t *t; SDL_Rect rc; uint32_t col; uint8_t r, g, b; int x0, y0, x1, y1; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; /* scale rect from font to pixel coordinates */ rc.x = x0 = t->tx + prc->x * sdl->font_w; rc.y = y0 = t->ty + prc->y * sdl->font_h; rc.w = x1 = prc->w * sdl->font_w; rc.h = y1 = prc->h * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); SDL_FillRect(sdl->scr, &rc, SDL_MapRGB(sdl->scr->format, 255, 255, 255)); x1 += x0; y1 += y0; x0++; y0++; x1--; y1--; while (graph) { /* set 1x1 pixels */ rc.w = 1; rc.h = 1; r = sdl_get_r(graph->col); g = sdl_get_g(graph->col); b = sdl_get_b(graph->col); col = SDL_MapRGB(sdl->scr->format, r, g, b); /* skip if no values or no range */ if (graph->max > 0 && graph->minval != graph->maxval) { double hscale = (double)(x1 - x0) / graph->max; double vscale = (double)(y1 - y0) / (graph->maxval - graph->minval); ssize_t n; for (n = 0; n < graph->max; n++) { ssize_t i = (graph->num + n) % graph->max; rc.x = x0 + n * hscale; rc.y = y1 - (graph->value[i] - graph->minval) * vscale; SDL_FillRect(sdl->scr, &rc, col); } } graph = graph->next; } SDL_UpdateRect(sdl->scr, x0, y0, x0 + 1 - x0, y1 + 1 - y0); return 0; } /** * @brief draw a progress bar in a text rectangle * * @param sdl pointer to a SDL context * @param prc pointer to a rectangle (text coordinates) */ int sdl_progress_bar(sdl_t *sdl, sdl_pane_t pane, rect_t *prc, uint32_t rgb0, uint32_t rgb1, uint32_t rgb2, int min, int cur, int max) { FUN("sdl_progress_bar"); sdl_text_t *t; SDL_Rect rc; uint32_t col0, col1; uint8_t r, g, b; int x0, y0, x1, y1, xs; double range; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } if (NULL == prc) { LOG(ERROR,(_fun,"invalid prc %p\n", prc)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; rc.x = t->tx; rc.y = t->ty; rc.w = t->tw * sdl->font_w; rc.h = t->th * sdl->font_h; SDL_SetClipRect(sdl->scr, &rc); sdl_dirty_rect(sdl, pane, prc); x0 = t->tx + prc->x * sdl->font_w + 1; y0 = t->ty + prc->y * sdl->font_h + 1; x1 = x0 + prc->w * sdl->font_w - 2; y1 = y0 + prc->h * sdl->font_h - 2; r = sdl_get_r(rgb0) & 0xff; g = sdl_get_g(rgb0) & 0xff; b = sdl_get_b(rgb0) & 0xff; col0 = SDL_MapRGB(sdl->scr->format, r, g, b); r = sdl_get_r(rgb1) & 0xff; g = sdl_get_g(rgb1) & 0xff; b = sdl_get_b(rgb1) & 0xff; col1 = SDL_MapRGB(sdl->scr->format, r, g, b); /* split x value */ range = (double)max + 1.0 - min; if (range <= 0) range = 1.0; xs = (int)(((double)cur - min) * (x1 + 1 - x0) / range); /* left part */ rc.x = x0; rc.y = y0; rc.w = xs + 1; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col0); /* right part */ rc.x = x0 + xs; rc.y = y0; rc.w = (x1 + 1 - x0) - xs; rc.h = y1 + 1 - y0; SDL_FillRect(sdl->scr, &rc, col1); sdl_printf(sdl, pane, NULL, prc->x + (prc->w - 4) / 2, prc->y, TEXT_GRAY | TEXT_SEL | TEXT_TRANSPARENT, "%3d%%", (int)(cur * 100 / range)); return sdl_frame_rect(sdl, pane, prc, 1, rgb2, rgb2); } /** * @brief update a sdl_t context * * @param sdl pointer to a SDL context * @param what update region (0 none, 1 picture, 2 text, 3 both) * @result 0 on sucess, -1 on error, 1 on resize event */ int sdl_update(sdl_t *sdl, int what) { FUN("sdl_update"); SDL_Event ev; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } while (SDL_PollEvent(&ev)) { switch (ev.type) { case SDL_VIDEORESIZE: sdl_resize(sdl, ev.resize.w, ev.resize.h); return 1; case SDL_MOUSEMOTION: sdl->mousex = ev.motion.x; sdl->mousey = ev.motion.y; sdl->mouseb = (sdl->mouseb & ~1) | (ev.motion.state & 1); SDL_ShowCursor(1); break; case SDL_MOUSEBUTTONDOWN: sdl->mouseb |= SDL_BUTTON(ev.button.button); break; case SDL_MOUSEBUTTONUP: sdl->mouseb &= ~SDL_BUTTON(ev.button.button); break; case SDL_QUIT: sdl->closing = 1; } } switch (what) { case 1: SDL_UpdateRect(sdl->scr, 0, 0, sdl->width, sdl->height); break; case 2: SDL_UpdateRect(sdl->scr, 0, sdl->height, sdl->width, sdl->border); break; case 3: SDL_UpdateRect(sdl->scr, 0, 0, sdl->width, sdl->height + sdl->border); } return sdl->closing ? -1 : 0; } /** * @brief delay a number of milliseconds * * @param sdl pointer to a SDL context * @param ms time in milliseconds to delay * @result 0 on sucess, -1 on error */ int sdl_delay(sdl_t *sdl, int ms) { FUN("sdl_delay"); if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } SDL_Delay(ms); return 0; } /** * @brief start a one-shot timer to call callback(cookie) * * @param sdl pointer to a SDL context * @param ms time in milliseconds to delay * @param cookie user data to pass to the callback * @param callback callback function pointer * @result 0 on sucess, -1 on error */ int sdl_set_timer(sdl_t *sdl, int ms, void *cookie, void (*callback)(void *cookie)) { FUN("sdl_set_timer"); int i; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %p\n", sdl)); errno = EINVAL; return -1; } for (i = 0; i < SDL_MAX_TIMER; i++) if (!timer_callback[i]) break; if (i >= SDL_MAX_TIMER) { LOG(ERROR,(_fun,"ran out of timers (%d)\n", i)); errno = EINVAL; return -1; } timer_callback[i] = callback; timer_cookie[i] = cookie; timer_interval[i] = ms; return SDL_SetTimer(ms, sdl_timer_callback); } /** * @brief callback that is called from SDL * * @param receives the interval in milliseconds * @result 0 to cancel the periodic alarm */ static uint32_t sdl_timer_callback(uint32_t interval) { void (*callback)(void *); void *cookie; int i; for (i = 0; i < SDL_MAX_TIMER; i++) { if (NULL == timer_callback[i]) continue; if (interval != timer_interval[i]) continue; cookie = timer_cookie[i]; timer_cookie[i] = NULL; callback = timer_callback[i]; timer_callback[i] = NULL; timer_interval[i] = 0; (void)(*callback)(cookie); } return 0; } /** * @brief make a cursor from a string of "pixels" * * A string of w*h characters defines the shape and mask of a cursor. * . is for an empty pixel (pix = 0, msk = 0) * x is for a set pixel (pix = 1, msk = 1) * # is for a masked pixel (pix = 0, msk = 1) * o is for a xor pixel (pix = 1, msk = 0) * * @param pix pointer to a buffer to receive the pixel data ((w*h+7)/8 bytes) * @param msk pointer to a buffer to receive the mask data ((w*h+7)/8 bytes) * @param w width of the cursor * @param h height of the cursor * @param src pointer to a string representing the cursor * @result 0 on success */ static int sdl_make_cursor(uint8_t *pix, uint8_t *msk, int w, int h, const char *src) { int x, y; for (y = 0; y < h; y++) { *pix = 0; *msk = 0; for (x = 0; x < w; x++) { switch (*src++) { case '.': /* both 0 */ break; case 'x': *pix |= 0x80 >> (x % 8); *msk |= 0x80 >> (x % 8); break; case '#': *msk |= 0x80 >> (x % 8); break; case 'o': *pix |= 0x80 >> (x % 8); break; } if (7 == (x & 7)) { pix++; *pix = 0; msk++; *msk = 0; } } if (w & 7) { pix++; msk++; } } return 0; } /** * @brief output a character to the border area * * @param sdl pointer to a SDL context * @param x text column between 0 and sdl->tw-1 (clipped) * @param y text row between 0 and sdl->th-1 (clipped) * @param ch character code between 0 and 255 * @param col color between 0 and TEXT_COLORS-1 (clipped) * @result 0 on success, -1 on error */ static int sdl_putch(sdl_t *sdl, sdl_pane_t pane, int x, int y, int ch, int col) { FUN("sdl_putch"); sdl_text_t *t; SDL_Rect src; SDL_Rect dst; ssize_t offs; int transp; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %t\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; if (x < 0 || x >= t->cw || y < 0 || y >= t->ch) return 0; if (col & TEXT_TRANSPARENT) { transp = 1; col &= ~TEXT_TRANSPARENT; } else { transp = 0; } if (col < 0 || col >= TEXT_COLORS) { LOG(INFO4,(_fun,"color off scope (%d)\n", col)); errno = ERANGE; return -1; } offs = y * t->tw + x; /* check if character code didn't change */ if (ch == t->text[offs] && col == t->cmap[offs]) return 0; /* set new text and color */ t->text[offs] = ch; t->cmap[offs] = col; /* blit from font surface */ src.y = (col & (TEXT_COLORS - 1)) * sdl->font_h; src.x = ch * sdl->font_w; src.w = sdl->font_w; src.h = sdl->font_h; /* blit to screen surface */ dst.x = t->tx + x * sdl->font_w; dst.y = t->ty + y * sdl->font_h; dst.w = sdl->font_w; dst.h = sdl->font_h; if (!transp) { uint8_t r, g, b; switch (col & (TEXT_SEL | TEXT_BUTTON)) { case TEXT_SEL: /* selected background */ r = sdl_get_r(t->rgb_bg[1]); g = sdl_get_r(t->rgb_bg[1]); b = sdl_get_r(t->rgb_bg[1]); break; case TEXT_BUTTON: /* button face background */ r = sdl_get_r(t->rgb_bg[2]); g = sdl_get_r(t->rgb_bg[2]); b = sdl_get_r(t->rgb_bg[2]); break; case TEXT_SEL | TEXT_BUTTON: /* selected button face background */ r = sdl_get_r(t->rgb_bg[3]); g = sdl_get_r(t->rgb_bg[3]); b = sdl_get_r(t->rgb_bg[3]); break; default: /* default background */ r = sdl_get_r(t->rgb_bg[0]); g = sdl_get_r(t->rgb_bg[0]); b = sdl_get_r(t->rgb_bg[0]); break; } SDL_FillRect(sdl->scr, &dst, SDL_MapRGB(sdl->scr->format, r,g,b)); } SDL_SetAlpha(sdl->font, SDL_SRCALPHA, 255); SDL_BlitSurface(sdl->font, &src, sdl->scr, &dst); return 0; } /** * @brief dirty a character (text/cmap) rectangle in one of the text panes * * @param sdl pointer to a SDL context * @param prc pointer to a rectangle to dirty * @result 0 on success, -1 on error */ int sdl_dirty_rect(sdl_t *sdl, sdl_pane_t pane, rect_t *prc) { FUN("sdl_dirty"); sdl_text_t *t; ssize_t offs; int x, y; if (!SDL_VALID(sdl)) { LOG(ERROR,(_fun,"invalid sdl_t* %t\n", sdl)); errno = EINVAL; return -1; } if (pane < 0 || pane >= SDL_PANES) { LOG(ERROR,(_fun,"invalid pane %d\n", pane)); errno = EINVAL; return -1; } t = &sdl->pane[pane]; for (y = MAX(prc->y, 0); y < MIN(t->th, prc->y + prc->h); y++) { for (x = MAX(prc->x, 0); x < MIN(t->tw, prc->x + prc->w); x++) { offs = y * t->tw + x; /* set new text and color */ t->text[offs] = 0xff; t->cmap[offs] = 0; } } return 0; }