/*
	YAMAHA YIS Emulator 'eYIS'

	Author : Takeda.Toshiya
	Date   : 2017.04.20-

	[ display ]
*/

#include <math.h>
#include "display.h"
#include "../../fifo.h"

#ifndef M_PI
#define M_PI	3.14159265358979323846
#endif
#define POW	2

//		Char	Graph10	Graph20	English
// PU-1-10	O	X	X	X
// PU-1-20	O	X	O	O
// PU-10	O	O	X	X

static const struct {
	int length;
	uint8_t dots[32];
} texture_table[8] = {
	{ 1,	{1}},
	{ 4,	{1, 1, 0, 0}},
	{11,	{1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0}},
	{16,	{1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}},
	{ 8,	{1, 1, 1, 1, 0, 0, 0, 0}},
	{16,	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0}},
	{32,	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}},
	{32,	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0}},
};

static const uint16_t pattern_table[128][16] = {
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},	// 0
	{0x7777, 0xffff, 0xffff, 0xffff, 0x7777, 0xffff, 0xffff, 0xffff, 0x7777, 0xffff, 0xffff, 0xffff, 0x7777, 0xffff, 0xffff, 0xffff},
	{0x7777, 0xffff, 0xdddd, 0xffff, 0x7777, 0xffff, 0xdddd, 0xffff, 0x7777, 0xffff, 0xdddd, 0xffff, 0x7777, 0xffff, 0xdddd, 0xffff},
	{0x5555, 0xffff, 0xdddd, 0xffff, 0x5555, 0xffff, 0xdddd, 0xffff, 0x5555, 0xffff, 0xdddd, 0xffff, 0x5555, 0xffff, 0xdddd, 0xffff},
	{0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff},
	{0x5555, 0xbbbb, 0x5555, 0xffff, 0x5555, 0xbbbb, 0x5555, 0xffff, 0x5555, 0xbbbb, 0x5555, 0xffff, 0x5555, 0xbbbb, 0x5555, 0xffff},
	{0x5555, 0xbbbb, 0x5555, 0xeeee, 0x5555, 0xbbbb, 0x5555, 0xeeee, 0x5555, 0xbbbb, 0x5555, 0xeeee, 0x5555, 0xbbbb, 0x5555, 0xeeee},
	{0x5555, 0xaaaa, 0x5555, 0xeeee, 0x5555, 0xaaaa, 0x5555, 0xeeee, 0x5555, 0xaaaa, 0x5555, 0xeeee, 0x5555, 0xaaaa, 0x5555, 0xeeee},
	{0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa},
	{0x1111, 0xaaaa, 0x5555, 0xaaaa, 0x1111, 0xaaaa, 0x5555, 0xaaaa, 0x1111, 0xaaaa, 0x5555, 0xaaaa, 0x1111, 0xaaaa, 0x5555, 0xaaaa},
	{0x1111, 0xaaaa, 0x4444, 0xaaaa, 0x1111, 0xaaaa, 0x4444, 0xaaaa, 0x1111, 0xaaaa, 0x4444, 0xaaaa, 0x1111, 0xaaaa, 0x4444, 0xaaaa},
	{0x0000, 0xaaaa, 0x4444, 0xaaaa, 0x0000, 0xaaaa, 0x4444, 0xaaaa, 0x0000, 0xaaaa, 0x4444, 0xaaaa, 0x0000, 0xaaaa, 0x4444, 0xaaaa},
	{0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa},
	{0x0000, 0x2222, 0x0000, 0xaaaa, 0x0000, 0x2222, 0x0000, 0xaaaa, 0x0000, 0x2222, 0x0000, 0xaaaa, 0x0000, 0x2222, 0x0000, 0xaaaa},
	{0x0000, 0x2222, 0x0000, 0x8888, 0x0000, 0x2222, 0x0000, 0x8888, 0x0000, 0x2222, 0x0000, 0x8888, 0x0000, 0x2222, 0x0000, 0x8888},
	{0x0000, 0x0000, 0x0000, 0x8888, 0x0000, 0x0000, 0x0000, 0x8888, 0x0000, 0x0000, 0x0000, 0x8888, 0x0000, 0x0000, 0x0000, 0x8888},

	{0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000},	// 16
	{0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000},
	{0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa},
	{0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555, 0x0000, 0x5555},
	{0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000},
	{0x5555, 0x5555, 0x0000, 0x0000, 0x5555, 0x5555, 0x0000, 0x0000, 0x5555, 0x5555, 0x0000, 0x0000, 0x5555, 0x5555, 0x0000, 0x0000},
	{0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0xaaaa, 0xaaaa},
	{0x0000, 0x0000, 0x5555, 0x5555, 0x0000, 0x0000, 0x5555, 0x5555, 0x0000, 0x0000, 0x5555, 0x5555, 0x0000, 0x0000, 0x5555, 0x5555},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},

	{0xffff, 0x8888, 0x8888, 0x8888, 0xffff, 0x8888, 0x8888, 0x8888, 0xffff, 0x8888, 0x8888, 0x8888, 0xffff, 0x8888, 0x8888, 0x8888},	// 32
	{0xffff, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0xffff, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080},
	{0xffff, 0xffff, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xffff, 0xffff, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0},
	{0xffff, 0xc0c0, 0xc0c0, 0xc0c0, 0xffff, 0xc0c0, 0xc0c0, 0xc0c0, 0xffff, 0xc0c0, 0xc0c0, 0xc0c0, 0xffff, 0xc0c0, 0xc0c0, 0xc0c0},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},

	{0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555},	// 48
	{0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333, 0xcccc, 0x3333},
	{0xaaaa, 0xaaaa, 0x5555, 0x5555, 0xaaaa, 0xaaaa, 0x5555, 0x5555, 0xaaaa, 0xaaaa, 0x5555, 0x5555, 0xaaaa, 0xaaaa, 0x5555, 0x5555},
	{0xcccc, 0xcccc, 0x3333, 0x3333, 0xcccc, 0xcccc, 0x3333, 0x3333, 0xcccc, 0xcccc, 0x3333, 0x3333, 0xcccc, 0xcccc, 0x3333, 0x3333},
	{0xcccc, 0xcccc, 0xcccc, 0xcccc, 0x3333, 0x3333, 0x3333, 0x3333, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0x3333, 0x3333, 0x3333, 0x3333},
	{0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f},
	{0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0x5555, 0x5555, 0x5555, 0x5555, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0x5555, 0x5555, 0x5555, 0x5555},
	{0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555},
	{0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333},
	{0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},

	{0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000},	// 64
	{0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa},
	{0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000},
	{0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0, 0xc0c0},
	{0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000},
	{0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
	{0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},

	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},	// 80
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},

	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},	// 96
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},
	{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff},

	{0xffff, 0x8181, 0x8181, 0x9999, 0x9999, 0x8181, 0x8181, 0xffff, 0xffff, 0x8181, 0x8181, 0x9999, 0x9999, 0x8181, 0x8181, 0xffff},	// 112
	{0xffff, 0x9999, 0x9999, 0x8181, 0x8181, 0x8181, 0x8181, 0xffff, 0xffff, 0x9999, 0x9999, 0x8181, 0x8181, 0x8181, 0x8181, 0xffff},
	{0xc3c3, 0x9999, 0x9999, 0x8181, 0x8181, 0x9999, 0x9999, 0xc3c3, 0xc3c3, 0x9999, 0x9999, 0x8181, 0x8181, 0x9999, 0x9999, 0xc3c3},
	{0xffff, 0xc3c3, 0x9999, 0x9999, 0x7e7e, 0x4242, 0x1818, 0x0000, 0xffff, 0xc3c3, 0x9999, 0x9999, 0x7e7e, 0x4242, 0x1818, 0x0000},
	{0xffff, 0x8080, 0x8c8c, 0x8c8c, 0x8181, 0x8f8f, 0x8f8f, 0x8787, 0xc3c3, 0xe1e1, 0xf0f0, 0xf8f8, 0xf0f0, 0xe1e1, 0xc3c3, 0x8787},
	{0x1818, 0x3030, 0x6060, 0xc0c0, 0x1818, 0x0c0c, 0x0606, 0x0303, 0x1818, 0x3030, 0x6060, 0xc0c0, 0x1818, 0x0c0c, 0x0606, 0x0303},
	{0x1818, 0x1818, 0x3030, 0x3030, 0x6060, 0x6060, 0xc0c0, 0xc0c0, 0x1818, 0x1818, 0x0c0c, 0x0c0c, 0x0606, 0x0606, 0x0303, 0x0303},
	{0x8888, 0x6666, 0x1111, 0x1111, 0x8888, 0x6666, 0x1111, 0x1111, 0x8888, 0x6666, 0x1111, 0x1111, 0x8888, 0x6666, 0x1111, 0x1111},
	{0x0f0f, 0x0e0e, 0x0c0c, 0x0808, 0xf0f0, 0x7070, 0x3030, 0x1010, 0x0f0f, 0x0e0e, 0x0c0c, 0x0808, 0xf0f0, 0x7070, 0x3030, 0x1010},
	{0x0f0f, 0x0f0f, 0x0e0e, 0x0e0e, 0x0c0c, 0x0c0c, 0x0808, 0x0808, 0xf0f0, 0xf0f0, 0x7070, 0x7070, 0x3030, 0x3030, 0x1010, 0x1010},
	{0xfcfc, 0x8c8c, 0xa4a4, 0xf4f4, 0x9f9f, 0xa4a4, 0x8484, 0xfcfc, 0x0303, 0x7373, 0x5b5b, 0x0b0b, 0x6b6b, 0x5b5b, 0x7b7b, 0x0303},
	{0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999, 0xaaaa, 0xbbbb, 0xcccc, 0xdddd, 0xeeee, 0xffff},	// 123 FIXME
	{0x0000, 0x0000, 0x1111, 0x1111, 0x2222, 0x2222, 0x3333, 0x3333, 0x4444, 0x4444, 0x5555, 0x5555, 0x6666, 0x6666, 0x7777, 0x7777},	// 124 FIXME
	{0xfe00, 0xfe00, 0xe1c0, 0xe1c0, 0x0e1c, 0x0e1c, 0x01fc, 0x01fc, 0xfe00, 0xfe00, 0xe1c0, 0xe1c0, 0x0e1c, 0x0e1c, 0x01fc, 0x01fc},
	{0xfe00, 0xfe00, 0xfe00, 0xe000, 0xe1c0, 0xe1c0, 0xe1c0, 0x0e1c, 0x0e1c, 0x0e1c, 0x001c, 0x01fc, 0x01fc, 0x01fc, 0x0000, 0x0000},
	{0x5555, 0x5555, 0x3333, 0x3333, 0x5555, 0x5555, 0x3333, 0x3333, 0xcccc, 0xcccc, 0xaaaa, 0xaaaa, 0xcccc, 0xcccc, 0xaaaa, 0xaaaa},
};

