/************************************************************************
 *
 * SDL layer
 *
 * Copyright (C) 2007, Juergen Buchmueller <pullmoll@t-online.de>
 *
 * Partially based on ShrinkTo5, Copyright (C) 2004-2005
 * Ocrana <info@shrinkto5.com> and Andrei Grecu <info@shrinkto5.com>
 *
 *  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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <SDL.h>

#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;
}
