From a66516e34ed1037cdc38fce8bd957fd77152c39f Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 30 Mar 2022 18:09:17 +0200 Subject: wip --- depends/mglpp | 2 +- include/window_texture.h | 38 ++++++++++ project.conf | 6 +- src/main.cpp | 55 +++++++++++++- src/window_texture.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 281 insertions(+), 5 deletions(-) create mode 100644 include/window_texture.h create mode 100644 src/window_texture.c diff --git a/depends/mglpp b/depends/mglpp index 2c879c3..14e64e6 160000 --- a/depends/mglpp +++ b/depends/mglpp @@ -1 +1 @@ -Subproject commit 2c879c34c9aeddae528d2818f7baa6a915d5d77a +Subproject commit 14e64e64c7da7535e62c275980669d9cf56b7a6d diff --git a/include/window_texture.h b/include/window_texture.h new file mode 100644 index 0000000..ea3ff10 --- /dev/null +++ b/include/window_texture.h @@ -0,0 +1,38 @@ +#ifndef WINDOW_TEXTURE_H +#define WINDOW_TEXTURE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define GLX_GLXEXT_PROTOTYPES +#include +#include +#include + +typedef struct { + Display *display; + Window window; + Pixmap pixmap; + GLXPixmap glx_pixmap; + GLuint texture_id; + int redirected; +} WindowTexture; + +/* Returns 0 on success */ +int window_texture_init(WindowTexture *window_texture, Display *display, Window window); +void window_texture_deinit(WindowTexture *self); + +/* + This should ONLY be called when the target window is resized. + Returns 0 on success. +*/ +int window_texture_on_resize(WindowTexture *self); + +GLuint window_texture_get_opengl_texture_id(WindowTexture *self); + +#ifdef __cplusplus +} +#endif + +#endif /* WINDOW_TEXTURE_H */ diff --git a/project.conf b/project.conf index f767638..81c8aa3 100644 --- a/project.conf +++ b/project.conf @@ -5,5 +5,7 @@ version = "0.1.0" platforms = ["posix"] [dependencies] -x11 = "1" -xext = "1" \ No newline at end of file +x11 = ">=1" +xext = ">=1" +xcomposite = ">=0" +gl = ">=1" \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 537011c..fb1f8ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include "../include/gui/Button.hpp" +#include "../include/window_texture.h" #include #include @@ -45,6 +46,20 @@ static bool string_to_i64(const char *str, int64_t *result) { return true; } +static void window_texture_get_size_or(WindowTexture *window_texture, int *width, int *height, int fallback_width, int fallback_height) { + Window root_window; + int x, y; + unsigned int w = 0, h = 0; + unsigned int border_width, depth; + if(!XGetGeometry(window_texture->display, window_texture->pixmap, &root_window, &x, &y, &w, &h, &border_width, &depth) || w == 0 || h == 0) { + *width = fallback_width; + *height = fallback_height; + } else { + *width = w; + *height = h; + } +} + int main(int argc, char **argv) { if(argc != 2) usage(); @@ -65,7 +80,7 @@ int main(int argc, char **argv) { return 1; } - XSelectInput(display, target_window, StructureNotifyMask); + XSelectInput(display, target_window, VisibilityChangeMask | StructureNotifyMask); mgl::vec2i target_window_size = { target_win_attr.width, target_win_attr.height }; @@ -199,7 +214,8 @@ int main(int argc, char **argv) { const mgl::vec2i settings_button_size(128, 128); shapes[main_buttons.size()] = { - (short)(main_buttons_start_pos.x + overlay_desired_size.x), (short)(main_buttons_start_pos.y - settings_button_size.y), (unsigned short)settings_button_size.x, (unsigned short)settings_button_size.y + (short)(main_buttons_start_pos.x + overlay_desired_size.x), (short)(main_buttons_start_pos.y - settings_button_size.y), + (unsigned short)settings_button_size.x, (unsigned short)settings_button_size.y }; if(shape_pixmap) { @@ -229,6 +245,27 @@ int main(int argc, char **argv) { }; update_overlay_shape(); + + WindowTexture target_window_texture; + window_texture_init(&target_window_texture, display, target_window); + + int target_window_texture_width = 0; + int target_window_texture_height = 0; + window_texture_get_size_or(&target_window_texture, &target_window_texture_width, &target_window_texture_height, target_window_size.x, target_window_size.y); + + mgl_texture window_texture_ref = { + window_texture_get_opengl_texture_id(&target_window_texture), + target_window_texture_width, + target_window_texture_height, + MGL_TEXTURE_FORMAT_RGB, + 32768, + 32768, + true + }; + + mgl::Texture window_texture = mgl::Texture::reference(window_texture_ref); + mgl::Sprite window_texture_sprite(&window_texture); + window.set_visible(true); Cursor default_cursor = XCreateFontCursor(display, XC_arrow); @@ -241,12 +278,26 @@ int main(int argc, char **argv) { mgl::Event event; while(window.is_open()) { + if(XCheckTypedWindowEvent(display, target_window, VisibilityNotify, &xev)) { + if(xev.xvisibility.state) { + window_texture_on_resize(&target_window_texture); + window_texture_ref.id = window_texture_get_opengl_texture_id(&target_window_texture); + window_texture_get_size_or(&target_window_texture, &window_texture_ref.width, &window_texture_ref.height, target_window_size.x, target_window_size.y); + window_texture = mgl::Texture::reference(window_texture_ref); + } + } + if(XCheckTypedWindowEvent(display, target_window, ConfigureNotify, &xev) && (xev.xconfigure.width != target_window_size.x || xev.xconfigure.height != target_window_size.y)) { while(XCheckTypedWindowEvent(display, target_window, ConfigureNotify, &xev)) {} target_window_size.x = xev.xconfigure.width; target_window_size.y = xev.xconfigure.height; window.set_size(target_window_size); update_overlay_shape(); + + window_texture_on_resize(&target_window_texture); + window_texture_ref.id = window_texture_get_opengl_texture_id(&target_window_texture); + window_texture_get_size_or(&target_window_texture, &window_texture_ref.width, &window_texture_ref.height, target_window_size.x, target_window_size.y); + window_texture = mgl::Texture::reference(window_texture_ref); } if(window.poll_event(event)) { diff --git a/src/window_texture.c b/src/window_texture.c new file mode 100644 index 0000000..bf687c6 --- /dev/null +++ b/src/window_texture.c @@ -0,0 +1,185 @@ +#include "../include/window_texture.h" +#include +#include +#include + +static int x11_supports_composite_named_window_pixmap(Display *display) { + int extension_major; + int extension_minor; + if(!XCompositeQueryExtension(display, &extension_major, &extension_minor)) + return 0; + + int major_version; + int minor_version; + return XCompositeQueryVersion(display, &major_version, &minor_version) && (major_version > 0 || minor_version >= 2); +} + +int window_texture_init(WindowTexture *window_texture, Display *display, Window window) { + window_texture->display = display; + window_texture->window = window; + window_texture->pixmap = None; + window_texture->glx_pixmap = None; + window_texture->texture_id = 0; + window_texture->redirected = 0; + + if(!x11_supports_composite_named_window_pixmap(display)) + return 1; + + XCompositeRedirectWindow(display, window, CompositeRedirectAutomatic); + window_texture->redirected = 1; + return window_texture_on_resize(window_texture); +} + +static void window_texture_cleanup(WindowTexture *self, int delete_texture) { + mgl_context *context = mgl_get_context(); + + if(delete_texture && self->texture_id) { + context->gl.glDeleteTextures(1, &self->texture_id); + self->texture_id = 0; + } + + if(self->glx_pixmap) { + glXDestroyPixmap(self->display, self->glx_pixmap); + glXReleaseTexImageEXT(self->display, self->glx_pixmap, GLX_FRONT_EXT); + self->glx_pixmap = None; + } + + if(self->pixmap) { + XFreePixmap(self->display, self->pixmap); + self->pixmap = None; + } +} + +void window_texture_deinit(WindowTexture *self) { + if(self->redirected) { + XCompositeUnredirectWindow(self->display, self->window, CompositeRedirectAutomatic); + self->redirected = 0; + } + window_texture_cleanup(self, 1); +} + +int window_texture_on_resize(WindowTexture *self) { + mgl_context *context = mgl_get_context(); + window_texture_cleanup(self, 0); + + int result = 0; + GLXFBConfig *configs = NULL; + Pixmap pixmap = None; + GLXPixmap glx_pixmap = None; + GLuint texture_id = 0; + int glx_pixmap_bound = 0; + + const int pixmap_config[] = { + GLX_BIND_TO_TEXTURE_RGB_EXT, True, + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT, + GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, + /*GLX_BIND_TO_MIPMAP_TEXTURE_EXT, True,*/ + GLX_BUFFER_SIZE, 24, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 0, + None + }; + + const int pixmap_attribs[] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, + /*GLX_MIPMAP_TEXTURE_EXT, True,*/ + None + }; + + XWindowAttributes attr; + if (!XGetWindowAttributes(self->display, self->window, &attr)) { + fprintf(stderr, "Failed to get window attributes\n"); + return 1; + } + + GLXFBConfig config; + int c; + configs = glXChooseFBConfig(self->display, 0, pixmap_config, &c); + if(!configs) { + fprintf(stderr, "Failed to choose fb config\n"); + return 1; + } + + int found = 0; + for (int i = 0; i < c; i++) { + config = configs[i]; + XVisualInfo *visual = glXGetVisualFromFBConfig(self->display, config); + if (!visual) + continue; + + if (attr.depth != visual->depth) { + XFree(visual); + continue; + } + XFree(visual); + found = 1; + break; + } + + if(!found) { + fprintf(stderr, "No matching fb config found\n"); + result = 1; + goto cleanup; + } + + pixmap = XCompositeNameWindowPixmap(self->display, self->window); + if(!pixmap) { + result = 2; + goto cleanup; + } + + glx_pixmap = glXCreatePixmap(self->display, config, pixmap, pixmap_attribs); + if(!glx_pixmap) { + result = 3; + goto cleanup; + } + + if(self->texture_id == 0) { + context->gl.glGenTextures(1, &texture_id); + if(texture_id == 0) { + result = 4; + goto cleanup; + } + context->gl.glBindTexture(GL_TEXTURE_2D, texture_id); + } else { + context->gl.glBindTexture(GL_TEXTURE_2D, self->texture_id); + } + + glXBindTexImageEXT(self->display, glx_pixmap, GLX_FRONT_EXT, NULL); + glx_pixmap_bound = 1; + + context->gl.glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + context->gl.glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + context->gl.glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + context->gl.glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + /* + float fLargest = 0.0f; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest); + */ + + context->gl.glBindTexture(GL_TEXTURE_2D, 0); + + XFree(configs); + self->pixmap = pixmap; + self->glx_pixmap = glx_pixmap; + if(texture_id != 0) + self->texture_id = texture_id; + return 0; + + cleanup: + if(texture_id != 0) context->gl.glDeleteTextures(1, &texture_id); + if(glx_pixmap) glXDestroyPixmap(self->display, glx_pixmap); + if(glx_pixmap_bound) glXReleaseTexImageEXT(self->display, glx_pixmap, GLX_FRONT_EXT); + if(pixmap) XFreePixmap(self->display, pixmap); + if(configs) XFree(configs); + return result; +} + +GLuint window_texture_get_opengl_texture_id(WindowTexture *self) { + return self->texture_id; +} -- cgit v1.2.3