Rudimentary GL window with keyboard support
This commit is contained in:
parent
f747675e22
commit
17c38de074
9
Makefile
9
Makefile
|
@ -1,11 +1,14 @@
|
||||||
CXXFLAGS = -g -O -Wall --std=c++11
|
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
|
||||||
|
|
||||||
OBJECTS = apple2e.o keyboard.o dis6502.o fake6502.o
|
OBJECTS = apple2e.o keyboard.o dis6502.o fake6502.o interface.o
|
||||||
|
|
||||||
all: apple2e
|
all: apple2e
|
||||||
|
|
||||||
apple2e: $(OBJECTS)
|
apple2e: $(OBJECTS)
|
||||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS)
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(INCFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm $(OBJECTS)
|
rm $(OBJECTS)
|
||||||
|
|
124
apple2e.cpp
124
apple2e.cpp
|
@ -8,8 +8,10 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <thread>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
|
||||||
#include "fake6502.h"
|
#include "fake6502.h"
|
||||||
|
|
||||||
const int rom_image_size = 0x3000;
|
const int rom_image_size = 0x3000;
|
||||||
|
@ -19,6 +21,7 @@ using namespace std;
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "dis6502.h"
|
#include "dis6502.h"
|
||||||
|
#include "interface.h"
|
||||||
|
|
||||||
const unsigned int DEBUG_ERROR = 0x01;
|
const unsigned int DEBUG_ERROR = 0x01;
|
||||||
const unsigned int DEBUG_WARN = 0x02;
|
const unsigned int DEBUG_WARN = 0x02;
|
||||||
|
@ -1514,6 +1517,119 @@ string read_bus_and_disassemble(bus_controller &bus, int pc)
|
||||||
|
|
||||||
int millis_per_slice = 16;
|
int millis_per_slice = 16;
|
||||||
|
|
||||||
|
struct key_to_ascii
|
||||||
|
{
|
||||||
|
unsigned char no_shift_no_control;
|
||||||
|
unsigned char yes_shift_no_control;
|
||||||
|
unsigned char no_shift_yes_control;
|
||||||
|
unsigned char yes_shift_yes_control;
|
||||||
|
};
|
||||||
|
|
||||||
|
map<int, key_to_ascii> interface_key_to_apple2e =
|
||||||
|
{
|
||||||
|
{'A', {97, 65, 1, 1}},
|
||||||
|
{'B', {98, 66, 2, 2}},
|
||||||
|
{'C', {99, 67, 3, 3}},
|
||||||
|
{'D', {100, 68, 4, 4}},
|
||||||
|
{'E', {101, 69, 5, 5}},
|
||||||
|
{'F', {102, 70, 6, 6}},
|
||||||
|
{'G', {103, 71, 7, 7}},
|
||||||
|
{'H', {104, 72, 8, 8}},
|
||||||
|
{'I', {105, 73, 9, 9}},
|
||||||
|
{'J', {106, 74, 10, 10}},
|
||||||
|
{'K', {107, 75, 11, 11}},
|
||||||
|
{'L', {108, 76, 12, 12}},
|
||||||
|
{'M', {109, 77, 13, 13}},
|
||||||
|
{'N', {110, 78, 14, 14}},
|
||||||
|
{'O', {111, 79, 15, 15}},
|
||||||
|
{'P', {112, 80, 16, 16}},
|
||||||
|
{'Q', {113, 81, 17, 17}},
|
||||||
|
{'R', {114, 82, 18, 18}},
|
||||||
|
{'S', {115, 83, 19, 19}},
|
||||||
|
{'T', {116, 84, 20, 20}},
|
||||||
|
{'U', {117, 85, 21, 21}},
|
||||||
|
{'V', {118, 86, 22, 22}},
|
||||||
|
{'W', {119, 87, 23, 23}},
|
||||||
|
{'X', {120, 88, 24, 24}},
|
||||||
|
{'Y', {121, 89, 25, 25}},
|
||||||
|
{'Z', {122, 90, 26, 26}},
|
||||||
|
{'1', {'1', '!', 0, 0}},
|
||||||
|
{'2', {'2', '@', 0, 0}},
|
||||||
|
{'3', {'3', '#', 0, 0}},
|
||||||
|
{'4', {'4', '$', 0, 0}},
|
||||||
|
{'5', {'5', '%', 0, 0}},
|
||||||
|
{'6', {'6', '^', 0, 0}},
|
||||||
|
{'7', {'7', '&', 0, 0}},
|
||||||
|
{'8', {'8', '*', 0, 0}},
|
||||||
|
{'9', {'9', '(', 0, 0}},
|
||||||
|
{'0', {'0', ')', 0, 0}},
|
||||||
|
{'-', {'-', '_', 0, 0}},
|
||||||
|
{'=', {'=', '+', 0, 0}},
|
||||||
|
{'[', {'[', '{', 0, 0}},
|
||||||
|
{']', {']', '}', 0, 0}},
|
||||||
|
{'\\', {'\\', '|', 0, 0}},
|
||||||
|
{';', {';', ':', 0, 0}},
|
||||||
|
{'\'', {'\'', '"', 0, 0}},
|
||||||
|
{',', {',', '<', 0, 0}},
|
||||||
|
{'.', {'.', '>', 0, 0}},
|
||||||
|
{'/', {'/', '?', 0, 0}},
|
||||||
|
{'`', {'`', '~', 0, 0}},
|
||||||
|
{' ', {' ', ' ', 0, 0}},
|
||||||
|
};
|
||||||
|
|
||||||
|
void keyboard_to_mainboard(MAINboard *board)
|
||||||
|
{
|
||||||
|
static bool shift_down = false;
|
||||||
|
static bool control_down = false;
|
||||||
|
// skip CAPS for now
|
||||||
|
|
||||||
|
if(interface_event_waiting()) {
|
||||||
|
event e = interface_dequeue_event();
|
||||||
|
if(e.type == event::KEYDOWN) {
|
||||||
|
if((e.value == event::LEFT_SHIFT) || (e.value == event::RIGHT_SHIFT))
|
||||||
|
shift_down = true;
|
||||||
|
else if((e.value == event::LEFT_CONTROL) || (e.value == event::RIGHT_CONTROL))
|
||||||
|
control_down = true;
|
||||||
|
else if(e.value == event::ENTER) {
|
||||||
|
board->enqueue_key(141 - 128);
|
||||||
|
} else if(e.value == event::TAB) {
|
||||||
|
board->enqueue_key(' ');
|
||||||
|
} else if(e.value == event::ESCAPE) {
|
||||||
|
board->enqueue_key('');
|
||||||
|
} else if(e.value == event::DELETE) {
|
||||||
|
board->enqueue_key(255 - 128);
|
||||||
|
} else if(e.value == event::RIGHT) {
|
||||||
|
board->enqueue_key(149 - 128);
|
||||||
|
} else if(e.value == event::LEFT) {
|
||||||
|
board->enqueue_key(136 - 128);
|
||||||
|
} else if(e.value == event::DOWN) {
|
||||||
|
board->enqueue_key(138 - 128);
|
||||||
|
} else if(e.value == event::UP) {
|
||||||
|
board->enqueue_key(139 - 128);
|
||||||
|
} else {
|
||||||
|
auto it = interface_key_to_apple2e.find(e.value);
|
||||||
|
if(it != interface_key_to_apple2e.end()) {
|
||||||
|
const key_to_ascii& k = (*it).second;
|
||||||
|
if(!shift_down && !control_down)
|
||||||
|
board->enqueue_key(k.no_shift_no_control);
|
||||||
|
else if(shift_down && !control_down)
|
||||||
|
board->enqueue_key(k.yes_shift_no_control);
|
||||||
|
else if(!shift_down && control_down)
|
||||||
|
board->enqueue_key(k.no_shift_yes_control);
|
||||||
|
else if(shift_down && control_down)
|
||||||
|
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))
|
||||||
|
shift_down = false;
|
||||||
|
else if((e.value == event::LEFT_CONTROL) || (e.value == event::RIGHT_CONTROL))
|
||||||
|
control_down = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *progname = argv[0];
|
char *progname = argv[0];
|
||||||
|
@ -1579,6 +1695,8 @@ int main(int argc, char **argv)
|
||||||
if(use_fake6502)
|
if(use_fake6502)
|
||||||
reset6502();
|
reset6502();
|
||||||
|
|
||||||
|
interface_start();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(!debugging) {
|
if(!debugging) {
|
||||||
poll_keyboard();
|
poll_keyboard();
|
||||||
|
@ -1586,6 +1704,8 @@ int main(int argc, char **argv)
|
||||||
char key;
|
char key;
|
||||||
bool have_key = peek_key(&key);
|
bool have_key = peek_key(&key);
|
||||||
|
|
||||||
|
keyboard_to_mainboard(mainboard);
|
||||||
|
|
||||||
if(have_key) {
|
if(have_key) {
|
||||||
if(key == '') {
|
if(key == '') {
|
||||||
debugging = true;
|
debugging = true;
|
||||||
|
@ -1613,6 +1733,7 @@ int main(int argc, char **argv)
|
||||||
textport_display();
|
textport_display();
|
||||||
textport_changed = false;
|
textport_changed = false;
|
||||||
}
|
}
|
||||||
|
interface_iterate();
|
||||||
chrono::time_point<chrono::system_clock> now;
|
chrono::time_point<chrono::system_clock> now;
|
||||||
|
|
||||||
auto elapsed_millis = chrono::duration_cast<chrono::milliseconds>(now - then);
|
auto elapsed_millis = chrono::duration_cast<chrono::milliseconds>(now - then);
|
||||||
|
@ -1662,6 +1783,9 @@ int main(int argc, char **argv)
|
||||||
textport_display();
|
textport_display();
|
||||||
textport_changed = false;
|
textport_changed = false;
|
||||||
}
|
}
|
||||||
|
interface_iterate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface_shutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
|
||||||
|
a = ord(c)
|
||||||
|
print " {'%c', {%d, %d, %d, %d}}," % (a, a + 32, a, a - 64, a - 64)
|
||||||
|
|
||||||
|
for c in "1234567890-=[]\;',./`":
|
||||||
|
a = ord(c)
|
||||||
|
print " {'%c', {'%c', '?', 0, 0}}," % (a, a)
|
||||||
|
|
||||||
|
# {'A', {'a', 'A', '', ''}}
|
|
@ -0,0 +1,183 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cctype>
|
||||||
|
#include <deque>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include "interface.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static int gWindowWidth;
|
||||||
|
static int gWindowHeight;
|
||||||
|
|
||||||
|
// to handle https://github.com/glfw/glfw/issues/161
|
||||||
|
static double gMotionReported = false;
|
||||||
|
|
||||||
|
static double gOldMouseX, gOldMouseY;
|
||||||
|
static int gButtonPressed = -1;
|
||||||
|
|
||||||
|
deque<event> event_queue;
|
||||||
|
|
||||||
|
bool interface_event_waiting()
|
||||||
|
{
|
||||||
|
return event_queue.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
event interface_dequeue_event()
|
||||||
|
{
|
||||||
|
if(interface_event_waiting()) {
|
||||||
|
event e = event_queue.front();
|
||||||
|
event_queue.pop_back();
|
||||||
|
return e;
|
||||||
|
} else
|
||||||
|
return {event::NONE, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
float aspectRatio = 1;
|
||||||
|
|
||||||
|
void initialize_gl(void)
|
||||||
|
{
|
||||||
|
glClearColor(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_OPENGL(l) {int _glerr ; if((_glerr = glGetError()) != GL_NO_ERROR) printf("GL Error: %04X at %d\n", _glerr, l); }
|
||||||
|
|
||||||
|
static void redraw(GLFWwindow *window)
|
||||||
|
{
|
||||||
|
CHECK_OPENGL(__LINE__);
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(0, gWindowWidth - 1, 0, gWindowHeight - 1, -1, 1);
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
glPushMatrix();
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
CHECK_OPENGL(__LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error_callback(int error, const char* description)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "GLFW: %s\n", description);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void key(GLFWwindow *window, int key, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
printf("key %d(%c), scancode %d, action %d, mods %02X\n", key, isprint(key) ? key : '?', scancode, action, mods);
|
||||||
|
if(action == GLFW_PRESS) {
|
||||||
|
event_queue.push_back({event::KEYDOWN, key});
|
||||||
|
} else if(action == GLFW_RELEASE) {
|
||||||
|
event_queue.push_back({event::KEYUP, key});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resize(GLFWwindow *window, int x, int y)
|
||||||
|
{
|
||||||
|
glfwGetFramebufferSize(window, &gWindowWidth, &gWindowHeight);
|
||||||
|
glViewport(0, 0, gWindowWidth, gWindowWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void button(GLFWwindow *window, int b, int action, int mods)
|
||||||
|
{
|
||||||
|
double x, y;
|
||||||
|
glfwGetCursorPos(window, &x, &y);
|
||||||
|
|
||||||
|
if(b == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS) {
|
||||||
|
gButtonPressed = 1;
|
||||||
|
gOldMouseX = x;
|
||||||
|
gOldMouseY = y;
|
||||||
|
} else {
|
||||||
|
gButtonPressed = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void motion(GLFWwindow *window, double x, double y)
|
||||||
|
{
|
||||||
|
// to handle https://github.com/glfw/glfw/issues/161
|
||||||
|
// If no motion has been reported yet, we catch the first motion
|
||||||
|
// reported and store the current location
|
||||||
|
if(!gMotionReported) {
|
||||||
|
gMotionReported = true;
|
||||||
|
gOldMouseX = x;
|
||||||
|
gOldMouseY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dx, dy;
|
||||||
|
|
||||||
|
dx = x - gOldMouseX;
|
||||||
|
dy = y - gOldMouseY;
|
||||||
|
|
||||||
|
gOldMouseX = x;
|
||||||
|
gOldMouseY = y;
|
||||||
|
|
||||||
|
if(gButtonPressed == 1) {
|
||||||
|
// mouse does nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scroll(GLFWwindow *window, double dx, double dy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWwindow* window;
|
||||||
|
|
||||||
|
void interface_start()
|
||||||
|
{
|
||||||
|
glfwSetErrorCallback(error_callback);
|
||||||
|
|
||||||
|
if(!glfwInit())
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||||
|
window = glfwCreateWindow(gWindowWidth = 280 * 4, gWindowHeight = 192 * 4, "Apple //e", NULL, NULL);
|
||||||
|
if (!window) {
|
||||||
|
glfwTerminate();
|
||||||
|
fprintf(stdout, "Couldn't open main window\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
initialize_gl();
|
||||||
|
|
||||||
|
glfwSetKeyCallback(window, key);
|
||||||
|
glfwSetMouseButtonCallback(window, button);
|
||||||
|
glfwSetCursorPosCallback(window, motion);
|
||||||
|
glfwSetScrollCallback(window, scroll);
|
||||||
|
glfwSetFramebufferSizeCallback(window, resize);
|
||||||
|
glfwSetWindowRefreshCallback(window, redraw);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void interface_iterate()
|
||||||
|
{
|
||||||
|
if(glfwWindowShouldClose(window)) {
|
||||||
|
// set to quit
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw(window);
|
||||||
|
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void interface_shutdown()
|
||||||
|
{
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
struct event {
|
||||||
|
enum EventType {NONE, KEYDOWN, KEYUP, RESET, REBOOT} 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;
|
||||||
|
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();
|
Loading…
Reference in New Issue