]> git.tdb.fi Git - geometrycompositor.git/blobdiff - source/main.c
Implement a spherical curvature correction
[geometrycompositor.git] / source / main.c
index bfb01a4dac17ebacaf28d7df339409bc4e699b1c..b1247d88d680ec012d36215fc0bede6fcb8f782b 100644 (file)
@@ -32,6 +32,12 @@ typedef struct CompositedWindow
        int recreate_mask;
 } CompositedWindow;
 
+enum
+{
+       CYLINDRICAL = 1,
+       SPHERICAL
+};
+
 typedef struct CompositedMonitor
 {
        char *name;
@@ -41,7 +47,8 @@ typedef struct CompositedMonitor
        unsigned width;
        unsigned height;
        float keystone_vertical;
-       float cylinder_depth;
+       float curvature_type;
+       float curvature_depth;
        float vertical_center;
        float perspective;
        unsigned vertex_buffer;
@@ -49,6 +56,8 @@ typedef struct CompositedMonitor
        unsigned vertex_array;
        unsigned tessellation;
        unsigned nelements;
+       short *geometry_data;
+       unsigned geometry_data_size;
 } CompositedMonitor;
 
 typedef struct CompositedScreen
@@ -71,6 +80,9 @@ typedef struct CompositedScreen
        unsigned window_vertex_array;
        unsigned framebuffer;
        unsigned fb_texture;
+       Pixmap root_pixmap;
+       GLXPixmap root_glx_pixmap;
+       unsigned root_texture;
        CompositedWindow *windows;
        unsigned nwindows;
        unsigned windows_capacity;
@@ -89,13 +101,16 @@ typedef struct Compositor
        PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
        PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
        PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
+       Atom root_pmap_atom;
        Atom correction_atom;
        Atom monitors_atom;
+       Atom geometry_data_atom;
+       Window selection_window;
        int dirty;
 } Compositor;
 
 static const char *vshader_src =
-       "#version 150\n"
+       "#version 130\n"
        "uniform vec4 geometry;\n"
        "in vec2 vertex;\n"
        "in vec2 texture_coord;\n"
@@ -107,7 +122,7 @@ static const char *vshader_src =
        "}\n";
 
 static const char *fshader_src =
-       "#version 150\n"
+       "#version 130\n"
        "uniform sampler2D image;\n"
        "in vec2 texcoord;\n"
        "out vec4 frag_color;\n"
@@ -117,7 +132,7 @@ static const char *fshader_src =
        "}\n";
 
 static const char *masked_fshader_src =
-       "#version 150\n"
+       "#version 130\n"
        "uniform sampler2D image;\n"
        "uniform sampler2D mask;\n"
        "in vec2 texcoord;\n"
@@ -325,6 +340,8 @@ int create_gl_resources(CompositedScreen *screen)
        glDepthMask(GL_FALSE);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
 
+       screen->root_texture = create_2d_texture();
+
        return 1;
 }
 
@@ -357,17 +374,11 @@ CompositedWindow *find_window_global(Compositor *compositor, Window w, Composite
        return NULL;
 }
 
-void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
+GLXPixmap pixmap_to_glx_pixmap(Compositor *compositor, CompositedScreen *screen, Pixmap pixmap)
 {
        int attribs[5];
        unsigned i;
 
-       if(window->pixmap)
-       {
-               glXDestroyPixmap(compositor->display, window->glx_pixmap);
-               XFreePixmap(compositor->display, window->pixmap);
-       }
-
        i = 0;
        attribs[i++] = GLX_TEXTURE_TARGET_EXT;
        attribs[i++] = GLX_TEXTURE_2D_EXT;
@@ -375,8 +386,19 @@ void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, Comp
        attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
        attribs[i++] = None;
 
+       return glXCreatePixmap(compositor->display, screen->fbconfig, pixmap, attribs);
+}
+
+void create_window_pixmap(Compositor *compositor, CompositedScreen *screen, CompositedWindow *window)
+{
+       if(window->pixmap)
+       {
+               glXDestroyPixmap(compositor->display, window->glx_pixmap);
+               XFreePixmap(compositor->display, window->pixmap);
+       }
+
        window->pixmap = XCompositeNameWindowPixmap(compositor->display, window->window);
-       window->glx_pixmap = glXCreatePixmap(compositor->display, screen->fbconfig, window->pixmap, attribs);
+       window->glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, window->pixmap);
        window->recreate_pixmap = 0;
 }
 