// KST32B
static const uint8_t char_table[256][32] = {
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x21, 0x7E, 0x00},
	{0x26, 0xA6, 0x42, 0xC3, 0x45, 0xC6, 0xA9, 0x68, 0xDB, 0x4C, 0x65, 0xC9, 0x00},
	{0x26, 0xB7, 0xDD, 0x2B, 0xD7, 0x00},
	{0x21, 0xAB, 0x4E, 0xB5, 0x40, 0x26, 0xBB, 0x61, 0xC4, 0x2B, 0x6D, 0xDB, 0x00},
	{0x21, 0xA4, 0x4B, 0x6E, 0xC7, 0xCD, 0x6B, 0xD0, 0x44, 0x61, 0xD3, 0xD7, 0x64, 0xDA, 0x4E, 0x2B, 0xBC, 0xC2, 0x28, 0xDC, 0x00},
	{0x21, 0xB4, 0x62, 0xD1, 0x44, 0x66, 0xD4, 0xD8, 0x64, 0xDB, 0x42, 0x60, 0xD8, 0xD4, 0xA3, 0x6E, 0xDB, 0xAA, 0x6C, 0xCD, 0x4A, 0x68, 0xCA, 0xC6, 0x6A, 0xC3, 0x4C, 0x6E, 0xC6, 0xCA, 0x00},
	{0x30, 0xA3, 0x6A, 0xC5, 0x67, 0xC9, 0x62, 0xD6, 0xDA, 0x64, 0xDC, 0x47, 0x69, 0xDA, 0xD7, 0x67, 0xD3, 0x62, 0xD0, 0x60, 0xCC, 0xC6, 0x63, 0xC3, 0x46, 0x68, 0xC4, 0x6E, 0xCD, 0x00},
	{0x28, 0xB6, 0xDC, 0x48, 0x66, 0xD8, 0x00},
	{0x2D, 0xBC, 0x68, 0xDA, 0x66, 0xD7, 0x65, 0xD3, 0xCB, 0x66, 0xC7, 0x68, 0xC4, 0x6B, 0xC2, 0x00},
	{0x24, 0xBC, 0x66, 0xDA, 0x68, 0xD7, 0x69, 0xD3, 0xCB, 0x68, 0xC7, 0x66, 0xC4, 0x63, 0xC2, 0x00},
	{0x21, 0xA9, 0x6E, 0xD6, 0x21, 0x6E, 0xC9, 0x29, 0xA6, 0xD9, 0x00},
	{0x22, 0xB0, 0x4D, 0x29, 0xB8, 0xC8, 0x00},
	{0x28, 0xA7, 0x65, 0xC5, 0x64, 0xC7, 0x65, 0xC9, 0x67, 0xC7, 0x66, 0xC4, 0x63, 0xC1, 0x00},
	{0x22, 0xB0, 0x4D, 0x00},
	{0x25, 0xA5, 0x66, 0xC3, 0x68, 0xC5, 0x66, 0xC7, 0x64, 0xC5, 0x48, 0x28, 0xA7, 0xC3, 0x00},
	{0x21, 0xA4, 0x6E, 0xDB, 0x00},
	{0x21, 0xB5, 0xC9, 0x62, 0xC5, 0x65, 0xC3, 0x48, 0x6B, 0xC5, 0x6D, 0xC9, 0xD5, 0x6B, 0xD9, 0x68, 0xDB, 0x45, 0x62, 0xD9, 0x60, 0xD5, 0x00},
	{0x24, 0xA3, 0x4B, 0x29, 0xDC, 0x63, 0xD6, 0x00},
	{0x21, 0xB6, 0x62, 0xD9, 0x65, 0xDB, 0x4A, 0x6C, 0xDA, 0x6E, 0xD7, 0xD3, 0x6C, 0xCE, 0x67, 0xC9, 0x60, 0xC3, 0x4E, 0x00},
	{0x21, 0xBB, 0x4D, 0x64, 0xD1, 0x49, 0x6C, 0xCF, 0x6D, 0xCD, 0xC7, 0x6C, 0xC5, 0x69, 0xC3, 0x44, 0x62, 0xC4, 0x60, 0xC6, 0x00},
	{0x2C, 0xA3, 0xDB, 0x29, 0xBC, 0x60, 0xCC, 0xCA, 0x4E, 0x00},
	{0x21, 0xA6, 0x61, 0xC4, 0x63, 0xC3, 0x49, 0x6B, 0xC4, 0x6D, 0xC7, 0xCE, 0x6C, 0xD0, 0x69, 0xD2, 0x43, 0x60, 0xD0, 0xAF, 0xDB, 0x4D, 0x00},
	{0x2F, 0xB9, 0x6A, 0xDB, 0x45, 0x62, 0xD9, 0x60, 0xD5, 0xC7, 0x61, 0xC5, 0x64, 0xC3, 0x49, 0x6C, 0xC5, 0x6D, 0xC7, 0xCD, 0x6C, 0xCF, 0x69, 0xD1, 0x44, 0x60, 0xCF, 0x00},
	{0x21, 0xB7, 0xDB, 0x4E, 0xD9, 0x69, 0xD1, 0x67, 0xCA, 0xC3, 0x00},
	{0x21, 0xA6, 0xCE, 0x63, 0xD1, 0x4B, 0x6E, 0xCE, 0xC6, 0x6B, 0xC3, 0x43, 0x60, 0xC6, 0x25, 0xB1, 0x61, 0xD4, 0xD8, 0x64, 0xDB, 0x4A, 0x6D, 0xD8, 0xD4, 0x6A, 0xD1, 0x00},
	{0x21, 0xA5, 0x64, 0xC3, 0x48, 0x6B, 0xC5, 0x6D, 0xC9, 0xD8, 0x6B, 0xDA, 0x69, 0xDB, 0x44, 0x62, 0xDA, 0x60, 0xD8, 0xD0, 0x62, 0xCE, 0x64, 0xCD, 0x4A, 0x6D, 0xD0, 0x00},
	{0x26, 0xAB, 0x67, 0xCD, 0x69, 0xCB, 0x67, 0xC9, 0x65, 0xCB, 0x49, 0xB4, 0x45, 0x67, 0xD2, 0x69, 0xD4, 0x67, 0xD6, 0x65, 0xD4, 0x00},
	{0x29, 0xB2, 0x65, 0xD4, 0x67, 0xD6, 0x69, 0xD4, 0x67, 0xD2, 0xD5, 0xA4, 0x69, 0xC7, 0xCB, 0x67, 0xCD, 0x65, 0xCB, 0x67, 0xC9, 0x49, 0x67, 0xCB, 0x00},
	{0x30, 0xA9, 0x60, 0xD0, 0x6E, 0xD7, 0x00},
	{0x22, 0xAD, 0x4D, 0xB3, 0x41, 0x00},
	{0x21, 0xA9, 0x6E, 0xD0, 0x60, 0xD7, 0x00},
	{0x21, 0xB5, 0xD8, 0x63, 0xDB, 0x4A, 0x6D, 0xD8, 0xD3, 0x6A, 0xD0, 0x67, 0xCC, 0xCA, 0xA6, 0x69, 0xC4, 0x67, 0xC2, 0x65, 0xC4, 0x67, 0xC6, 0xC3, 0x00},
	{0x2C, 0xA3, 0x44, 0x60, 0xC7, 0xD8, 0x64, 0xDC, 0x4A, 0x6E, 0xD8, 0xC7, 0xB2, 0x6B, 0xD5, 0x48, 0x65, 0xD1, 0xCB, 0x67, 0xC8, 0x4A, 0x6E, 0xCC, 0x00},
	{0x21, 0xA3, 0x67, 0xDC, 0x6E, 0xC3, 0x24, 0xAC, 0x4B, 0x00},
	{0x21, 0xA3, 0x4A, 0x6D, 0xC5, 0x6E, 0xC7, 0xCD, 0x6D, 0xCF, 0x69, 0xD1, 0x41, 0xA3, 0xDC, 0x21, 0x49, 0x6C, 0xDA, 0x6D, 0xD8, 0xD5, 0x6C, 0xD3, 0x69, 0xD1, 0x00},
	{0x30, 0xBC, 0xD6, 0xB8, 0x6A, 0xDC, 0x44, 0x62, 0xDA, 0x60, 0xD6, 0xCA, 0x62, 0xC5, 0x64, 0xC3, 0x4A, 0x6D, 0xC6, 0x6E, 0xC9, 0x00},
	{0x21, 0xBC, 0x48, 0x6B, 0xDA, 0x6D, 0xD7, 0xC8, 0x6B, 0xC5, 0x68, 0xC3, 0x40, 0x22, 0xDC, 0x00},
	{0x21, 0xBC, 0x4E, 0xA3, 0x40, 0x22, 0xDC, 0xB1, 0x4C, 0x00},
	{0x21, 0xBC, 0x4E, 0x22, 0xC3, 0xB0, 0x4B, 0x00},
	{0x30, 0xB7, 0x6C, 0xDA, 0x69, 0xDC, 0x45, 0x62, 0xDA, 0x60, 0xD7, 0xC8, 0x62, 0xC5, 0x65, 0xC3, 0x4A, 0x6E, 0xC6, 0xCE, 0x4B, 0x00},
	{0x22, 0xA3, 0xDC, 0x2F, 0xC3, 0xB0, 0x41, 0x00},
	{0x24, 0xA3, 0x4B, 0x29, 0xDC, 0x24, 0x4B, 0x00},
	{0x21, 0xA5, 0x63, 0xC2, 0x47, 0x6A, 0xC4, 0x6C, 0xC8, 0xDC, 0x00},
	{0x22, 0xA3, 0xDC, 0x2F, 0x61, 0xD0, 0x23, 0xB1, 0x6E, 0xC3, 0x00},
	{0x21, 0xA3, 0x4E, 0x22, 0xDC, 0x00},
	{0x21, 0xA3, 0x62, 0xDC, 0x67, 0xC9, 0x6C, 0xDC, 0x6E, 0xC3, 0x00},
	{0x22, 0xA3, 0xDC, 0x6D, 0xC3, 0xDC, 0x00},
	{0x21, 0xAA, 0x62, 0xC5, 0x64, 0xC3, 0x49, 0x6B, 0xC5, 0x6D, 0xCA, 0xD5, 0x6B, 0xDA, 0x69, 0xDC, 0x44, 0x62, 0xDA, 0x60, 0xD5, 0xCA, 0x00},
	{0x21, 0xBC, 0x4A, 0x6C, 0xDB, 0x6E, 0xD9, 0xD3, 0x6C, 0xD1, 0x6A, 0xD0, 0x41, 0xBC, 0xC3, 0x00},
	{0x21, 0xA9, 0xD6, 0x62, 0xDA, 0x65, 0xDC, 0x48, 0x6B, 0xDA, 0x6D, 0xD6, 0xC9, 0x6B, 0xC5, 0x68, 0xC3, 0x45, 0x62, 0xC5, 0x60, 0xC9, 0x25, 0x47, 0x6A, 0xC7, 0x6E, 0xC1, 0x00},
	{0x21, 0xBC, 0x4A, 0x6C, 0xDB, 0x6E, 0xD8, 0xD4, 0x6C, 0xD1, 0x6A, 0xD0, 0x41, 0x29, 0x6D, 0xC3, 0x4E, 0x22, 0xDC, 0x00},
	{0x21, 0xA6, 0x62, 0xC3, 0x4A, 0x6D, 0xC6, 0xCC, 0x6A, 0xCF, 0x62, 0xD2, 0x60, 0xD5, 0xD9, 0x63, 0xDC, 0x4A, 0x6D, 0xDA, 0x00},
	{0x21, 0xBC, 0x4E, 0x29, 0xC3, 0x00},
	{0x22, 0xBC, 0xC8, 0x62, 0xC5, 0x64, 0xC3, 0x4A, 0x6C, 0xC5, 0x6D, 0xC8, 0xDC, 0x00},
	{0x21, 0xBC, 0x67, 0xC3, 0x6E, 0xDC, 0x00},
	{0x21, 0xBC, 0x63, 0xC3, 0x67, 0xD5, 0x6B, 0xC3, 0x6E, 0xDC, 0x00},
	{0x21, 0xA3, 0x6E, 0xDC, 0x21, 0x6E, 0xC3, 0x00},
	{0x21, 0xBC, 0x67, 0xD1, 0xC3, 0xB1, 0x6E, 0xDC, 0x00},
	{0x21, 0xBC, 0x4D, 0x60, 0xC3, 0x4D, 0x00},
	{0x2E, 0xBC, 0x47, 0xC2, 0x4C, 0x00},
	{0x21, 0xBB, 0x6E, 0xC4, 0x2A, 0xB0, 0x45, 0x00},
	{0x23, 0xBC, 0x47, 0xC2, 0x42, 0x00},
	{0x24, 0xB8, 0x67, 0xDD, 0x6B, 0xD8, 0x00},
	{0x21, 0xA1, 0x4E, 0x00},
	{0x2B, 0xB7, 0x68, 0xDD, 0x46, 0x68, 0xDA, 0x00},
	{0x30, 0xA3, 0x6C, 0xC6, 0xD2, 0x6A, 0xD5, 0x43, 0x60, 0xD3, 0x2E, 0xB0, 0x63, 0xCE, 0x60, 0xCB, 0xC6, 0x63, 0xC3, 0x49, 0x6C, 0xC6, 0x00},
	{0x22, 0xA3, 0xDC, 0xB1, 0x64, 0xD5, 0x4A, 0x6D, 0xD1, 0xC7, 0x6A, 0xC3, 0x44, 0x61, 0xC7, 0x00},
	{0x2F, 0xB5, 0xD0, 0xB1, 0x6A, 0xD5, 0x43, 0x60, 0xD1, 0xC7, 0x63, 0xC3, 0x4A, 0x6D, 0xC7, 0x00},
	{0x2F, 0xBC, 0xC3, 0xA7, 0x6A, 0xC3, 0x43, 0x60, 0xC7, 0xD1, 0x63, 0xD5, 0x4A, 0x6D, 0xD1, 0x00},
	{0x21, 0xAE, 0x4D, 0xD0, 0x6B, 0xD3, 0x68, 0xD5, 0x45, 0x62, 0xD3, 0x60, 0xD0, 0xC8, 0x62, 0xC5, 0x65, 0xC3, 0x48, 0x6B, 0xC5, 0x6D, 0xC7, 0x00},
	{0x29, 0xA3, 0xD7, 0x68, 0xDA, 0x6B, 0xDC, 0x4E, 0x2E, 0xB4, 0x42, 0x00},
	{0x21, 0xA2, 0x63, 0xC0, 0x4A, 0x6D, 0xC3, 0xD5, 0xB2, 0x6A, 0xD5, 0x44, 0x61, 0xD2, 0xCA, 0x64, 0xC7, 0x4A, 0x6D, 0xC9, 0x00},
	{0x22, 0xA3, 0xDC, 0xB2, 0x64, 0xD5, 0x4A, 0x6D, 0xD2, 0xC3, 0x00},
	{0x23, 0xA3, 0x4B, 0x29, 0xD5, 0x44, 0xBB, 0x66, 0xD8, 0x68, 0xDB, 0x44, 0x00},
	{0x21, 0xA3, 0x63, 0xC1, 0x46, 0x69, 0xC3, 0x6B, 0xC7, 0xD4, 0x48, 0xBA, 0x6A, 0xD7, 0x6C, 0xDA, 0x48, 0x00},
	{0x22, 0xA3, 0xDC, 0xAD, 0x6D, 0xD5, 0xA3, 0x63, 0xCE, 0x00},
	{0x23, 0xA3, 0x4B, 0x29, 0xDC, 0x44, 0x00},
	{0x21, 0xA3, 0xD5, 0xB2, 0x62, 0xD5, 0x45, 0x67, 0xD2, 0xC3, 0xB2, 0x69, 0xD5, 0x4C, 0x6E, 0xD2, 0xC3, 0x00},
	{0x22, 0xA3, 0xD5, 0xB1, 0x64, 0xD5, 0x4A, 0x6D, 0xD1, 0xC3, 0x00},
	{0x22, 0xB1, 0xC7, 0x62, 0xC5, 0x64, 0xC3, 0x4A, 0x6C, 0xC5, 0x6D, 0xC7, 0xD1, 0x6C, 0xD3, 0x6A, 0xD5, 0x44, 0x62, 0xD3, 0x61, 0xD1, 0x00},
	{0x22, 0xB5, 0xC0, 0xB2, 0x64, 0xD5, 0x49, 0x6B, 0xD4, 0x6D, 0xD1, 0xCA, 0x6B, 0xC7, 0x69, 0xC6, 0x44, 0x61, 0xC9, 0x00},
	{0x21, 0xB1, 0xCA, 0x62, 0xC7, 0x64, 0xC6, 0x49, 0x6C, 0xCA, 0x7E, 0xD5, 0xB1, 0x69, 0xD5, 0x44, 0x62, 0xD4, 0x60, 0xD1, 0x00},
	{0x23, 0xA3, 0xD5, 0xAE, 0x64, 0xD1, 0x66, 0xD3, 0x69, 0xD5, 0x4C, 0x00},
	{0x2F, 0xB2, 0x6A, 0xD5, 0x44, 0x61, 0xD3, 0xCF, 0x64, 0xCD, 0x4A, 0x6D, 0xCA, 0xC6, 0x6A, 0xC3, 0x43, 0x60, 0xC6, 0x00},
	{0x22, 0xB5, 0x4D, 0xA3, 0x49, 0x66, 0xC6, 0xD9, 0x00},
	{0x22, 0xB5, 0xC7, 0x64, 0xC3, 0x49, 0x6D, 0xC8, 0xB5, 0xC3, 0x00},
	{0x21, 0xB5, 0x67, 0xC3, 0x6E, 0xD5, 0x00},
	{0x21, 0xB5, 0x64, 0xC3, 0x67, 0xD1, 0x6A, 0xC3, 0x6E, 0xD5, 0x00},
	{0x22, 0xA3, 0x6D, 0xD5, 0x22, 0x6D, 0xC3, 0x00},
	{0x22, 0x7E, 0x64, 0xC2, 0x6D, 0xD5, 0x21, 0x66, 0xC6, 0x00},
	{0x21, 0xB5, 0x4D, 0x60, 0xC3, 0x4D, 0x00},
	{0x2E, 0xBC, 0x49, 0x66, 0xD9, 0xD0, 0x63, 0xCF, 0x66, 0xCE, 0xC5, 0x69, 0xC2, 0x4C, 0x00},
	{0x29, 0xA1, 0xDE, 0x00},
	{0x23, 0xBC, 0x45, 0x68, 0xD9, 0xD0, 0x6B, 0xCF, 0x68, 0xCE, 0xC5, 0x65, 0xC2, 0x42, 0x00},
	{0x21, 0xB9, 0x63, 0xDC, 0x45, 0x69, 0xD7, 0x4B, 0x6E, 0xDA, 0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x22, 0xA4, 0x63, 0xC2, 0x45, 0x67, 0xC4, 0xC7, 0x65, 0xC9, 0x43, 0x61, 0xC7, 0xC4, 0x00},
	{0x2A, 0xAB, 0xDD, 0x4D, 0x00},
	{0x22, 0xA2, 0x46, 0xD4, 0x00},
	{0x22, 0xAA, 0x64, 0xC7, 0x66, 0xC3, 0x65, 0xC2, 0x63, 0xC4, 0x64, 0xC5, 0x00},
	{0x29, 0xB2, 0x65, 0xD0, 0x67, 0xCE, 0x69, 0xD0, 0x67, 0xD2, 0xCE, 0x26, 0xB0, 0x49, 0x00},
	{0x21, 0xBA, 0x4D, 0x6C, 0xD1, 0x6A, 0xCB, 0x67, 0xC6, 0x64, 0xC3, 0x22, 0xB2, 0x4C, 0x00},
	{0x21, 0xB3, 0x4C, 0x68, 0xCC, 0x29, 0xB1, 0xCE, 0x66, 0xC9, 0x63, 0xC3, 0x00},
	{0x21, 0xA8, 0x64, 0xCB, 0x68, 0xD0, 0x6B, 0xD6, 0x29, 0xAE, 0xC3, 0x00},
	{0x21, 0xAE, 0xD2, 0x4B, 0xCD, 0x69, 0xC8, 0x67, 0xC5, 0x64, 0xC3, 0x28, 0xB2, 0xD6, 0x00},
	{0x21, 0xA5, 0x4C, 0x28, 0xD1, 0x22, 0x4B, 0x00},
	{0x21, 0xB1, 0x4C, 0x29, 0x63, 0xC9, 0x60, 0xC6, 0x2A, 0xB6, 0xC3, 0x65, 0xC5, 0x00},
	{0x21, 0xB0, 0x6C, 0xD2, 0x69, 0xCD, 0x25, 0xB6, 0x67, 0xC3, 0x00},
	{0x21, 0xA5, 0x4C, 0x28, 0x68, 0xC9, 0x69, 0xCD, 0xD1, 0x42, 0x00},
	{0x21, 0xA4, 0x49, 0x6B, 0xD0, 0xD4, 0x41, 0xAD, 0x4A, 0x00},
	{0x21, 0xB2, 0x62, 0xCC, 0x28, 0x64, 0xD2, 0xA3, 0x67, 0xC5, 0x6A, 0xCA, 0x6C, 0xD3, 0x00},
	{0x22, 0xB1, 0x62, 0xD0, 0x4D, 0x00},
	{0x21, 0xBA, 0x4E, 0x6C, 0xD4, 0x69, 0xCF, 0x2A, 0xB5, 0xCE, 0x67, 0xC9, 0x65, 0xC5, 0x63, 0xC3, 0x00},
	{0x21, 0xAE, 0x65, 0xD2, 0x69, 0xD7, 0x6C, 0xDD, 0x29, 0xB4, 0xC3, 0x00},
	{0x21, 0xB2, 0xD7, 0x4E, 0xD2, 0x6C, 0xCA, 0x6A, 0xC6, 0x67, 0xC3, 0xB7, 0xDC, 0x00},
	{0x21, 0xA5, 0x4E, 0x29, 0xD6, 0x22, 0x4D, 0x00},
	{0x2C, 0xBC, 0xC3, 0x67, 0xC5, 0x21, 0xA4, 0x64, 0xCA, 0x69, 0xD6, 0x30, 0x40, 0x00},
	{0x2A, 0xA5, 0x6B, 0xC3, 0x6E, 0xD2, 0xD6, 0x40, 0xA4, 0x64, 0xCA, 0x67, 0xD4, 0xDC, 0x00},
	{0x30, 0xAE, 0x60, 0xCC, 0xB5, 0x6C, 0xD7, 0x26, 0xBC, 0x69, 0xC3, 0x00},
	{0x21, 0xB1, 0x62, 0xD7, 0x63, 0xDD, 0x23, 0xB7, 0x4D, 0x6B, 0xCD, 0x68, 0xC6, 0x66, 0xC3, 0x00},
	{0x21, 0xB0, 0x62, 0xD6, 0x63, 0xDB, 0xDD, 0x23, 0xB6, 0x4E, 0x2C, 0xD2, 0x69, 0xCB, 0x66, 0xC3, 0x00},
	{0x21, 0xA5, 0x4D, 0xD7, 0x30, 0x41, 0x00},
	{0x21, 0xB5, 0x4E, 0x2C, 0xBC, 0xCE, 0x69, 0xC9, 0x67, 0xC5, 0x65, 0xC3, 0x24, 0xAF, 0xDB, 0x00},
	{0x21, 0xB2, 0x66, 0xD0, 0x2A, 0xB6, 0x62, 0xD8, 0x30, 0xB1, 0x6A, 0xC9, 0x66, 0xC5, 0x62, 0xC3, 0x00},
	{0x2A, 0xAE, 0x6B, 0xC9, 0x6E, 0xC3, 0x21, 0x67, 0xCC, 0x6B, 0xD4, 0x6D, 0xDB, 0x41, 0x00},
	{0x21, 0xB4, 0x6E, 0xD6, 0x6C, 0xCF, 0x6A, 0xCC, 0x24, 0xBB, 0xCB, 0x64, 0xC8, 0x67, 0xC5, 0x6A, 0xC4, 0x4D, 0x00},
	{0x21, 0xBA, 0x63, 0xD5, 0x65, 0xD0, 0x24, 0xA3, 0x67, 0xC6, 0x6A, 0xCA, 0x6C, 0xCF, 0x6E, 0xDA, 0x00},
	{0x23, 0xB2, 0x6B, 0xCF, 0x21, 0x62, 0xD4, 0x64, 0xDD, 0x24, 0xB8, 0x4D, 0xD3, 0x6B, 0xCC, 0x68, 0xC6, 0x65, 0xC3, 0x00},
	{0x21, 0xB1, 0x4E, 0x2E, 0xBC, 0x66, 0xD9, 0x61, 0xD7, 0x2A, 0xBA, 0xCA, 0x67, 0xC7, 0x65, 0xC5, 0x62, 0xC3, 0x00},
	{0x21, 0xB8, 0x62, 0xD0, 0x26, 0xBA, 0x67, 0xD2, 0x2F, 0xB9, 0xD2, 0x6B, 0xCA, 0x69, 0xC6, 0x66, 0xC3, 0x00},
	{0x21, 0xB3, 0x4E, 0x2A, 0xCB, 0x67, 0xC7, 0x65, 0xC4, 0x63, 0xC3, 0x23, 0xBB, 0x4C, 0x00},
	{0x23, 0xA3, 0xDC, 0xB3, 0x68, 0xCF, 0x6C, 0xCB, 0x00},
	{0x21, 0xB5, 0x4E, 0x2B, 0xBC, 0xCC, 0x68, 0xC8, 0x66, 0xC5, 0x63, 0xC3, 0x00},
	{0x21, 0xA6, 0x4E, 0x22, 0xB6, 0x4C, 0x00},
	{0x21, 0xBA, 0x4D, 0xD7, 0x6C, 0xD2, 0x69, 0xCC, 0x62, 0xC3, 0x24, 0xB4, 0x6E, 0xCB, 0x00},
	{0x21, 0xA9, 0x64, 0xCB, 0x68, 0xCE, 0x6B, 0xD2, 0x6D, 0xD8, 0x41, 0x29, 0xDC, 0xA3, 0xCD, 0x6E, 0xC9, 0x00},
	{0x21, 0xA3, 0x66, 0xC7, 0x6A, 0xCC, 0x6D, 0xD3, 0x6E, 0xD8, 0xDB, 0x00},
	{0x21, 0xA6, 0x63, 0xCC, 0x65, 0xD5, 0x2A, 0xB9, 0x6B, 0xD2, 0x6D, 0xCB, 0x6E, 0xC5, 0x00},
	{0x22, 0xBC, 0xC8, 0x62, 0xC6, 0x64, 0xC4, 0x67, 0xC3, 0x4E, 0xB7, 0x69, 0xD4, 0x61, 0xD1, 0x00},
	{0x21, 0xB9, 0x4D, 0xD5, 0x6C, 0xD0, 0x69, 0xCA, 0x66, 0xC6, 0x63, 0xC3, 0x00},
	{0x21, 0xAF, 0x64, 0xD7, 0x45, 0x6E, 0xC5, 0x00},
	{0x21, 0xB5, 0x4E, 0xA7, 0x6B, 0xD0, 0x24, 0x60, 0xC7, 0x29, 0xBC, 0xC3, 0x00},
	{0x21, 0xB7, 0x4E, 0x6C, 0xD0, 0x69, 0xCB, 0x67, 0xC9, 0x24, 0xAE, 0x6B, 0xC3, 0x00},
	{0x21, 0xA7, 0x68, 0xC5, 0x6E, 0xC3, 0x23, 0xB1, 0x6C, 0xCE, 0xB8, 0x62, 0xDB, 0x00},
	{0x28, 0xBB, 0xD8, 0x64, 0xCE, 0x60, 0xC6, 0x6C, 0xC9, 0x2D, 0xAE, 0x6E, 0xC3, 0x00},
	{0x2F, 0xBB, 0xD9, 0x6C, 0xD4, 0x69, 0xCE, 0x65, 0xC8, 0x60, 0xC3, 0x25, 0xB3, 0x68, 0xD1, 0x6E, 0xCD, 0x00},
	{0x21, 0xB1, 0x4E, 0x2D, 0xBB, 0x66, 0xD9, 0x61, 0xD8, 0x26, 0xCA, 0x66, 0xC7, 0x69, 0xC4, 0x6C, 0xC3, 0x00},
	{0x21, 0xB4, 0x6E, 0xD6, 0x6C, 0xD2, 0x6A, 0xD0, 0x26, 0xBC, 0x69, 0xC3, 0x00},
	{0x23, 0xB6, 0x4C, 0xD2, 0x6B, 0xCC, 0x69, 0xC5, 0x21, 0x4E, 0x00},
	{0x21, 0xBA, 0x4D, 0xD3, 0x6B, 0xC3, 0x40, 0x22, 0xB0, 0x4C, 0x00},
	{0x21, 0xB5, 0x4D, 0xD2, 0x6C, 0xCC, 0x6A, 0xC8, 0x67, 0xC5, 0x64, 0xC3, 0x22, 0xBB, 0x4C, 0x00},
	{0x23, 0xAE, 0xDA, 0x2E, 0xBC, 0xCD, 0x6B, 0xC9, 0x69, 0xC5, 0x67, 0xC3, 0x00},
	{0x21, 0xA5, 0x63, 0xC9, 0x65, 0xCF, 0xD9, 0x2B, 0xBB, 0xC3, 0x6C, 0xC6, 0x6E, 0xCA, 0x00},
	{0x23, 0xBB, 0xC3, 0x66, 0xC5, 0x6A, 0xC8, 0x6E, 0xCC, 0x00},
	{0x21, 0xB7, 0x4E, 0x6D, 0xC5, 0x41, 0x60, 0xD7, 0x00},
	{0x21, 0xB5, 0xDA, 0x4D, 0xD4, 0x6C, 0xCF, 0x69, 0xC9, 0x64, 0xC3, 0x00},
	{0x21, 0xB8, 0x66, 0xD5, 0x23, 0xA3, 0x65, 0xC6, 0x69, 0xCB, 0x6E, 0xD7, 0x00},
	{0x21, 0xBA, 0x64, 0xD5, 0xBC, 0x68, 0xD7, 0x00},
	{0x21, 0xBA, 0xD7, 0x62, 0xD5, 0x44, 0x66, 0xD7, 0xDA, 0x64, 0xDC, 0x42, 0x60, 0xDA, 0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
	{0x00},
};

