From cabfe5191e3a6579e619f5ac2c4b4593234eb9bd Mon Sep 17 00:00:00 2001 From: Brad Grantham Date: Fri, 18 Nov 2016 20:54:19 -0800 Subject: [PATCH] Mostly rewrite graphics to use shaders Move to GL 3.2 Draw a quad with shaders depending on the mode in that part of the screen HIRES shader reads from hires texture TEXTPORT shader reads from textpor texture and indirects through a font to get pixel values MIXED now supported Still to do: BLINK text, INVERSE text, LORES, gang up HGR memory updates Why doesn't cursor flash the checkerboard? --- Makefile | 6 +- apple2e.cpp | 271 ++-------- interface.cpp | 1444 ++++++++++++++++++++++++++++++++++++++++++++++--- interface.h | 73 +-- 4 files changed, 1467 insertions(+), 327 deletions(-) diff --git a/Makefile b/Makefile index afc7fd0..33b4303 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,14 @@ INCFLAGS += -I/opt/local/include -I/opt/local/include/freetype2 CXXFLAGS += $(INCFLAGS) -g -Wall --std=c++11 -O -LDFLAGS += -L/opt/local/lib -LDLIBS += -lglfw -lglew -lfreeimageplus -lfreetype -framework OpenGL -framework Cocoa -framework IOkit +LDFLAGS += -L/opt/local/lib +LDLIBS += -lglfw -lfreeimageplus -lfreetype -framework OpenGL -framework Cocoa -framework IOkit OBJECTS = apple2e.o keyboard.o dis6502.o fake6502.o interface.o all: apple2e apple2e: $(OBJECTS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(INCFLAGS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) clean: rm $(OBJECTS) diff --git a/apple2e.cpp b/apple2e.cpp index 8c7b30a..664ae6b 100644 --- a/apple2e.cpp +++ b/apple2e.cpp @@ -60,181 +60,6 @@ struct SoftSwitch } }; -struct APPLE2Edisplay -{ - static constexpr int hires_row_base_offsets[] = - { - 0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, - 0x0080, 0x0480, 0x0880, 0x0C80, 0x1080, 0x1480, 0x1880, 0x1C80, - 0x0100, 0x0500, 0x0900, 0x0D00, 0x1100, 0x1500, 0x1900, 0x1D00, - 0x0180, 0x0580, 0x0980, 0x0D80, 0x1180, 0x1580, 0x1980, 0x1D80, - 0x0200, 0x0600, 0x0A00, 0x0E00, 0x1200, 0x1600, 0x1A00, 0x1E00, - 0x0280, 0x0680, 0x0A80, 0x0E80, 0x1280, 0x1680, 0x1A80, 0x1E80, - 0x0300, 0x0700, 0x0B00, 0x0F00, 0x1300, 0x1700, 0x1B00, 0x1F00, - 0x0380, 0x0780, 0x0B80, 0x0F80, 0x1380, 0x1780, 0x1B80, 0x1F80, - 0x0028, 0x0428, 0x0828, 0x0C28, 0x1028, 0x1428, 0x1828, 0x1C28, - 0x00A8, 0x04A8, 0x08A8, 0x0CA8, 0x10A8, 0x14A8, 0x18A8, 0x1CA8, - 0x0128, 0x0528, 0x0928, 0x0D28, 0x1128, 0x1528, 0x1928, 0x1D28, - 0x01A8, 0x05A8, 0x09A8, 0x0DA8, 0x11A8, 0x15A8, 0x19A8, 0x1DA8, - 0x0228, 0x0628, 0x0A28, 0x0E28, 0x1228, 0x1628, 0x1A28, 0x1E28, - 0x02A8, 0x06A8, 0x0AA8, 0x0EA8, 0x12A8, 0x16A8, 0x1AA8, 0x1EA8, - 0x0328, 0x0728, 0x0B28, 0x0F28, 0x1328, 0x1728, 0x1B28, 0x1F28, - 0x03A8, 0x07A8, 0x0BA8, 0x0FA8, 0x13A8, 0x17A8, 0x1BA8, 0x1FA8, - 0x0050, 0x0450, 0x0850, 0x0C50, 0x1050, 0x1450, 0x1850, 0x1C50, - 0x00D0, 0x04D0, 0x08D0, 0x0CD0, 0x10D0, 0x14D0, 0x18D0, 0x1CD0, - 0x0150, 0x0550, 0x0950, 0x0D50, 0x1150, 0x1550, 0x1950, 0x1D50, - 0x01D0, 0x05D0, 0x09D0, 0x0DD0, 0x11D0, 0x15D0, 0x19D0, 0x1DD0, - 0x0250, 0x0650, 0x0A50, 0x0E50, 0x1250, 0x1650, 0x1A50, 0x1E50, - 0x02D0, 0x06D0, 0x0AD0, 0x0ED0, 0x12D0, 0x16D0, 0x1AD0, 0x1ED0, - 0x0350, 0x0750, 0x0B50, 0x0F50, 0x1350, 0x1750, 0x1B50, 0x1F50, - 0x03D0, 0x07D0, 0x0BD0, 0x0FD0, 0x13D0, 0x17D0, 0x1BD0, 0x1FD0, - }; - static int hires_memory_to_scanout_address[8192]; - static constexpr int text_row_base_offsets[] = - { - 0x000, - 0x080, - 0x100, - 0x180, - 0x200, - 0x280, - 0x300, - 0x380, - 0x028, - 0x0A8, - 0x128, - 0x1A8, - 0x228, - 0x2A8, - 0x328, - 0x3A8, - 0x050, - 0x0D0, - 0x150, - 0x1D0, - 0x250, - 0x2D0, - 0x350, - 0x3D0, - }; - APPLE2Edisplay() - { - } - static void initialize_memory_to_scanout() __attribute__((constructor)); - - // External display switches - enum {TEXT, LORES, HIRES} mode = TEXT; - int display_page = 0; // Apple //e page minus 1 (so 0,1 not 1,2) - bool mixed_mode = false; - - bool changed = false; - unsigned char text_page[2][24][40]; - unsigned char hires_page[2][192 * 40]; - bool hires_row_changed[2][192]; - - void display_text(int page) - { - fputs("------------------------------------------\n", stdout); - for(int row = 0; row < 24; row++) { - fputs("|", stdout); - for(int col = 0; col < 40; col++) { - int ch = text_page[page][row][col] & 0x7F; - fputc(isprint(ch) ? ch : '?', stdout); - } - fputs("|\n", stdout); - } - fputs("------------------------------------------\n", stdout); - } - - void display_hires(int page, std::function update) - { - for(int row = 0; row < 192; row++) { - if(hires_row_changed[page][row]) { - hires_row_changed[page][row] = false; - static unsigned char pixels[280 * 3]; - for(int i = 0; i < 280; i++) { - unsigned char *rowpixels = hires_page[page] + row * 40; - int byte = i / 7; - int bit = i % 7; - if(rowpixels[byte] & (1 << bit)) { - pixels[i * 3 + 0] = 255; - pixels[i * 3 + 1] = 255; - pixels[i * 3 + 2] = 255; - } else { - pixels[i * 3 + 0] = 0; - pixels[i * 3 + 1] = 0; - pixels[i * 3 + 2] = 0; - } - } - update(0, row, 280, 1, pixels); - } - } - } - - void display(std::function update) - { - // enum {TEXT, LORES, HIRES} mode = TEXT; - // int display_page = 0; - // bool mixed_mode = false; - if(mode == TEXT) { - display_text(display_page); - } // else if(mode == HIRES) { - display_hires(display_page, update); - // } - } - - static const int text_page1_base = 0x400; - static const int text_page2_base = 0x800; - static const int text_page_size = 0x400; - static const int hires_page1_base = 0x2000; - static const int hires_page2_base = 0x4000; - static const int hires_page_size = 8192; - bool write(int addr, unsigned char data) - { - // We know text page 1 and 2 are contiguous - if((addr >= text_page1_base) && (addr < text_page2_base + text_page_size)) { - int page = (addr >= text_page2_base) ? 1 : 0; - int within_page = addr - text_page1_base - page * text_page_size; - for(int row = 0; row < 24; row++) { - int row_offset = text_row_base_offsets[row]; - if((within_page >= row_offset) && - (within_page < row_offset + 40)){ - int col = within_page - row_offset; - text_page[page][row][col] = data; - } - } - changed = true; - return true; - - } else if(((addr >= hires_page1_base) && (addr < hires_page1_base + hires_page_size)) || ((addr >= hires_page2_base) && (addr < hires_page2_base + hires_page_size))) { - - int page = (addr < hires_page2_base) ? 0 : 1; - int page_base = (page == 0) ? hires_page1_base : hires_page2_base; - int within_page = addr - page_base; - int scanout_address = hires_memory_to_scanout_address[within_page]; - hires_page[page][scanout_address] = data; - int row = scanout_address / 40; - hires_row_changed[page][row] = true; - changed = true; - return true; - } - return false; - } -}; -constexpr int APPLE2Edisplay::text_row_base_offsets[24]; -constexpr int APPLE2Edisplay::hires_row_base_offsets[192]; -int APPLE2Edisplay::hires_memory_to_scanout_address[8192]; - -void APPLE2Edisplay::initialize_memory_to_scanout() -{ - for(int row = 0; row < 192; row++) { - int row_address = hires_row_base_offsets[row]; - for(int byte = 0; byte < 40; byte++) { - hires_memory_to_scanout_address[row_address + byte] = row * 40 + byte; - } - } -} - struct region { string name; @@ -397,16 +222,15 @@ struct MAINboard : board_base deque keyboard_buffer; - APPLE2Edisplay *display; - void enqueue_key(unsigned char k) { keyboard_buffer.push_back(k); } - - MAINboard(unsigned char rom_image[32768], APPLE2Edisplay *d) : + typedef std::function display_write_func; + display_write_func display_write; + MAINboard(unsigned char rom_image[32768], display_write_func display_write_) : internal_C800_ROM_selected(true), - display(d) + display_write(display_write_) { std::copy(rom_image + rom_D000.base - 0x8000, rom_image + rom_D000.base - 0x8000 + rom_D000.size, rom_D000.memory.begin()); std::copy(rom_image + rom_E000.base - 0x8000, rom_image + rom_E000.base - 0x8000 + rom_E000.size, rom_E000.memory.begin()); @@ -427,9 +251,9 @@ struct MAINboard : board_base switches_by_address[i] = NULL; for(auto it = switches.begin(); it != switches.end(); it++) { SoftSwitch* sw = *it; - switches_by_address[sw->clear_address] = sw; - switches_by_address[sw->set_address] = sw; - switches_by_address[sw->read_address] = sw; + switches_by_address[sw->clear_address - 0xC000] = sw; + switches_by_address[sw->set_address - 0xC000] = sw; + switches_by_address[sw->read_address - 0xC000] = sw; } } @@ -460,7 +284,7 @@ struct MAINboard : board_base printf("bank switch control %04X, aborting\n", addr); exit(1); } - SoftSwitch* sw = switches_by_address[addr]; + SoftSwitch* sw = switches_by_address[addr - 0xC000]; if(sw != NULL) { if(addr == sw->read_address) { data = sw->enabled ? 0x80 : 0x00; @@ -571,14 +395,14 @@ struct MAINboard : board_base if(((addr >= 0x400) && (addr <= 0xBFF)) || ((addr >= 0x2000) && (addr <= 0x5FFF))) #endif { - display->write(addr, data); + display_write(addr, data); } if(io_region.contains(addr)) { if(exit_on_banking && (banking_write_switches.find(addr) != banking_write_switches.end())) { printf("bank switch control %04X, exiting\n", addr); exit(1); } - SoftSwitch* sw = switches_by_address[addr]; + SoftSwitch* sw = switches_by_address[addr - 0xC000]; if(sw != NULL) { if(addr == sw->set_address) { if(!sw->implemented) { printf("%s ; set is unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); } @@ -1699,36 +1523,36 @@ map interface_key_to_apple2e = {' ', {' ', ' ', 0, 0}}, }; -enum event::Type keyboard_to_mainboard(MAINboard *board) +enum APPLE2Einterface::EventType keyboard_to_mainboard(MAINboard *board) { static bool shift_down = false; static bool control_down = false; // skip CAPS for now - while(interface_event_waiting()) { - event e = interface_dequeue_event(); - if(e.type == event::QUIT) { - return event::QUIT; - } else if(e.type == event::KEYDOWN) { - if((e.value == event::LEFT_SHIFT) || (e.value == event::RIGHT_SHIFT)) + while(APPLE2Einterface::event_waiting()) { + APPLE2Einterface::event e = APPLE2Einterface::dequeue_event(); + if(e.type == APPLE2Einterface::QUIT) { + return APPLE2Einterface::QUIT; + } else if(e.type == APPLE2Einterface::KEYDOWN) { + if((e.value == APPLE2Einterface::LEFT_SHIFT) || (e.value == APPLE2Einterface::RIGHT_SHIFT)) shift_down = true; - else if((e.value == event::LEFT_CONTROL) || (e.value == event::RIGHT_CONTROL)) + else if((e.value == APPLE2Einterface::LEFT_CONTROL) || (e.value == APPLE2Einterface::RIGHT_CONTROL)) control_down = true; - else if(e.value == event::ENTER) { + else if(e.value == APPLE2Einterface::ENTER) { board->enqueue_key(141 - 128); - } else if(e.value == event::TAB) { + } else if(e.value == APPLE2Einterface::TAB) { board->enqueue_key(' '); - } else if(e.value == event::ESCAPE) { + } else if(e.value == APPLE2Einterface::ESCAPE) { board->enqueue_key(''); - } else if(e.value == event::DELETE) { + } else if(e.value == APPLE2Einterface::DELETE) { board->enqueue_key(255 - 128); - } else if(e.value == event::RIGHT) { + } else if(e.value == APPLE2Einterface::RIGHT) { board->enqueue_key(149 - 128); - } else if(e.value == event::LEFT) { + } else if(e.value == APPLE2Einterface::LEFT) { board->enqueue_key(136 - 128); - } else if(e.value == event::DOWN) { + } else if(e.value == APPLE2Einterface::DOWN) { board->enqueue_key(138 - 128); - } else if(e.value == event::UP) { + } else if(e.value == APPLE2Einterface::UP) { board->enqueue_key(139 - 128); } else { auto it = interface_key_to_apple2e.find(e.value); @@ -1744,14 +1568,14 @@ enum event::Type keyboard_to_mainboard(MAINboard *board) board->enqueue_key(k.yes_shift_yes_control); } } - } else if(e.type == event::KEYUP) { - if((e.value == event::LEFT_SHIFT) || (e.value == event::RIGHT_SHIFT)) + } else if(e.type == APPLE2Einterface::KEYUP) { + if((e.value == APPLE2Einterface::LEFT_SHIFT) || (e.value == APPLE2Einterface::RIGHT_SHIFT)) shift_down = false; - else if((e.value == event::LEFT_CONTROL) || (e.value == event::RIGHT_CONTROL)) + else if((e.value == APPLE2Einterface::LEFT_CONTROL) || (e.value == APPLE2Einterface::RIGHT_CONTROL)) control_down = false; } } - return event::NONE; + return APPLE2Einterface::NONE; } int main(int argc, char **argv) @@ -1760,8 +1584,6 @@ int main(int argc, char **argv) argc -= 1; argv += 1; - atexit(cleanup); - while((argc > 0) && (argv[0][0] == '-')) { if(strcmp(argv[0], "-debugger") == 0) { debugging = true; @@ -1805,14 +1627,16 @@ int main(int argc, char **argv) } fclose(fp); - APPLE2Edisplay display; MAINboard* mainboard; - bus.boards.push_back(mainboard = new MAINboard(b, &display)); + MAINboard::display_write_func display = [](int addr, unsigned char data)->bool{return APPLE2Einterface::write(addr, data);}; + bus.boards.push_back(mainboard = new MAINboard(b, display)); bus.reset(); CPU6502 cpu; + atexit(cleanup); + if(!debugging) { start_keyboard(); } @@ -1820,9 +1644,7 @@ int main(int argc, char **argv) if(use_fake6502) reset6502(); - interface_start(); - - interface_setregion(280, 192); + APPLE2Einterface::start(); while(1) { if(!debugging) { @@ -1831,7 +1653,7 @@ int main(int argc, char **argv) char key; bool have_key = peek_key(&key); - if(keyboard_to_mainboard(mainboard) == event::QUIT) { + if(keyboard_to_mainboard(mainboard) == APPLE2Einterface::QUIT) { break; } @@ -1858,11 +1680,10 @@ int main(int argc, char **argv) else cpu.cycle(bus); } - if(display.changed) { - display.display([&](int x, int y, int w, int h, unsigned char *p){interface_updaterect(x, y, w, h, p);}); - display.changed = false; - } - interface_iterate(); + APPLE2Einterface::DisplayMode mode = mainboard->TEXT ? APPLE2Einterface::TEXT : (mainboard->HIRES ? APPLE2Einterface::HIRES : APPLE2Einterface::LORES); + int page = mainboard->PAGE2 ? 1 : 0; + APPLE2Einterface::set_switches(mode, mainboard->MIXED, page); + APPLE2Einterface::iterate(); chrono::time_point now; auto elapsed_millis = chrono::duration_cast(now - then); @@ -1917,14 +1738,14 @@ int main(int argc, char **argv) step6502(); else cpu.cycle(bus); - if(display.changed) { - display.display([&](int x, int y, int w, int h, unsigned char *p){interface_updaterect(x, y, w, h, p);}); - display.changed = false; - } - interface_iterate(); + + APPLE2Einterface::DisplayMode mode = mainboard->TEXT ? APPLE2Einterface::TEXT : (mainboard->HIRES ? APPLE2Einterface::HIRES : APPLE2Einterface::LORES); + int page = mainboard->PAGE2 ? 1 : 0; + APPLE2Einterface::set_switches(mode, mainboard->MIXED, page); + APPLE2Einterface::iterate(); } } stop_keyboard(); - interface_shutdown(); + APPLE2Einterface::shutdown(); } diff --git a/interface.cpp b/interface.cpp index 72be471..bbe797e 100644 --- a/interface.cpp +++ b/interface.cpp @@ -2,16 +2,31 @@ #include #include #include -#include +#include + +#define GLFW_INCLUDE_GLCOREARB #include +#include #include "interface.h" using namespace std; +namespace APPLE2Einterface +{ + +DisplayMode mode = TEXT; +int display_page = 0; // Apple //e page minus 1 (so 0,1 not 1,2) +bool mixed_mode = false; + +extern int font_offset; +extern unsigned char font_bytes[96 * 7 * 8]; + static int gWindowWidth; static int gWindowHeight; +bool gPrintShaderLog = true; + // to handle https://github.com/glfw/glfw/issues/161 static double gMotionReported = false; @@ -20,99 +35,400 @@ static int gButtonPressed = -1; deque event_queue; -bool interface_event_waiting() +bool event_waiting() { return event_queue.size() > 0; } -event interface_dequeue_event() +event dequeue_event() { - if(interface_event_waiting()) { + if(event_waiting()) { event e = event_queue.front(); event_queue.pop_back(); return e; } else - return {event::NONE, 0}; + return {NONE, 0}; } using namespace std; float aspectRatio = 1; -int region_w; -int region_h; -GLuint texture; -// unsigned char *texture_bytes; +GLuint font_texture; +GLuint font_texture_location; +const int fonttexture_w = 7; +const int fonttexture_h = 8 * 96; +GLuint textport_texture[2]; +GLuint textport_texture_location; +const int textport_w = 40; +const int textport_h = 24; +GLuint hires_texture[2]; +GLuint hires_texture_location; +const int hires_w = 320; // MSBit is color chooser, Apple ][ weirdness +const int hires_h = 192; -void interface_setregion(int w, int h) +static void CheckOpenGL(const char *filename, int line) { - region_w = w; - region_h = h; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + int glerr; + + if((glerr = glGetError()) != GL_NO_ERROR) { + printf("GL Error: %04X at %s:%d\n", glerr, filename, line); + } } -#define CHECK_OPENGL(l) {int _glerr ; if((_glerr = glGetError()) != GL_NO_ERROR) printf("GL Error: %04X at %d\n", _glerr, l); } +GLuint upper_screen_area; +GLuint lower_screen_area; +const int raster_coords_attrib = 0; -void interface_updaterect(int x, int y, int w, int h, unsigned char *rgb) +static bool CheckShaderCompile(GLuint shader, const std::string& shader_name) { - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, rgb); - CHECK_OPENGL(__LINE__); + int status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(status == GL_TRUE) + return true; + + if(gPrintShaderLog) { + int length; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + + if (length > 0) { + char log[length]; + glGetShaderInfoLog(shader, length, NULL, log); + fprintf(stderr, "%s shader error log:\n%s\n", shader_name.c_str(), log); + } + + fprintf(stderr, "%s compile failure.\n", shader_name.c_str()); + fprintf(stderr, "shader text:\n"); + glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &length); + char source[length]; + glGetShaderSource(shader, length, NULL, source); + fprintf(stderr, "%s\n", source); + } + return false; +} + +static bool CheckProgramLink(GLuint program) +{ + int status; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(status == GL_TRUE) + return true; + + if(gPrintShaderLog) { + int log_length; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); + + if (log_length > 0) { + char log[log_length]; + glGetProgramInfoLog(program, log_length, NULL, log); + fprintf(stderr, "program error log: %s\n",log); + } + } + + return false; +} + +GLuint hires_program; +GLuint text_program; +GLuint lores_program; + +static const char *hires_vertex_shader = "\n\ + in vec2 vertex_coords;\n\ + out vec2 raster_coords;\n\ + \n\ + void main()\n\ + {\n\ + vec2 eye_coords = vertex_coords / vec2(280,192) * vec2(2, 2) - vec2(1, 1);\n\ + raster_coords = vertex_coords;\n\ + gl_Position = vec4(eye_coords * .9 * vec2(1, -1), 0.5, 1.0);\n\ + }\n"; + +static const char *text_vertex_shader = "\n\ + in vec2 vertex_coords;\n\ + out vec2 text_coords;\n\ + out vec2 raster_coords;\n\ + \n\ + void main()\n\ + {\n\ + vec2 eye_coords = vertex_coords / vec2(280,192) * vec2(2, 2) - vec2(1, 1);\n\ + raster_coords = vertex_coords;\n\ + text_coords = vec2(int(vertex_coords.x / 7), int(vertex_coords.y / 8));\n\ + gl_Position = vec4(eye_coords * .9 * vec2(1, -1), 0.5, 1.0);\n\ + }\n"; + +static const char *hires_fragment_shader = "\n\ + in vec2 raster_coords;\n\ + uniform usampler2DRect hires_texture;\n\ + \n\ + out vec4 color;\n\ + \n\ + void main()\n\ + {\n\ + int byte = int(raster_coords.x) / 7;\n\ + int bit = int(raster_coords.x) % 7;\n\ + int texturex = byte * 8 + bit;\n\ + ivec2 tc = ivec2(texturex, raster_coords.y);\n\ + uint pixel = texture(hires_texture, tc).x;\n\ + float value = pixel / 255.0;\n\ + color = vec4(value, value, value, value);\n\ + }\n"; + +// 0-31 is inverse 32-63 +// 32-63 is inverse 0-31 +// 64-95 is blink 32-63 +// 96-127 is blink 0-31 +// 128-159 is normal 32-63 +// 160-191 is normal 0-31 +// 192-223 is normal 32-63 +// 224-255 is normal 64-95 + +static const char *text_fragment_shader = "\n\ + in vec2 raster_coords;\n\ + in vec2 text_coords;\n\ + uniform usampler2DRect font_texture;\n\ + uniform usampler2DRect textport_texture;\n\ + \n\ + out vec4 color;\n\ + \n\ + void main()\n\ + {\n\ + uint character;\n\ + character = texture(textport_texture, uvec2(uint(raster_coords.x) / 7u, uint(raster_coords.y) / 8u)).x; \n\ + if(character >= 0u && character <= 31u)\n\ + character = character - 0u + 32u; // INVERSE \n\ + else if(character >= 32u && character <= 63u)\n\ + character = character - 32u + 0u; // INVERSE \n\ + else if(character >= 64u && character <= 95u)\n\ + character = character - 64u + 32u; // BLINK \n\ + else if(character >= 96u && character <= 127u)\n\ + character = character - 96u + 0u; // BLINK \n\ + else if(character >= 128u && character <= 159u)\n\ + character = character - 128u + 32u;\n\ + else if(character >= 160u && character <= 191u)\n\ + character = character - 160u + 0u;\n\ + else if(character >= 192u && character <= 223u)\n\ + character = character - 192u + 32u;\n\ + else if(character >= 224u && character <= 255u)\n\ + character = character - 224u + 64u;\n\ + else \n\ + character = 33u;\n\ + uvec2 inglyph = uvec2(uint(raster_coords.x) % 7u, uint(raster_coords.y) % 8u);\n\ + uvec2 infont = inglyph + uvec2(0, character * 8u);\n\ + uint pixel = texture(font_texture, infont).x;\n\ + float value = pixel / 255.0;\n\ + color = vec4(value, value, value, value);\n\ + // color = vec4(value, float(inglyph.x)/7, float(inglyph.y)/8, value);\n\ + // color = vec4(vec2(inglyph) / vec2(7, 8), 0, 1);\n\ + // BLINK?? \n\ + // INVERSE?? \n\ + }\n"; + +static GLuint GenerateProgram(const string& shader_name, const string& vertex_shader_text, const string& fragment_shader_text) +{ + std::string spec_string; + + spec_string = "#version 140\n"; + + // reset line number so that I can view errors with the line number + // they have in the base shaders. + spec_string += "#line 0\n"; + + std::string vertex_shader_string = spec_string + vertex_shader_text; + std::string fragment_shader_string = spec_string + fragment_shader_text; + + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + const char *string = vertex_shader_string.c_str(); + glShaderSource(vertex_shader, 1, &string, NULL); + glCompileShader(vertex_shader); + if(!CheckShaderCompile(vertex_shader, shader_name + " vertex shader")) + return 0; + + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + string = fragment_shader_string.c_str(); + glShaderSource(fragment_shader, 1, &string, NULL); + glCompileShader(fragment_shader); + if(!CheckShaderCompile(fragment_shader, shader_name + " fragment shader")) + return 0; + + GLuint program = glCreateProgram(); + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + + // XXX Really need to do this generically + glBindAttribLocation(program, raster_coords_attrib, "vertex_coords"); + CheckOpenGL(__FILE__, __LINE__); + + glLinkProgram(program); + CheckOpenGL(__FILE__, __LINE__); + if(!CheckProgramLink(program)) + return 0; + + return program; +} + +void initialize_screen_areas() +{ + glGenVertexArrays(1, &upper_screen_area); + glBindVertexArray(upper_screen_area); + CheckOpenGL(__FILE__, __LINE__); + + /* just x, y, also pixel coords */ + GLuint vertices; + + glGenBuffers(1, &vertices); + glBindBuffer(GL_ARRAY_BUFFER, vertices); + static float upper[4][2] = { + {0, 0}, + {280, 0}, + {0, 160}, + {280, 160}, + }; + glBufferData(GL_ARRAY_BUFFER, sizeof(upper[0]) * 4, upper, GL_STATIC_DRAW); + CheckOpenGL(__FILE__, __LINE__); + + glVertexAttribPointer(raster_coords_attrib, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(raster_coords_attrib); + CheckOpenGL(__FILE__, __LINE__); + + + glGenVertexArrays(1, &lower_screen_area); + glBindVertexArray(lower_screen_area); + CheckOpenGL(__FILE__, __LINE__); + + glGenBuffers(1, &vertices); + glBindBuffer(GL_ARRAY_BUFFER, vertices); + static float lower[4][2] = { + {0, 160}, + {280, 160}, + {0, 192}, + {280, 192}, + }; + glBufferData(GL_ARRAY_BUFFER, sizeof(lower[0]) * 4, lower, GL_STATIC_DRAW); + CheckOpenGL(__FILE__, __LINE__); + + glVertexAttribPointer(raster_coords_attrib, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(raster_coords_attrib); + CheckOpenGL(__FILE__, __LINE__); + + glBindVertexArray(GL_NONE); +} + +GLuint initialize_texture(int w, int h, unsigned char *pixels = NULL) +{ + GLuint texture; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_RECTANGLE, texture); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CheckOpenGL(__FILE__, __LINE__); + glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_R8UI, w, h, 0, GL_RED_INTEGER_EXT, GL_UNSIGNED_BYTE, pixels); + CheckOpenGL(__FILE__, __LINE__); + return texture; } void initialize_gl(void) { glClearColor(0, 0, 0, 1); - CHECK_OPENGL(__LINE__); + CheckOpenGL(__FILE__, __LINE__); - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - CHECK_OPENGL(__LINE__); - glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - CHECK_OPENGL(__LINE__); - // glGenerateMipmapEXT(GL_TEXTURE_2D); + font_texture = initialize_texture(fonttexture_w, fonttexture_h, font_bytes); + textport_texture[0] = initialize_texture(textport_w, textport_h); + textport_texture[1] = initialize_texture(textport_w, textport_h); + hires_texture[0] = initialize_texture(hires_w, hires_h); + hires_texture[1] = initialize_texture(hires_w, hires_h); + CheckOpenGL(__FILE__, __LINE__); + + hires_program = GenerateProgram("hires", hires_vertex_shader, hires_fragment_shader); + hires_texture_location = glGetUniformLocation(hires_program, "hires_texture"); + + text_program = GenerateProgram("textport", text_vertex_shader, text_fragment_shader); + textport_texture_location = glGetUniformLocation(text_program, "textport_texture"); + font_texture_location = glGetUniformLocation(text_program, "font_texture"); + CheckOpenGL(__FILE__, __LINE__); + + initialize_screen_areas(); + CheckOpenGL(__FILE__, __LINE__); } +unsigned char textport[2][24][40]; + static void redraw(GLFWwindow *window) { - CHECK_OPENGL(__LINE__); + CheckOpenGL(__FILE__, __LINE__); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, region_w - 1, 0, region_h - 1, -1, 1); + if(0) if(mode == TEXT) { + printf("------------------------------------------\n"); + for(int row = 0; row < 24; row++) { + printf("|"); + for(int col = 0; col < 24; col++) + fputc(textport[display_page][row][col] & 0x7F, stdout); + printf("|\n"); + } + printf("------------------------------------------\n"); + } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glPushMatrix(); + if(mode == HIRES) { - glEnable(GL_TEXTURE_2D); - glColor3f(1, 1, 1); + glUseProgram(hires_program); - glBegin(GL_TRIANGLES); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE, hires_texture[display_page]); + glUniform1i(hires_texture_location, 0); - glTexCoord2f(0, 1); - glVertex3f(0, 0, 0); - glTexCoord2f(1, 1); - glVertex3f(279, 0, 0); - glTexCoord2f(1, 0); - glVertex3f(279, 191, 0); + } else if(mode == LORES) { - glTexCoord2f(0, 1); - glVertex3f(0, 0, 0); - glTexCoord2f(1, 0); - glVertex3f(279, 191, 0); - glTexCoord2f(0, 0); - glVertex3f(0, 191, 0); + // LORES!! - glEnd(); + } else { - glPopMatrix(); - CHECK_OPENGL(__LINE__); + glUseProgram(text_program); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE, textport_texture[display_page]); + glUniform1i(textport_texture_location, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_RECTANGLE, font_texture); + glUniform1i(font_texture_location, 1); + } + + // bind upper shader + glBindVertexArray(upper_screen_area); + CheckOpenGL(__FILE__, __LINE__); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + CheckOpenGL(__FILE__, __LINE__); + + if(mixed_mode || (mode == TEXT)) { + + glUseProgram(text_program); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE, textport_texture[display_page]); + glUniform1i(textport_texture_location, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_RECTANGLE, font_texture); + glUniform1i(font_texture_location, 1); + + } else if(mode == LORES) { + + } else if(mode == HIRES) { + + glUseProgram(hires_program); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_RECTANGLE, hires_texture[display_page]); + glUniform1i(hires_texture_location, 0); + + } + + // bind lower shader + glBindVertexArray(lower_screen_area); + CheckOpenGL(__FILE__, __LINE__); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + CheckOpenGL(__FILE__, __LINE__); } static void error_callback(int error, const char* description) @@ -123,9 +439,9 @@ static void error_callback(int error, const char* description) static void key(GLFWwindow *window, int key, int scancode, int action, int mods) { if(action == GLFW_PRESS) { - event_queue.push_back({event::KEYDOWN, key}); + event_queue.push_back({KEYDOWN, key}); } else if(action == GLFW_RELEASE) { - event_queue.push_back({event::KEYUP, key}); + event_queue.push_back({KEYUP, key}); } } @@ -179,15 +495,20 @@ static void scroll(GLFWwindow *window, double dx, double dy) static GLFWwindow* window; -const int pixel_scale = 2; +const int pixel_scale = 3; -void interface_start() +void start() { glfwSetErrorCallback(error_callback); if(!glfwInit()) exit(EXIT_FAILURE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_SAMPLES, 4); window = glfwCreateWindow(gWindowWidth = 280 * pixel_scale, gWindowHeight = 192 * pixel_scale, "Apple //e", NULL, NULL); if (!window) { @@ -197,15 +518,13 @@ void interface_start() } glfwMakeContextCurrent(window); - - GLenum err = glewInit(); - if (GLEW_OK != err) { - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - exit(EXIT_FAILURE); - } - fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); + CheckOpenGL(__FILE__, __LINE__); + printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER)); + printf("GL_VERSION: %s\n", glGetString(GL_VERSION)); + CheckOpenGL(__FILE__, __LINE__); initialize_gl(); + CheckOpenGL(__FILE__, __LINE__); glfwSetKeyCallback(window, key); glfwSetMouseButtonCallback(window, button); @@ -213,21 +532,1012 @@ void interface_start() glfwSetScrollCallback(window, scroll); glfwSetFramebufferSizeCallback(window, resize); glfwSetWindowRefreshCallback(window, redraw); + CheckOpenGL(__FILE__, __LINE__); } -void interface_iterate() +void iterate() { + CheckOpenGL(__FILE__, __LINE__); if(glfwWindowShouldClose(window)) { - event_queue.push_back({event::QUIT, 0}); + event_queue.push_back({QUIT, 0}); } + CheckOpenGL(__FILE__, __LINE__); redraw(window); + CheckOpenGL(__FILE__, __LINE__); glfwSwapBuffers(window); + CheckOpenGL(__FILE__, __LINE__); glfwPollEvents(); } -void interface_shutdown() +void shutdown() { glfwTerminate(); } + +void set_switches(DisplayMode mode_, bool mixed, int page) +{ + mode = mode_; + mixed_mode = mixed; + display_page = page; +} + +static const int text_page1_base = 0x400; +static const int text_page2_base = 0x800; +static const int text_page_size = 0x400; +static const int hires_page1_base = 0x2000; +static const int hires_page2_base = 0x4000; +static const int hires_page_size = 8192; + +extern int text_row_base_offsets[24]; +extern int hires_memory_to_scanout_address[8192]; + +bool write(int addr, unsigned char data) +{ + // We know text page 1 and 2 are contiguous + if((addr >= text_page1_base) && (addr < text_page2_base + text_page_size)) { + int page = (addr >= text_page2_base) ? 1 : 0; + int within_page = addr - text_page1_base - page * text_page_size; + for(int row = 0; row < 24; row++) { + int row_offset = text_row_base_offsets[row]; + if((within_page >= row_offset) && + (within_page < row_offset + 40)){ + int col = within_page - row_offset; + glBindTexture(GL_TEXTURE_RECTANGLE, textport_texture[page]); + glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, col, row, 1, 1, GL_RED_INTEGER_EXT, GL_UNSIGNED_BYTE, &data); + textport[page][row][col] = data; + CheckOpenGL(__FILE__, __LINE__); + } + } + return true; + + } else if(((addr >= hires_page1_base) && (addr < hires_page1_base + hires_page_size)) || ((addr >= hires_page2_base) && (addr < hires_page2_base + hires_page_size))) { + + int page = (addr < hires_page2_base) ? 0 : 1; + int page_base = (page == 0) ? hires_page1_base : hires_page2_base; + int within_page = addr - page_base; + int scanout_address = hires_memory_to_scanout_address[within_page]; + int row = scanout_address / 40; + int col = scanout_address % 40; + glBindTexture(GL_TEXTURE_RECTANGLE, hires_texture[page]); + unsigned char pixels[8]; + for(int i = 0; i < 8 ; i++) + pixels[i] = ((data & (1 << i)) ? 255 : 0); + glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, col * 8, row, 8, 1, GL_RED_INTEGER_EXT, GL_UNSIGNED_BYTE, pixels); + CheckOpenGL(__FILE__, __LINE__); + return true; + } + return false; +} + +int text_row_base_offsets[24] = +{ + 0x000, + 0x080, + 0x100, + 0x180, + 0x200, + 0x280, + 0x300, + 0x380, + 0x028, + 0x0A8, + 0x128, + 0x1A8, + 0x228, + 0x2A8, + 0x328, + 0x3A8, + 0x050, + 0x0D0, + 0x150, + 0x1D0, + 0x250, + 0x2D0, + 0x350, + 0x3D0, +}; + +int hires_row_base_offsets[192] = +{ + 0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, + 0x0080, 0x0480, 0x0880, 0x0C80, 0x1080, 0x1480, 0x1880, 0x1C80, + 0x0100, 0x0500, 0x0900, 0x0D00, 0x1100, 0x1500, 0x1900, 0x1D00, + 0x0180, 0x0580, 0x0980, 0x0D80, 0x1180, 0x1580, 0x1980, 0x1D80, + 0x0200, 0x0600, 0x0A00, 0x0E00, 0x1200, 0x1600, 0x1A00, 0x1E00, + 0x0280, 0x0680, 0x0A80, 0x0E80, 0x1280, 0x1680, 0x1A80, 0x1E80, + 0x0300, 0x0700, 0x0B00, 0x0F00, 0x1300, 0x1700, 0x1B00, 0x1F00, + 0x0380, 0x0780, 0x0B80, 0x0F80, 0x1380, 0x1780, 0x1B80, 0x1F80, + 0x0028, 0x0428, 0x0828, 0x0C28, 0x1028, 0x1428, 0x1828, 0x1C28, + 0x00A8, 0x04A8, 0x08A8, 0x0CA8, 0x10A8, 0x14A8, 0x18A8, 0x1CA8, + 0x0128, 0x0528, 0x0928, 0x0D28, 0x1128, 0x1528, 0x1928, 0x1D28, + 0x01A8, 0x05A8, 0x09A8, 0x0DA8, 0x11A8, 0x15A8, 0x19A8, 0x1DA8, + 0x0228, 0x0628, 0x0A28, 0x0E28, 0x1228, 0x1628, 0x1A28, 0x1E28, + 0x02A8, 0x06A8, 0x0AA8, 0x0EA8, 0x12A8, 0x16A8, 0x1AA8, 0x1EA8, + 0x0328, 0x0728, 0x0B28, 0x0F28, 0x1328, 0x1728, 0x1B28, 0x1F28, + 0x03A8, 0x07A8, 0x0BA8, 0x0FA8, 0x13A8, 0x17A8, 0x1BA8, 0x1FA8, + 0x0050, 0x0450, 0x0850, 0x0C50, 0x1050, 0x1450, 0x1850, 0x1C50, + 0x00D0, 0x04D0, 0x08D0, 0x0CD0, 0x10D0, 0x14D0, 0x18D0, 0x1CD0, + 0x0150, 0x0550, 0x0950, 0x0D50, 0x1150, 0x1550, 0x1950, 0x1D50, + 0x01D0, 0x05D0, 0x09D0, 0x0DD0, 0x11D0, 0x15D0, 0x19D0, 0x1DD0, + 0x0250, 0x0650, 0x0A50, 0x0E50, 0x1250, 0x1650, 0x1A50, 0x1E50, + 0x02D0, 0x06D0, 0x0AD0, 0x0ED0, 0x12D0, 0x16D0, 0x1AD0, 0x1ED0, + 0x0350, 0x0750, 0x0B50, 0x0F50, 0x1350, 0x1750, 0x1B50, 0x1F50, + 0x03D0, 0x07D0, 0x0BD0, 0x0FD0, 0x13D0, 0x17D0, 0x1BD0, 0x1FD0, +}; + +int hires_memory_to_scanout_address[8192]; + +static void initialize_memory_to_scanout() __attribute__((constructor)); +void initialize_memory_to_scanout() +{ + for(int row = 0; row < 192; row++) { + int row_address = hires_row_base_offsets[row]; + for(int byte = 0; byte < 40; byte++) { + hires_memory_to_scanout_address[row_address + byte] = row * 40 + byte; + } + } +} + +int font_offset = 32; +unsigned char font_bytes[96 * 7 * 8] = { + // + 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, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // ! + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // " + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,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,0x00,0x00, + // # + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // $ + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // % + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // & + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // ' + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,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,0x00,0x00,0x00, + // ( + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // ) + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // * + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,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,0xFF,0xFF,0xFF,0xFF,0xFF,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,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,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // / + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0 + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 1 + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 2 + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 3 + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 4 + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 5 + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 6 + 0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 7 + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 8 + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 9 + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,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,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,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,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // < + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // = + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // > + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // ? + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // @ + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // A + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // B + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // C + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // D + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // E + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // F + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // G + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // H + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // I + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // J + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // K + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // L + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // M + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // N + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // O + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // P + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // Q + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // R + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // S + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // T + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // U + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // V + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // W + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // X + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // Y + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // Z + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // [ + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // backslash + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // ] + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,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,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,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,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,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + // ` + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,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,0x00,0x00, + // a + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // b + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // c + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // d + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // e + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // f + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // g + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + // h + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // i + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // j + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + // k + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // l + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // m + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // n + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // o + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // p + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + // q + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + // r + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // s + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // t + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // u + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // v + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // w + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0xFF,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // x + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0xFF,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // y + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00, + // z + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // { + 0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // | + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0x00,0x00,0x00, + // } + 0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0x00,0xFF,0xFF,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0x00,0x00,0xFF,0xFF,0x00,0x00, + 0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // ~ + 0x00,0x00,0xFF,0xFF,0x00,0xFF,0x00, + 0x00,0xFF,0x00,0xFF,0xFF,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,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +}; + diff --git a/interface.h b/interface.h index 6e11d13..50cf6b5 100644 --- a/interface.h +++ b/interface.h @@ -1,42 +1,51 @@ #include +namespace APPLE2Einterface +{ +enum EventType {NONE, KEYDOWN, KEYUP, RESET, REBOOT, QUIT}; + +const int LEFT_SHIFT = 340; +const int LEFT_CONTROL = 341; +const int LEFT_ALT = 342; +const int LEFT_SUPER = 343; +const int RIGHT_SHIFT = 344; +const int RIGHT_CONTROL = 345; +const int RIGHT_ALT = 346; +const int RIGHT_SUPER = 347; +const int ESCAPE = 256; +const int ENTER = 257; +const int TAB = 258; +const int BACKSPACE = 259; +const int INSERT = 260; +const int DELETE = 261; +const int RIGHT = 262; +const int LEFT = 263; +const int DOWN = 264; +const int UP = 265; +const int PAGE_UP = 266; +const int PAGE_DOWN = 267; +const int HOME = 268; +const int END = 269; +const int CAPS_LOCK = 280; + struct event { - enum Type {NONE, KEYDOWN, KEYUP, RESET, REBOOT, QUIT} type; - static const int LEFT_SHIFT = 340; - static const int LEFT_CONTROL = 341; - static const int LEFT_ALT = 342; - static const int LEFT_SUPER = 343; - static const int RIGHT_SHIFT = 344; - static const int RIGHT_CONTROL = 345; - static const int RIGHT_ALT = 346; - static const int RIGHT_SUPER = 347; - static const int ESCAPE = 256; - static const int ENTER = 257; - static const int TAB = 258; - static const int BACKSPACE = 259; - static const int INSERT = 260; - static const int DELETE = 261; - static const int RIGHT = 262; - static const int LEFT = 263; - static const int DOWN = 264; - static const int UP = 265; - static const int PAGE_UP = 266; - static const int PAGE_DOWN = 267; - static const int HOME = 268; - static const int END = 269; - static const int CAPS_LOCK = 280; + EventType type; int value; - event(Type type_, int value_) : + event(EventType type_, int value_) : type(type_), value(value_) {} }; -bool interface_event_waiting(); -event interface_dequeue_event(); -void interface_start(); -void interface_iterate(); -void interface_shutdown(); +void start(); +void iterate(); // display +void shutdown(); -void interface_setregion(int w, int h); -void interface_updaterect(int x, int y, int w, int h, unsigned char *rgb); +bool event_waiting(); +event dequeue_event(); + +enum DisplayMode {TEXT, LORES, HIRES}; +void set_switches(DisplayMode mode, bool mixed, int page); +bool write(int addr, unsigned char data); + +};