use the depth buffer when rendering in gl, but it's pretty slow right now. add ...
[dana/dcompmgr.git] / glxrender.c
index 1c5ad24..ed17279 100644 (file)
@@ -33,6 +33,7 @@ typedef struct {
     void (*screen_root_pixmap_change)(d_screen_t *sc);
     void (*window_show)(d_window_t *w);
     void (*window_zombie_dead)(d_window_t *w);
+    void (*window_move)(d_window_t *w);
     void (*window_resize)(d_window_t *w);
     void (*window_reshape)(d_window_t *w);
 
@@ -65,11 +66,11 @@ static void glxrender_paint(d_screen_t *sc);
 static void glxrender_root_pixmap_change(d_screen_t *sc);
 static void paint_root(d_screen_t *sc, data_t *d);
 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
-                         gboolean opaque, int x, int y);
-static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
-                         int x, int y);
+                         GLfloat z);
+static void paint_shadow(data_t *d, window_data_t *wd, GLfloat z);
 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
                                            window_data_t *wd);
+static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
                                          window_data_t *wd);
 static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
@@ -77,6 +78,7 @@ static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
 
 static void glxrender_window_show(d_window_t *window);
 static void glxrender_window_zombie_dead(d_window_t *window);
+static void glxrender_window_move(d_window_t *window);
 static void glxrender_window_resize(d_window_t *window);
 static void glxrender_window_reshape(d_window_t *window);
 
@@ -100,6 +102,7 @@ glxrender_init(d_screen_t *sc, int id)
     d->window_show = sc->window_show;
     d->window_zombie_dead = sc->window_zombie_dead;
     d->window_resize = sc->window_resize;
+    d->window_move = sc->window_move;
     d->window_reshape = sc->window_reshape;
     screen_add_plugin_data(sc, plugin_id, d);
 
@@ -108,6 +111,7 @@ glxrender_init(d_screen_t *sc, int id)
     sc->window_show = glxrender_window_show;
     sc->window_zombie_dead = glxrender_window_zombie_dead;
     sc->window_resize = glxrender_window_resize;
+    sc->window_move = glxrender_window_move;
     sc->window_reshape = glxrender_window_reshape;
 
     d->shadowalpha = 0.2f; /* 20% */
@@ -137,13 +141,14 @@ glxrender_init(d_screen_t *sc, int id)
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     glEnable(GL_TEXTURE_2D);
+    glEnable(GL_DEPTH_TEST);
 
     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
     glDisable(GL_BLEND);
 
     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
 
     d->bind_func = (BindEXTFunc)
@@ -245,8 +250,10 @@ void
 glxrender_free(d_screen_t *sc)
 {
     data_t *d = screen_find_plugin_data(sc, plugin_id);
-    glxrender_free_root_pixmap(sc, d);
-    free(d);
+    if (d) {
+        glxrender_free_root_pixmap(sc, d);
+        free(d);
+    }
     screen_remove_plugin_data(sc, plugin_id);
 }
 
@@ -328,6 +335,8 @@ glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
         glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
         wd->glpixmap = XCB_NONE;
 
+    }
+    if (wd->nrects) {
         free(wd->texcoords);
         free(wd->vertices);
         wd->nrects = 0;
@@ -394,25 +403,61 @@ glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
 
     glBindTexture(GL_TEXTURE_2D, 0);
 
-    {
-        int x, y, width, height, bwidth;
-
-        window_get_area(w, &x, &y, &width, &height, &bwidth);
-
-        wd->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 4);
-        wd->texcoords[LEFT] = 0.0f;
-        wd->texcoords[TOP] = 0.0f;
-        wd->texcoords[RIGHT] = 1.0f;
-        wd->texcoords[BOTTOM] = 1.0f;
+    glxrender_update_window_region(w, wd);
+}
 
-        wd->vertices = (GLint*)malloc(sizeof(GLint) * 4);
-        wd->vertices[LEFT] = 0;
-        wd->vertices[TOP] = 0;
-        wd->vertices[RIGHT] = width + bwidth;
-        wd->vertices[BOTTOM] = height + bwidth;
+static void
+glxrender_update_window_region(d_window_t *w, window_data_t *wd)
+{
+    xcb_xfixes_region_t reg;
+    xcb_xfixes_fetch_region_cookie_t ck;
+    xcb_xfixes_fetch_region_reply_t *rep;
+    xcb_rectangle_t area, *rects;
+    int nrects, i, x, y, wid, hei, bwid;
+
+    reg = window_get_region(w);
+    ck = xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn, reg);
+
+    window_get_area(w, &x, &y, &wid, &hei, &bwid);
+    area.x = x;
+    area.y = y;
+    area.width = wid + bwid * 2;
+    area.height = hei + bwid * 2;
+
+    rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, ck, NULL);
+    if (!rep) {
+        rects = &area;
+        nrects = 1;
+    }
+    else {
+        rects = xcb_xfixes_fetch_region_rectangles(rep);
+        nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
+    }
 
