From ddf4655a4324aebd7930748b40d4690632201e86 Mon Sep 17 00:00:00 2001 From: Brad Grantham Date: Sun, 4 Dec 2016 22:07:00 -0800 Subject: [PATCH] Implement 80-column mode - ProDOS boots to 80 cols Catch ALTCHAR but do nothing about it Catch VID80 (80VID) Add aux pages to interface.cpp Plumb aux pages through apple2e.cpp display_write functions Implement 80-column text shader using aux page --- apple2e.cpp | 28 +++++---- interface.cpp | 166 ++++++++++++++++++++++++++++++++++++++++++++------ interface.h | 4 +- 3 files changed, 164 insertions(+), 34 deletions(-) diff --git a/apple2e.cpp b/apple2e.cpp index 366c7be..7ab688e 100644 --- a/apple2e.cpp +++ b/apple2e.cpp @@ -321,8 +321,10 @@ struct DISKIIboard : board_base floppy_present[number] = true; unsigned char *skew; - if(strcmp(name + strlen(name) - 3, ".po") == 0) + if(strcmp(name + strlen(name) - 3, ".po") == 0) { + printf("ProDOS floppy\n"); skew = floppy_poSector; + } else skew = floppy_doSector; floppy_NybblizeImage(floppy_image[number], floppy_nybblized[number], skew); @@ -463,8 +465,8 @@ struct MAINboard : board_base SoftSwitch RAMWRT {"RAMWRT", 0xC004, 0xC005, 0xC014, false, switches, true}; SoftSwitch ALTZP {"ALTZP", 0xC008, 0xC009, 0xC016, false, switches, true}; SoftSwitch C3ROM {"C3ROM", 0xC00A, 0xC00B, 0xC017, false, switches, true}; - SoftSwitch ALTCHAR {"ALTCHAR", 0xC00E, 0xC00F, 0xC01E, false, switches}; - SoftSwitch VID80 {"VID80", 0xC00C, 0xC00D, 0xC01F, false, switches}; + SoftSwitch ALTCHAR {"ALTCHAR", 0xC00E, 0xC00F, 0xC01E, false, switches, true}; + SoftSwitch VID80 {"VID80", 0xC00C, 0xC00D, 0xC01F, false, switches, true}; SoftSwitch TEXT {"TEXT", 0xC050, 0xC051, 0xC01A, true, switches, true}; SoftSwitch MIXED {"MIXED", 0xC052, 0xC053, 0xC01B, true, switches, true}; SoftSwitch PAGE2 {"PAGE2", 0xC054, 0xC055, 0xC01C, true, switches, true}; @@ -495,8 +497,8 @@ struct MAINboard : board_base backed_region ram_6000 = {"ram_6000", 0x6000, 0x6000, RAM, ®ions, read_from_main_ram, write_to_main_ram}; backed_region ram_6000_x = {"ram_6000_x", 0x6000, 0x6000, RAM, ®ions, read_from_aux_ram, write_to_aux_ram}; - enabled_func read_from_aux_text1 = [&]{return RAMRD && ((!STORE80) || (STORE80 && PAGE2));}; - enabled_func write_to_aux_text1 = [&]{return RAMWRT && ((!STORE80) || (STORE80 && PAGE2));}; + enabled_func read_from_aux_text1 = [&]{return (RAMRD && !STORE80) || (STORE80 && PAGE2);}; + enabled_func write_to_aux_text1 = [&]{return (RAMWRT && !STORE80) || (STORE80 && PAGE2);}; enabled_func read_from_main_text1 = [&]{return !read_from_aux_text1();}; enabled_func write_to_main_text1 = [&]{return !write_to_aux_text1();}; @@ -583,7 +585,7 @@ struct MAINboard : board_base keyboard_buffer.push_back(k); } - typedef std::function display_write_func; + typedef std::function display_write_func; display_write_func display_write; typedef std::function audio_flush_func; audio_flush_func audio_flush; @@ -794,7 +796,7 @@ struct MAINboard : board_base if(((addr >= 0x400) && (addr <= 0xBFF)) || ((addr >= 0x2000) && (addr <= 0x5FFF))) #endif { - display_write(addr, data); + display_write(addr, write_to_aux_text1(), data); } for(auto it = boards.begin(); it != boards.end(); it++) { board_base* b = *it; @@ -2356,7 +2358,7 @@ void cleanup(void) fflush(stderr); } -bool use_fake6502 = false; +bool use_fake6502 = true; struct saved_inst { int pc; @@ -2660,7 +2662,7 @@ int main(int argc, char **argv) MAINboard* mainboard; - MAINboard::display_write_func display = [](int addr, unsigned char data)->bool{return APPLE2Einterface::write(addr, data);}; + MAINboard::display_write_func display = [](int addr, bool aux, unsigned char data)->bool{return APPLE2Einterface::write(addr, aux, data);}; MAINboard::audio_flush_func audio; MAINboard::get_paddle_func paddle = [](int num)->tuple{return APPLE2Einterface::get_paddle(num);}; if(have_audio) @@ -2767,8 +2769,8 @@ int main(int argc, char **argv) } mainboard->sync(); 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); + int page = (mainboard->PAGE2 && !mainboard->STORE80) ? 1 : 0; + APPLE2Einterface::set_switches(mode, mainboard->MIXED, page, mainboard->VID80, mainboard->ALTCHAR); APPLE2Einterface::iterate(); chrono::time_point now = std::chrono::system_clock::now(); @@ -2833,8 +2835,8 @@ int main(int argc, char **argv) mainboard->sync(); 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); + int page = (mainboard->PAGE2 && !mainboard->STORE80) ? 1 : 0; + APPLE2Einterface::set_switches(mode, mainboard->MIXED, page, mainboard->VID80, mainboard->ALTCHAR); APPLE2Einterface::iterate(); } } diff --git a/interface.cpp b/interface.cpp index 4d7f879..089f9be 100644 --- a/interface.cpp +++ b/interface.cpp @@ -30,6 +30,8 @@ static GLFWwindow* my_window; DisplayMode display_mode = TEXT; int display_page = 0; // Apple //e page minus 1 (so 0,1 not 1,2) bool mixed_mode = false; +bool vid80 = false; +bool altchar = false; bool use_joystick = false; int joystick_axis0 = 0; @@ -75,18 +77,30 @@ GLuint font_texture; const int fonttexture_w = 7; const int fonttexture_h = 8 * 96; +GLuint textport_texture[2][2]; // [aux][page] + GLuint text_program; const int textport_w = 40; const int textport_h = 24; -GLuint textport_texture[2]; GLuint textport_texture_location; -GLuint blink_location; +GLuint textport_blink_location; GLuint textport_x_offset_location; GLuint textport_y_offset_location; GLuint textport_to_screen_location; GLuint textport_foreground_location; GLuint textport_background_location; -GLuint font_texture_location; +GLuint textport_font_texture_location; + +GLuint text80_program; +GLuint textport80_texture_location; +GLuint textport80_aux_texture_location; +GLuint textport80_blink_location; +GLuint textport80_x_offset_location; +GLuint textport80_y_offset_location; +GLuint textport80_to_screen_location; +GLuint textport80_foreground_location; +GLuint textport80_background_location; +GLuint textport80_font_texture_location; GLuint lores_program; GLuint lores_texture_location; @@ -275,6 +289,58 @@ static const char *text_fragment_shader = "\n\ color = mix(background, foreground, pixel / 255.0);\n\ }\n"; +static const char *text80_fragment_shader = "\n\ + in vec2 raster_coords;\n\ + uniform int blink;\n\ + uniform vec4 foreground;\n\ + uniform vec4 background;\n\ + uniform usampler2DRect font_texture;\n\ + uniform usampler2DRect textport_texture;\n\ + uniform usampler2DRect textport_aux_texture;\n\ + \n\ + out vec4 color;\n\ + \n\ + void main()\n\ + {\n\ + uint character;\n\ + uint x = uint(raster_coords.x * 2) / 7u; \n\ + if(x % 2u == 1u) \n\ + character = texture(textport_texture, uvec2((x - 1u) / 2u, uint(raster_coords.y) / 8u)).x; \n\ + else \n\ + character = texture(textport_aux_texture, uvec2(x / 2u, uint(raster_coords.y) / 8u)).x; \n\ + bool inverse = false;\n\ + if(character >= 0u && character <= 31u) {\n\ + character = character - 0u + 32u;\n\ + inverse = true;\n\ + } else if(character >= 32u && character <= 63u) {\n\ + character = character - 32u + 0u;\n\ + inverse = true;\n\ + } else if(character >= 64u && character <= 95u) {\n\ + character = character - 64u + 32u; // XXX BLINK \n\ + inverse = blink == 1;\n\ + } else if(character >= 96u && character <= 127u){\n\ + character = character - 96u + 0u; // XXX BLINK \n\ + inverse = blink == 1;\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 * 2) % 7u + 1u, uint(raster_coords.y) % 8u);\n\ + uvec2 infont = inglyph + uvec2(0, character * 8u);\n\ + uint pixel = texture(font_texture, infont).x;\n\ + float value;\n\ + if(inverse)\n\ + color = mix(background, foreground, 1.0 - pixel / 255.0);\n\ + else\n\ + color = mix(background, foreground, pixel / 255.0);\n\ + }\n"; + static const char *lores_fragment_shader = "\n\ in vec2 raster_coords;\n\ uniform usampler2DRect font_texture;\n\ @@ -435,7 +501,7 @@ GLuint initialize_texture(int w, int h, unsigned char *pixels = NULL) return texture; } -unsigned char textport[2][24][40]; +// unsigned char textport[2][2][24][40]; void set_textport_shader(float to_screen[9], GLuint textport_texture, int blink, float x, float y, float fg[4], float bg[4]) { @@ -446,8 +512,8 @@ void set_textport_shader(float to_screen[9], GLuint textport_texture, int blink, glUniform1i(textport_texture_location, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_RECTANGLE, font_texture); - glUniform1i(font_texture_location, 1); - glUniform1i(blink_location, blink); + glUniform1i(textport_font_texture_location, 1); + glUniform1i(textport_blink_location, blink); glUniform1f(textport_x_offset_location, x); glUniform1f(textport_y_offset_location, y); glUniform4fv(textport_background_location, 1, bg); @@ -455,20 +521,58 @@ void set_textport_shader(float to_screen[9], GLuint textport_texture, int blink, glUniformMatrix3fv(textport_to_screen_location, 1, GL_FALSE, to_screen); } -void set_shader(float to_screen[9], DisplayMode display_mode, bool mixed_mode, int blink, float x, float y) +void set_textport80_shader(float to_screen[9], GLuint textport80_texture, GLuint textport80_aux_texture, int blink, float x, float y, float fg[4], float bg[4]) +{ + glUseProgram(text80_program); + CheckOpenGL(__FILE__, __LINE__); + + int tex = 0; + glActiveTexture(GL_TEXTURE0 + tex); + glBindTexture(GL_TEXTURE_RECTANGLE, textport80_texture); + glUniform1i(textport80_texture_location, tex); + tex += 1; + CheckOpenGL(__FILE__, __LINE__); + glActiveTexture(GL_TEXTURE0 + tex); + glBindTexture(GL_TEXTURE_RECTANGLE, textport80_aux_texture); + glUniform1i(textport80_aux_texture_location, tex); + tex += 1; + CheckOpenGL(__FILE__, __LINE__); + glActiveTexture(GL_TEXTURE0 + tex); + glBindTexture(GL_TEXTURE_RECTANGLE, font_texture); + glUniform1i(textport80_font_texture_location, tex); + tex += 1; + CheckOpenGL(__FILE__, __LINE__); + glUniform1i(textport80_blink_location, blink); + CheckOpenGL(__FILE__, __LINE__); + glUniform1f(textport80_x_offset_location, x); + CheckOpenGL(__FILE__, __LINE__); + glUniform1f(textport80_y_offset_location, y); + CheckOpenGL(__FILE__, __LINE__); + glUniform4fv(textport80_background_location, 1, bg); + CheckOpenGL(__FILE__, __LINE__); + glUniform4fv(textport80_foreground_location, 1, fg); + CheckOpenGL(__FILE__, __LINE__); + glUniformMatrix3fv(textport80_to_screen_location, 1, GL_FALSE, to_screen); + CheckOpenGL(__FILE__, __LINE__); +} + +void set_shader(float to_screen[9], DisplayMode display_mode, bool mixed_mode, bool vid80, int blink, float x, float y) { if(mixed_mode || (display_mode == TEXT)) { float bg[4] = {0, 0, 0, 1}; float fg[4] = {1, 1, 1, 1}; - set_textport_shader(to_screen, textport_texture[display_page], blink, x, y, fg, bg); + if(vid80) + set_textport80_shader(to_screen, textport_texture[0][display_page], textport_texture[1][display_page], blink, x, y, fg, bg); + else + set_textport_shader(to_screen, textport_texture[0][display_page], blink, x, y, fg, bg); } else if(display_mode == LORES) { glUseProgram(lores_program); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE, textport_texture[display_page]); + glBindTexture(GL_TEXTURE_RECTANGLE, textport_texture[0][display_page]); glUniform1i(lores_texture_location, 0); glUniformMatrix3fv(lores_to_screen_location, 1, GL_FALSE, to_screen); glUniform1f(lores_x_offset_location, x); @@ -768,14 +872,15 @@ struct apple2screen : public widget w = w_; h = h_; long long elapsed_millis = now * 1000; - set_shader(to_screen, display_mode, false, (elapsed_millis / 300) % 2, x, y); + set_shader(to_screen, display_mode, false, vid80, (elapsed_millis / 300) % 2, x, y); + CheckOpenGL(__FILE__, __LINE__); glBindVertexArray(upper_screen_area); CheckOpenGL(__FILE__, __LINE__); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CheckOpenGL(__FILE__, __LINE__); - set_shader(to_screen, display_mode, mixed_mode, (elapsed_millis / 300) % 2, x, y); + set_shader(to_screen, display_mode, mixed_mode, vid80, (elapsed_millis / 300) % 2, x, y); glBindVertexArray(lower_screen_area); CheckOpenGL(__FILE__, __LINE__); @@ -1054,8 +1159,10 @@ void initialize_gl(void) CheckOpenGL(__FILE__, __LINE__); 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); + textport_texture[0][0] = initialize_texture(textport_w, textport_h); + textport_texture[0][1] = initialize_texture(textport_w, textport_h); + textport_texture[1][0] = initialize_texture(textport_w, textport_h); + textport_texture[1][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__); @@ -1068,8 +1175,8 @@ void initialize_gl(void) 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"); - blink_location = glGetUniformLocation(text_program, "blink"); + textport_font_texture_location = glGetUniformLocation(text_program, "font_texture"); + textport_blink_location = glGetUniformLocation(text_program, "blink"); textport_x_offset_location = glGetUniformLocation(text_program, "x_offset"); textport_y_offset_location = glGetUniformLocation(text_program, "y_offset"); textport_to_screen_location = glGetUniformLocation(text_program, "to_screen"); @@ -1077,6 +1184,18 @@ void initialize_gl(void) textport_background_location = glGetUniformLocation(text_program, "background"); CheckOpenGL(__FILE__, __LINE__); + text80_program = GenerateProgram("textport80", text_vertex_shader, text80_fragment_shader); + textport80_texture_location = glGetUniformLocation(text80_program, "textport_texture"); + textport80_aux_texture_location = glGetUniformLocation(text80_program, "textport_aux_texture"); + textport80_font_texture_location = glGetUniformLocation(text80_program, "font_texture"); + textport80_blink_location = glGetUniformLocation(text80_program, "blink"); + textport80_x_offset_location = glGetUniformLocation(text80_program, "x_offset"); + textport80_y_offset_location = glGetUniformLocation(text80_program, "y_offset"); + textport80_to_screen_location = glGetUniformLocation(text80_program, "to_screen"); + textport80_foreground_location = glGetUniformLocation(text80_program, "foreground"); + textport80_background_location = glGetUniformLocation(text80_program, "background"); + CheckOpenGL(__FILE__, __LINE__); + lores_program = GenerateProgram("textport", text_vertex_shader, lores_fragment_shader); lores_texture_location = glGetUniformLocation(lores_program, "lores_texture"); lores_x_offset_location = glGetUniformLocation(lores_program, "x_offset"); @@ -1491,11 +1610,20 @@ void shutdown() glfwTerminate(); } -void set_switches(DisplayMode mode_, bool mixed, int page) +void set_switches(DisplayMode mode_, bool mixed, int page, bool vid80_, bool altchar_) { display_mode = mode_; mixed_mode = mixed; display_page = page; + vid80 = vid80_; + altchar = altchar_; + + // XXX + static bool altchar_warned = false; + if(altchar && !altchar_warned) { + fprintf(stderr, "Warning: ALTCHAR activated, is not implemented\n"); + altchar_warned = true; + } } static const int text_page1_base = 0x400; @@ -1508,7 +1636,7 @@ 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) +bool write(int addr, bool aux, unsigned char data) { // We know text page 1 and 2 are contiguous if((addr >= text_page1_base) && (addr < text_page2_base + text_page_size)) { @@ -1519,9 +1647,9 @@ bool write(int addr, unsigned char data) if((within_page >= row_offset) && (within_page < row_offset + 40)){ int col = within_page - row_offset; - glBindTexture(GL_TEXTURE_RECTANGLE, textport_texture[page]); + glBindTexture(GL_TEXTURE_RECTANGLE, textport_texture[aux ? 1 : 0][page]); glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, col, row, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, &data); - textport[page][row][col] = data; + // textport[aux ? 1 : 0][page][row][col] = data; CheckOpenGL(__FILE__, __LINE__); } } diff --git a/interface.h b/interface.h index 2625c46..c4713b3 100644 --- a/interface.h +++ b/interface.h @@ -47,8 +47,8 @@ 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); +void set_switches(DisplayMode mode, bool mixed, int page, bool vid80, bool altchar); +bool write(int addr, bool aux, unsigned char data); std::tuple get_paddle(int num);