void DISPLAY::initialize()
{
	// load rom image
	FILEIO* fio = new FILEIO();
	if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
		fio->Fread(font + 0x000, 0x1000, 1);
		memcpy(font + 0x1000, font, 0x1000);
		fio->Fread(font + 0x1000, 0x1000, 1);
		fio->Fclose();
	}
	delete fio;
	
	// create pc palette
	for(int i = 0; i < 8; i++) {
		palette_text[i]  = RGB_COLOR((i & 1) ? 255 : 0, (i & 2) ? 255 : 0, (i & 4) ? 255 : 0); // text
		palette_graph[i] = RGB_COLOR((i & 1) ? 255 : 0, (i & 2) ? 255 : 0, (i & 4) ? 255 : 0); // graph
	}
	
	cmd_buffer = new FIFO(32);
	dpp_ctrl = 0xff;
	
	// register event
	register_frame_event(this);
}

void DISPLAY::release()
{
	cmd_buffer->release();
	delete cmd_buffer;
}

void DISPLAY::reset()
{
	switch(monitor_type = config.monitor_type) {
	case 0: dpp_data = 0x43; break; // PU-1-10
	case 1: dpp_data = 0x47; break; // PU-1-20
	case 2: dpp_data = 0x5a; break; // PU-10 ???
	}
	for(int y = 0; y < 25; y++) {
		for(int x = 0; x < 80; x++) {
			cvram[y][x].code = 0x20;
			cvram[y][x].attr = 0x0e;
		}
	}
	memset(gvram, 0, sizeof(gvram));
	
	cmd_buffer->clear();
	active_cmd = -1;
	
	// character
	scroll_x0 = 0;
	scroll_y0 = 0;
	scroll_x1 = 79;
	scroll_y1 = 24;
	cursor_x = cursor_y = 0;
	read_x = read_y = 0;
	mode1 = 0x0e;
	mode2 = 0x30;
	mode3 = 0x01;
	write_cr = false;
	
	// graphic
	window_x0 = view_x0 = -256;
	window_y0 = view_y0 = -192;
	window_x1 = view_x1 =  255;
	window_y1 = view_y1 =  191;
	expand = 1.0;
	rotate = 0;
	translate_x = translate_y = 0;
	point_x = point_y = 0;
	fore_color = 7;
	back_color = 0;
	erase = false;
	texture = texture_index = 0;
	pattern = 0;
}