-        wd->nrects = 1;
+    wd->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * (nrects * 4));
+    wd->vertices = (GLint*)malloc(sizeof(GLint) * (nrects * 4));
+    wd->nrects = nrects;
+
+    for (i = 0; i < nrects * 4; i += 4) {
+        wd->texcoords[i+LEFT] =
+            (GLfloat)(rects[i].x - area.x) / (GLfloat)area.width;
+        wd->texcoords[i+TOP] =
+            (GLfloat)(rects[i].y - area.y) / (GLfloat)area.height;
+        wd->texcoords[i+RIGHT] =
+            (GLfloat)(rects[i].x - area.x + rects[i].width) /
+            (GLfloat)area.width;
+        wd->texcoords[i+BOTTOM] =
+            (GLfloat)(rects[i].y - area.y + rects[i].height) /
+            (GLfloat)area.height;
+
+        wd->vertices[i+LEFT] = rects[i].x;
+        wd->vertices[i+TOP] = rects[i].y;
+        wd->vertices[i+RIGHT] = rects[i].x + rects[i].width;
+        wd->vertices[i+BOTTOM] = rects[i].y + rects[i].height;
     }
+
+    if (rep)
+        free(rep);
 }
 
 static void
@@ -469,6 +514,22 @@ glxrender_window_resize(d_window_t *w)
 }
 
 static void
+glxrender_window_move(d_window_t *w)
+{
+    data_t *d;
+    window_data_t *wd;
+
+    d = screen_find_plugin_data(w->sc, plugin_id);
+    wd = window_find_plugin_data(w, plugin_id);
+
+    /* pass it on */
+    d->window_move(w);
+
+    assert(wd != NULL);
+    glxrender_update_window_region(w, wd);
+}
+
+static void
 glxrender_window_reshape(d_window_t *w)
 {
     data_t *d;
@@ -502,11 +563,55 @@ glxrender_paint(d_screen_t *sc)
 {
     data_t *d = screen_find_plugin_data(sc, plugin_id);
     d_list_it_t *it;
+    GLfloat z;
 
     //printf("painting\n");
 
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    /* add 0.1f to keep everything above the root */
+    z = list_length(sc->stacking) * 0.1f + 0.1f;
+    for (it = list_top(sc->stacking); it; it = it->next) {
+        d_window_t *w = it->data;
+
+        if (!window_is_input_only(w) &&
+            (window_is_mapped(w) || window_is_zombie(w)))
+        {
+            int x, y, width, height, bwidth;
+            gboolean opaque;
+            window_data_t *wd;
+
+            window_get_area(w, &x, &y, &width, &height, &bwidth);
+
+            if (!(x < sc->super->width_in_pixels &&
+                  y < sc->super->height_in_pixels &&
+                  (x + width > 0 || x + width + d->xshadowoff > 0) &&
+                  (y + height > 0 || y + height + d->yshadowoff > 0)))
+            {
+                continue;
+            }
+
+            opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
+
+            if (opaque) {
+                wd = window_find_plugin_data(w, plugin_id);
+
+                //glPushMatrix();
+
+                paint_window(w, d, wd, z + 0.05f);
+
+                //glPopMatrix();
+            }
+
+            z -= 0.1f;
+        }
+    }
+
     paint_root(sc, d);
 
+    glEnable(GL_BLEND);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
     for (it = list_bottom(sc->stacking); it; it = it->prev) {
         d_window_t *w = it->data;
 
@@ -516,6 +621,8 @@ glxrender_paint(d_screen_t *sc)
             int x, y, width, height, bwidth;
             gboolean opaque;
             window_data_t *wd;
+            uint16_t opac;
+            GLfloat alpha;
 
             window_get_area(w, &x, &y, &width, &height, &bwidth);
 
@@ -527,22 +634,37 @@ glxrender_paint(d_screen_t *sc)
                 continue;
             }
 
-            opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
+            opac = window_get_opacity(w);
+            opaque = !window_is_argb(w) && opac == 0xffff;
 
             wd = window_find_plugin_data(w, plugin_id);
 
-            glPushMatrix();
+            //glPushMatrix();
+
+            /* black shadow */
+            alpha = d->shadowalpha;
+            alpha *= opac;
+            alpha /= 0xffff;
+            if (alpha >= 0.01) {
+                glColor4f(0.0f, 0.0f, 0.0f, alpha);
+                paint_shadow(d, wd, z);
+            }
 
-            glTranslatef(d->xshadowoff, d->yshadowoff, 0.0f);
-            paint_shadow(w, d, wd, x, y);
+            if (!opaque) {
+                glColor4us(opac, opac, opac, opac);
+                paint_window(w, d, wd, z + 0.05f);
+            }
 
-            glTranslatef(-d->xshadowoff, -d->yshadowoff, 0.0f);
-            paint_window(w, d, wd, opaque, x, y);
+            //glPopMatrix();
 
-            glPopMatrix();
+            z += 0.1f;
         }
     }
 
