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
This commit is contained in:
Brad Grantham 2016-12-04 22:07:00 -08:00
parent 85b741e61c
commit ddf4655a43
3 changed files with 164 additions and 34 deletions

View File

@ -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, &regions, read_from_main_ram, write_to_main_ram};
backed_region ram_6000_x = {"ram_6000_x", 0x6000, 0x6000, RAM, &regions, 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<bool (int addr, unsigned char data)> display_write_func;
typedef std::function<bool (int addr, bool aux, unsigned char data)> display_write_func;
display_write_func display_write;
typedef std::function<void (char *audiobuffer, size_t dist)> 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<float, bool>{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<chrono::system_clock> 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();
}
}

View File

@ -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__);
}
}

View File

@ -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<float,bool> get_paddle(int num);