void DISPLAY::event_frame()
{
	blink = (blink + 1) & 0x1f;
}

void DISPLAY::write_io8(uint32_t addr, uint32_t data)
{
	switch(addr) {
	case 0xf040: // CAP: WRITE DATA
	case 0xf048: // GRP: WRITE DATA
		if(active_cmd == 0x18) {
			emu->force_out_debug_log(_T("Send GPP: %02X\n"), data);
			if(data == 0x00) {
				cmd_buffer->clear();
				active_cmd = -1;
				emu->force_out_debug_log(_T("\n"));
			} else {
				put_code(data);
			}
		} else {
			if(active_cmd != -1) {
				cmd_buffer->clear();
				active_cmd = -1;
				emu->out_debug_log(_T("\n"));
			}
			emu->force_out_debug_log(_T("Send GPP: %02X\n"), data);
			cmd_buffer->write(data);
			process_cmd();
		}
		break;
	case 0xf041: // CAP: CONTROL
	case 0xf049: // GRP: CONTROL
		if(!(dpp_ctrl & 1) && (data & 1)) {
			// bit0: L->H RESET CAP/GRP
			reset();
		}
		dpp_ctrl = data;
		break;
	}
}

uint32_t DISPLAY::read_io8(uint32_t addr)
{
	switch(addr) {
	case 0xf041: // CAP: WRITE DATA READY
	case 0xf049: // GRP: WRITE DATA READY
		// bit0: H=READY
		return 0x01;
	case 0xf042: // CAP: READ DATA
	case 0xf04a: // GRP: READ DATA
		if(active_cmd == 0x1a) {
			dpp_data = get_code();
		} else if(active_cmd == 0x11 || active_cmd == 0x1e) {
			dpp_data = report & 0xff;
			report >>= 8;
		}
		emu->out_debug_log(_T("Recv GPP: %02X\n"), dpp_data);
		return dpp_data;
	case 0xf043: // CAP: READ DATA READY
	case 0xf04b: // GRP: READ DATA READY
		// bit0: H=READY
		return 0x01;
	}
	return 0xff;
}

