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