diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d075d49..98c27ba6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,6 +432,11 @@ elseif(BACKEND_PLATFORM MATCHES "Null") "src/Backends/Controller/Null.cpp" "src/Backends/Platform/Null.cpp" ) +elseif(BACKEND_PLATFORM MATCHES "X11") + target_sources(CSE2 PRIVATE + "src/Backends/Controller/Null.cpp" + "src/Backends/Platform/X11.cpp" + ) endif() if(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "OpenGL3") @@ -458,6 +463,8 @@ elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "Software") elseif(BACKEND_PLATFORM MATCHES "3DS" AND BACKEND_RENDERER MATCHES "3DS") elseif(BACKEND_PLATFORM MATCHES "3DS" AND BACKEND_RENDERER MATCHES "Software") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/3DS.cpp") +elseif(BACKEND_PLATFORM MATCHES "X11" AND BACKEND_RENDERER MATCHES "Software") + target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/X11.cpp") elseif(BACKEND_PLATFORM MATCHES "Null" AND BACKEND_RENDERER MATCHES "Software") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/Null.cpp") else() @@ -564,6 +571,10 @@ if(BACKEND_PLATFORM MATCHES "GLFW3") endif() endif() +if(BACKEND_PLATFORM MATCHES "X11") + target_link_libraries(CSE2 PRIVATE "-lX11") +endif() + if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2") if(NOT FORCE_LOCAL_LIBS) find_package(SDL2) diff --git a/src/Backends/Platform/X11.cpp b/src/Backends/Platform/X11.cpp new file mode 100644 index 00000000..8d7ed2b4 --- /dev/null +++ b/src/Backends/Platform/X11.cpp @@ -0,0 +1,147 @@ +// Released under the MIT license. X11 backend by Duuqnd. +// See LICENSE.txt for details. + +#include "../Misc.h" + +#include "../Rendering.h" +#include "../../Attributes.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static bool keyboardState[BACKEND_KEYBOARD_TOTAL]; +Display* xDisplay; +Visual* xVisual; +static XVisualInfo xvisinfo; +static unsigned long startTime; + +bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*window_focus_callback)(bool focus)) { + // we're ignoring the hell out of focus and drag & drop + xDisplay = XOpenDisplay(NULL); + //XMatchVisualInfo(xDisplay, DefaultScreen(xDisplay), 24, DirectColor, &xvisinfo); + //xVisual = xvisinfo.visual; + + struct timeval time; // time.tv_usec is microseconds + gettimeofday(&time, NULL); + startTime = (time.tv_sec * 1000) + (time.tv_usec / 1000); + + return true; +} + +void Backend_Deinit(void) { + XCloseDisplay(xDisplay); +} + +void Backend_PostWindowCreation(void) {} + +bool Backend_GetPaths(std::string *module_path, std::string *data_path) { + return false; // I assume this means "do it yourself, lazy" +} + +void Backend_HideMouse(void) {} + +void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height) { + // Oh we'll want this for sure! +} + +void Backend_SetCursor(const unsigned char *rgb_pixels, size_t width, size_t height) {} + +void Backend_EnableDragAndDrop(void) {} + +#define DOKEY(keych, keymac) { if(keysym == keych) keyboardState[keymac] = press; } + +static void DoKeys(KeySym keysym, bool press) { + // X keysyms are case sensitive. Isn't it great?! + DOKEY(XK_z, BACKEND_KEYBOARD_Z); + DOKEY(XK_x, BACKEND_KEYBOARD_X); + DOKEY(XK_Z, BACKEND_KEYBOARD_Z); + DOKEY(XK_X, BACKEND_KEYBOARD_X); + DOKEY(XK_a, BACKEND_KEYBOARD_A); + DOKEY(XK_s, BACKEND_KEYBOARD_S); + DOKEY(XK_A, BACKEND_KEYBOARD_A); + DOKEY(XK_S, BACKEND_KEYBOARD_S); + + DOKEY(XK_q, BACKEND_KEYBOARD_Q); + DOKEY(XK_w, BACKEND_KEYBOARD_W); + DOKEY(XK_Q, BACKEND_KEYBOARD_Q); + DOKEY(XK_W, BACKEND_KEYBOARD_W); + + DOKEY(XK_Escape, BACKEND_KEYBOARD_ESCAPE); + DOKEY(XK_F1, BACKEND_KEYBOARD_F1); + DOKEY(XK_F2, BACKEND_KEYBOARD_F2); + + DOKEY(XK_Left, BACKEND_KEYBOARD_LEFT); + DOKEY(XK_Right, BACKEND_KEYBOARD_RIGHT); + DOKEY(XK_Up, BACKEND_KEYBOARD_UP); + DOKEY(XK_Down, BACKEND_KEYBOARD_DOWN); +} + +bool Backend_SystemTask(bool active) { + if(!active) { + return false; + } + + XEvent e; + while(XPending(xDisplay) > 0) { + XNextEvent(xDisplay, &e); + if(e.type == KeyPress) { + KeySym keysym = XLookupKeysym((XKeyEvent*)&e, 0); + if(keysym == XK_Insert) { + return false; + } + DoKeys(keysym, true); + } + if(e.type == KeyRelease) { + KeySym keysym = XLookupKeysym((XKeyEvent*)&e, 0); + DoKeys(keysym, false); + } + } + + return true; +} + +void Backend_GetKeyboardState(bool *out_keyboard_state) { + memcpy(out_keyboard_state, keyboardState, sizeof(keyboardState)); +} + +ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...) { + va_list argumentList; + va_start(argumentList, format); + fputs("ERROR: ", stderr); + vfprintf(stderr, format, argumentList); + fputc('\n', stderr); + va_end(argumentList); +} + +ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...) { + va_list argumentList; + va_start(argumentList, format); + fputs("INFO: ", stdout); + vfprintf(stdout, format, argumentList); + fputc('\n', stdout); + va_end(argumentList); +} + +void Backend_ShowMessageBox(const char* title, const char* message) { + printf("ShowMessageBox: %s - %s\n", title, message); +} + +unsigned long Backend_GetTicks(void) { + struct timeval time; // time.tv_usec is microseconds + gettimeofday(&time, NULL); + unsigned long ticktime = ((time.tv_sec * 1000) + (time.tv_usec / 1000)) - startTime; + return ticktime; +} + +void Backend_Delay(unsigned int ticks) { + usleep(ticks * 1000); +} diff --git a/src/Backends/Rendering/Window/Software/X11.cpp b/src/Backends/Rendering/Window/Software/X11.cpp new file mode 100644 index 00000000..d715710b --- /dev/null +++ b/src/Backends/Rendering/Window/Software/X11.cpp @@ -0,0 +1,103 @@ +#include "../Software.h" +#include "../../../Misc.h" + +#include +#include +#include + +#include +#include + +static Window window; +static XImage* framebufferImage; +static char* framebufferPixels; +static int framebufferPitch; +static char* xfriendlyFB; +static GC gc; +static int screenWidth; +static int screenHeight; +static Pixmap intermediate; +extern Display* xDisplay; +extern Visual* xVisual; + +bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen) { + screenWidth = screen_width; + screenHeight = screen_height; + + int screen = DefaultScreen(xDisplay); + Window rootWindow = RootWindow(xDisplay, screen); + //window = XCreateWindow(display, rootWindow, 0, 0, screen_width, screen_height, 0, 16, InputOutput, CopyFromParent, 0, NULL); + window = XCreateSimpleWindow(xDisplay, rootWindow, 0, 0, screen_width, screen_height, 1, 0, 0); + XSelectInput(xDisplay, window, ExposureMask | KeyPressMask | KeyReleaseMask); + XMapRaised(xDisplay, window); + XStoreName(xDisplay, window, window_title); + + // Make the close button work. This is also required for the window to show up. + // weird + Atom WM_DELETE_WINDOW = XInternAtom(xDisplay, "WM_DELETE_WINDOW", false); + XSetWMProtocols(xDisplay, window, &WM_DELETE_WINDOW, 1); + + gc = DefaultGC(xDisplay, DefaultScreen(xDisplay)); + + int depth = DefaultDepth(xDisplay, DefaultScreen(xDisplay)); + + intermediate = XCreatePixmap(xDisplay, window, screenWidth, screenHeight, depth); + + // Setting up the framebuffer + framebufferPixels = (char*)malloc(screen_width * screen_height * 3); + xfriendlyFB = (char*)malloc(screen_width * screen_height * 4); + framebufferImage = XCreateImage(xDisplay, DefaultVisual(xDisplay, DefaultScreen(xDisplay)), + depth, ZPixmap, 0, + xfriendlyFB, screen_width, screen_height, + 32, 0); + if(framebufferImage == 0) { + return false; + } + framebufferPitch = screen_width * 3; + return true; +} + +unsigned char* WindowBackend_Software_GetFramebuffer(size_t *pitch) +{ + *pitch = framebufferPitch; + + return (unsigned char*)framebufferPixels; +} + +void WindowBackend_Software_DestroyWindow(void) { + XDestroyWindow(xDisplay, window); +} + +void WindowBackend_Software_HandleWindowResize(size_t width, size_t height) { + (void)width; + (void)height; + + Backend_PrintError("Bro I can't resize, I'm too lazy."); +} + +void WindowBackend_Software_Display(void) { + int srci = 0; + for(int i = 0; i < screenWidth * screenHeight * 4; i++) { + int src; + switch(i % 4) { + case 0: + src = srci + 2; + break; + case 1: + src = srci + 1; + break; + case 2: + src = srci + 0; + break; + case 3: + srci += 3; + } + xfriendlyFB[i] = framebufferPixels[src]; + // if(i % 4 != 3) { + // xfriendlyFB[i] = framebufferPixels[srci]; + // srci++; + // } + } + XPutImage(xDisplay, window, gc, framebufferImage, 0, 0, 0, 0, screenWidth, screenHeight); + //XCopyArea(xDisplay, intermediate, window, gc, 0, 0, screenWidth, screenHeight, 0, 0); +}