minecraft-pi-reborn/mods/src/compat.c

270 lines
8.2 KiB
C

#define _GNU_SOURCE
#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <X11/Xlib.h>
#include <libcore/libcore.h>
#include "extra.h"
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()
return 0;
}
// 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;
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
HOOK(eglInitialize, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLint *major, __attribute__((unused)) EGLint *minor)) {
return EGL_TRUE;
}
// Handled In SDL_WM_SetCaption
HOOK(eglChooseConfig, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLint const *attrib_list, __attribute__((unused)) EGLConfig *configs, __attribute__((unused)) EGLint config_size, __attribute__((unused)) EGLint *num_config)) {
return EGL_TRUE;
}
// Handled In SDL_WM_SetCaption
HOOK(eglBindAPI, EGLBoolean, (__attribute__((unused)) EGLenum api)) {
return EGL_TRUE;
}
// Handled In SDL_WM_SetCaption
HOOK(eglCreateContext, EGLContext, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) EGLContext share_context, __attribute__((unused)) EGLint const *attrib_list)) {
return 0;
}
// Handled In SDL_WM_SetCaption
HOOK(eglCreateWindowSurface, EGLSurface, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list)) {
return 0;
}
// Handled In SDL_WM_SetCaption
HOOK(eglMakeCurrent, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface draw, __attribute__((unused)) EGLSurface read, __attribute__((unused)) EGLContext context)) {
return EGL_TRUE;
}
// Handled In SDL_Quit
HOOK(eglDestroySurface, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface)) {
return EGL_TRUE;
}
// Handled In SDL_Quit
HOOK(eglDestroyContext, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLContext context)) {
return EGL_TRUE;
}
// Handled In SDL_Quit
HOOK(eglTerminate, EGLBoolean, (__attribute__((unused)) EGLDisplay display)) {
return EGL_TRUE;
}
// Handled In SDL_WM_SetCaption
HOOK(SDL_SetVideoMode, SDL_Surface *, (__attribute__((unused)) int width, __attribute__((unused)) int height, __attribute__((unused)) int bpp, __attribute__((unused)) Uint32 flags)) {
// Return Value Is Only Used For A NULL-Check
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
};
#define WINDOW_VIDEO_FLAGS SDL_RESIZABLE
#define FULLSCREEN_VIDEO_FLAGS SDL_FULLSCREEN
// Init EGL
HOOK(SDL_WM_SetCaption, void, (const char *title, const char *icon)) {
// Enable Unicode
SDL_EnableUNICODE(SDL_ENABLE);
ensure_SDL_SetVideoMode();
sdl_surface = (*real_SDL_SetVideoMode)(848, 480, 32, WINDOW_VIDEO_FLAGS);
ensure_SDL_WM_SetCaption();
(*real_SDL_WM_SetCaption)(title, icon);
ensure_x11_window();
ensure_eglInitialize();
(*real_eglInitialize)(egl_display, NULL, NULL);
EGLint number_of_config;
ensure_eglChooseConfig();
(*real_eglChooseConfig)(egl_display, set_attrib_list, &egl_config, 1, &number_of_config);
ensure_eglBindAPI();
(*real_eglBindAPI)(EGL_OPENGL_ES_API);
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);
}
HOOK(eglSwapBuffers, EGLBoolean, (__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface)) {
ensure_eglSwapBuffers();
EGLBoolean ret = (*real_eglSwapBuffers)(egl_display, egl_surface);
return ret;
}
static void resize(int width, int height, int fullscreen) {
Uint32 flags = fullscreen ? FULLSCREEN_VIDEO_FLAGS : WINDOW_VIDEO_FLAGS;
ensure_SDL_SetVideoMode();
sdl_surface = (*real_SDL_SetVideoMode)(width, height, 32, 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 old_width = 0;
static int old_height = 0;
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 void toggle_fullscreen() {
if (is_fullscreen) {
push_resize_event(old_width, old_height);
old_width = 0;
old_height = 0;
} else {
old_width = sdl_surface->w;
old_height = sdl_surface->h;
Screen *screen = DefaultScreenOfDisplay(x11_display);
push_resize_event(WidthOfScreen(screen), HeightOfScreen(screen));
}
is_fullscreen = !is_fullscreen;
}
HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
// Poll Events
ensure_SDL_PollEvent();
int ret = (*real_SDL_PollEvent)(event);
// Resize EGL
if (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->key.keysym.sym == SDLK_F11) {
toggle_fullscreen();
handled = 1;
} else {
key_press((char) event->key.keysym.unicode);
}
}
if (handled) {
// Event Was Handled
return SDL_PollEvent(event);
}
}
return ret;
}
// Terminate EGL
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);
}
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)) {
ensure_XTranslateCoordinates();
if (window_loaded) {
return (*real_XTranslateCoordinates)(x11_display, x11_window, x11_root_window, src_x, src_y, dest_x_return, dest_y_return, child_return);
} else {
return (*real_XTranslateCoordinates)(display, src_w, dest_w, src_x, src_y, dest_x_return, dest_y_return, child_return);
}
}
HOOK(XGetWindowAttributes, int, (Display *display, Window w, XWindowAttributes *window_attributes_return)) {
ensure_XGetWindowAttributes();
if (window_loaded) {
return (*real_XGetWindowAttributes)(x11_display, x11_window, window_attributes_return);
} else {
return (*real_XGetWindowAttributes)(display, w, window_attributes_return);
}
}
#include <stdlib.h>
// Use VirGL
__attribute__((constructor)) static void init() {
setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
setenv("GALLIUM_DRIVER", "virpipe", 1);
}