diff options
Diffstat (limited to 'src/os/linux/linux_window.c')
| -rw-r--r-- | src/os/linux/linux_window.c | 304 | 
1 files changed, 304 insertions, 0 deletions
diff --git a/src/os/linux/linux_window.c b/src/os/linux/linux_window.c new file mode 100644 index 0000000..d739b3c --- /dev/null +++ b/src/os/linux/linux_window.c @@ -0,0 +1,304 @@ +// Note: This is probably deprecated and can be deleted. + +#include <basic/basic.h> +#include <os/os.h> + +#include <SDL3/SDL.h> +#include <X11/Xlib.h> +#include <GL/gl.h> +#include <GL/glx.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +struct OSWindow { +    Window xid; +    Atom wm_delete_window; +    u32 event_mask; + +    i32 width; +    i32 height; + +    GLXContext glx_context; +    u32 gl_texture_id; +    OSOffscreenBuffer offscreen_buffer; + +    OSEvent current_event; +}; + + +internal_var Display *g_display; + +internal_fn b32 +os_connect_to_x(void) +{ +    const char *display_name = 0; +    g_display = XOpenDisplay(display_name); +    if (!g_display) +    { +        printf("XOpenDisplay(%s) failed\n", display_name); +        return false; +    } + +    return true; +} + + +void +os_window_destroy_offscreen_buffer(OSOffscreenBuffer *offscreen_buffer) +{ +    free(offscreen_buffer->pixels); +} + +void +os_offscreen_buffer_resize(OSOffscreenBuffer *offscreen, i32 width, i32 height) +{ +    u32 *new_pixels = realloc(offscreen->pixels, width*height*4); +    if (new_pixels) { +        offscreen->width = width; +        offscreen->height = height; +        offscreen->pixels = new_pixels; +        glViewport(0, 0, width, height); +    } +} + +void +os_offscreen_buffer_destroy(OSOffscreenBuffer *offscreen_buffer) +{ +    free(offscreen_buffer->pixels); +    free(offscreen_buffer); +} + +OSOffscreenBuffer * +os_offscreen_buffer_create(i32 width, i32 height) +{ +    OSOffscreenBuffer *offscreen_buffer = malloc(sizeof(OSOffscreenBuffer)); +    if (offscreen_buffer) { +        offscreen_buffer->green_shift = 8; +        offscreen_buffer->blue_shift = 16; +        offscreen_buffer->red_shift = 0; +        offscreen_buffer->alpha_shift = 24; +        offscreen_buffer->width = 0; +        offscreen_buffer->height = 0; +        offscreen_buffer->pixels = 0; +    } +    os_offscreen_buffer_resize(offscreen_buffer, width, height); +    return offscreen_buffer; +} + +void +os_window_swap_buffers(OSWindow *window, OSOffscreenBuffer *offscreen_buffer) +{ +    glActiveTexture(GL_TEXTURE0); +    glBindTexture(GL_TEXTURE_2D, window->gl_texture_id); +    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, offscreen_buffer->width, offscreen_buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, offscreen_buffer->pixels); + +    glBegin(GL_QUADS); +    glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f); +    glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f); +    glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f,  1.0f); +    glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f,  1.0f); +    glEnd(); + +    glBindTexture(GL_TEXTURE_2D, 0); + +    glXSwapBuffers(g_display, window->xid); +} + + +#define ADD_KEY_PRESS(c) \ +    event->type = OS_EVENT_KEY_PRESS; \ +    event->ev.key_press.code = c; \ +    event->ev.key_press.is_unicode = true; \ +    return true; +#define ADD_SPECIAL_KEY_PRESS(c) \ +    event->type = OS_EVENT_KEY_PRESS; \ +    event->ev.key_press.code = c; \ +    event->ev.key_press.is_unicode = false; \ +    return true; + +b32 +os_window_get_event(OSWindow *window, OSEvent *event) +{ +    while (XPending(g_display)) { +        XEvent xevent; +        XNextEvent(g_display, &xevent); + +        // Todo: Rework this whole shift/caps-lock logic. +        persist_var b32 is_caps; +        persist_var b32 is_shift_l; +        persist_var b32 is_shift_r; +        b32 is_uppercase = ( is_caps && !(is_shift_l || is_shift_r)) || +                           (!is_caps &&  (is_shift_l || is_shift_r)); + +        switch (xevent.type) { +            case ClientMessage: { +                if ((Atom)xevent.xclient.data.l[0] == window->wm_delete_window) { +                    event->type = OS_EVENT_WINDOW_DESTROYED; +                    return true; +                } +                continue; +            } break; + +            case DestroyNotify: { +                event->type = OS_EVENT_WINDOW_DESTROYED; +                return true; +            } break; + +            case ConfigureNotify: { +                i32 width = xevent.xconfigure.width; +                i32 height = xevent.xconfigure.height; +                if (width != window->width || height != window->height) { +                    event->type = OS_EVENT_WINDOW_RESIZE; +                    event->ev.resize.width = width; +                    event->ev.resize.height = height; +                    window->width = width; +                    window->height = height; +                    return true; +                } +                continue; +            } break; + +            case KeyPress: { +                int index = is_uppercase ? 1 : 0; +                KeySym keysym = XLookupKeysym(&xevent.xkey, index); +                if (keysym >= 32 && keysym <= 126) {ADD_KEY_PRESS(keysym);} +                else if (keysym == XK_Tab)         {ADD_KEY_PRESS('\t');  } +                else if (keysym == XK_Return)      {ADD_KEY_PRESS('\r');  } +                else if (keysym == XK_BackSpace)   {ADD_KEY_PRESS('\b');     } +                else if (keysym == XK_Delete)      {ADD_KEY_PRESS(127);   }  +                else if (keysym == XK_Left)        {ADD_SPECIAL_KEY_PRESS(OS_KEYCODE_LEFT); } +                else if (keysym == XK_Right)       {ADD_SPECIAL_KEY_PRESS(OS_KEYCODE_RIGHT);} +                else if (keysym == XK_Up)          {ADD_SPECIAL_KEY_PRESS(OS_KEYCODE_UP);   } +                else if (keysym == XK_Down)        {ADD_SPECIAL_KEY_PRESS(OS_KEYCODE_DOWN); } +                else if (keysym == XK_Shift_L)     is_shift_l = true; +                else if (keysym == XK_Shift_R)     is_shift_r = true; +                else if (keysym == XK_Caps_Lock)   is_caps = true; +            } break; + +            case KeyRelease: { +                int index = 0; +                KeySym keysym = XLookupKeysym(&xevent.xkey, index); +                if (keysym == XK_Shift_L)        is_shift_l = false; +                else if (keysym == XK_Shift_R)   is_shift_r = false; +                else if (keysym == XK_Caps_Lock) is_caps = false; +                continue; // ignore this for now i guess +            } break; + +            case GraphicsExpose: { +                printf("graphics exposure happened\n"); +                continue; +            } break; + +            default:; +        } +    } +    return false; +} + +#undef ADD_KEY_PRESS +#undef ADD_SPECIAL_KEY_PRESS + + +void os_window_destroy(OSWindow *window) { +    os_window_destroy_offscreen_buffer(&window->offscreen_buffer); +    XDestroyWindow(g_display, window->xid); +    free(window); +} + +OSWindow *os_window_create(const char *name, i32 width, i32 height) { +    if (!g_display) { +        if (!os_connect_to_x()) +            return 0; +    } + +    int screen_number = XDefaultScreen(g_display); +    Window root_window_id = XRootWindow(g_display, screen_number); +    if (!root_window_id) +    { +        printf("XDefaultRootWindow(display) failed\n"); +        XCloseDisplay(g_display); +        return 0; +    } + +    // get visual info +    int depth = 24; +    int va[] = { +        GLX_RGBA, 1, +        GLX_DOUBLEBUFFER, 1, +        GLX_RED_SIZE,   8, +        GLX_GREEN_SIZE, 8, +        GLX_BLUE_SIZE,  8, +        GLX_ALPHA_SIZE, 8, +        GLX_DEPTH_SIZE, depth, +        None +    }; +    XVisualInfo* vinfo = glXChooseVisual(g_display, screen_number, va); +    if (!vinfo) +    { +        printf("glXChooseVisual failed\n"); +        return 0; +    } + +    // set window attribs +    long swa_mask = CWEventMask | CWColormap | CWBackPixmap |CWBorderPixel;  +    long swa_event_mask = PropertyChangeMask | SubstructureNotifyMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask; +    Colormap colormap = XCreateColormap(g_display, root_window_id, vinfo->visual, AllocNone); + +    XSetWindowAttributes swa; +    memset(&swa, 0, sizeof(swa)); +    swa.background_pixmap = None; +    swa.border_pixel = 0; +    swa.event_mask = swa_event_mask; +    swa.colormap = colormap; + +    Window window_id = XCreateWindow(g_display, root_window_id, 0, 0, width, height, 0, depth, InputOutput, vinfo->visual, swa_mask, &swa); +    XStoreName(g_display, window_id, name); +    XMapWindow(g_display, window_id); + + +    // I support the WM_DELETE_WINDOW protocol @Leak? +    Atom wm_delete_window = XInternAtom(g_display, "WM_DELETE_WINDOW", False);  +    XSetWMProtocols(g_display, window_id, &wm_delete_window, 1); + + +    // glx context +    Bool direct = True; +    GLXContext glx_context = glXCreateContext(g_display, vinfo, 0, direct); +    if (glx_context == 0) +    { +        printf("glXCreateContext failed\n"); +        return 0; +    } +    Bool made_current = glXMakeCurrent(g_display, window_id, glx_context); +    if (made_current == False) +    { +        printf("glXMakeCurrent failed\n"); +        return 0; +    } + + +    OSWindow *window = malloc(sizeof(OSWindow)); +    window->xid = window_id; +    window->wm_delete_window = wm_delete_window; +    window->event_mask = swa_event_mask; +    window->glx_context = glx_context; +    XSync(g_display, False); + + +    glEnable(GL_TEXTURE_2D); + +    glActiveTexture(GL_TEXTURE0); +    glGenTextures(1, &window->gl_texture_id); +    glBindTexture(GL_TEXTURE_2D, window->gl_texture_id); + +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	 +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + +    return window; +} +  | 
