Rudimentary GL window with keyboard support

This commit is contained in:
Brad Grantham 2016-11-16 16:16:10 -08:00
parent f747675e22
commit 17c38de074
5 changed files with 361 additions and 3 deletions

View File

@ -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
apple2e: $(OBJECTS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(INCFLAGS)
clean:
rm $(OBJECTS)

View File

@ -8,8 +8,10 @@
#include <iostream>
#include <deque>
#include <map>
#include <thread>
#include <signal.h>
#include "fake6502.h"
const int rom_image_size = 0x3000;
@ -19,6 +21,7 @@ using namespace std;
#include "emulator.h"
#include "keyboard.h"
#include "dis6502.h"
#include "interface.h"
const unsigned int DEBUG_ERROR = 0x01;
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;
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)
{
char *progname = argv[0];
@ -1579,6 +1695,8 @@ int main(int argc, char **argv)
if(use_fake6502)
reset6502();
interface_start();
while(1) {
if(!debugging) {
poll_keyboard();
@ -1586,6 +1704,8 @@ int main(int argc, char **argv)
char key;
bool have_key = peek_key(&key);
keyboard_to_mainboard(mainboard);
if(have_key) {
if(key == '') {
debugging = true;
@ -1613,6 +1733,7 @@ int main(int argc, char **argv)
textport_display();
textport_changed = false;
}
interface_iterate();
chrono::time_point<chrono::system_clock> now;
auto elapsed_millis = chrono::duration_cast<chrono::milliseconds>(now - then);
@ -1662,6 +1783,9 @@ int main(int argc, char **argv)
textport_display();
textport_changed = false;
}
interface_iterate();
}
}
interface_shutdown();
}

9
genkeys.py Normal file
View File

@ -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', '', ''}}

183
interface.cpp Normal file
View File

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

39
interface.h Normal file
View File

@ -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();