hires graphics in a separate window

This commit is contained in:
Brad Grantham 2016-11-16 22:50:09 -08:00
parent 33a78aabe9
commit dac35cccb1
4 changed files with 161 additions and 21 deletions

View File

@ -1,5 +1,5 @@
INCFLAGS += -I/opt/local/include -I/opt/local/include/freetype2
CXXFLAGS += $(INCFLAGS) -g -Wall --std=c++11 # -O
CXXFLAGS += $(INCFLAGS) -g -Wall --std=c++11 -O
LDFLAGS += -L/opt/local/lib
LDLIBS += -lglfw -lglew -lfreeimageplus -lfreetype -framework OpenGL -framework Cocoa -framework IOkit

View File

@ -33,6 +33,7 @@ volatile unsigned int debug = DEBUG_ERROR | DEBUG_WARN ; // | DEBUG_DECODE | DEB
volatile bool exit_on_banking = false;
volatile bool exit_on_memory_fallthrough = true;
volatile bool run_fast = false;
struct SoftSwitch
{
@ -61,6 +62,33 @@ 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 constexpr int text_row_base_offsets[] =
{
0x000,
@ -96,35 +124,66 @@ struct APPLE2Edisplay
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)
{
printf("------------------------------------------\n");
fputs("------------------------------------------\n", stdout);
for(int row = 0; row < 24; row++) {
printf("|");
fputs("|", stdout);
for(int col = 0; col < 40; col++) {
int ch = text_page[page][row][col] & 0x7F;
printf("%c", isprint(ch) ? ch : '?');
fputc(isprint(ch) ? ch : '?', stdout);
}
printf("|\n");
fputs("|\n", stdout);
}
printf("------------------------------------------\n");
fputs("------------------------------------------\n", stdout);
}
void display()
void display_hires(int page, std::function<void(int,int,int,int,unsigned char*)> 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];
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<void(int,int,int,int,unsigned char*)> update)
{
// enum {TEXT, LORES, HIRES} mode = TEXT;
// int display_page = 0;
// bool mixed_mode = false;
if(mode == TEXT) {
display_text(display_page);
} else {
}
} // 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 = 0x2000;
bool write(int addr, unsigned char data)
{
// We know text page 1 and 2 are contiguous
@ -142,10 +201,27 @@ struct APPLE2Edisplay
changed = true;
return true;
}
if((addr >= hires_page1_base) && (addr < hires_page2_base + hires_page_size)) {
int page = (addr >= hires_page2_base) ? 1 : 0;
int within_page = addr - hires_page1_base - page * hires_page_size;
// YUCK - use a lookup or at least a map...
for(int row = 0; row < 192; row++) {
int row_offset = hires_row_base_offsets[row];
if((within_page >= row_offset) &&
(within_page < row_offset + 40)){
int col = within_page - row_offset;
hires_page[page][row][col] = data;
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];
struct region
{
@ -1643,7 +1719,6 @@ enum event::Type keyboard_to_mainboard(MAINboard *board)
return event::NONE;
}
int main(int argc, char **argv)
{
char *progname = argv[0];
@ -1712,6 +1787,8 @@ int main(int argc, char **argv)
interface_start();
interface_setregion(280, 192);
while(1) {
if(!debugging) {
poll_keyboard();
@ -1736,7 +1813,7 @@ int main(int argc, char **argv)
}
chrono::time_point<chrono::system_clock> then;
const int inst_per_slice = 255750 * millis_per_slice / 1000;
int inst_per_slice = 255750 * millis_per_slice / 1000 * 2;
for(int i = 0; i < inst_per_slice; i++) {
string dis = read_bus_and_disassemble(bus, cpu.pc);
if(debug & DEBUG_DECODE)
@ -1747,15 +1824,16 @@ int main(int argc, char **argv)
cpu.cycle(bus);
}
if(display.changed) {
display.display();
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();
chrono::time_point<chrono::system_clock> now;
auto elapsed_millis = chrono::duration_cast<chrono::milliseconds>(now - then);
this_thread::sleep_for(chrono::milliseconds(millis_per_slice) - elapsed_millis);
if(!run_fast)
this_thread::sleep_for(chrono::milliseconds(millis_per_slice) - elapsed_millis);
} else {
printf("> ");
@ -1769,6 +1847,14 @@ int main(int argc, char **argv)
debugging = false;
start_keyboard();
continue;
} else if(strcmp(line, "fast") == 0) {
printf("run flat out\n");
run_fast = true;
continue;
} else if(strcmp(line, "1mhz") == 0) {
printf("run 1mhz\n");
run_fast = false;
continue;
} else if(strcmp(line, "banking") == 0) {
printf("abort on any banking\n");
exit_on_banking = true;
@ -1797,7 +1883,7 @@ int main(int argc, char **argv)
else
cpu.cycle(bus);
if(display.changed) {
display.display();
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();

View File

@ -39,20 +39,50 @@ using namespace std;
float aspectRatio = 1;
void initialize_gl(void)
int region_w;
int region_h;
GLuint texture;
// unsigned char *texture_bytes;
void interface_setregion(int w, int h)
{
glClearColor(0, 0, 0, 1);
region_w = w;
region_h = h;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
}
#define CHECK_OPENGL(l) {int _glerr ; if((_glerr = glGetError()) != GL_NO_ERROR) printf("GL Error: %04X at %d\n", _glerr, l); }
void interface_updaterect(int x, int y, int w, int h, unsigned char *rgb)
{
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, rgb);
CHECK_OPENGL(__LINE__);
}
void initialize_gl(void)
{
glClearColor(0, 0, 0, 1);
CHECK_OPENGL(__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);
}
static void redraw(GLFWwindow *window)
{
CHECK_OPENGL(__LINE__);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, gWindowWidth - 1, 0, gWindowHeight - 1, -1, 1);
glOrtho(0, region_w - 1, 0, region_h - 1, -1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -60,6 +90,27 @@ static void redraw(GLFWwindow *window)
glLoadIdentity();
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glColor3f(1, 1, 1);
glBegin(GL_TRIANGLES);
glTexCoord2f(0, 1);
glVertex3f(0, 0, 0);
glTexCoord2f(1, 1);
glVertex3f(279, 0, 0);
glTexCoord2f(1, 0);
glVertex3f(279, 191, 0);
glTexCoord2f(0, 1);
glVertex3f(0, 0, 0);
glTexCoord2f(1, 0);
glVertex3f(279, 191, 0);
glTexCoord2f(0, 0);
glVertex3f(0, 191, 0);
glEnd();
glPopMatrix();
CHECK_OPENGL(__LINE__);
}
@ -128,6 +179,8 @@ static void scroll(GLFWwindow *window, double dx, double dy)
static GLFWwindow* window;
const int pixel_scale = 2;
void interface_start()
{
glfwSetErrorCallback(error_callback);
@ -136,7 +189,7 @@ void interface_start()
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_SAMPLES, 4);
window = glfwCreateWindow(gWindowWidth = 280 * 4, gWindowHeight = 192 * 4, "Apple //e", NULL, NULL);
window = glfwCreateWindow(gWindowWidth = 280 * pixel_scale, gWindowHeight = 192 * pixel_scale, "Apple //e", NULL, NULL);
if (!window) {
glfwTerminate();
fprintf(stdout, "Couldn't open main window\n");
@ -160,7 +213,6 @@ void interface_start()
glfwSetScrollCallback(window, scroll);
glfwSetFramebufferSizeCallback(window, resize);
glfwSetWindowRefreshCallback(window, redraw);
}
void interface_iterate()
@ -170,7 +222,6 @@ void interface_iterate()
}
redraw(window);
glfwSwapBuffers(window);
glfwPollEvents();

View File

@ -37,3 +37,6 @@ event interface_dequeue_event();
void interface_start();
void interface_iterate();
void interface_shutdown();
void interface_setregion(int w, int h);
void interface_updaterect(int x, int y, int w, int h, unsigned char *rgb);