int get_word(uint8_t flag, uint8_t h, uint8_t l)
{
	pair_t tmp;
	tmp.b.h = flag ? (h & 0x7f) | ((h & 0x40) << 1) : (h & 0x7f);
	tmp.b.l = l;
	return (int)tmp.sw.l;
}

void DISPLAY::process_cmd()
{
	switch(cmd_buffer->read_not_remove(0)) {
	// CAP
	case 0x18:
		if(cmd_buffer->count() == 1) {
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x19:
		if(cmd_buffer->count() == 3) {
			cursor_x = cmd_buffer->read_not_remove(1) & 0x7f;
			cursor_y = cmd_buffer->read_not_remove(2) & 0x1f;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x1a:
		if(cmd_buffer->count() == 1) {
			read_x = cursor_x;
			read_y = cursor_y;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x1b:
		if(cmd_buffer->count() == 5) {
			scroll_x0 = cmd_buffer->read_not_remove(1) & 0x7f;
			scroll_y0 = cmd_buffer->read_not_remove(2) & 0x1f;
			scroll_x1 = cmd_buffer->read_not_remove(3) & 0x7f;
			scroll_y1 = cmd_buffer->read_not_remove(4) & 0x1f;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x1c:
		if(cmd_buffer->count() == 5) {
			int x = cmd_buffer->read_not_remove(1) & 0x7f;
			int y = cmd_buffer->read_not_remove(2) & 0x1f;
			cvram[y % 25][x % 80].code = cmd_buffer->read_not_remove(3);
			cvram[y % 25][x % 80].attr = cmd_buffer->read_not_remove(4);
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x1d:
		if(cmd_buffer->count() == 7) {
			int x0 = cmd_buffer->read_not_remove(1) & 0x7f;
			int y0 = cmd_buffer->read_not_remove(2) & 0x1f;
			int x1 = cmd_buffer->read_not_remove(3) & 0x7f;
			int y1 = cmd_buffer->read_not_remove(4) & 0x1f;
			for(int y = y0; y <= y1 && y <= 24; y++) {
				for(int x = x0; x <= x1 && x <= 79; x++) {
					cvram[y % 25][x % 80].code = cmd_buffer->read_not_remove(5);
					cvram[y % 25][x % 80].attr = cmd_buffer->read_not_remove(6);
				}
			}
			cursor_x = cursor_y = 0;
			write_cr = false;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x1e:
		if(cmd_buffer->count() == 3) {
			int x = cmd_buffer->read_not_remove(1) & 0x7f;
			int y = cmd_buffer->read_not_remove(2) & 0x1f;
			report  = cvram[y % 25][x % 80].code << 0;
			report |= cvram[y % 25][x % 80].attr << 8;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x1f:
		if(cmd_buffer->count() == 4) {
			mode1 = cmd_buffer->read_not_remove(1);
			mode2 = cmd_buffer->read_not_remove(2);
			mode3 = cmd_buffer->read_not_remove(3);
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	// GRP
	case 0x06: // F
		if(cmd_buffer->count() == 1) {
//			for(int y = 0; y < 25; y++) {
//				for(int x = 0; x < 80; x++) {
//					cvram[y][x].code = 0x20;
//					cvram[y][x].attr = 0x0e;
//				}
//			}
			memset(gvram, 0, sizeof(gvram));
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x07: // N
		if(cmd_buffer->count() == 1) {
			erase = true;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x08: // O
		if(cmd_buffer->count() == 1) {
			erase = false;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x11: // z
		if(cmd_buffer->count() == 1) {
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x50: // ???
		if(cmd_buffer->count() == 2) {
			back_color = cmd_buffer->read_not_remove(1) & 7;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x51: // $14
		if(cmd_buffer->count() > 2 && cmd_buffer->read_not_remove(cmd_buffer->count() - 1) == 0) {
			int pow = (cmd_buffer->read_not_remove(1) >> 0) & 0x0f;
			int rot = (cmd_buffer->read_not_remove(1) >> 4) & 0x03;
			
//			int x0, y0;
//			transform_to_vram(point_x, point_y, &x0, &y0);
//			draw_solid_pixel(x0, y0);
			for(int i = 2; i < cmd_buffer->count() - 1; i++) {
				draw_char(point_x, point_y, pow, rot, cmd_buffer->read_not_remove(i));
				switch(rot) {
				case 0: point_x += 6 * pow; break;
				case 1: point_y += 6 * pow; break;
				case 2: point_x -= 6 * pow; break;
				case 3: point_y -= 6 * pow; break;
				}
			}
//			transform_to_vram(point_x, point_y, &x0, &y0);
//			draw_solid_pixel(x0, y0);
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x53: // M
		if(cmd_buffer->count() == 5) {
			point_x = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			point_y = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x54: // D
		if(cmd_buffer->count() == 5) {
			int dest_x = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			int dest_y = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int x0, y0, x1, y1;
			transform_to_vram(point_x, point_y, &x0, &y0);
			transform_to_vram(dest_x,  dest_y,  &x1, &y1);
			draw_texture_line(x0, y0, x1, y1);
			point_x = dest_x;
			point_y = dest_y;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x55: // P
		if(cmd_buffer->count() == 5) {
			point_x = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			point_y = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int x0, y0;
			transform_to_vram(point_x, point_y, &x0, &y0);
			draw_solid_pixel(x0, y0);
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x56: // T
		if(cmd_buffer->count() == 2) {
			texture = cmd_buffer->read_not_remove(1) & 7;
			texture_index = 0;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x59: // p
		if(cmd_buffer->count() >= 2) {
			int num = cmd_buffer->read_not_remove(1);
			if(cmd_buffer->count() == 2 + 4 * num) {
				bool fill = ((cmd_buffer->read_not_remove(2) & 0x80) != 0);
				bool line = ((cmd_buffer->read_not_remove(2) & 0x80) == 0) || ((pattern & 0x80) != 0);
				int x[256], y[256];
				
				for(int i = 0; i < num; i++) {
					x[i] = get_word(1, cmd_buffer->read_not_remove(4 * i + 2), cmd_buffer->read_not_remove(4 * i + 3));
					y[i] = get_word(1, cmd_buffer->read_not_remove(4 * i + 4), cmd_buffer->read_not_remove(4 * i + 5));
				}
				if(num == 0) {
					// do nothing
				} else if(num == 1) {
					int x0, y0;
					transform_to_vram(x[0], y[0], &x0, &y0);
					draw_solid_pixel(x0, y0);
				} else if(num == 2) {
					int x0, y0, x1, y1;
					transform_to_vram(x[0], y[0], &x0, &y0);
					transform_to_vram(x[1], y[1], &x1, &y1);
					draw_texture_line(x0, y0, x1, y1);
				} else {
					if(fill) {
						int xmin = x[0], ymin = y[0];
						int xmax = x[0], ymax = y[0];
						for(int i = 1; i < num; i++) {
							xmin = min(xmin, x[i]);
							xmax = max(xmax, x[i]);
							ymin = min(ymin, y[i]);
							ymax = max(ymax, y[i]);
						}
						int pow = (expand >= 1.0) ? (int)expand * POW : POW;
						for(int yy = ymin * pow; yy <= ymax * pow; yy++) {
							double dy = (double)yy / (double)pow;
							for(int xx = xmin * pow; xx <= xmax * pow; xx++) {
								double dx = (double)xx / (double)pow;
								// http://home.a00.itscom.net/hatada/c01/algorithm/polygon01.html
								bool inside = false;
								double old_x = (double)x[num - 1], old_y = (double)y[num - 1];
								for(int i = 0; i < num; i++) {
									double new_x = (double)x[i], new_y = (double)y[i];
									double p1_x = (new_x > old_x) ? old_x : new_x;
									double p1_y = (new_x > old_x) ? old_y : new_y;
									double p2_x = (new_x > old_x) ? new_x : old_x;
									double p2_y = (new_x > old_x) ? new_y : old_y;
									if((p1_x < dx) == (dx <= p2_x) && (dy - p1_y) * (p2_x - p1_x) < (p2_y - p1_y) * (dx - p1_x)) {
										inside = !inside;
									}
									old_x = new_x;
									old_y = new_y;
								}
								if(inside) {
									int x0, y0;
									transform_to_vram(dx, dy, &x0, &y0);
									draw_pattern_pixel(x0, y0);
								}
							}
						}
					}
					if(line) {
						int xs, ys;
						transform_to_vram(x[0], y[0], &xs, &ys);
						int x0 = xs, y0 = ys, x1, y1;
						for(int i = 0; i < num; i++) {
							if(i == num - 1) {
								x1 = xs;
								y1 = ys;
							} else {
								transform_to_vram(x[i + 1], y[i + 1], &x1, &y1);
							}
							if(x0 != x1 || y0 != y1) {
								if(fill) {
									draw_solid_cont_line(x0, y0, x1, y1);
								} else {
									draw_texture_cont_line(x0, y0, x1, y1);
								}
								x0 = x1;
								y0 = y1;
							}
						}
					}
				}
				active_cmd = cmd_buffer->read_not_remove(0);
			}
		}
		break;
	case 0x5a: // R
		if(cmd_buffer->count() == 9) {
			bool fill = ((cmd_buffer->read_not_remove(1) & 0x80) != 0);
			bool line = ((cmd_buffer->read_not_remove(1) & 0x80) == 0) || ((pattern & 0x80) != 0);
			int ax = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			int ay = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int bx = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			int by = get_word(1, cmd_buffer->read_not_remove(7), cmd_buffer->read_not_remove(8));
			
			if(ax > bx) {
				int tx = ax;
				ax = bx;
				bx = tx;
			}
			if(ay > by) {
				int ty = ay;
				ay = by;
				by = ty;
			}
			if(fill) {
				int pow = (expand >= 1.0) ? (int)expand * POW : POW;
				for(int yy = ay * pow; yy <= by * pow; yy++) {
					double dy = (double)yy / (double)pow;
					for(int xx = ax * pow; xx <= bx * pow; xx++) {
						double dx = (double)xx / (double)pow;
						int x0, y0;
						transform_to_vram(dx, dy, &x0, &y0);
						draw_pattern_pixel(x0, y0);
					}
				}
			}
			if(line) {
				int x0, y0, x1, y1, x2, y2, x3, y3;
				transform_to_vram(ax, ay, &x0, &y0);
				transform_to_vram(bx, ay, &x1, &y1);
				transform_to_vram(bx, by, &x2, &y2);
				transform_to_vram(ax, by, &x3, &y3);
				if(fill) {
					draw_solid_cont_line(x0, y0, x1, y1);
					draw_solid_cont_line(x1, y1, x2, y2);
					draw_solid_cont_line(x2, y2, x3, y3);
					draw_solid_cont_line(x3, y3, x0, y0);
				} else {
					draw_texture_cont_line(x0, y0, x1, y1);
					draw_texture_cont_line(x1, y1, x2, y2);
					draw_texture_cont_line(x2, y2, x3, y3);
					draw_texture_cont_line(x3, y3, x0, y0);
				}
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x5d: // G
		if(cmd_buffer->count() == 11) {
			int x  = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			int y  = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int nx = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			int dx = cmd_buffer->read_not_remove(7);
			int ny = get_word(1, cmd_buffer->read_not_remove(8), cmd_buffer->read_not_remove(9));
			int dy = cmd_buffer->read_not_remove(10);
			
			for(int yy = 0; yy < ny; yy++) {
				for(int xx = 0; xx < nx; xx++) {
					int x0, y0;
					transform_to_vram((double)(x + dx * xx), (double)(y + dy * yy), &x0, &y0);
					draw_solid_pixel(x0, y0);
				}
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x5e: // S
		if(cmd_buffer->count() == 2) {
			pattern = cmd_buffer->read_not_remove(1);
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x5f: // L
		if(cmd_buffer->count() == 2) {
			fore_color = cmd_buffer->read_not_remove(1) & 7;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x60: // m
		if(cmd_buffer->count() == 9) {
			for(int i = 0; i < 8; i++) {
				int c = 255 - cmd_buffer->read_not_remove(i + 1);
				int b = (((c >> 0) & 7) * 255) / 7;
				int r = (((c >> 3) & 7) * 255) / 7;
				int g = (((c >> 6) & 3) * 255) / 3;
				palette_graph[i] = RGB_COLOR(r, g, b);
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x61: // a
		if(cmd_buffer->count() == 11) {
			int cx = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			int cy = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int r  = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			int t0 = get_word(0, cmd_buffer->read_not_remove(7), cmd_buffer->read_not_remove(8));
			int t1 = get_word(0, cmd_buffer->read_not_remove(9), cmd_buffer->read_not_remove(10));
			
			while(t0 < 0) {
				t0 += 36000;
				t1 += 36000;
			}
			while(t0 > t1) {
				t1 += 36000;
			}
			while((t1 - t0) > 36000) {
				t1 -= 36000;
			}
			int xs, ys, xe, ye;
			double rad;
			rad = 2.0 * M_PI * (double)t0 / 36000.0;
			transform_to_vram((double)cx + (double)r * cos(rad), (double)cy + (double)r * sin(rad), &xs, &ys);
			rad = 2.0 * M_PI * (double)t1 / 36000.0;
			transform_to_vram((double)cx + (double)r * cos(rad), (double)cy + (double)r * sin(rad), &xe, &ye);
			int x0 = xs, y0 = ys, x1, y1;
			for(; t0 < t1; t0 += 100) {
				double rad = 2.0 * M_PI * (double)t0 / 36000.0;
				transform_to_vram((double)cx + (double)r * cos(rad), (double)cy + (double)r * sin(rad), &x1, &y1);
				if(x0 != x1 || y0 != y1) {
					draw_texture_cont_line(x0, y0, x1, y1);
					x0 = x1;
					y0 = y1;
				}
			}
			if(x0 != xe || y0 != ye) {
				draw_texture_line(x0, y0, xe, ye);
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x62: // f
		if(cmd_buffer->count() == 11) {
			bool fill = ((cmd_buffer->read_not_remove(5) & 0x80) != 0);
			bool line = ((cmd_buffer->read_not_remove(5) & 0x80) == 0) || ((pattern & 0x80) != 0);
			int cx = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			int cy = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int r  = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			int t0 = get_word(0, cmd_buffer->read_not_remove(7), cmd_buffer->read_not_remove(8));
			int t1 = get_word(0, cmd_buffer->read_not_remove(9), cmd_buffer->read_not_remove(10));
			
			while(t0 < 0) {
				t0 += 36000;
				t1 += 36000;
			}
			while(t0 > t1) {
				t1 += 36000;
			}
			while((t1 - t0) > 36000) {
				t1 -= 36000;
			}
			int xc, yc, xs, ys, xe, ye;
			transform_to_vram((double)cx, (double)cy, &xc, &yc);
			double rad;
			rad = 2.0 * M_PI * (double)t0 / 36000.0;
			transform_to_vram((double)cx + (double)r * cos(rad), (double)cy + (double)r * sin(rad), &xs, &ys);
			rad = 2.0 * M_PI * (double)t1 / 36000.0;
			transform_to_vram((double)cx + (double)r * cos(rad), (double)cy + (double)r * sin(rad), &xe, &ye);
			
			if(fill) {
				int pow = (expand >= 1.0) ? (int)expand * POW : POW;
				double dr2 = (double)r * (double)r;
				for(int yy = -abs(r) * pow; yy <= abs(r) * pow; yy++) {
					double dy = (double)yy / (double)pow;
					double dy2 = dy * dy;
					for(int xx = -abs(r) * pow; xx <= abs(r) * pow; xx++) {
						double dx = (double)xx / (double)pow;
						double dx2 = dx * dx;
						if(dx2 + dy2 <= dr2) {
							double deg = atan2(dy, dx) * 180.0 / M_PI * 100.0;
							while(deg < t0) {
								deg += 36000.0;
							}
							if(/*deg >= t0 && */deg <= t1) {
								int x0, y0;
								transform_to_vram((double)cx + dx, (double)cy + dy, &x0, &y0);
								draw_pattern_pixel(x0, y0);
							}
						}
					}
				}
			}
			if(line) {
				if(fill) {
					draw_solid_cont_line(xc, yc, xs, ys);
				} else {
					draw_texture_cont_line(xc, yc, xs, ys);
				}
				int x0 = xs, y0 = ys, x1, y1;
				for(; t0 < t1; t0 += 100) {
					double rad = 2.0 * M_PI * (double)t0 / 36000.0;
					transform_to_vram((double)cx + (double)r * cos(rad), (double)cy + (double)r * sin(rad), &x1, &y1);
					if(x0 != x1 || y0 != y1) {
						if(fill) {
							draw_solid_cont_line(x0, y0, x1, y1);
						} else {
							draw_texture_cont_line(x0, y0, x1, y1);
						}
						x0 = x1;
						y0 = y1;
					}
				}
				if(x0 != xe || y0 != ye) {
					if(fill) {
						draw_solid_cont_line(x0, y0, xe, ye);
					} else {
						draw_texture_cont_line(x0, y0, xe, ye);
					}
				}
				if(fill) {
					draw_solid_cont_line(xe, ye, xc, yc);
				} else {
					draw_texture_cont_line(xe, ye, xc, yc);
				}
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x64: // n
		if(cmd_buffer->count() == 2) {
			if(cmd_buffer->read_not_remove(1) & 1) {
				expand = 1.0;
			}
			if(cmd_buffer->read_not_remove(1) & 2) {
				rotate = 0;
			}
			if(cmd_buffer->read_not_remove(1) & 4) {
				translate_x = translate_y = 0;
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x65: // c
		if(cmd_buffer->count() == 7) {
			bool fill = ((cmd_buffer->read_not_remove(5) & 0x80) != 0);
			bool line = ((cmd_buffer->read_not_remove(5) & 0x80) == 0) || ((pattern & 0x80) != 0);
			int cx = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			int cy = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int r  = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			
			if(fill) {
				int pow = (expand >= 1.0) ? (int)expand * POW : POW;
				double dr2 = (double)r * (double)r;
				for(int yy = -abs(r) * pow; yy <= abs(r) * pow; yy++) {
					double dy = (double)yy / (double)pow;
					double dy2 = dy * dy;
					for(int xx = -abs(r) * pow; xx <= abs(r) * pow; xx++) {
						double dx = (double)xx / (double)pow;
						double dx2 = dx * dx;
						if(dx2 + dy2 <= dr2) {
							int x0, y0;
							transform_to_vram((double)cx + dx, (double)cy + dy, &x0, &y0);
							draw_pattern_pixel(x0, y0);
						}
					}
				}
			}
			if(line) {
				int xs, ys;
				transform_to_vram((double)(cx + r), (double)cy, &xs, &ys);
				int x0 = xs, y0 = ys, x1, y1;
				for(int i = 1; i <= 360; i++) {
					if(i == 360) {
						x1 = xs;
						y1 = ys;
					} else {
						double rad = 2.0 * M_PI * (double)i / 360.0;
						transform_to_vram((double)cx + (double)r * cos(rad), (double)cy + (double)r * sin(rad), &x1, &y1);
					}
					if(x0 != x1 || y0 != y1) {
						if(fill) {
							draw_solid_cont_line(x0, y0, x1, y1);
						} else {
							draw_texture_cont_line(x0, y0, x1, y1);
						}
						x0 = x1;
						y0 = y1;
					}
				}
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x66: // e
		if(cmd_buffer->count() == 9) {
			bool fill = ((cmd_buffer->read_not_remove(5) & 0x80) != 0);
			bool line = ((cmd_buffer->read_not_remove(5) & 0x80) == 0) || ((pattern & 0x80) != 0);
			int cx = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			int cy = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			int a  = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			int b  = get_word(1, cmd_buffer->read_not_remove(7), cmd_buffer->read_not_remove(8));
			
			if(fill) {
				int pow = (expand >= 1.0) ? (int)expand * POW : POW;
				double da2 = (double)a * (double)a, db2 = (double)b * (double)b;
				double da2b2 = da2 * db2;
				for(int yy = -abs(b) * pow; yy <= abs(b) * pow; yy++) {
					double dy = (double)yy / (double)pow;
					double dy2 = dy * dy;
					for(int xx = -abs(a) * pow; xx <= abs(a) * pow; xx++) {
						double dx = (double)xx / (double)pow;
						double dx2 = dx * dx;
						if(db2 * dx2 + da2 * dy2 <= da2b2) {
							int x0, y0;
							transform_to_vram((double)cx + dx, (double)cy + dy, &x0, &y0);
							draw_pattern_pixel(x0, y0);
						}
					}
				}
			}
			if(line) {
				int xs, ys;
				transform_to_vram((double)(cx + a), (double)cy, &xs, &ys);
				int x0 = xs, y0 = ys, x1, y1;
				for(int i = 1; i <= 360; i++) {
					if(i == 360) {
						x1 = xs;
						y1 = ys;
					} else {
						double rad = 2.0 * M_PI * (double)i / 360.0;
						transform_to_vram((double)cx + (double)a * cos(rad), (double)cy + (double)b * sin(rad), &x1, &y1);
					}
					if(x0 != x1 || y0 != y1) {
						if(fill) {
							draw_solid_cont_line(x0, y0, x1, y1);
						} else {
							draw_texture_cont_line(x0, y0, x1, y1);
						}
						x0 = x1;
						y0 = y1;
					}
				}
			}
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x68: // C
		if(cmd_buffer->count() == 3) {
			int num = cmd_buffer->read_not_remove(1) & 7;
			int c = 255 - cmd_buffer->read_not_remove(2);
			int b = (((c >> 0) & 7) * 255) / 7;
			int r = (((c >> 3) & 7) * 255) / 7;
			int g = (((c >> 6) & 3) * 255) / 3;
			palette_graph[num] = RGB_COLOR(r, g, b);
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x70: // w
		if(cmd_buffer->count() == 9) {
			window_x0 = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			window_y0 = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			window_x1 = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			window_y1 = get_word(1, cmd_buffer->read_not_remove(7), cmd_buffer->read_not_remove(8));
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x71: // v
		if(cmd_buffer->count() == 9) {
			view_x0 = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			view_y0 = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			view_x1 = get_word(1, cmd_buffer->read_not_remove(5), cmd_buffer->read_not_remove(6));
			view_y1 = get_word(1, cmd_buffer->read_not_remove(7), cmd_buffer->read_not_remove(8));
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x72: // s
		if(cmd_buffer->count() == 2) {
			expand *= (double)cmd_buffer->read_not_remove(1) / 16.0;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x74: // t
		if(cmd_buffer->count() == 5) {
			translate_x = get_word(1, cmd_buffer->read_not_remove(1), cmd_buffer->read_not_remove(2));
			translate_y = get_word(1, cmd_buffer->read_not_remove(3), cmd_buffer->read_not_remove(4));
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x75: // r
		if(cmd_buffer->count() == 4) {
			rotate += get_word(1, cmd_buffer->read_not_remove(2), cmd_buffer->read_not_remove(3));
			while(rotate < 0) {
				rotate += 36000;
			}
			rotate %= 36000;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	case 0x7f: // I
		if(cmd_buffer->count() == 2) {
			window_x0 = view_x0 = -256;
			window_y0 = view_y0 = -192;
			window_x1 = view_x1 =  255;
			window_y1 = view_y1 =  191;
			expand = 1.0;
			rotate = 0;
			translate_x = translate_y = 0;
			point_x = point_y = 0;
			fore_color = 7;
			back_color = 0;
			erase = false;
			texture = texture_index = 0;
			pattern = 0;
			active_cmd = cmd_buffer->read_not_remove(0);
		}
		break;
	default:
		emu->force_out_debug_log(_T("Unknown GPP: %02X\n\n"), cmd_buffer->read_not_remove(0));
		cmd_buffer->clear();
		break;
	}
}

void DISPLAY::put_code(uint8_t data)
{
	switch(data) {
	case 0x00:
		break;
	case 0x08: // BS
	case 0x1d:
		if(--cursor_x < scroll_x0) {
			if(--cursor_y < scroll_y0) {
				cursor_x = scroll_x0;
				cursor_y = scroll_y0;
			} else {
				cursor_x = scroll_x1;
			}
		}
		break;
	case 0x0a: // LF
		if(++cursor_y > scroll_y1) {
			cursor_y = scroll_y1;
			scroll();
		}
		break;
	case 0x0d: // CR
		cvram[cursor_y % 25][cursor_x % 80].code = data;
		cvram[cursor_y % 25][cursor_x % 80].attr = mode1;
		cursor_x = scroll_x0;
		write_cr = true;
		break;
	case 0x10: // FS
	case 0x1c: // FS
		if(++cursor_x > scroll_x1) {
			if(++cursor_y > scroll_y1) {
				cursor_y = scroll_y1;
				scroll();
			}
			cursor_x = scroll_x0;
		}
		break;
	case 0x1e: // UP
		if(--cursor_y < scroll_y0) {
			cursor_y = scroll_y0;
		}
		break;
	case 0x1f: // DOWN
		if(++cursor_y > scroll_y1) {
			cursor_y = scroll_y1;
		}
		break;
	default:
		cvram[cursor_y % 25][cursor_x % 80].code = data;
		cvram[cursor_y % 25][cursor_x % 80].attr = mode1;
		if(++cursor_x > scroll_x1) {
			if(++cursor_y > scroll_y1) {
				cursor_y = scroll_y1;
				scroll();
			}
			cursor_x = scroll_x0;
		}
		break;
	}
}

uint8_t DISPLAY::get_code()
{
	uint8_t data = 0x0d;
	
	if(write_cr) {
		if((data = cvram[read_y % 25][read_x % 80].code) != 0x0d) {
			if(++read_x > scroll_x1) {
				if(++read_y > scroll_y1) {
					write_cr = false; // ???
				}
				read_x = scroll_x0;
			}
		} else {
			write_cr = false;
		}
	}
	return data;
}

void DISPLAY::scroll()
{
	for(int y = scroll_y0; y <= scroll_y1 - 1; y++) {
		for(int x = scroll_x0; x <= scroll_x1; x++) {
			cvram[y % 25][x % 80].code = cvram[(y + 1) % 25][x % 80].code;
			cvram[y % 25][x % 80].attr = cvram[(y + 1) % 25][x % 80].attr;
		}
	}
	for(int x = scroll_x0; x <= scroll_x1; x++) {
		cvram[scroll_y1 % 25][x % 80].code = 0x20;
		cvram[scroll_y1 % 25][x % 80].attr = mode1;
	}
}

void DISPLAY::transform(double world_x, double world_y, double *x, double *y)
{
	double rad = 2.0 * M_PI * (double)rotate / 36000.0;
	double tmp_x = world_x * expand;
	double tmp_y = world_y * expand;
	*x = (double)translate_x + tmp_x * cos(rad) - tmp_y * sin(rad);
	*y = (double)translate_y + tmp_x * sin(rad) + tmp_y * cos(rad);
}

void DISPLAY::world_to_view(double world_x, double world_y, double *x, double *y)
{
	*x = view_x0 + (double)(view_x1 - view_x0 + 1) * (world_x - (double)window_x0 + 1.0) / (double)(window_x1 - window_x0 + 1);
	*y = view_y0 + (double)(view_y1 - view_y0 + 1) * (world_y - (double)window_y0 + 1.0) / (double)(window_y1 - window_y0 + 1);
}

void DISPLAY::view_to_vram(double view_x, double view_y, int *x, int *y)
{
	double tmp_x = 320.0 + (view_x * 320.0) / 256.0;
	double tmp_y = 239.0 - (view_y * 320.0) / 256.0;
	*x = (int)(tmp_x + 0.5 - (tmp_x < 0));
	*y = (int)(tmp_y + 0.5 - (tmp_y < 0));
}

void DISPLAY::transform_to_vram(double world_x, double world_y, int *x, int *y)
{
	double trans_x, trans_y;
	double view_x, view_y;
	
	transform(world_x, world_y, &trans_x, &trans_y);
	world_to_view(trans_x, trans_y, &view_x, &view_y);
	view_to_vram(view_x, view_y, x, y);
}

void DISPLAY::draw_solid_pixel(int x, int y)
{
	if(x >= 0 && x < 640 && y >= 0 && y < 480) {
		gvram[y][x] = erase ? back_color : fore_color;
	}
}

void DISPLAY::draw_texture_pixel(int x, int y)
{
	if(texture_index < 0 || texture_index >= texture_table[texture & 7].length) {
		texture_index = 0;
	}
	if(texture_table[texture & 7].dots[texture_index]) {
		draw_solid_pixel(x, y);
	} else {
//		erase = !erase;
//		draw_solid_pixel(x, y);
//		erase = !erase;
	}
	texture_index++;
}

void DISPLAY::draw_pattern_pixel(int x, int y)
{
	if(pattern_table[pattern & 127][y & 15] & (0x8000 >> (x & 15))) {
		draw_solid_pixel(x, y);
	} else {
//		erase = !erase;
//		draw_solid_pixel(x, y);
//		erase = !erase;
	}
}

void DISPLAY::draw_solid_line(int x0, int y0, int x1, int y1)
{
	int _texture = texture;
	int _index = texture_index;
	
	texture = texture_index = 0;
	draw_texture_line(x0, y0, x1, y1);
	
	texture = _texture;
	texture_index = _index;
}

void DISPLAY::draw_solid_cont_line(int x0, int y0, int x1, int y1)
{
	int _texture = texture;
	int _index = texture_index;
	
	texture = texture_index = 0;
	draw_texture_cont_line(x0, y0, x1, y1);
	
	texture = _texture;
	texture_index = _index;
}

void DISPLAY::draw_texture_line(int x0, int y0, int x1, int y1)
{
	draw_texture_cont_line(x0, y0, x1, y1);
	draw_texture_pixel(x1, y1);
}

void DISPLAY::draw_texture_cont_line(int x0, int y0, int x1, int y1)
{
	// do not set the last pixel
	int dx = abs(x1 - x0);
	int dy = abs(y1 - y0);
	int sx = (x0 < x1) ? 1 : -1;
	int sy = (y0 < y1) ? 1 : -1;
	int e1 = dx - dy;
	
	while(!(x0 == x1 && y0 == y1)) {
		draw_texture_pixel(x0, y0);
		int e2 = 2 * e1;
		if(e2 > -dy) {
			e1 -= dy;
			x0 += sx;
		}
		if(e2 < dx) {
			e1 += dx;
			y0 += sy;
		}
	}
}

void DISPLAY::draw_char(int x, int y, int pow, int rot, int code)
{
	// KST32B fcsf1_shp_src/csf12shp.c
	static const double vector[4][4] = {
		{ 1,  0,  0,  1},
		{ 0,  1, -1,  0},
		{-1,  0,  0, -1},
		{ 0, -1,  1,  0},
	};
	int from_x = 0, to_x = 0, from_y = 0;
	
	for(int i = 0; i < 32; i++) {
		uint8_t data = char_table[code][i];
		int value, draw_x = 0, draw_y = 0;
		
		if(data >= 0x21 && data <= 0x26) {
			from_x = to_x = data - 0x21;
		} else if(data >= 0x28 && data <= 0x3f) {
			from_x = to_x = data - 0x28 + 6;
		} else if(data >= 0x40 && data <= 0x5b) {
			value = data - 0x40;
			draw_x = 1;
		} else if(data >= 0x5e && data <= 0x5f) {
			value = data - 0x5e + 28;
			draw_x = 1;
		} else if(data >= 0x60 && data <= 0x7d) {
			to_x = data - 0x60;
		} else if(data == 0x7e) {
			from_y = 0;
		} else if(data >= 0xa1 && data <= 0xbf) {
			from_y = data - 0xa1 + 1;
		} else if(data >= 0xc0 && data <= 0xdf) {
			value = data - 0xc0;
			draw_y = 1;
		} else {
			break;
		}
		if(draw_x) {
			// (from_x, from_y) - (value, from_y)
			double xs = (double)from_x * 6.0 * (double)pow / 16.0;
			double ys = (double)from_y * 8.0 * (double)pow / 32.0;
			double xe = (double)value  * 6.0 * (double)pow / 16.0;
			double ye = (double)from_y * 8.0 * (double)pow / 32.0;
			int x0, y0, x1, y1;
			transform_to_vram(point_x + xs * vector[rot][0] + ys * vector[rot][2], point_y + xs * vector[rot][1] + ys * vector[rot][3], &x0, &y0);
			transform_to_vram(point_x + xe * vector[rot][0] + ye * vector[rot][2], point_y + xe * vector[rot][1] + ye * vector[rot][3], &x1, &y1);
			draw_solid_line(x0, y0, x1, y1);
			from_x = to_x = value;
		} else if(draw_y) {
			// (from_x, from_y) - (to_x, value)
			double xs = (double)from_x * 6.0 * (double)pow / 16.0;
			double ys = (double)from_y * 8.0 * (double)pow / 32.0;
			double xe = (double)to_x   * 6.0 * (double)pow / 16.0;
			double ye = (double)value  * 8.0 * (double)pow / 32.0;
			int x0, y0, x1, y1;
			transform_to_vram(point_x + xs * vector[rot][0] + ys * vector[rot][2], point_y + xs * vector[rot][1] + ys * vector[rot][3], &x0, &y0);
			transform_to_vram(point_x + xe * vector[rot][0] + ye * vector[rot][2], point_y + xe * vector[rot][1] + ye * vector[rot][3], &x1, &y1);
			draw_solid_line(x0, y0, x1, y1);
			from_x = to_x;
			from_y = value;
		}
	}
}

void DISPLAY::draw_screen()
{
	// render screen
	memset(screen, 0, sizeof(screen));
	draw_text();
	
	// copy to real screen
	for(int y = 0; y < 480; y++) {
		scrntype_t* dest = emu->get_screen_buffer(y);
		uint8_t* src_t = screen[y];
		for(int x = 0; x < 640; x++) {
			dest[x] = src_t[x] ? palette_text[src_t[x]] : palette_graph[gvram[y][x]];
		}
	}
	emu->screen_skip_line(false);
}

void DISPLAY::draw_text()
{
	for(int y = 0; y < 25; y++) {
		for(int x = 0; x < 80; x++) {
			uint8_t code = cvram[y][x].code;
			uint8_t fore = (mode3 & 1) ? (cvram[y][x].attr >> 1) & 7 : 7;
			uint8_t back = (mode3 & 1) ? (cvram[y][x].attr >> 5) & 7 : 0;
			
			if(fore == back) {
				fore = 7 - back;
			}
			for(int l = 0; l < 16; l++) {
				uint8_t pat = (mode3 & 4) ? 0 : font[((mode3 & 2) ? 0x1000 : 0) + (code << 4) + l];
				uint8_t* d = &screen[y * 19 + l + 2][x << 3];
				
				d[0] = (pat & 0x80) ? fore : back;
				d[1] = (pat & 0x40) ? fore : back;
				d[2] = (pat & 0x20) ? fore : back;
				d[3] = (pat & 0x10) ? fore : back;
				d[4] = (pat & 0x08) ? fore : back;
				d[5] = (pat & 0x04) ? fore : back;
				d[6] = (pat & 0x02) ? fore : back;
				d[7] = (pat & 0x01) ? fore : back;
			}
			if(x == cursor_x && y == cursor_y && (mode2 & 0x10) && (blink & 0x10)) {
				if(mode2 & 0x80) {
					for(int l = 0; l < 16; l++) {
						uint8_t* d = &screen[y * 19 + l + 2][x << 3];
						for(int c = 0; c < 8; c++) {
							d[c] = 7 - d[c];
						}
					}
				} else {
					for(int l = 16; l < 18; l++) {
						uint8_t* d = &screen[y * 19 + l + 2][x << 3];
						memset(d, 7, 8);
					}
				}
			}
		}
	}
}

#define STATE_VERSION	2

void DISPLAY::save_state(FILEIO* state_fio)
{
	state_fio->FputUint32(STATE_VERSION);
	state_fio->FputInt32(this_device_id);
	
	cmd_buffer->save_state((void *)state_fio);
	state_fio->FputInt32(active_cmd);
	state_fio->FputUint8(dpp_data);
	state_fio->FputUint8(dpp_ctrl);
	state_fio->FputInt32(scroll_x0);
	state_fio->FputInt32(scroll_y0);
	state_fio->FputInt32(scroll_x1);
	state_fio->FputInt32(scroll_y1);
	state_fio->FputInt32(cursor_x);
	state_fio->FputInt32(cursor_y);
	state_fio->FputInt32(read_x);
	state_fio->FputInt32(read_y);
	state_fio->FputUint8(mode1);
	state_fio->FputUint8(mode2);
	state_fio->FputUint8(mode3);
	state_fio->FputUint32(report);
	state_fio->FputBool(write_cr);
	state_fio->Fwrite(cvram, sizeof(cvram), 1);
	state_fio->Fwrite(gvram, sizeof(gvram), 1);
	state_fio->FputInt32(window_x0);
	state_fio->FputInt32(window_y0);
	state_fio->FputInt32(window_x1);
	state_fio->FputInt32(window_y1);
	state_fio->FputInt32(view_x0);
	state_fio->FputInt32(view_y0);
	state_fio->FputInt32(view_x1);
	state_fio->FputInt32(view_y1);
	state_fio->FputDouble(expand);
	state_fio->FputInt32(rotate);
	state_fio->FputInt32(translate_x);
	state_fio->FputInt32(translate_y);
	state_fio->FputInt32(point_x);
	state_fio->FputInt32(point_y);
	state_fio->FputInt32(fore_color);
	state_fio->FputInt32(back_color);
	state_fio->FputBool(erase);
	state_fio->FputInt32(texture);
	state_fio->FputInt32(texture_index);
	state_fio->FputInt32(pattern);
	state_fio->Fwrite(palette_graph, sizeof(palette_graph), 1);
	state_fio->FputInt32(blink);
}

bool DISPLAY::load_state(FILEIO* state_fio)
{
	if(state_fio->FgetUint32() != STATE_VERSION) {
		return false;
	}
	if(state_fio->FgetInt32() != this_device_id) {
		return false;
	}
	if(!cmd_buffer->load_state((void *)state_fio)) {
		return false;
	}
	active_cmd = state_fio->FgetInt32();
	dpp_data = state_fio->FgetUint8();
	dpp_ctrl = state_fio->FgetUint8();
	scroll_x0 = state_fio->FgetInt32();
	scroll_y0 = state_fio->FgetInt32();
	scroll_x1 = state_fio->FgetInt32();
	scroll_y1 = state_fio->FgetInt32();
	cursor_x = state_fio->FgetInt32();
	cursor_y = state_fio->FgetInt32();
	read_x = state_fio->FgetInt32();
	read_y = state_fio->FgetInt32();
	mode1 = state_fio->FgetUint8();
	mode2 = state_fio->FgetUint8();
	mode3 = state_fio->FgetUint8();
	report = state_fio->FgetUint32();
	write_cr = state_fio->FgetBool();
	state_fio->Fread(cvram, sizeof(cvram), 1);
	state_fio->Fread(gvram, sizeof(gvram), 1);
	window_x0 = state_fio->FgetInt32();
	window_y0 = state_fio->FgetInt32();
	window_x1 = state_fio->FgetInt32();
	window_y1 = state_fio->FgetInt32();
	view_x0 = state_fio->FgetInt32();
	view_y0 = state_fio->FgetInt32();
	view_x1 = state_fio->FgetInt32();
	view_y1 = state_fio->FgetInt32();
	expand = state_fio->FgetDouble();
	rotate = state_fio->FgetInt32();
	translate_x = state_fio->FgetInt32();
	translate_y = state_fio->FgetInt32();
	point_x = state_fio->FgetInt32();
	point_y = state_fio->FgetInt32();
	fore_color = state_fio->FgetInt32();
	back_color = state_fio->FgetInt32();
	erase = state_fio->FgetBool();
	texture = state_fio->FgetInt32();
	texture_index = state_fio->FgetInt32();
	pattern = state_fio->FgetInt32();
	state_fio->Fread(palette_graph, sizeof(palette_graph), 1);
	blink = state_fio->FgetInt32();
	return true;
}