@@ -495,6 +517,7 @@ CompositedWindow *add_window(Compositor *compositor, CompositedScreen *screen, W
 
        window->texture = create_2d_texture();
        window->mask_texture = create_2d_texture();
+       window->use_mask = 0;
        window->recreate_mask = (window->map_state==IsViewable);
 
        XShapeSelectInput(compositor->display, window->window, ShapeNotifyMask);
@@ -595,9 +618,9 @@ void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monito
 
        aspect = (float)monitor->width/monitor->height;
 
-       if(monitor->cylinder_depth)
+       if(monitor->curvature_depth)
        {
-               cyl_radius = (monitor->cylinder_depth*monitor->cylinder_depth+0.25f)/(2.0f*monitor->cylinder_depth);
+               cyl_radius = (monitor->curvature_depth*monitor->curvature_depth+0.25f)/(2.0f*monitor->curvature_depth);
                cyl_arc = 2.0f*asin(0.5f/cyl_radius);
        }
 
@@ -622,13 +645,41 @@ void update_monitor_vertices(CompositedScreen *screen, CompositedMonitor *monito
                        v[0] = (float)x/t-0.5f;
                        v[1] = ((float)y/t-0.5f)/aspect;
                        v[2] = 0;
-                       if(monitor->cylinder_depth)
+                       if(monitor->curvature_depth)
                        {
-                               v[2] = (1.0f-cos(v[0]*cyl_arc))*cyl_radius-monitor->cylinder_depth;
-                               v[0] = sin(v[0]*cyl_arc)*cyl_radius;
+                               if(monitor->curvature_type==CYLINDRICAL)
+                               {
+                                       v[2] = (1.0f-cos(v[0]*cyl_arc))*cyl_radius-monitor->curvature_depth;
+                                       v[0] = sin(v[0]*cyl_arc)*cyl_radius;
+                               }
+                               else if(monitor->curvature_type==SPHERICAL)
+                               {
+                                       float r;
+
+                                       v[0] = tan(v[0]*cyl_arc)*cyl_radius;
+                                       v[1] = tan(v[1]*cyl_arc)*cyl_radius;
+                                       r = sqrt(v[0]*v[0]+v[1]*v[1]+cyl_radius*cyl_radius)/fabs(cyl_radius);
+                                       v[0] /= r;
+                                       v[1] /= r;
+                                       v[2] = cyl_radius-cyl_radius/r-monitor->curvature_depth;
+                               }
                        }
                }
 
+       monitor->geometry_data[0] = t;
+       for(i=0; i<3; ++i)
+               monitor->geometry_data[1+i] = eye[i]*4096;
+       for(y=0; y<2; ++y)
+               for(x=0; x<2; ++x)
+               {
+                       i = 1+(1+y*2+x)*3;
+                       monitor->geometry_data[i] = ((x-0.5f)*distance/monitor->perspective)*4096;
+                       monitor->geometry_data[i+1] = (eye[1]+look[1]*distance-(y-monitor->vertical_center)*look[2]*distance/monitor->perspective/aspect)*4096;
+                       monitor->geometry_data[i+2] = (eye[2]+look[2]*distance+(y-monitor->vertical_center)*look[1]*distance/monitor->perspective/aspect)*4096;
+               }
+       for(i=0; i<(t+1)*(t+1)*3; ++i)
+               monitor->geometry_data[16+i] = vertex_data[i]*4096;
+
        for(y=t; y<=t; --y)
                for(x=t; x<=t; --x)
                {
@@ -693,6 +744,7 @@ int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScre
        if(!monitor->enabled)
        {
                XRRFreeOutputInfo(output);
+               monitor->geometry_data = NULL;
                return 1;
        }
 
@@ -705,7 +757,8 @@ int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScre
        XRRFreeOutputInfo(output);
 
        monitor->keystone_vertical = 0.0f;
-       monitor->cylinder_depth = 0.0f;
+       monitor->curvature_type = CYLINDRICAL;
+       monitor->curvature_depth = 0.0f;
        monitor->vertical_center = 0.5f;
        monitor->perspective = 1.0f;
 
@@ -714,6 +767,8 @@ int initialize_monitor(Compositor *compositor, CompositedScreen *screen, XRRScre
        monitor->index_buffer = buffers[1];
 
        monitor->tessellation = 50;
+       monitor->geometry_data_size = (monitor->tessellation+1)*(monitor->tessellation+1)*3+16;
+       monitor->geometry_data = (short *)malloc(monitor->geometry_data_size*sizeof(short));
        update_monitor_vertices(screen, monitor);
        stride = 4*sizeof(float);
 
@@ -742,6 +797,24 @@ CompositedMonitor *find_monitor_by_name(CompositedScreen *screen, char *name)
        return NULL;
 }
 
+CompositedMonitor *find_monitor_by_name_global(Compositor *compositor, char *name, CompositedScreen **screen)
+{
+       unsigned i, j;
+
+       for(i=0; i<compositor->nscreens; ++i)
+               for(j=0; j<compositor->screens[i].nmonitors; ++j)
+                       if(!strcmp(compositor->screens[i].monitors[j].name, name))
+                       {
+                               if(screen)
+                                       *screen = &compositor->screens[i];
+                               return &compositor->screens[i].monitors[j];
+                       }
+
+       if(screen)
+               *screen = NULL;
+       return NULL;
+}
+
 void update_geometry_correction(Compositor *compositor, CompositedScreen *screen)
 {
        Atom prop_type;
@@ -770,7 +843,7 @@ void update_geometry_correction(Compositor *compositor, CompositedScreen *screen
        use_gl(compositor, screen);
 
        name_ptr = names;
-       for(i=0; i*4<values_length; ++i)
+       for(i=0; i*5+4<values_length; ++i)
        {
                CompositedMonitor *monitor;
 
@@ -780,10 +853,11 @@ void update_geometry_correction(Compositor *compositor, CompositedScreen *screen
                monitor = find_monitor_by_name(screen, name_ptr);
                if(monitor)
                {
-                       monitor->keystone_vertical = values[i*4]/10000.0f;
-                       monitor->cylinder_depth = values[i*4+1]/10000.0f;
-                       monitor->vertical_center = values[i*4+2]/10000.0f;
-                       monitor->perspective = values[i*4+3]/10000.0f;
+                       monitor->keystone_vertical = values[i*5]/4096.0f;
+                       monitor->curvature_type = values[i*5+1];
+                       monitor->curvature_depth = values[i*5+2]/4096.0f;
+                       monitor->vertical_center = values[i*5+3]/4096.0f;
+                       monitor->perspective = values[i*5+4]/4096.0f;
 
                        if(monitor->enabled)
                                update_monitor_vertices(screen, monitor);
@@ -796,6 +870,45 @@ void update_geometry_correction(Compositor *compositor, CompositedScreen *screen
        XFree(values);
 }
 
+void update_root_pixmap(Compositor *compositor, CompositedScreen *screen)
+{
+       Atom prop_type;
+       int prop_format;
+       unsigned long overflow;
+       unsigned long length;
+       long *pixmap;
+       Window root;
+       int x, y;
+       unsigned width;
+       unsigned height;
+       unsigned border;
+       unsigned depth;
+
+       use_gl(compositor, screen);
+
+       if(screen->root_glx_pixmap)
+       {
+               glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
+               screen->root_glx_pixmap = None;
+       }
+
+       XGetWindowProperty(compositor->display, screen->root, compositor->root_pmap_atom, 0, 1, False, XA_PIXMAP,
+               &prop_type, &prop_format, &length, &overflow, (unsigned char **)&pixmap);
+       if(prop_type!=XA_PIXMAP || prop_format!=32)
+       {
+               screen->root_pixmap = None;
+               return;
+       }
+
+       screen->root_pixmap = pixmap[0];
+       if(XGetGeometry(compositor->display, screen->root_pixmap, &root, &x, &y, &width, &height, &border, &depth))
+               screen->root_glx_pixmap = pixmap_to_glx_pixmap(compositor, screen, screen->root_pixmap);
+       else
+               screen->root_pixmap = None;
+
+       XFree(pixmap);
+}
+
 int initialize_screen(Compositor *compositor, unsigned number)
 {
        CompositedScreen *screen;
@@ -841,7 +954,11 @@ int initialize_screen(Compositor *compositor, unsigned number)
                        return 0;
        XRRFreeScreenResources(xrr_res);
 
+       screen->root_pixmap = None;
+       screen->root_glx_pixmap = None;
+
        update_geometry_correction(compositor, screen);
+       update_root_pixmap(compositor, screen);
 
        XQueryTree(compositor->display, screen->root, &dummy_root, &dummy_parent, &children, &nchildren);
 
@@ -912,8 +1029,10 @@ int initialize_compositor(Compositor *compositor)
        compositor->glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXBindTexImageEXT");
        compositor->glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((unsigned char *)"glXReleaseTexImageEXT");
 
-       compositor->correction_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION", False);
-       compositor->monitors_atom = XInternAtom(compositor->display, "GEOMETRY_CORRECTION_MONITORS", False);
+       compositor->root_pmap_atom = XInternAtom(compositor->display, "_XROOTPMAP_ID", False);
+       compositor->correction_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION", False);
+       compositor->monitors_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_MONITORS", False);
+       compositor->geometry_data_atom = XInternAtom(compositor->display, "_MSP_GEOMETRY_CORRECTION_DATA", False);
 
        compositor->nscreens = ScreenCount(compositor->display);
        compositor->screens = (CompositedScreen *)malloc(compositor->nscreens*sizeof(CompositedScreen));
@@ -921,6 +1040,9 @@ int initialize_compositor(Compositor *compositor)
                if(!initialize_screen(compositor, i))
                        return 0;
 
+       compositor->selection_window = XCreateWindow(compositor->display, compositor->screens[0].root, 0, 0, 1, 1, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
+       XSetSelectionOwner(compositor->display, compositor->geometry_data_atom, compositor->selection_window, CurrentTime);
+
        compositor->dirty = 1;
 
        return 1;
@@ -953,8 +1075,13 @@ void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
                        glDeleteBuffers(1, &screen->monitors[i].index_buffer);
                        glDeleteVertexArrays(1, &screen->monitors[i].vertex_array);
                }
+               if(screen->monitors[i].geometry_data)
+                       free(screen->monitors[i].geometry_data);
        }
 
+       glDeleteTextures(1, &screen->root_texture);
+       glXDestroyPixmap(compositor->display, screen->root_glx_pixmap);
+
        glDeleteBuffers(1, &screen->window_vertex_buffer);
        glDeleteVertexArrays(1, &screen->window_vertex_array);
        glDeleteFramebuffers(1, &screen->framebuffer);
@@ -964,7 +1091,7 @@ void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
        for(i=0; i<3; ++i)
                glDeleteShader(screen->shaders[i]);
 
-       glXMakeContextCurrent(compositor->display, 0, 0, NULL);
+       glXMakeContextCurrent(compositor->display, None, None, NULL);
        glXDestroyContext(compositor->display, screen->glx_context);
        glXDestroyWindow(compositor->display, screen->glx_window);
        XDestroyWindow(compositor->display, screen->render_window);
@@ -983,6 +1110,8 @@ void shutdown_compositor(Compositor *compositor)
                shutdown_screen(compositor, &compositor->screens[i]);
        free(compositor->screens);
 
+       XDestroyWindow(compositor->display, compositor->selection_window);
+
        XCloseDisplay(compositor->display);
 }
 
@@ -1105,14 +1234,46 @@ void process_property_event(Compositor *compositor, XPropertyEvent *event)
 {
        CompositedScreen *screen;
 
-       if(event->atom!=compositor->correction_atom)
-               return;
-
        screen = find_screen_by_root(compositor, event->window);
        if(!screen)
                return;
 
-       update_geometry_correction(compositor, screen);
+       if(event->atom==compositor->correction_atom)
+               update_geometry_correction(compositor, screen);
+       else if(event->atom==compositor->root_pmap_atom)
+               update_root_pixmap(compositor, screen);
+}
+
+void process_selection_request_event(Compositor *compositor, XSelectionRequestEvent *event)
+{
+       Atom prop_type;
+       int prop_format;
+       unsigned long overflow;
+       unsigned long names_length;
+       XSelectionEvent notify;
+
+       if(event->selection==compositor->geometry_data_atom)
+       {
+               char *monitor_name;
+               CompositedMonitor *monitor;
+
+               XGetWindowProperty(compositor->display, event->requestor, event->property, 0, 64, False, XA_STRING,
+                       &prop_type, &prop_format, &names_length, &overflow, (unsigned char **)&monitor_name);
+               if(prop_type!=XA_STRING || prop_format!=8)
+                       return;
+
+               monitor = find_monitor_by_name_global(compositor, monitor_name, NULL);
+               if(monitor && monitor->enabled)
+                       XChangeProperty(compositor->display, event->requestor, event->property, XA_INTEGER, 16, PropModeReplace, (unsigned char *)monitor->geometry_data, monitor->geometry_data_size);
+
+               notify.type = SelectionNotify;
+               notify.requestor = event->requestor;
+               notify.selection = event->selection;
+               notify.target = event->target;
+               notify.property = (monitor ? event->property : None);
+               notify.time = event->time;
+               XSendEvent(compositor->display, event->requestor, False, 0, (XEvent *)&notify);
+       }
 }
 
 void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
@@ -1179,6 +1340,9 @@ void process_events(Compositor *compositor)
                case PropertyNotify:
                        process_property_event(compositor, &event.xproperty);
                        break;
+               case SelectionRequest:
+                       process_selection_request_event(compositor, &event.xselectionrequest);
+                       break;
                default:
                        if(event.type==compositor->damage_event+XDamageNotify)
                                process_damage_event(compositor, (XDamageNotifyEvent *)&event);
@@ -1195,15 +1359,32 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen)
        unsigned i;
        int use_mask;
 
+       for(i=0; i<screen->nwindows; ++i)
+               if(screen->windows[i].map_state==IsViewable)
+                       XDamageSubtract(compositor->display, screen->windows[i].damage, None, None);
+       glXWaitX();
+
        use_gl(compositor, screen);
 
+       glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, screen->framebuffer);
 
-       glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
-       glClear(GL_COLOR_BUFFER_BIT);
-
        use_mask = -1;
        glBindVertexArray(screen->window_vertex_array);
+
+       if(screen->root_pixmap)
+       {
+               use_mask = 0;
+               glUseProgram(screen->program);
+               glBindTexture(GL_TEXTURE_2D, screen->root_texture);
+               compositor->glXBindTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
+               glUniform4f(screen->geometry_loc, 0.0f, 0.0f, 1.0f, 1.0f);
+               glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+               compositor->glXReleaseTexImageEXT(compositor->display, screen->root_glx_pixmap, GLX_FRONT_LEFT_EXT);
+       }
+       else
+               glClear(GL_COLOR_BUFFER_BIT);
+
        for(i=0; i<screen->nwindows; ++i)
        {
                CompositedWindow *window;
@@ -1225,8 +1406,6 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen)
                        glActiveTexture(GL_TEXTURE0);
                }
 
-               XDamageSubtract(compositor->display, window->damage, None, None);
-
                if(window->recreate_pixmap)
                        create_window_pixmap(compositor, screen, window);
                if(window->recreate_mask)
@@ -1242,7 +1421,6 @@ void refresh_screen(Compositor *compositor, CompositedScreen *screen)
        }
 
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-       glClearColor(0.5f, 0.0f, 0.5f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glBindTexture(GL_TEXTURE_2D, screen->fb_texture);
        glEnable(GL_PRIMITIVE_RESTART);