+    glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glDisable(GL_BLEND);
+
     //xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
     glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
 
@@ -556,28 +678,24 @@ paint_root(d_screen_t *sc, data_t *d)
     if (!d->root_glpixmap)
         glxrender_update_root_pixmap(sc, d);
 
-    glClear(GL_COLOR_BUFFER_BIT);
-
     glBindTexture(GL_TEXTURE_2D, d->root_texname);
     glBegin(GL_QUADS);
     glTexCoord2f(0, 0);
-    glVertex2i(0, 0);
+    glVertex3i(0, 0, 0);
     glTexCoord2f(1, 0);
-    glVertex2i(sc->super->width_in_pixels, 0);
+    glVertex3i(sc->super->width_in_pixels, 0, 0);
     glTexCoord2f(1, 1);
-    glVertex2i(sc->super->width_in_pixels, sc->super->height_in_pixels);
+    glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
     glTexCoord2f(0, 1);
-    glVertex2i(0, sc->super->height_in_pixels);
+    glVertex3i(0, sc->super->height_in_pixels, 0);
     glEnd();
 
     glBindTexture(GL_TEXTURE_2D, 0);
 }
 
 static void
-paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque,
-             int x, int y)
+paint_window(d_window_t *w, data_t *d, window_data_t *wd, GLfloat z)
 {
-    uint16_t o = window_get_opacity(w);
     int i;
 
     if (!wd->glpixmap)
@@ -587,73 +705,46 @@ paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque,
 
     glBindTexture(GL_TEXTURE_2D, wd->texname);
 
-    if (!opaque) {
-        glEnable(GL_BLEND);
-
-        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-        glColor4us(o, o, o, o);
-    }
-
     glBegin(GL_QUADS);
     for (i = 0; i < wd->nrects * 4; i += 4) {
-        // XXX use glVertex3i
         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
-        glVertex2i(x + wd->vertices[i+LEFT], y + wd->vertices[i+TOP]);
+        glVertex3f(wd->vertices[i+LEFT], wd->vertices[i+TOP], z);
         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
-        glVertex2i(x + wd->vertices[i+RIGHT], y + wd->vertices[i+TOP]);
+        glVertex3f(wd->vertices[i+RIGHT], wd->vertices[i+TOP], z);
         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
-        glVertex2i(x + wd->vertices[i+RIGHT], y + wd->vertices[i+BOTTOM]);
+        glVertex3f(wd->vertices[i+RIGHT], wd->vertices[i+BOTTOM], z);
         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
-        glVertex2i(x + wd->vertices[i+LEFT], y + wd->vertices[i+BOTTOM]);
+        glVertex3f(wd->vertices[i+LEFT], wd->vertices[i+BOTTOM], z);
     }
     glEnd();
 
     glBindTexture(GL_TEXTURE_2D, 0);
-
-    if (!opaque) {
-        glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
-        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        glDisable(GL_BLEND);
-    }
 }
 
 static void
-paint_shadow(d_window_t *w, data_t *d, window_data_t *wd, int x, int y)
+paint_shadow(data_t *d, window_data_t *wd, GLfloat z)
 {
-    float alpha = d->shadowalpha;
+    int xoff = d->xshadowoff;
+    int yoff = d->yshadowoff;
     int i;
 
     if (wd->nrects < 1) return;
 
-    alpha *= window_get_opacity(w);
-    alpha /= 0xffff;
-
-    if (alpha < 0.01) return;
-
-    glEnable(GL_BLEND);
-    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-    /* black shadow */
-    glColor4f(0.0f, 0.0f, 0.0f, alpha);
-
     /* shape the shadow to the window */
     glBindTexture(GL_TEXTURE_2D, wd->texname);
 
     glBegin(GL_QUADS);
     for (i = 0; i < wd->nrects * 4; i += 4) {
         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
-        glVertex2i(x + wd->vertices[i+LEFT], y + wd->vertices[i+TOP]);
+        glVertex3f(xoff+wd->vertices[i+LEFT], yoff+wd->vertices[i+TOP], z);
         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
-        glVertex2i(x + wd->vertices[i+RIGHT], y + wd->vertices[i+TOP]);
+        glVertex3f(xoff+wd->vertices[i+RIGHT], yoff+wd->vertices[i+TOP], z);
         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
-        glVertex2i(x + wd->vertices[i+RIGHT], y + wd->vertices[i+BOTTOM]);
+        glVertex3f(xoff+wd->vertices[i+RIGHT], yoff+wd->vertices[i+BOTTOM], z);
         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
-        glVertex2i(x + wd->vertices[i+LEFT], y + wd->vertices[i+BOTTOM]);
+        glVertex3f(xoff+wd->vertices[i+LEFT], yoff+wd->vertices[i+BOTTOM], z);
     }
     glEnd();
 
     glBindTexture(GL_TEXTURE_2D, 0);
-
-    glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
-    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-    glDisable(GL_BLEND);
 }