Port From SDL 1.2 To GLFW

This commit is contained in:
TheBrokenRail 2020-10-05 18:17:55 -04:00
parent 34eb1cb3c2
commit eddfcea819
5 changed files with 224 additions and 119 deletions

View File

@ -5,7 +5,7 @@ RUN dpkg --add-architecture armhf
RUN \
apt-get update && \
apt-get upgrade -y && \
apt-get install -y libglvnd-dev:armhf libsdl1.2-dev:armhf libx11-dev:armhf build-essential zlib1g-dev:armhf git cmake curl gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libfreeimage-dev:armhf
apt-get install -y libglvnd-dev:armhf libsdl1.2-dev:armhf libx11-dev:armhf build-essential zlib1g-dev:armhf git cmake curl gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libfreeimage-dev:armhf libglfw3-dev:armhf xinput:armhf libxfixes-dev:armhf
RUN ln -s /usr/lib/arm-linux-gnueabihf/libGLESv2.so.2 /usr/lib/libGLESv2.so
RUN ln -s /usr/lib/arm-linux-gnueabihf/libEGL.so.1 /usr/lib/libEGL.so

2
Jenkinsfile vendored
View File

@ -30,7 +30,7 @@ pipeline {
}
post {
success {
archiveArtifacts artifacts: 'out/*', fingerprint: true
archiveArtifacts artifacts: 'out/**', fingerprint: true
}
}
}

View File

@ -3,7 +3,7 @@ Name=Minecraft: Pi Edition
Comment=Fun with Blocks
Icon=/usr/share/pixmaps/minecraft-pi.png
StartupNotify=false
StartupWMClass=minecraft-pi
StartupWMClass=Minecraft - Pi edition
Exec=/usr/bin/minecraft-pi
Terminal=false
Type=Application

View File

@ -14,8 +14,10 @@ target_link_libraries(core dl)
add_library(extra SHARED src/extra.c src/extra.cpp)
target_link_libraries(extra core dl)
find_package(glfw3 3.3 REQUIRED)
add_library(compat SHARED src/compat.c)
target_link_libraries(compat core extra SDL EGL GLESv1_CM GLESv2 X11 dl freeimage)
target_link_libraries(compat core extra SDL EGL GLESv1_CM GLESv2 X11 dl freeimage glfw Xfixes)
# Force GLESv1 Link
target_link_options(compat PRIVATE "-Wl,--no-as-needed")

View File

