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 \ RUN \
apt-get update && \ apt-get update && \
apt-get upgrade -y && \ 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/libGLESv2.so.2 /usr/lib/libGLESv2.so
RUN ln -s /usr/lib/arm-linux-gnueabihf/libEGL.so.1 /usr/lib/libEGL.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 { post {
success { 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 Comment=Fun with Blocks
Icon=/usr/share/pixmaps/minecraft-pi.png Icon=/usr/share/pixmaps/minecraft-pi.png
StartupNotify=false StartupNotify=false
StartupWMClass=minecraft-pi StartupWMClass=Minecraft - Pi edition
Exec=/usr/bin/minecraft-pi Exec=/usr/bin/minecraft-pi
Terminal=false Terminal=false
Type=Application Type=Application

View File

@ -14,8 +14,10 @@ target_link_libraries(core dl)
add_library(extra SHARED src/extra.c src/extra.cpp) add_library(extra SHARED src/extra.c src/extra.cpp)
target_link_libraries(extra core dl) target_link_libraries(extra core dl)
find_package(glfw3 3.3 REQUIRED)
add_library(compat SHARED src/compat.c) 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 # Force GLESv1 Link
target_link_options(compat PRIVATE "-Wl,--no-as-needed") target_link_options(compat PRIVATE "-Wl,--no-as-needed")

View File

@ -5,6 +5,13 @@
#include <FreeImage.h> #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.h>
#include <SDL/SDL_syswm.h> #include <SDL/SDL_syswm.h>
#include <EGL/egl.h> #include <EGL/egl.h>
@ -15,15 +22,11 @@
#include "extra.h" #include "extra.h"
static GLFWwindow *glfw_window;
static Display *x11_display; static Display *x11_display;
static EGLDisplay egl_display;
static Window x11_window; static Window x11_window;
static Window x11_root_window; static Window x11_root_window;
static EGLConfig egl_config;
static int window_loaded = 0; 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)) { HOOK(eglGetDisplay, EGLDisplay, (__attribute__((unused)) NativeDisplayType native_display)) {
// Handled In ensure_x11_window() // Handled In ensure_x11_window()
@ -31,20 +34,12 @@ HOOK(eglGetDisplay, EGLDisplay, (__attribute__((unused)) NativeDisplayType nativ
} }
// Get Reference To X Window // Get Reference To X Window
static void ensure_x11_window() { static void store_x11_window() {
if (!window_loaded) { x11_display = glfwGetX11Display();
SDL_SysWMinfo info; x11_window = glfwGetX11Window(glfw_window);
SDL_VERSION(&info.version); x11_root_window = RootWindow(x11_display, DefaultScreen(x11_display));
SDL_GetWMInfo(&info);
x11_display = info.info.x11.display; window_loaded = 1;
x11_window = info.info.x11.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 // Handled In SDL_WM_SetCaption
@ -98,112 +93,188 @@ HOOK(SDL_SetVideoMode, SDL_Surface *, (__attribute__((unused)) int width, __attr
return (SDL_Surface *) 1; return (SDL_Surface *) 1;
} }
// EGL Config // Handle GLFW Error
EGLint const set_attrib_list[] = { static void glfw_error(__attribute__((unused)) int error, const char *description) {
EGL_RED_SIZE, 8, fprintf(stderr, "GLFW Error: %s\n", description);
EGL_GREEN_SIZE, 8, exit(1);
EGL_BLUE_SIZE, 8, }
EGL_DEPTH_SIZE, 16,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
#define WINDOW_VIDEO_FLAGS SDL_RESIZABLE // Convert GLFW Key To SDL Key
#define FULLSCREEN_VIDEO_FLAGS SDL_FULLSCREEN 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 // Pass Text To Minecraft
HOOK(SDL_WM_SetCaption, void, (const char *title, const char *icon)) { static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) {
// Enable Unicode key_press((char) codepoint);
SDL_EnableUNICODE(SDL_ENABLE); }
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); FreeImage_Initialise(0);
ensure_SDL_SetVideoMode(); glfwSetErrorCallback(glfw_error);
sdl_surface = (*real_SDL_SetVideoMode)(848, 480, BPP, WINDOW_VIDEO_FLAGS);
ensure_SDL_WM_SetCaption(); if (!glfwInit()) {
(*real_SDL_WM_SetCaption)(title, icon); 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(); glfw_window = glfwCreateWindow(840, 480, title, NULL, NULL);
(*real_eglInitialize)(egl_display, NULL, NULL); if (!glfw_window) {
fprintf(stderr, "Unable To Create GLFW Window\n");
exit(1);
}
EGLint number_of_config; glfwSetKeyCallback(glfw_window, glfw_key);
ensure_eglChooseConfig(); glfwSetCharCallback(glfw_window, glfw_char);
(*real_eglChooseConfig)(egl_display, set_attrib_list, &egl_config, 1, &number_of_config); glfwSetCursorPosCallback(glfw_window, glfw_motion);
glfwSetMouseButtonCallback(glfw_window, glfw_click);
ensure_eglBindAPI(); store_x11_window();
(*real_eglBindAPI)(EGL_OPENGL_ES_API);
ensure_eglCreateContext(); glfwMakeContextCurrent(glfw_window);
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);
} }
HOOK(eglSwapBuffers, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface)) { HOOK(eglSwapBuffers, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface)) {
ensure_eglSwapBuffers(); glfwSwapBuffers(glfw_window);
EGLBoolean ret = (*real_eglSwapBuffers)(egl_display, egl_surface);
return ret; return EGL_TRUE;
}
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();
} }
static int is_fullscreen = 0; static int is_fullscreen = 0;
static int old_width = 0; static int old_width = -1;
static int old_height = 0; static int old_height = -1;
static void push_resize_event(int width, int height) { static int old_x = -1;
SDL_ResizeEvent resize; static int old_y = -1;
resize.type = SDL_VIDEORESIZE;
resize.w = width;
resize.h = height;
SDL_Event event;
event.type = SDL_VIDEORESIZE;
event.resize = resize;
SDL_PushEvent(&event);
}
// Toggle Fullscreen
static void toggle_fullscreen() { static void toggle_fullscreen() {
if (is_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_width = -1;
old_height = 0; old_height = -1;
old_x = -1;
old_y = -1;
} else { } else {
old_width = sdl_surface->w; glfwGetWindowSize(glfw_window, &old_width, &old_height);
old_height = sdl_surface->h; glfwGetWindowPos(glfw_window, &old_x, &old_y);
Screen *screen = DefaultScreenOfDisplay(x11_display); 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; 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) // 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 #define TIME_SIZE 20
// Take Screenshot
static void screenshot() { static void screenshot() {
time_t rawtime; time_t rawtime;
struct tm *timeinfo; struct tm *timeinfo;
@ -231,11 +303,15 @@ static void screenshot() {
num++; num++;
} }
int line_size = sdl_surface->w * 3; int width;
int size = sdl_surface->h * line_size; int height;
glfwGetWindowSize(glfw_window, &width, &height);
int line_size = width * 3;
int size = height * line_size;
unsigned char pixels[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 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
// Swap Red And Blue // Swap Red And Blue
@ -248,7 +324,7 @@ static void screenshot() {
} }
#endif #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)) { if (!FreeImage_Save(FIF_PNG, image, file, 0)) {
fprintf(stderr, "Screenshot Failed: %s\n", file); fprintf(stderr, "Screenshot Failed: %s\n", file);
} else { } else {
@ -260,27 +336,34 @@ static void screenshot() {
free(screenshots); free(screenshots);
} }
// Intercept SDL Events
HOOK(SDL_PollEvent, int, (SDL_Event *event)) { 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 // Poll Events
ensure_SDL_PollEvent(); ensure_SDL_PollEvent();
int ret = (*real_SDL_PollEvent)(event); int ret = (*real_SDL_PollEvent)(event);
// Resize EGL // Handle Events
if (event != NULL && ret == 1) { if (ret == 1 && event != NULL) {
int handled = 0; int handled = 0;
if (event->type == SDL_VIDEORESIZE) { if (event->type == SDL_KEYDOWN) {
resize(event->resize.w, event->resize.h, is_fullscreen);
handled = 1;
} else if (event->type == SDL_KEYDOWN) {
if (event->key.keysym.sym == SDLK_F11) { if (event->key.keysym.sym == SDLK_F11) {
toggle_fullscreen(); toggle_fullscreen();
handled = 1; handled = 1;
} else if (event->key.keysym.sym == SDLK_F2) { } else if (event->key.keysym.sym == SDLK_F2) {
screenshot(); screenshot();
handled = 1; handled = 1;
} else {
key_press((char) event->key.keysym.unicode);
} }
} }
@ -298,12 +381,32 @@ HOOK(SDL_Quit, void, ()) {
ensure_SDL_Quit(); ensure_SDL_Quit();
(*real_SDL_Quit)(); (*real_SDL_Quit)();
ensure_eglDestroyContext(); glfwDestroyWindow(glfw_window);
(*real_eglDestroyContext)(egl_display, egl_context); glfwTerminate();
ensure_eglDestroySurface(); }
(*real_eglDestroySurface)(egl_display, egl_surface);
ensure_eglTerminate(); // Fix SDL Cursor Visibility/Grabbing
(*real_eglTerminate)(egl_display); 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)) { 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)) {