@ -5,6 +5,13 @@
#include <FreeImage.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_INCLUDE_ES1
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <X11/extensions/Xfixes.h>
#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>
#include <EGL/egl.h>
@ -15,15 +22,11 @@
#include "extra.h"
static GLFWwindow *glfw_window;
static Display *x11_display;
static EGLDisplay egl_display;
static Window x11_window;
static Window x11_root_window;
static EGLConfig egl_config;
static int window_loaded = 0;
static EGLContext egl_context;
static EGLSurface egl_surface;
static SDL_Surface *sdl_surface;
HOOK(eglGetDisplay, EGLDisplay, (__attribute__((unused)) NativeDisplayType native_display)) {
// Handled In ensure_x11_window()
@ -31,20 +34,12 @@ HOOK(eglGetDisplay, EGLDisplay, (__attribute__((unused)) NativeDisplayType nativ
}
// Get Reference To X Window
static void ensure_x11_window() {
if (!window_loaded) {
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWMInfo(&info);
x11_display = info.info.x11.display;
x11_window = info.info.x11.window;
static void store_x11_window() {
x11_display = glfwGetX11Display();
x11_window = glfwGetX11Window(glfw_window);
x11_root_window = RootWindow(x11_display, DefaultScreen(x11_display));
ensure_eglGetDisplay();
egl_display = (*real_eglGetDisplay)(x11_display);
window_loaded = 1;
}
}
// Handled In SDL_WM_SetCaption
@ -98,112 +93,188 @@ HOOK(SDL_SetVideoMode, SDL_Surface *, (__attribute__((unused)) int width, __attr
return (SDL_Surface *) 1;
}
// EGL Config
EGLint const set_attrib_list[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 16,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
// Handle GLFW Error
static void glfw_error(__attribute__((unused)) int error, const char *description) {
fprintf(stderr, "GLFW Error: %s\n", description);
exit(1);
}
#define WINDOW_VIDEO_FLAGS SDL_RESIZABLE
#define FULLSCREEN_VIDEO_FLAGS SDL_FULLSCREEN
// Convert GLFW Key To SDL Key
static SDLKey glfw_key_to_sdl_key(int key) {
switch (key) {
// Movement
case GLFW_KEY_W:
return SDLK_w;
case GLFW_KEY_A:
return SDLK_a;
case GLFW_KEY_S:
return SDLK_s;
case GLFW_KEY_D:
return SDLK_d;
case GLFW_KEY_SPACE:
return SDLK_SPACE;
case GLFW_KEY_LEFT_SHIFT:
return SDLK_LSHIFT;
case GLFW_KEY_RIGHT_SHIFT:
return SDLK_RSHIFT;
// Inventory
case GLFW_KEY_E:
return SDLK_e;
// Hotbar
case GLFW_KEY_1:
return SDLK_1;
case GLFW_KEY_2:
return SDLK_2;
case GLFW_KEY_3:
return SDLK_3;
case GLFW_KEY_4:
return SDLK_4;
case GLFW_KEY_5:
return SDLK_5;
case GLFW_KEY_6:
return SDLK_6;
case GLFW_KEY_7:
return SDLK_7;
case GLFW_KEY_8:
return SDLK_8;
// UI Control
case GLFW_KEY_ESCAPE:
return SDLK_ESCAPE;
case GLFW_KEY_UP:
return SDLK_UP;
case GLFW_KEY_DOWN:
return SDLK_DOWN;
case GLFW_KEY_LEFT:
return SDLK_LEFT;
case GLFW_KEY_RIGHT:
return SDLK_RIGHT;
case GLFW_KEY_TAB:
return SDLK_TAB;
case GLFW_KEY_ENTER:
return SDLK_RETURN;
case GLFW_KEY_BACKSPACE:
return SDLK_BACKSPACE;
// Fullscreen
case GLFW_KEY_F11:
return SDLK_F11;
// Screenshot
case GLFW_KEY_F2:
return SDLK_F2;
// Unknown
default:
return SDLK_UNKNOWN;
}
}
#define BPP 32
// Pass Key Presses To SDL
static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int scancode, int action, __attribute__((unused)) int mods) {
SDL_Event event;
int up = action == GLFW_RELEASE;
event.type = up ? SDL_KEYUP : SDL_KEYDOWN;
event.key.state = up ? SDL_RELEASED : SDL_PRESSED;
event.key.keysym.scancode = scancode;
event.key.keysym.mod = KMOD_NONE;
event.key.keysym.sym = glfw_key_to_sdl_key(key);
SDL_PushEvent(&event);
if (key == GLFW_KEY_BACKSPACE && !up) {
key_press((char) '\b');
}
}
// Init EGL
HOOK(SDL_WM_SetCaption, void, (const char *title, const char *icon)) {
// Enable Unicode
SDL_EnableUNICODE(SDL_ENABLE);
// Pass Text To Minecraft
static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) {
key_press((char) codepoint);
}
static double last_mouse_x = 0;
static double last_mouse_y = 0;
// Pass Mouse Movement To SDL
static void glfw_motion(__attribute__((unused)) GLFWwindow *window, double xpos, double ypos) {
SDL_Event event;
event.type = SDL_MOUSEMOTION;
event.motion.x = xpos;
event.motion.y = ypos;
event.motion.xrel = (xpos - last_mouse_x);
event.motion.yrel = (ypos - last_mouse_y);
last_mouse_x = xpos;
last_mouse_y = ypos;
SDL_PushEvent(&event);
}
// Pass Mouse Click To SDL
static void glfw_click(__attribute__((unused)) GLFWwindow *window, int button, int action, __attribute__((unused)) int mods) {
int up = action == GLFW_RELEASE;
SDL_Event event;
event.type = up ? SDL_MOUSEBUTTONUP : SDL_MOUSEBUTTONDOWN;
event.button.x = last_mouse_x;
event.button.y = last_mouse_y;
event.button.state = up ? SDL_RELEASED : SDL_PRESSED;
event.button.button = button == GLFW_MOUSE_BUTTON_RIGHT ? SDL_BUTTON_RIGHT : (button == GLFW_MOUSE_BUTTON_LEFT ? SDL_BUTTON_LEFT : SDL_BUTTON_MIDDLE);
SDL_PushEvent(&event);
}
// Init GLFW
HOOK(SDL_WM_SetCaption, void, (const char *title, __attribute__((unused)) const char *icon)) {
FreeImage_Initialise(0);
ensure_SDL_SetVideoMode();
sdl_surface = (*real_SDL_SetVideoMode)(848, 480, BPP, WINDOW_VIDEO_FLAGS);
glfwSetErrorCallback(glfw_error);
ensure_SDL_WM_SetCaption();
(*real_SDL_WM_SetCaption)(title, icon);
if (!glfwInit()) {
fprintf(stderr, "Unable To Initialize GLFW\n");
exit(1);
}
ensure_x11_window();
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
ensure_eglInitialize();
(*real_eglInitialize)(egl_display, NULL, NULL);
glfw_window = glfwCreateWindow(840, 480, title, NULL, NULL);
if (!glfw_window) {
fprintf(stderr, "Unable To Create GLFW Window\n");
exit(1);
}
EGLint number_of_config;
ensure_eglChooseConfig();
(*real_eglChooseConfig)(egl_display, set_attrib_list, &egl_config, 1, &number_of_config);
glfwSetKeyCallback(glfw_window, glfw_key);
glfwSetCharCallback(glfw_window, glfw_char);
glfwSetCursorPosCallback(glfw_window, glfw_motion);
glfwSetMouseButtonCallback(glfw_window, glfw_click);
ensure_eglBindAPI();
(*real_eglBindAPI)(EGL_OPENGL_ES_API);
store_x11_window();
ensure_eglCreateContext();
egl_context = (*real_eglCreateContext)(egl_display, egl_config, EGL_NO_CONTEXT, NULL);
ensure_eglCreateWindowSurface();
egl_surface = (*real_eglCreateWindowSurface)(egl_display, egl_config, x11_window, NULL);
ensure_eglMakeCurrent();
(*real_eglMakeCurrent)(egl_display, egl_surface, egl_surface, egl_context);
eglSwapInterval(egl_display, 1);
glfwMakeContextCurrent(glfw_window);
}
HOOK(eglSwapBuffers, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface)) {
ensure_eglSwapBuffers();
EGLBoolean ret = (*real_eglSwapBuffers)(egl_display, egl_surface);
glfwSwapBuffers(glfw_window);
return ret;
}
static void resize(int width, int height, int fullscreen) {
uint32_t flags = fullscreen ? FULLSCREEN_VIDEO_FLAGS : WINDOW_VIDEO_FLAGS;
ensure_SDL_SetVideoMode();
sdl_surface = (*real_SDL_SetVideoMode)(width, height, BPP, flags);
// OpenGL state modification for resizing
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glOrthox(0, width, 0, height, -1, 1);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
return EGL_TRUE;
}
static int is_fullscreen = 0;
static int old_width = 0;
static int old_height = 0;
static int old_width = -1;
static int old_height = -1;
static void push_resize_event(int width, int height) {
SDL_ResizeEvent resize;
resize.type = SDL_VIDEORESIZE;
resize.w = width;
resize.h = height;
SDL_Event event;
event.type = SDL_VIDEORESIZE;
event.resize = resize;
SDL_PushEvent(&event);
}
static int old_x = -1;
static int old_y = -1;
// Toggle Fullscreen
static void toggle_fullscreen() {
if (is_fullscreen) {
push_resize_event(old_width, old_height);
glfwSetWindowMonitor(glfw_window, NULL, old_x, old_y, old_width, old_height, GLFW_DONT_CARE);
old_width = 0;
old_height = 0;
old_width = -1;
old_height = -1;
old_x = -1;
old_y = -1;
} else {
old_width = sdl_surface->w;
old_height = sdl_surface->h;
glfwGetWindowSize(glfw_window, &old_width, &old_height);
glfwGetWindowPos(glfw_window, &old_x, &old_y);
Screen *screen = DefaultScreenOfDisplay(x11_display);
push_resize_event(WidthOfScreen(screen), HeightOfScreen(screen));
glfwSetWindowMonitor(glfw_window, glfwGetPrimaryMonitor(), 0, 0, WidthOfScreen(screen), HeightOfScreen(screen), GLFW_DONT_CARE);
}
is_fullscreen = !is_fullscreen;
}
@ -211,6 +282,7 @@ static void toggle_fullscreen() {
// 4 (Year + 1 (Hyphen) + 2 (Month) + 1 (Hyphen) + 2 (Day) + 1 (Underscore) + 2 (Hour) + 1 (Period) + 2 (Minute) + 1 (Period) + 2 (Second) + 1 (Terminator)
#define TIME_SIZE 20
// Take Screenshot
static void screenshot() {
time_t rawtime;
struct tm *timeinfo;
@ -231,11 +303,15 @@ static void screenshot() {
num++;
}
int line_size = sdl_surface->w * 3;
int size = sdl_surface->h * line_size;
int width;
int height;
glfwGetWindowSize(glfw_window, &width, &height);
int line_size = width * 3;
int size = height * line_size;
unsigned char pixels[size];
glReadPixels(0, 0, sdl_surface->w, sdl_surface->h, GL_RGB, GL_UNSIGNED_BYTE, pixels);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
// Swap Red And Blue
@ -248,7 +324,7 @@ static void screenshot() {
}
#endif
FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, sdl_surface->w, sdl_surface->h, line_size, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0);
FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, line_size, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0);
if (!FreeImage_Save(FIF_PNG, image, file, 0)) {
fprintf(stderr, "Screenshot Failed: %s\n", file);
} else {
@ -260,27 +336,34 @@ static void screenshot() {
free(screenshots);
}
// Intercept SDL Events
HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
// Process GLFW Events
glfwPollEvents();
// Close Window
if (glfwWindowShouldClose(glfw_window)) {
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
glfwSetWindowShouldClose(glfw_window, 0);
}
// Poll Events
ensure_SDL_PollEvent();
int ret = (*real_SDL_PollEvent)(event);
// Resize EGL
if (event != NULL && ret == 1) {
// Handle Events
if (ret == 1 && event != NULL) {
int handled = 0;
if (event->type == SDL_VIDEORESIZE) {
resize(event->resize.w, event->resize.h, is_fullscreen);
handled = 1;
} else if (event->type == SDL_KEYDOWN) {
if (event->type == SDL_KEYDOWN) {
if (event->key.keysym.sym == SDLK_F11) {
toggle_fullscreen();
handled = 1;
} else if (event->key.keysym.sym == SDLK_F2) {
screenshot();
handled = 1;
} else {
key_press((char) event->key.keysym.unicode);
}
}
@ -298,12 +381,32 @@ HOOK(SDL_Quit, void, ()) {
ensure_SDL_Quit();
(*real_SDL_Quit)();
ensure_eglDestroyContext();
(*real_eglDestroyContext)(egl_display, egl_context);
ensure_eglDestroySurface();
(*real_eglDestroySurface)(egl_display, egl_surface);
ensure_eglTerminate();
(*real_eglTerminate)(egl_display);
glfwDestroyWindow(glfw_window);
glfwTerminate();
}
// Fix SDL Cursor Visibility/Grabbing
HOOK(SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode)) {
if (mode != SDL_GRAB_QUERY && mode != SDL_WM_GrabInput(SDL_GRAB_QUERY)) {
glfwSetInputMode(glfw_window, GLFW_CURSOR, mode == SDL_GRAB_OFF ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED);
glfwSetInputMode(glfw_window, GLFW_RAW_MOUSE_MOTION, mode == SDL_GRAB_OFF ? GLFW_FALSE : GLFW_TRUE);
// GLFW Cursor Hiding is Broken
if (window_loaded) {
if (mode == SDL_GRAB_OFF) {
XFixesShowCursor(x11_display, x11_window);
} else {
XFixesHideCursor(x11_display, x11_window);
}
XFlush(x11_display);
}
}
return mode == SDL_GRAB_QUERY ? (glfwGetInputMode(glfw_window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL ? SDL_GRAB_OFF : SDL_GRAB_ON) : mode;
}
// Stub SDL Cursor Visibility
HOOK(SDL_ShowCursor, int, (int toggle)) {
return toggle == SDL_QUERY ? (glfwGetInputMode(glfw_window, GLFW_CURSOR) == GLFW_CURSOR_NORMAL ? SDL_ENABLE : SDL_DISABLE) : toggle;
}
HOOK(XTranslateCoordinates, int, (Display *display, Window src_w, Window dest_w, int src_x, int src_y, int *dest_x_return, int *dest_y_return, Window *child_return)) {