Logo Search packages:      
Sourcecode: beryl-plugins version File versions

blurfx.c

/*
 * Beryl blur and reflection effect plugin
 *
 * blurfx.c
 *
 * Copyright : (C) 2006 by Dennis Kasprzyk
 * E-mail    : onestone@beryl-project.org
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
#include <sys/stat.h>
#include <unistd.h>
#include <beryl.h>
#include <beryl_helpers.h>

#include "blurfx.h"

// return plugin data
CompPluginVTable *getCompPluginInfo(void)
{
      return &blurfxVTable;
}

static Bool blurfxInit(CompPlugin * p)
{
      blurShader[0][0] = gaussian5x5_V;
      blurShader[0][1] = gaussian5x5_H;
      blurShader[1][0] = linear5x5_V;
      blurShader[1][1] = linear5x5_H;

      blurShader[2][0] = gaussian9x9_V;
      blurShader[2][1] = gaussian9x9_H;
      blurShader[3][0] = linear9x9_V;
      blurShader[3][1] = linear9x9_H;

      blurShader[4][0] = gaussian13x13_V;
      blurShader[4][1] = gaussian13x13_H;
      blurShader[5][0] = linear13x13_V;
      blurShader[5][1] = linear13x13_H;

      blurShader[6][0] = gaussian17x17_V;
      blurShader[6][1] = gaussian17x17_H;
      blurShader[7][0] = linear17x17_V;
      blurShader[7][1] = linear17x17_H;

      blurShader[8][0] = gaussian21x21_V;
      blurShader[8][1] = gaussian21x21_H;
      blurShader[9][0] = linear21x21_V;
      blurShader[9][1] = linear21x21_H;

      displayPrivateIndex = allocateDisplayPrivateIndex();
      if (displayPrivateIndex < 0)
            return FALSE;
      return TRUE;
}

static void blurfxFini(CompPlugin * p)
{
      if (displayPrivateIndex >= 0)
            freeDisplayPrivateIndex(displayPrivateIndex);
}

static Bool blurfxInitDisplay(CompPlugin * p, CompDisplay * d)
{
      //Generate a blur display
      BlurfxDisplay *bd = (BlurfxDisplay *) calloc(1, sizeof(BlurfxDisplay));

      //Allocate a private index
      bd->screenPrivateIndex = allocateScreenPrivateIndex(d);
      //Check if its valid
      if (bd->screenPrivateIndex < 0)
      {
            //Its invalid so free memory and return
            free(bd);
            return FALSE;
      }

      blurfxDisplayInitOptions(bd);

      //Record the display
      d->privates[displayPrivateIndex].ptr = bd;
      return TRUE;
}

static void blurfxFiniDisplay(CompPlugin * p, CompDisplay * d)
{
      BLURFX_DISPLAY(d);
      //Free the private index
      freeScreenPrivateIndex(d, bd->screenPrivateIndex);
      //Free the pointer
      free(bd);
}

static Bool blurfxInitScreen(CompPlugin * p, CompScreen * s)
{
      BLURFX_DISPLAY(s->display);
      // Create a blur screen
      BlurfxScreen *bs = (BlurfxScreen *) calloc(1, sizeof(BlurfxScreen));

      s->privates[bd->screenPrivateIndex].ptr = bs;

      bs->blur_supported = TRUE;
      bs->fboBlur_supported = TRUE;
      bs->mblur_supported = TRUE;
      bs->reflection_supported = TRUE;

      // Check for extensions and disable unsupported features
      if (!s->fbo)
      {
            fprintf(stderr,
                        "No framebuffer_object support! (only simple Blur aviable).\n");
            bs->fboBlur_supported = FALSE;
      }
      if (!s->fragmentProgram)
      {
            fprintf(stderr,
                        "No fragment_program support! (only simple Blur aviable).\n");
            bs->fboBlur_supported = FALSE;
      }
      if (!s->textureRectangle)
      {
            fprintf(stderr,
                        "No texture_rectangle support! (Blur effects disabled).\n");
            bs->blur_supported = FALSE;
            bs->fboBlur_supported = FALSE;
            bs->mblur_supported = FALSE;
      }
      if (!s->textureEnvCombine)
      {
            fprintf(stderr,
                        "No texture_env_combine support! (Blur and Reflection effects disabled).\n");
            bs->blur_supported = FALSE;
            bs->fboBlur_supported = FALSE;
            bs->reflection_supported = FALSE;
      }

      // initialize all variables
      bs->windowPrivateIndex = allocateWindowPrivateIndex(s);

      bs->vertArray.vertices = 0;
      bs->vertArray.vCount = 0;
      bs->vertArray.vertexSize = 0;

      bs->screenDamage = XCreateRegion();
      bs->occlusion = XCreateRegion();
      bs->blurredRegion = XCreateRegion();

      bs->mb_activated = FALSE;
      bs->mb_update = TRUE;

      bs->noBlurWMask = 0;
      bs->noReflectionWMask = 0;

      // setup settings
      blurfxScreenInitOptions(bs);

      int i = 0;

      for (i = 0; i < LIST_SIZE(mBlurModes); i++)
            if (strcmp
                  (bs->opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_MODE].value.
                   s, mBlurModes[i]) == 0)
                  bs->mb_mode = i;

      for (i = 0; i < LIST_SIZE(blurShaderNames); i++)
            if (strcmp
                  (bs->opt[BLURFX_SCREEN_OPTION_BLUR_SHADER].value.s,
                   blurShaderNames[i]) == 0)
                  bs->blur_shader = i;

      addScreenAction(s,
                              &bd->opt[BLURFX_DISPLAY_OPTION_MOTION_BLUR_TOGGLE].
                              value.action);

      //Take over the window draw function
      WRAP(bs, s, drawWindowTexture, blurfxDrawWindowTexture);
      WRAP(bs, s, drawWindow, blurfxDrawWindow);
      WRAP(bs, s, damageWindowRect, blurfxDamageWindowRect);
      WRAP(bs, s, paintScreen, blurfxPaintScreen);
      WRAP(bs, s, addWindowGeometry, blurfxAddWindowGeometry);
      WRAP(bs, s, preparePaintScreen, blurfxPreparePaintScreen);
      WRAP(bs, s, paintTransformedScreen, blurfxPaintTransformedScreen);

      damageScreen(s);

      bs->ipcs_disable_blur =
                  IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "DISABLE_BLUR", TRUE);
      bs->ipcs_disable_reflection =
                  IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "DISABLE_REFLECTION",
                                     TRUE);
      bs->ipcs_disable_mblur =
                  IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "DISABLE_MOTION_BLUR",
                                     TRUE);

      return TRUE;
}

static void blurfxFiniScreen(CompPlugin * p, CompScreen * s)
{
      BLURFX_SCREEN(s);
      BLURFX_DISPLAY(s->display);

      // delete shaders
      if (bs->blurShaderV)
            (*s->deletePrograms) (1, &bs->blurShaderV);
      if (bs->blurShaderH)
            (*s->deletePrograms) (1, &bs->blurShaderH);

      // delete the textures
      if (bs->backTex.handle)
            glDeleteTextures(1, &bs->backTex.handle);
      if (bs->motionTex.handle)
            glDeleteTextures(1, &bs->motionTex.handle);
      if (bs->blurTempTexV.handle)
            glDeleteTextures(1, &bs->blurTempTexV.handle);
      if (bs->blurTempTexH.handle)
            glDeleteTextures(1, &bs->blurTempTexH.handle);
      if (bs->modTex.handle)
            glDeleteTextures(1, &bs->modTex.handle);

      // delete framebuffer object
      if (bs->fbo)
      {
            s->deleteFramebuffers(1, &bs->fbo);
      }
      // free some pointers
      free(bs->vertArray.vertices);

      freeWindowPrivateIndex(s, bs->windowPrivateIndex);

      XDestroyRegion(bs->screenDamage);
      XDestroyRegion(bs->occlusion);
      XDestroyRegion(bs->blurredRegion);


      // restore the original function
      UNWRAP(bs, s, drawWindowTexture);
      UNWRAP(bs, s, drawWindow);
      UNWRAP(bs, s, damageWindowRect);
      UNWRAP(bs, s, paintScreen);
      UNWRAP(bs, s, addWindowGeometry);
      UNWRAP(bs, s, preparePaintScreen);
      UNWRAP(bs, s, paintTransformedScreen);

      removeScreenAction(s,
                                 &bd->
                                 opt[BLURFX_DISPLAY_OPTION_MOTION_BLUR_TOGGLE].
                                 value.action);

      // free the screen pointer
      free(bs);

}

static Bool blurfxInitWindow(CompPlugin * p, CompWindow * w)
{
      BlurfxWindow *bw;

      BLURFX_SCREEN(w->screen);

      // create window
      bw = calloc(1, sizeof(BlurfxWindow));
      if (!bw)
            return FALSE;

      // initialize variables
      bw->my_next = w->next;
      bw->lastX = w->attrib.x;
      bw->lastY = w->attrib.y;
      bw->lastPAttrib = w->lastPaint;
      bw->decoArray.vertices = NULL;
      bw->decoArray.indices = NULL;
      bw->decoArray.vCount = 0;
      bw->decoArray.vertexSize = 0;
      bw->decoArray.indexSize = 0;
      bw->decoArray.indexCount = 0;
      bw->paintRegion = XCreateRegion();
      bw->damageRegion = XCreateRegion();
      bw->texDamage = XCreateRegion();
      bw->bTexRegion = XCreateRegion();
      bw->clip = XCreateRegion();
      bw->hasTexture = FALSE;
      bw->vertArray.vertices = 0;
      bw->vertArray.vCount = 0;
      bw->vertArray.vertexSize = 0;
      bw->isSwitcher = FALSE;

      Atom type;
      int format;
      unsigned long nitems;
      unsigned long bytes_after;
      Window *xw;

      int result = XGetWindowProperty(w->screen->display->display, w->id,
                                                      XInternAtom(w->screen->display->display,
                                                                        "_SWITCH_SELECT_WINDOW",
                                                                        0),
                                                      0L, 1L,
                                                      False, XA_WINDOW, &type, &format,
                                                      &nitems,
                                                      &bytes_after, (void *)&xw);

      if (result == Success && type == XA_WINDOW)
            bw->isSwitcher = TRUE;

      w->privates[bs->windowPrivateIndex].ptr = bw;

      damageScreen(w->screen);

      bw->ipcs_disable_blur =
                  IPCS_GetAtom(IPCS_OBJECT(w), IPCS_BOOL, "DISABLE_BLUR", TRUE);
      bw->ipcs_disable_reflection =
                  IPCS_GetAtom(IPCS_OBJECT(w), IPCS_BOOL, "DISABLE_REFLECTION",
                                     TRUE);

      return TRUE;
}

static void blurfxFiniWindow(CompPlugin * p, CompWindow * w)
{
      BLURFX_WINDOW(w);

      // free regions
      XDestroyRegion(bw->paintRegion);
      XDestroyRegion(bw->damageRegion);
      XDestroyRegion(bw->texDamage);
      XDestroyRegion(bw->bTexRegion);
      XDestroyRegion(bw->clip);

      // delete blur cache texture
      if (bw->hasTexture)
            glDeleteTextures(1, &bw->blurTex.handle);

      // free used memory
      if (bw->decoArray.vertices)
            free(bw->decoArray.vertices);
      if (bw->decoArray.indices)
            free(bw->decoArray.indices);
      if (bw->vertArray.vertices)
            free(bw->vertArray.vertices);

      // free window pointer
      free(bw);
}

static CompOption *blurfxGetDisplayOptions(CompDisplay * display, int *count)
{
      if (display)
      {
            BLURFX_DISPLAY(display);

            *count = NUM_OPTIONS(bd);
            return bd->opt;
      }
      else
      {
            BlurfxDisplay *bd =
                        (BlurfxDisplay *) calloc(1, sizeof(BlurfxDisplay));
            blurfxDisplayInitOptions(bd);
            *count = NUM_OPTIONS(bd);
            return bd->opt;
      }
}

static Bool
blurfxSetDisplayOption(CompDisplay * display, char *name,
                                 CompOptionValue * value)
{
      CompOption *o;
      int index;

      BLURFX_DISPLAY(display);

      o = compFindOption(bd->opt, NUM_OPTIONS(bd), name, &index);
      if (!o)
            return FALSE;

      switch (index)
      {
      case BLURFX_DISPLAY_OPTION_MOTION_BLUR_TOGGLE:
            if (setDisplayAction(display, o, value))
                  return TRUE;
            break;
      default:
            break;
      }

      return FALSE;
}

static void blurfxDisplayInitOptions(BlurfxDisplay * bd)
{
      CompOption *o;

      o = &bd->opt[BLURFX_DISPLAY_OPTION_MOTION_BLUR_TOGGLE];
      o->advanced = False;
      o->name = "motion_blur_toggle";
      o->group = N_("Motion Blur");
      o->subGroup = N_("Activate");
      o->displayHints = "";
      o->shortDesc = N_("Toggle Motion Blur");
      o->longDesc = N_("Toggle motion Blur effect.");
      o->type = CompOptionTypeAction;
      o->value.action.initiate = blurfxToggleMotionBlur;
      o->value.action.terminate = 0;
      o->value.action.bell = FALSE;
      o->value.action.edgeMask = 0;
      o->value.action.type = CompBindingTypeKey;
      o->value.action.state = CompActionStateInitKey;
      o->value.action.key.modifiers =
                  BLURFX_DISPLAY_OPTION_MOTION_BLUR_TOGGLE_MOD_DEFAULT;
      o->value.action.key.keysym =
                  XStringToKeysym
                  (BLURFX_DISPLAY_OPTION_MOTION_BLUR_TOGGLE_KEY_DEFAULT);
}


static Bool
blurfxSetScreenOption(CompScreen * s, char *name, CompOptionValue * value)
{
      CompOption *o;
      int index;

      BLURFX_SCREEN(s);

      o = compFindOption(bs->opt, NUM_OPTIONS(bs), name, &index);
      if (!o)
            return FALSE;

      switch (index)
      {
      case BLURFX_SCREEN_OPTION_BLUR_WINDOWS:
      case BLURFX_SCREEN_OPTION_BLUR_DECORATION:
      case BLURFX_SCREEN_OPTION_REFLECTION_WINDOWS:
      case BLURFX_SCREEN_OPTION_REFLECTION_DECORATION:
      case BLURFX_SCREEN_OPTION_BLUR_ON_TRANSFORMED_SCREEN:
      case BLURFX_SCREEN_OPTION_BLUR_TRANSFORMED_WINDOW:
      case BLURFX_SCREEN_OPTION_REFLECTION_ON_TRANSFORMED_SCREEN:
      case BLURFX_SCREEN_OPTION_REFLECTION_TRANSFORMED_WINDOW:
      case BLURFX_SCREEN_OPTION_REFLECTION_SCALE:
      case BLURFX_SCREEN_OPTION_REFLECTION_PROPORTIONAL:
      case BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_TRANSFORMED_SCREEN:
      case BLURFX_SCREEN_OPTION_DISABLE_DECORATION_ALPHADEP:
      case BLURFX_SCREEN_OPTION_NO_BLUR_CACHE_ON_TRANSFORMED_SCREEN:
            if (compSetBoolOption(o, value))
            {
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_BLUR_CACHE_TEXTURES:
            if (compSetBoolOption(o, value))
            {
                  if (!value->b)
                  {
                        CompWindow *w;

                        for (w = s->windows; w; w = w->next)
                        {
                              BLURFX_WINDOW(w);
                              if (bw->hasTexture)
                              {
                                    bw->hasTexture = FALSE;
                                    glDeleteTextures(1, &bw->blurTex.handle);
                                    bw->blurTex.handle = 0;
                              }
                        }
                  }
                  damageScreen(s);
                  return TRUE;
            }
            break;

      case BLURFX_SCREEN_OPTION_BLUR_SHADER:
            if (compSetStringOption(o, value))
            {
                  int i = 0;

                  for (i = 0; i < LIST_SIZE(blurShaderNames); i++)
                        if (strcmp(value->s, blurShaderNames[i]) == 0)
                              bs->blur_shader = i;

                  if (bs->fboBlur_supported && bs->hasInit
                        && !bs->opt[BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR].value.b)
                  {
                        loadShader(GL_FRAGMENT_PROGRAM_ARB, s,
                                       &bs->blurShaderV, blurShader[bs->blur_shader][0]);
                        loadShader(GL_FRAGMENT_PROGRAM_ARB, s,
                                       &bs->blurShaderH, blurShader[bs->blur_shader][1]);
                        damageScreen(s);
                        CompWindow *w;

                        for (w = s->windows; w; w = w->next)
                        {
                              BLURFX_WINDOW(w);
                              if (bw->hasTexture)
                              {
                                    bw->hasTexture = FALSE;
                                    glDeleteTextures(1, &bw->blurTex.handle);
                                    bw->blurTex.handle = 0;
                              }
                        }
                  }
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF:
      case BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_ON_SCREENGRAB_OF:
      case BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_SCREENGRAB_OF:
            if (compSetOptionList(o, value))
            {
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_REFLECTION_FILE:
            if (compSetStringOption(o, value))
            {
                  if (bs->reflection_supported)
                  {
                        loadPngToTexture2D(s, &bs->modTex, value->s);
                        damageScreen(s);
                  }
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_COLOR:
      case BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_ALPHA:
            if (compSetBoolOption(o, value))
            {
                  if (bs->reflection_supported)
                  {
                        loadPngToTexture2D(s, &bs->modTex,
                                                   bs->
                                                   opt
                                                   [BLURFX_SCREEN_OPTION_REFLECTION_FILE].
                                                   value.s);
                        damageScreen(s);
                  }
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_BLUR_SATURATION:
      case BLURFX_SCREEN_OPTION_MOTION_BLUR_STRENGTH:
            if (compSetFloatOption(o, value))
            {
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_DISABLE_BLUR_WINDOW_TYPE:
            if (compSetOptionList(o, value))
            {
                  bs->noBlurWMask = compWindowTypeMaskFromStringList(&o->value);
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_WINDOW_TYPE:
            if (compSetOptionList(o, value))
            {
                  bs->noReflectionWMask =
                              compWindowTypeMaskFromStringList(&o->value);
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_MOTION_BLUR_MODE:
            if (compSetStringOption(o, value))
            {
                  int i;

                  for (i = 0; i < LIST_SIZE(mBlurModes); i++)
                        if (strcmp(value->s, mBlurModes[i]) == 0)
                              bs->mb_mode = i;

                  if (bs->hasInit && bs->mblur_supported && bs->motionTex.handle)
                  {
                        glDeleteTextures(1, &bs->motionTex.handle);
                        bs->motionTex.handle = 0;
                  }
                  if (bs->hasInit && bs->mblur_supported
                        && (bs->mb_mode == 0 || bs->mb_mode == 2))
                  {
                        genBlurTexture(bs, &bs->motionTex,
                                             s->width, s->height, bs->mb_mode);
                  }
                  bs->mb_update = TRUE;
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR:
            if (compSetBoolOption(o, value))
            {
                  if (!bs->hasInit)
                        return TRUE;

                  if (bs->fboBlur_supported && !value->b)
                  {
                        // load shaders
                        loadShader(GL_FRAGMENT_PROGRAM_ARB, s,
                                       &bs->blurShaderV, blurShader[bs->blur_shader][0]);
                        loadShader(GL_FRAGMENT_PROGRAM_ARB, s,
                                       &bs->blurShaderH, blurShader[bs->blur_shader][1]);
                        bs->downSample = 1.0;
                  }
                  CompWindow *w;

                  for (w = s->windows; w; w = w->next)
                  {
                        BLURFX_WINDOW(w);
                        if (bw->hasTexture)
                        {
                              bw->hasTexture = FALSE;
                              glDeleteTextures(1, &bw->blurTex.handle);
                              bw->blurTex.handle = 0;
                        }
                  }
                  damageScreen(s);
                  return TRUE;
            }
            break;
      case BLURFX_SCREEN_OPTION_NON_FBO_BLUR_STRENGTH:
            if (compSetIntOption(o, value))
            {
                  if (!bs->hasInit)
                        return TRUE;

                  if (!bs->fboBlur_supported
                        || bs->opt[BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR].value.b)
                  {
                        bs->downSample =
                                    bs->
                                    opt[BLURFX_SCREEN_OPTION_NON_FBO_BLUR_STRENGTH].value.
                                    i;
                        CompWindow *w;

                        for (w = s->windows; w; w = w->next)
                        {
                              BLURFX_WINDOW(w);
                              if (bw->hasTexture)
                              {
                                    bw->hasTexture = FALSE;
                                    glDeleteTextures(1, &bw->blurTex.handle);
                                    bw->blurTex.handle = 0;
                              }
                        }
                  }
                  damageScreen(s);
                  return TRUE;
            }
            break;
      default:
            break;
      }
      return FALSE;
}

static CompOption *blurfxGetScreenOptions(CompScreen * s, int *count)
{
      if (s)
      {
            BLURFX_SCREEN(s);

            *count = NUM_OPTIONS(bs);
            return bs->opt;
      }
      else
      {
            BlurfxScreen *bs = (BlurfxScreen *) calloc(1, sizeof(BlurfxScreen));

            blurfxScreenInitOptions(bs);
            *count = NUM_OPTIONS(bs);
            return bs->opt;
      }
}

static void blurfxScreenInitOptions(BlurfxScreen * bs)
{
      CompOption *o;
      int i;

      o = &bs->opt[BLURFX_SCREEN_OPTION_BLUR_DECORATION];
      o->advanced = False;
      o->name = "blur_decoration";
      o->group = N_("Blur");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Blur Decorations");
      o->longDesc = N_("Blur behind decorations.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_BLUR_DECORATION_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_BLUR_WINDOWS];
      o->advanced = False;
      o->name = "blur_windows";
      o->group = N_("Blur");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Blur Windows");
      o->longDesc = N_("Blur behind windows.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_BLUR_WINDOWS_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_DECORATION];
      o->advanced = False;
      o->name = "reflection_decoration";
      o->group = N_("Reflection");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Reflection for Decorations");
      o->longDesc = N_("Draw Reflection for decorations.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_REFLECTION_DECORATION_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_WINDOWS];
      o->advanced = False;
      o->name = "reflection_windows";
      o->group = N_("Reflection");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Reflection for Windows");
      o->longDesc = N_("Draw Reflection for windows.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_REFLECTION_WINDOWS_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_BLUR_ON_TRANSFORMED_SCREEN];
      o->advanced = False;
      o->name = "blur_transformed_screen";
      o->group = N_("Blur");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Blur on Transformed Screen");
      o->longDesc = N_("Draw Blur if the screen is transformed.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_BLUR_ON_TRANSFORMED_SCREEN_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_BLUR_TRANSFORMED_WINDOW];
      o->advanced = False;
      o->name = "blur_transformed_window";
      o->group = N_("Blur");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Blur Transformed Windows");
      o->longDesc = N_("Draw Blur if window is transformed.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_BLUR_TRANSFORMED_WINDOW_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_BLUR_SHADER];
      o->advanced = False;
      o->name = "blur_shader";
      o->group = N_("Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Blur Shader");
      o->longDesc = N_("Blur shader.");
      o->type = CompOptionTypeString;
      o->value.s = strdup(BLURFX_SCREEN_OPTION_BLUR_SHADER_DEFAULT);
      o->rest.s.string = blurShaderNames;
      o->rest.s.nString = LIST_SIZE(blurShaderNames);

      o = &bs->opt[BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR];
      o->advanced = False;
      o->name = "force_non_fbo_blur";
      o->group = N_("Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Force non FBO Blur");
      o->longDesc = N_("Force non FBO Blur.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_NON_FBO_BLUR_STRENGTH];
      o->advanced = False;
      o->name = "non_fbo_blur_strength";
      o->group = N_("Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Non FBO Blur Strength");
      o->longDesc = N_("Non FBO mode Blur strength.");
      o->type = CompOptionTypeInt;
      o->value.i = BLURFX_SCREEN_OPTION_NON_FBO_BLUR_STRENGTH_DEFAULT;
      o->rest.i.min = 2;
      o->rest.i.max = 12;

      o = &bs->opt[BLURFX_SCREEN_OPTION_BLUR_CACHE_TEXTURES];
      o->advanced = False;
      o->name = "blur_cache";
      o->group = N_("Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Use Blur Cache");
      o->longDesc = N_("Enables Blur cache texture system.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_BLUR_CACHE_TEXTURES_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_NO_BLUR_CACHE_ON_TRANSFORMED_SCREEN];
      o->advanced = False;
      o->name = "no_cache_when_transformed";
      o->group = N_("Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Disable Blur Cache on Transformed Screen");
      o->longDesc = N_("Disables Blur cache on transformed screen.");
      o->type = CompOptionTypeBool;
      o->value.b =
                  BLURFX_SCREEN_OPTION_NO_BLUR_CACHE_ON_TRANSFORMED_SCREEN_DEFAULT;


      o = &bs->opt[BLURFX_SCREEN_OPTION_DISABLE_DECORATION_ALPHADEP];
      o->advanced = False;
      o->name = "disable_deco_alpha_dep";
      o->group = N_("Blur");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Disable Decoration Alpha Dependency");
      o->longDesc = N_("Disable decoration alpha dependency.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_DISABLE_DECORATION_ALPHADEP_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF];
      o->advanced = False;
      o->name = "disable_blur_on_screengrab_of";
      o->group = N_("Blur");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Disable Blur on ScreenGrab");
      o->longDesc =
                  N_
                  ("Disable drawing of Blur when an other plugin grabs the input.");
      o->type = CompOptionTypeList;
      o->value.list.type = CompOptionTypeString;
      o->value.list.nValue = LIST_SIZE(blurDisable);
      o->value.list.value =
                  malloc(sizeof(CompOptionValue) * LIST_SIZE(blurDisable));
      for (i = 0; i < LIST_SIZE(blurDisable); i++)
            o->value.list.value[i].s = strdup(blurDisable[i]);

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_ON_TRANSFORMED_SCREEN];
      o->advanced = False;
      o->name = "reflection_transformed_screen";
      o->group = N_("Reflection");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Reflection on Transformed Screen");
      o->longDesc = N_("Draw Reflection if the screen is transformed.");
      o->type = CompOptionTypeBool;
      o->value.b =
                  BLURFX_SCREEN_OPTION_REFLECTION_ON_TRANSFORMED_SCREEN_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_TRANSFORMED_WINDOW];
      o->advanced = False;
      o->name = "reflection_transformed_window";
      o->group = N_("Reflection");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Reflection Transformed Windows");
      o->longDesc = N_("Draw Reflection if the window is transformed.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_REFLECTION_TRANSFORMED_WINDOW_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_ON_SCREENGRAB_OF];
      o->advanced = False;
      o->name = "disable_reflection_on_screengrab_of";
      o->group = N_("Reflection");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Disable Reflection on ScreenGrab");
      o->longDesc =
                  N_
                  ("Disable drawing of Reflection when an other plugin grabs the input.");
      o->type = CompOptionTypeList;
      o->value.list.type = CompOptionTypeString;
      o->value.list.nValue = 0;
      o->value.list.value = NULL;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_FILE];
      o->advanced = False;
      o->name = "reflection_file";
      o->group = N_("Reflection");
      o->subGroup = N_("Image");
      o->displayHints = "file;image;pngonly;";
      o->shortDesc = N_("Reflection Image File");
      o->longDesc = N_("Reflection image file.");
      o->type = CompOptionTypeString;
      o->value.s = strdup(BLURFX_SCREEN_OPTION_REFLECTION_FILE_DEFAULT);
      o->rest.s.string = 0;
      o->rest.s.nString = 0;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_SCALE];
      o->advanced = False;
      o->name = "reflection_scale";
      o->group = N_("Reflection");
      o->subGroup = N_("Image");
      o->displayHints = "";
      o->shortDesc = N_("Scale Reflection");
      o->longDesc = N_("Scale Reflection image.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_REFLECTION_SCALE_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_PROPORTIONAL];
      o->advanced = False;
      o->name = "reflection_proportional";
      o->group = N_("Reflection");
      o->subGroup = N_("Image");
      o->displayHints = "";
      o->shortDesc = N_("Scale Proportionally");
      o->longDesc = N_("Scale Reflection proportionally.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_REFLECTION_PROPORTIONAL_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_COLOR];
      o->advanced = False;
      o->name = "reflection_use_image_colors";
      o->group = N_("Reflection");
      o->subGroup = N_("Image");
      o->displayHints = "";
      o->shortDesc = N_("Use Image Colors");
      o->longDesc = N_("Do not generate grayscale Reflection.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_COLOR_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_ALPHA];
      o->advanced = False;
      o->name = "reflection_use_image_alpha";
      o->group = N_("Reflection");
      o->subGroup = N_("Image");
      o->displayHints = "";
      o->shortDesc = N_("Use Image Alpha");
      o->longDesc = N_("Use image alpha channel.");
      o->type = CompOptionTypeBool;
      o->value.b = BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_ALPHA_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_MODE];
      o->advanced = False;
      o->name = "motion_blur_mode";
      o->group = N_("Motion Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Motion Blur Mode");
      o->longDesc =
                  N_
                  ("Motion Blur mode: simple = uses texture copy and blending; accum = "
                   "uses gl accumulation buffer; fbo = uses framebuffer objects and float texture.");
      o->type = CompOptionTypeString;
      o->value.s = strdup(BLURFX_SCREEN_OPTION_MOTION_BLUR_MODE_DEFAULT);
      o->rest.s.string = mBlurModes;
      o->rest.s.nString = LIST_SIZE(mBlurModes);

      o = &bs->opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_SCREENGRAB_OF];
      o->advanced = False;
      o->name = "motion_blur_on_screengrab_of";
      o->group = N_("Motion Blur");
      o->subGroup = N_("Activate");
      o->displayHints = "";
      o->shortDesc = N_("Blur on ScreenGrab");
      o->longDesc = N_("Activate Motion Blur on screengrab.");
      o->type = CompOptionTypeList;
      o->value.list.type = CompOptionTypeString;
      o->value.list.nValue = 0;
      o->value.list.value = NULL;

      o = &bs->opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_TRANSFORMED_SCREEN];
      o->advanced = False;
      o->name = "motion_blur_on_transformed_screen";
      o->group = N_("Motion Blur");
      o->subGroup = N_("Activate");
      o->displayHints = "";
      o->shortDesc = N_("Motion Blur on Transformed Screen");
      o->longDesc = N_("Execute Motion Blur if the screen is transformed.");
      o->type = CompOptionTypeBool;
      o->value.b =
                  BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_TRANSFORMED_SCREEN_DEFAULT;

      o = &bs->opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_STRENGTH];
      o->advanced = False;
      o->name = "motion_blur_strength";
      o->group = N_("Motion Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Motion Blur Strength");
      o->longDesc = N_("Motion Blur strength.");
      o->type = CompOptionTypeFloat;
      o->value.f = BLURFX_SCREEN_OPTION_MOTION_BLUR_STRENGTH_DEFAULT;
      o->rest.f.min = 0.0;
      o->rest.f.max = 100.0;
      o->rest.f.precision = 0.01;

      o = &bs->opt[BLURFX_SCREEN_OPTION_DISABLE_BLUR_WINDOW_TYPE];
      o->advanced = False;
      o->name = "disable_blur_window_types";
      o->group = N_("Blur");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Disable Blur Window Types");
      o->longDesc = N_("Window types that Blur shouldn't affect.");
      o->type = CompOptionTypeList;
      o->value.list.type = CompOptionTypeString;
      o->value.list.nValue = 0;
      o->value.list.value = NULL;
      o->rest.s.string = (char **)windowTypeString;
      o->rest.s.nString = nWindowTypeString;

      o = &bs->opt[BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_WINDOW_TYPE];
      o->advanced = False;
      o->name = "disable_reflection_window_types";
      o->group = N_("Reflection");
      o->subGroup = N_("Special cases");
      o->displayHints = "";
      o->shortDesc = N_("Disable Reflection Window Types");
      o->longDesc = N_("Window types that Reflection shouldn't affect.");
      o->type = CompOptionTypeList;
      o->value.list.type = CompOptionTypeString;
      o->value.list.nValue = 0;
      o->value.list.value = NULL;
      o->rest.s.string = (char **)windowTypeString;
      o->rest.s.nString = nWindowTypeString;

      o = &bs->opt[BLURFX_SCREEN_OPTION_BLUR_SATURATION];
      o->advanced = False;
      o->name = "blur_saturation";
      o->group = N_("Blur");
      o->subGroup = N_("Visibility/Performance");
      o->displayHints = "";
      o->shortDesc = N_("Blur Saturation");
      o->longDesc = N_("Blur saturation.");
      o->type = CompOptionTypeFloat;
      o->value.f = BLURFX_SCREEN_OPTION_BLUR_SATURATION_DEFAULT;
      o->rest.f.min = 0.0;
      o->rest.f.max = 100.0;
      o->rest.f.precision = 0.1;

      o = &bs->opt[BLURFX_SCREEN_OPTION_WARNING];
      o->advanced = False;
      o->name = "warning";
      o->group = N_("Warning");
      o->subGroup = N_("");
      o->displayHints = "";
      o->shortDesc = N_("Warning: NVidia users experiencing the black window bug should disable Blur");
      o->longDesc = N_("Warning: NVidia users experiencing the black window bug should disable Blur.");
      o->type = CompOptionTypeBool;
      o->value.f = TRUE;


}

static void blurfxPreparePaintScreen(CompScreen * s, int ms)
{
      BLURFX_SCREEN(s);
      Bool mba = FALSE;
      int i;

      // activate motion blur on desired screen grab
      for (i = 0;
             i <
             bs->opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_SCREENGRAB_OF].
             value.list.nValue; i++)
      {
            mba |= screenGrabExist(s,
                                             bs->
                                             opt
                                             [BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_SCREENGRAB_OF].
                                             value.list.value[i].s, 0);
      }

      bs->motion_blur_active |= bs->mb_activated;
      bs->motion_blur_active |= mba;

      bs->motion_blur_active &= bs->mblur_supported;

      // fade motion blur out if no longer active
      if (mba || bs->mb_activated)
      {
            bs->mb_timer = 500;
      }
      else
      {
            bs->mb_timer -= ms;
      }

      // calculate motion blur strength dependent on framerate
      float val = 101 - MIN(100, MAX(1, ms));

      float a_val =
                  (bs->opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_STRENGTH].value.f /
                   20.0);
      a_val = a_val * a_val;
      a_val /= 100.0;

      bs->mb_alpha = 1.0 - pow(a_val, 1.0 / val);

      if (bs->motion_blur_active && bs->mb_timer <= 0)
            damageScreen(s);

      if (bs->mb_timer <= 0)
      {
            bs->motion_blur_active = FALSE;
      }
      if (bs->mb_update && bs->motion_blur_active)
            damageScreen(s);

      UNWRAP(bs, s, preparePaintScreen);
      (*s->preparePaintScreen) (s, ms);
      WRAP(bs, s, preparePaintScreen, blurfxPreparePaintScreen);
}


static Bool
blurfxPaintScreen(CompScreen * s, const ScreenPaintAttrib * sa,
                          Region region, int output, unsigned int mask)
{

      Bool status, blur_fbo;

      BLURFX_SCREEN(s);

      int i;
      Region bigregion = XCreateRegion();
      XRectangle rect;

      bs->fboActive = FALSE;

      bs->realPaintRegion = region;

      bs->output = output;

      // blur needs bigger repaint regions
      for (i = 0; i < region->numRects; i++)
      {
            rect.x = region->rects[i].x1 - 7;
            rect.y = region->rects[i].y1 - 7;
            rect.width = region->rects[i].x2 - rect.x + 14;
            rect.height = region->rects[i].y2 - rect.y + 14;

            XUnionRectWithRegion(&rect, bigregion, bigregion);
      }

      //Initiliaze the screen if ith hasnt beens
      if (bs->hasInit != 1)
      {
            initBlurfxScreen(bs, s->width, s->height, s);
      }
      // clear screen damage region
      XUnionRegion(getEmptyRegion(), getEmptyRegion(), bs->screenDamage);

      // enable blur if needed
      blur_fbo = bs->blur_supported && bs->fboBlur_supported
                  && !bs->opt[BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR].value.b;
      blur_fbo &= bs->opt[BLURFX_SCREEN_OPTION_BLUR_DECORATION].value.b
                  || bs->opt[BLURFX_SCREEN_OPTION_BLUR_WINDOWS].value.b;

      if (!bs->opt[BLURFX_SCREEN_OPTION_BLUR_ON_TRANSFORMED_SCREEN].value.b)
            blur_fbo &= !(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);

      for (i = 0;
             i <
             bs->opt[BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF].
             value.list.nValue; i++)
      {
            blur_fbo &=
                        !screenGrabExist(s,
                                                 bs->
                                                 opt
                                                 [BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF].
                                                 value.list.value[i].s, 0);
      }

      bs->od_active = FALSE;

      // calculate occluted regions
      if (bs->opt[BLURFX_SCREEN_OPTION_BLUR_DECORATION].value.b
            || bs->opt[BLURFX_SCREEN_OPTION_BLUR_WINDOWS].value.b
            || bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_WINDOWS].value.b)
      {
            bs->mode = MODE_OCCLUSION;
            bs->od_active = TRUE;
            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bs->occlusion);
            CompWindow *w;

            for (w = s->reverseWindows; w; w = w->prev)
            {
                  BLURFX_WINDOW(w);
                  if (w->destroyed)
                        continue;

                  if (w->state & CompWindowStateOffscreenMask)
                        continue;

                  if (!w->shaded)
                  {
                        if (w->attrib.map_state != IsViewable || !w->damaged)
                              continue;
                  }
                  XUnionRegion(bs->occlusion, getEmptyRegion(), bw->clip);
                  (*s->drawWindow) (w, &w->paint, &s->region,
                                            PAINT_WINDOW_SOLID_MASK);
            }
      }

      bs->mode = MODE_NORMAL;

      Bool splash = IPCS_GetBoolND(IPCS_OBJECT(s), "SPLASH_IS_ACTIVE", FALSE);

      blur_fbo &= !DISABLE_FEATURE(s, bs->ipcs_disable_blur);
      blur_fbo &= !splash;
      bs->motion_blur_active &= !DISABLE_FEATURE(s, bs->ipcs_disable_mblur);
      bs->motion_blur_active &= !splash;

      if (!bs->motion_blur_active)
            bs->mb_update = TRUE;

      Bool enable_scissor = FALSE;

      // store the projection matrix
      glGetFloatv(GL_PROJECTION_MATRIX, bs->pm);

      if ((blur_fbo || (bs->motion_blur_active && bs->mb_mode == 2)) && s->fbo)
      {

            float ModelView[16];

            glGetFloatv(GL_MODELVIEW_MATRIX, ModelView);


            // redirect all drawing operations into background texture
            Bool fbo_ok = bindFbo(s, bs->backTex);

            glMatrixMode(GL_PROJECTION);
            glLoadMatrixf(bs->pm);
            glMatrixMode(GL_MODELVIEW);
            glLoadMatrixf(ModelView);

            // paint the screen into fbo
            UNWRAP(bs, s, paintScreen);
            status = (*s->paintScreen) (s, sa, bigregion, output, mask);
            WRAP(bs, s, paintScreen, blurfxPaintScreen);

            unbindFbo(s);

            if (fbo_ok)
            {

                  if (bs->motion_blur_active && bs->mb_mode == 2
                        && output + 1 == s->nOutputDev)
                  {

                        // blend actual screen into motion blur texture
                        if (glIsEnabled(GL_SCISSOR_TEST))
                        {
                              glDisable(GL_SCISSOR_TEST);
                              enable_scissor = TRUE;
                        }
                        glPushAttrib(GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT);
                        GLERR;
                        bindFbo(s, bs->motionTex);
                        glPushMatrix();
                        glLoadIdentity();
                        glViewport(0, 0, s->width, s->height);
                        glTranslatef(-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
                        glScalef(1.0f / s->width, -1.0f / s->height, 1.0f);
                        glTranslatef(0.0f, -s->height, 0.0f);

                        if (bs->mb_update)
                        {
                              glClearColor(1.0, 1.0, 1.0, 1.0);
                              glClear(GL_COLOR_BUFFER_BIT);
                              glDisable(GL_BLEND);
                        }
                        else
                              glEnable(GL_BLEND);

                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                        bs->mb_alpha =
                                    (bs->mb_timer / 500.0) * bs->mb_alpha + (1.0 -
                                                                                                 (bs->
                                                                                                  mb_timer
                                                                                                  / 500.0)) *
                                    0.5;
                        bs->mb_alpha = MIN(1.0, bs->mb_alpha);
                        glColor4f(1, 1, 1, (bs->mb_update) ? 1.0 : bs->mb_alpha);
                        enableBlurfxTexture(&bs->backTex, COMP_TEXTURE_FILTER_FAST);

                        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

                        glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
                        glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
                        glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

                        glBegin(GL_QUADS);
                        glTexCoord2f(0, bs->backTex.height);
                        glVertex2f(0, 0);
                        glTexCoord2f(0, 0);
                        glVertex2f(0, bs->backTex.height);
                        glTexCoord2f(bs->backTex.width, 0);
                        glVertex2f(bs->backTex.width, bs->backTex.height);
                        glTexCoord2f(bs->backTex.width, bs->backTex.height);
                        glVertex2f(bs->backTex.width, 0);

                        glEnd();

                        glDisable(GL_BLEND);

                        glPopMatrix();
                        unbindFbo(s);

                        // paint motion blur texture
                        glPushMatrix();
                        glLoadIdentity();
                        glViewport(0, 0, s->width, s->height);
                        glTranslatef(-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
                        glScalef(1.0f / s->width, -1.0f / s->height, 1.0f);
                        glTranslatef(0.0f, -s->height, 0.0f);

                        glColor4f(1.0, 1.0, 1.0, 1.0);

                        switchBlurfxTexture(&bs->backTex, &bs->motionTex,
                                                      COMP_TEXTURE_FILTER_FAST);

                        glBegin(GL_QUADS);
                        glTexCoord2f(0, bs->backTex.height);
                        glVertex2f(0, 0);
                        glTexCoord2f(0, 0);
                        glVertex2f(0, bs->backTex.height);
                        glTexCoord2f(bs->backTex.width, 0);
                        glVertex2f(bs->backTex.width, bs->backTex.height);
                        glTexCoord2f(bs->backTex.width, bs->backTex.height);
                        glVertex2f(bs->backTex.width, 0);

                        glEnd();

                        disableBlurfxTexture(&bs->motionTex);

                        glPopMatrix();
                        glViewport(s->outputDev[bs->output].region.extents.
                                       x1,
                                       s->height -
                                       s->outputDev[bs->output].region.extents.
                                       y2, s->outputDev[bs->output].width,
                                       s->outputDev[bs->output].height);

                        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
                        glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);

                        glPopAttrib();
                        GLERR;

                        bs->mb_update = FALSE;
                        damageScreen(s);

                  }
                  else
                  {

                        glPushMatrix();
                        glLoadIdentity();
                        prepareXCoords(s, output, -DEFAULT_Z_CAMERA);

                        // draw background texture
                        int stride;
                        CompMatrix mat;

                        mat.xx = 1.0;
                        mat.yx = 0.0;
                        mat.xy = 0.0;
                        mat.yy = -1.0;
                        mat.x0 = 0;
                        mat.y0 = s->height;

                        stride = 4 * sizeof(GLfloat);
                        genGeometry(&bs->vertArray, mat, 0,
                                          &s->outputDev[bs->output].region);
                        glVertexPointer(2, GL_FLOAT, stride,
                                                bs->vertArray.vertices + 2);
                        glTexCoordPointer(2, GL_FLOAT, stride,
                                                  bs->vertArray.vertices);
                        glColor4f(1.0, 1.0, 1.0, 1.0);

                        enableBlurfxTexture(&bs->backTex, COMP_TEXTURE_FILTER_FAST);

                        glDrawArrays(GL_QUADS, 0, bs->vertArray.vCount);

                        disableBlurfxTexture(&bs->backTex);

                        glPopMatrix();
                  }
            }
      }
      else
      {
            UNWRAP(bs, s, paintScreen);
            status = (*s->paintScreen) (s, sa, bigregion, output, mask);
            WRAP(bs, s, paintScreen, blurfxPaintScreen);
      }

      if (bs->motion_blur_active && glIsEnabled(GL_SCISSOR_TEST))
      {
            glDisable(GL_SCISSOR_TEST);
            enable_scissor = TRUE;
      }

      if (bs->motion_blur_active && bs->mb_mode == 0
            && output + 1 == s->nOutputDev)
      {

            // blend motion blur texture to screen
            glPushAttrib(GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT);
            GLERR;
            glPushMatrix();
            glLoadIdentity();
            glViewport(0, 0, s->width, s->height);
            glTranslatef(-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
            glScalef(1.0f / s->width, -1.0f / s->height, 1.0f);
            glTranslatef(0.0f, -s->height, 0.0f);

            enableBlurfxTexture(&bs->motionTex, COMP_TEXTURE_FILTER_FAST);

            if (!bs->mb_update)
            {
                  glEnable(GL_BLEND);

                  glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
                  bs->mb_alpha =
                              (bs->mb_timer / 500.0) * bs->mb_alpha + (1.0 -
                                                                                           (bs->
                                                                                            mb_timer
                                                                                            / 500.0)) * 0.5;
                  glColor4f(1, 1, 1, bs->mb_alpha);

                  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

                  glBegin(GL_QUADS);
                  glTexCoord2f(0, bs->motionTex.height);
                  glVertex2f(0, 0);
                  glTexCoord2f(0, 0);
                  glVertex2f(0, bs->motionTex.height);
                  glTexCoord2f(bs->motionTex.width, 0);
                  glVertex2f(bs->motionTex.width, bs->motionTex.height);
                  glTexCoord2f(bs->motionTex.width, bs->motionTex.height);
                  glVertex2f(bs->motionTex.width, 0);
                  glEnd();

                  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

                  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
                  GLERR;
                  glDisable(GL_BLEND);
            }
            // copy new screen to motion blur texture
            glCopyTexSubImage2D(bs->motionTex.target, 0, 0, 0, 0, 0,
                                          s->width, s->height);
            GLERR;

            disableBlurfxTexture(&bs->motionTex);

            glViewport(s->outputDev[bs->output].region.extents.x1,
                           s->height -
                           s->outputDev[bs->output].region.extents.y2,
                           s->outputDev[bs->output].width,
                           s->outputDev[bs->output].height);

            glPopMatrix();
            glPopAttrib();
            GLERR;

            bs->mb_update = FALSE;
            damageScreen(s);
      }

      if (bs->motion_blur_active && bs->mb_mode == 1
            && output + 1 == s->nOutputDev)
      {

            // create motion blur effect using accumulation buffer
            bs->mb_alpha =
                        (bs->mb_timer / 500.0) * bs->mb_alpha + (1.0 -
                                                                                     (bs->
                                                                                      mb_timer /
                                                                                      500.0)) * 0.5;
            if (bs->mb_update)
            {
                  glAccum(GL_LOAD, 1.0);
            }
            else
            {
                  glAccum(GL_MULT, 1.0 - bs->mb_alpha);
                  glAccum(GL_ACCUM, bs->mb_alpha);
                  glAccum(GL_RETURN, 1.0);
            }
            bs->mb_update = FALSE;
            damageScreen(s);
      }

      if (enable_scissor)
            glEnable(GL_SCISSOR_TEST);

      XDestroyRegion(bigregion);
      return status;
}

static void
blurfxPaintTransformedScreen(CompScreen * s, const ScreenPaintAttrib * sa,
                                           Region region, int output, unsigned int mask)
{

      BLURFX_SCREEN(s);

      bs->realPaintRegion = &s->region;

      // calculate occluted regions
      if (bs->opt[BLURFX_SCREEN_OPTION_BLUR_DECORATION].value.b
            || bs->opt[BLURFX_SCREEN_OPTION_BLUR_WINDOWS].value.b
            || bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_WINDOWS].value.b)
      {
            bs->mode = MODE_OCCLUSION;
            bs->od_active = TRUE;
            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bs->occlusion);
            CompWindow *w;

            for (w = s->reverseWindows; w; w = w->prev)
            {
                  BLURFX_WINDOW(w);
                  if (w->destroyed)
                        continue;

                  if (!w->shaded)
                  {
                        if (w->attrib.map_state != IsViewable || !w->damaged)
                              continue;
                  }
                  XUnionRegion(bs->occlusion, getEmptyRegion(), bw->clip);
                  (*s->drawWindow) (w, &w->paint, &s->region,
                                            PAINT_WINDOW_SOLID_MASK);
            }
      }
      bs->mode = MODE_NORMAL;
      UNWRAP(bs, s, paintTransformedScreen);
      (*s->paintTransformedScreen) (s, sa, region, output, mask);
      WRAP(bs, s, paintTransformedScreen, blurfxPaintTransformedScreen);
}


static Bool
blurfxDrawWindow(CompWindow * w, const WindowPaintAttrib * attrib,
                         Region region, unsigned int mask)
{
      Bool status;
      int i;

      BLURFX_SCREEN(w->screen);
      BLURFX_WINDOW(w);

      CompScreen *s = w->screen;
      Bool blur_enabled, reflection_enabled;

      if (bs->mode == MODE_OCCLUSION)
      {
            UNWRAP(bs, s, drawWindow);
            status = (*s->drawWindow) (w, attrib, region, mask);
            WRAP(bs, s, drawWindow, blurfxDrawWindow);
            return status;
      }

      // enable blur and/or reflection
      blur_enabled = bs->blur_supported;
      reflection_enabled = bs->reflection_supported;

      blur_enabled &=
                  bs->opt[BLURFX_SCREEN_OPTION_BLUR_DECORATION].value.b
                  || bs->opt[BLURFX_SCREEN_OPTION_BLUR_WINDOWS].value.b;
      reflection_enabled &=
                  bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_DECORATION].value.b
                  || bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_WINDOWS].value.b;

      blur_enabled &= !(mask & PAINT_WINDOW_SOLID_MASK);

      reflection_enabled &= !(mask & PAINT_WINDOW_SOLID_MASK);
      reflection_enabled &= bs->modTex.handle > 0;

      if (bs->
            opt[BLURFX_SCREEN_OPTION_MOTION_BLUR_ON_TRANSFORMED_SCREEN].
            value.b && (mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK))
      {
            bs->motion_blur_active = bs->mblur_supported;
            bs->mb_timer = 500;
      }

      if (!bs->opt[BLURFX_SCREEN_OPTION_BLUR_ON_TRANSFORMED_SCREEN].value.b)
            blur_enabled &= !(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);
      if (!bs->
            opt[BLURFX_SCREEN_OPTION_REFLECTION_ON_TRANSFORMED_SCREEN].value.b)
            reflection_enabled &=
                        !(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);

      if (!bs->opt[BLURFX_SCREEN_OPTION_BLUR_TRANSFORMED_WINDOW].value.b)
            blur_enabled &= !(mask & PAINT_WINDOW_TRANSFORMED_MASK);
      if (!bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_TRANSFORMED_WINDOW].value.b)
            reflection_enabled &= !(mask & PAINT_WINDOW_TRANSFORMED_MASK);

      for (i = 0;
             i <
             bs->opt[BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF].
             value.list.nValue; i++)
      {
            blur_enabled &=
                        !screenGrabExist(s,
                                                 bs->
                                                 opt
                                                 [BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF].
                                                 value.list.value[i].s, 0);
      }

      for (i = 0;
             i <
             bs->
             opt[BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_ON_SCREENGRAB_OF].
             value.list.nValue; i++)
      {
            reflection_enabled &=
                        !screenGrabExist(s,
                                                 bs->
                                                 opt
                                                 [BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_ON_SCREENGRAB_OF].
                                                 value.list.value[i].s, 0);
      }

      Bool splash = IPCS_GetBoolND(IPCS_OBJECT(s), "SPLASH_IS_ACTIVE", FALSE);

      blur_enabled &= !DISABLE_FEATURE(s, bs->ipcs_disable_blur);
      blur_enabled &= !DISABLE_FEATURE(w, bw->ipcs_disable_blur);
      blur_enabled &= !splash;

      reflection_enabled &= !DISABLE_FEATURE(s, bs->ipcs_disable_reflection);
      reflection_enabled &= !DISABLE_FEATURE(w, bw->ipcs_disable_reflection);
      reflection_enabled &= !splash;


      // check for restacking and update damage if needed
      if (w->next != bw->my_next)
      {
            XRectangle rect;

            rect.x = WIN_X(w) - 7;
            rect.y = WIN_Y(w) - 7;
            rect.width = WIN_W(w) + 14;
            rect.height = WIN_H(w) + 14;

            XUnionRectWithRegion(&rect, bs->screenDamage, bs->screenDamage);
            bw->my_next = w->next;
      }

      if (bs->opt[BLURFX_SCREEN_OPTION_BLUR_CACHE_TEXTURES].value.b)
            XUnionRegion(bw->texDamage, bs->screenDamage, bw->texDamage);

      bw->mvm_updated = FALSE;

      if (blur_enabled || reflection_enabled)
      {

            // clear our decoration vertex array
            bw->decoArray.vCount = 0;
            bw->decoArray.indexSize = 0;
            bw->decoArray.indexCount = 0;

            // store region we need to paint
            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bw->paintRegion);
            XIntersectRegion(bs->realPaintRegion, region, bw->paintRegion);
            bw->texUpdated = FALSE;

            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bs->blurredRegion);

            // paint blur and reflection

            bs->mode = MODE_BLURREFLECTION;

            bs->paintingSwitcher = bw->isSwitcher;

            UNWRAP(bs, s, drawWindow);
            status = (*s->drawWindow) (w, attrib, region, mask);
            WRAP(bs, s, drawWindow, blurfxDrawWindow);

            glColor4usv(defaultColor);
            screenTexEnvMode(w->screen, GL_REPLACE);
            glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
            GLERR;

            // paint window
            bs->mode = MODE_NORMAL;
            bs->was_transformed = FALSE;

            UNWRAP(bs, s, drawWindow);
            status = (*s->drawWindow) (w, attrib, region, mask);
            WRAP(bs, s, drawWindow, blurfxDrawWindow);

      }
      else
      {
            // paint window
            bs->mode = MODE_NORMAL;
            bs->was_transformed = FALSE;

            UNWRAP(bs, s, drawWindow);
            status = (*s->drawWindow) (w, attrib, region, mask);
            WRAP(bs, s, drawWindow, blurfxDrawWindow);

      }

      if (bs->was_transformed)
            XUnionRegion(&s->outputDev[bs->output].region,
                               bs->screenDamage, bs->screenDamage);

      if (!(mask & PAINT_WINDOW_SOLID_MASK) && !WINDOW_INPUT_INVISIBLE(w))
      {

            // not all plugins send damage events on move or scale
            XRectangle rect;

            if (bw->lastX != w->attrib.x || bw->lastY != w->attrib.y
                  || w->lastPaint.xScale != attrib->xScale
                  || w->lastPaint.yScale != attrib->yScale)
            {
                  rect.x = bw->lastPAttrib.xTranslate +
                              (-w->output.left * bw->lastPAttrib.xScale) + bw->lastX;
                  rect.y = bw->lastPAttrib.yTranslate +
                              (-w->output.top * bw->lastPAttrib.yScale) + bw->lastY;
                  rect.width = WIN_W(w) * bw->lastPAttrib.xScale;
                  rect.height = WIN_H(w) * bw->lastPAttrib.yScale;
                  XUnionRectWithRegion(&rect, bs->screenDamage, bs->screenDamage);
                  rect.x = attrib->xTranslate +
                              (-w->output.left * attrib->xScale) + w->attrib.x;
                  rect.y = attrib->yTranslate +
                              (-w->output.top * attrib->yScale) + w->attrib.x;
                  rect.width = WIN_W(w) * attrib->xScale;
                  rect.height = WIN_H(w) * attrib->yScale;
                  XUnionRectWithRegion(&rect, bs->screenDamage, bs->screenDamage);
            }
            bw->lastX = w->attrib.x;
            bw->lastY = w->attrib.y;

            if (bw->lastPAttrib.xScale != 1.0 || bw->lastPAttrib.yScale != 1.0)
            {
                  for (i = 0; i < bw->damageRegion->numRects; i++)
                  {
                        BOX box = bw->damageRegion->rects[i];

                        rect.x = bw->lastPAttrib.xTranslate +
                                    (box.x1 - w->attrib.x) * bw->lastPAttrib.xScale;
                        rect.y = bw->lastPAttrib.yTranslate + (box.y1 -
                                                                                 w->
                                                                                 attrib.
                                                                                 y) *
                                    bw->lastPAttrib.yScale;
                        rect.width = (box.x2 - box.x1) * bw->lastPAttrib.xScale;
                        rect.height = (box.y2 - box.y1) * bw->lastPAttrib.yScale;
                        XUnionRectWithRegion(&rect,
                                                       bs->screenDamage, bs->screenDamage);
                  }
            }
            else
            {
                  XUnionRegion(bw->damageRegion, bs->screenDamage,
                                     bs->screenDamage);
            }
            bw->lastPAttrib = *attrib;
            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bw->damageRegion);
      }

      return status;
}

static void
blurfxDrawWindowTexture(CompWindow * w, CompTexture * texture,
                                    const WindowPaintAttrib * attrib, unsigned int mask)
{

      CompScreen *s = w->screen;
      Bool blur_enabled, reflection_enabled;
      int i;


      BLURFX_SCREEN(w->screen);
      BLURFX_WINDOW(w);

      // enable blur and/or reflection
      blur_enabled = bs->blur_supported;
      reflection_enabled = bs->reflection_supported;

      blur_enabled &=
                  (mask & PAINT_WINDOW_DECORATION_MASK) ? bs->
                  opt[BLURFX_SCREEN_OPTION_BLUR_DECORATION].value.b : bs->
                  opt[BLURFX_SCREEN_OPTION_BLUR_WINDOWS].value.b;
      reflection_enabled &=
                  (mask & PAINT_WINDOW_DECORATION_MASK) ? bs->
                  opt[BLURFX_SCREEN_OPTION_REFLECTION_DECORATION].value.b : bs->
                  opt[BLURFX_SCREEN_OPTION_REFLECTION_WINDOWS].value.b;

      if ((mask & PAINT_WINDOW_DECORATION_MASK) && w->input.top == 0
            && w->input.bottom == 0 && w->input.left == 0 && w->input.right == 0)
      {
            if (!bw->isSwitcher)
            {
                  blur_enabled = FALSE;
                  reflection_enabled = FALSE;
            }
      }

      if (!(mask & PAINT_WINDOW_DECORATION_MASK))
      {
            blur_enabled &= !(bs->noBlurWMask & w->type);
            reflection_enabled &= !(bs->noReflectionWMask & w->type);
            blur_enabled &= w->alpha || attrib->opacity < OPAQUE;
            reflection_enabled &= w->alpha || attrib->opacity < OPAQUE;
      }

      reflection_enabled &= bs->modTex.handle > 0;

      if (!bs->opt[BLURFX_SCREEN_OPTION_BLUR_ON_TRANSFORMED_SCREEN].value.b)
            blur_enabled &= !(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);
      if (!bs->
            opt[BLURFX_SCREEN_OPTION_REFLECTION_ON_TRANSFORMED_SCREEN].value.b)
            reflection_enabled &=
                        !(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);

      if (!bs->opt[BLURFX_SCREEN_OPTION_BLUR_TRANSFORMED_WINDOW].value.b)
            blur_enabled &= !(mask & PAINT_WINDOW_TRANSFORMED_MASK);
      if (!bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_TRANSFORMED_WINDOW].value.b)
            reflection_enabled &= !(mask & PAINT_WINDOW_TRANSFORMED_MASK);

      for (i = 0;
             i <
             bs->opt[BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF].
             value.list.nValue; i++)
      {
            blur_enabled &=
                        !screenGrabExist(s,
                                                 bs->
                                                 opt
                                                 [BLURFX_SCREEN_OPTION_DISABLE_BLUR_ON_SCREENGRAB_OF].
                                                 value.list.value[i].s, 0);
      }

      for (i = 0;
             i <
             bs->
             opt[BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_ON_SCREENGRAB_OF].
             value.list.nValue; i++)
      {
            reflection_enabled &=
                        !screenGrabExist(s,
                                                 bs->
                                                 opt
                                                 [BLURFX_SCREEN_OPTION_DISABLE_REFLECTION_ON_SCREENGRAB_OF].
                                                 value.list.value[i].s, 0);
      }

      Bool splash = IPCS_GetBoolND(IPCS_OBJECT(s), "SPLASH_IS_ACTIVE", FALSE);

      blur_enabled &= !DISABLE_FEATURE(s, bs->ipcs_disable_blur);
      blur_enabled &= !DISABLE_FEATURE(w, bw->ipcs_disable_blur);
      blur_enabled &= !splash;

      reflection_enabled &= !DISABLE_FEATURE(s, bs->ipcs_disable_reflection);
      reflection_enabled &= !DISABLE_FEATURE(w, bw->ipcs_disable_reflection);
      reflection_enabled &= !splash;

      // add window region to occlusion region
      if (bs->mode == MODE_OCCLUSION)
      {
            if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK))
                  return;
            if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
                  return;
            if (mask & PAINT_WINDOW_DECORATION_MASK)
                  return;
            if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
                  return;
            if (WINDOW_INPUT_INVISIBLE(w))
                  return;
            XUnionRegion(w->region, bs->occlusion, bs->occlusion);
            return;
      }
      // draw normal window
      if (bs->mode == MODE_NORMAL)
      {
            GLERR;
            UNWRAP(bs, w->screen, drawWindowTexture);
            (*w->screen->drawWindowTexture) (w, texture, attrib, mask);
            WRAP(bs, w->screen, drawWindowTexture, blurfxDrawWindowTexture);
#ifdef GL_DEBUG
            glGetError();
#endif
            bs->was_transformed |= (mask & PAINT_WINDOW_TRANSFORMED_MASK);
            return;
      }

      if (!(mask & PAINT_WINDOW_TRANSLUCENT_MASK)
            || bs->mode != MODE_BLURREFLECTION
            || (mask & PAINT_WINDOW_SHADOW_MASK))
            return;

      if (WINDOW_INPUT_INVISIBLE(w)
            && !(w->shaded && (mask & PAINT_WINDOW_DECORATION_MASK)))
            return;

      if (bs->paintingSwitcher && !bw->isSwitcher)
            return;

      int filter;

      Bool useFbo = bs->fboActive
                  && !bs->opt[BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR].value.b;

      // select texture filter
      if (mask &
            (PAINT_WINDOW_TRANSFORMED_MASK |
             PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK) && useFbo)
            filter = COMP_TEXTURE_FILTER_FAST;
      else
            filter = COMP_TEXTURE_FILTER_GOOD;

      // draw blur
      if (blur_enabled)
      {
            Bool enable_scissor = FALSE;
            Bool enable_clipPlanes = FALSE;

            if (useFbo)
            {
                  if (glIsEnabled(GL_CLIP_PLANE0))
                  {
                        glDisable (GL_CLIP_PLANE0);
                        glDisable (GL_CLIP_PLANE1);
                        glDisable (GL_CLIP_PLANE2);
                        glDisable (GL_CLIP_PLANE3);
                        enable_clipPlanes = TRUE;
                  }
                  if (glIsEnabled(GL_SCISSOR_TEST))
                  {
                        glDisable(GL_SCISSOR_TEST);
                        enable_scissor = TRUE;
                  }
                  bs->downSample = 1.0;
            }
            else
            {
                  bs->downSample =
                              bs->opt[BLURFX_SCREEN_OPTION_NON_FBO_BLUR_STRENGTH].value.
                              i;
            }
            if (bs->opt[BLURFX_SCREEN_OPTION_BLUR_CACHE_TEXTURES].value.b)
            {
                  // update blur cache texture
                  bw->texUpdated = TRUE;
                  updateBlurTextureSize(w, s, attrib, mask);
                  GLERR;
                  if (useFbo)
                  {
                        updateBlurTexture(w, s, attrib, mask, filter);
                        GLERR;
                  }
                  else
                  {
                        updateBlurTextureNoFBO(w, s, attrib, mask);
                        GLERR;
                  }
            }
            if (useFbo)
            {
                  updateBlur(w, s, attrib, mask, filter);
                  GLERR;

                  if (enable_clipPlanes)
                  {
                        glEnable (GL_CLIP_PLANE0);
                        glEnable (GL_CLIP_PLANE1);
                        glEnable (GL_CLIP_PLANE2);
                        glEnable (GL_CLIP_PLANE3);
                  }
                  if (enable_scissor)
                        glEnable(GL_SCISSOR_TEST);
            }
            else
            {
                  updateBlurNoFBO(w, s, attrib, mask);
                  GLERR;
            }
            drawBlur(w, s, texture, attrib, mask, filter);
      }

      // draw reflection
      if (reflection_enabled)
            drawReflection(w, s, texture, attrib, mask, COMP_TEXTURE_FILTER_GOOD);

}

static void
blurfxAddWindowGeometry(CompWindow * w, CompMatrix * m, int nM,
                                    Region region, Region clip)
{
      BLURFX_SCREEN(w->screen);
      BLURFX_WINDOW(w);
      REGION box;

      if (bs->mode == MODE_OCCLUSION)
            return;


      // try to detect decorations
      if (bs->mode == MODE_BLURREFLECTION && region->numRects == 1
            &&
            ((region->extents.x1 < w->attrib.x
              && region->extents.x2 <= w->attrib.x)
             || (region->extents.y1 < w->attrib.y
                   && region->extents.y2 <= w->attrib.y)
             || (region->extents.x1 >= w->attrib.x + w->width
                   && region->extents.x2 > w->attrib.x + w->width)
             || (region->extents.y1 >= w->attrib.y + w->height
                   && region->extents.y2 > w->attrib.y + w->height)))
      {
            box.numRects = 1;
            // create vertex array without shadow
            box.rects = &box.extents;
            box.extents.x1 = MAX(region->extents.x1, WIN_XO(w));
            box.extents.y1 = MAX(region->extents.y1, WIN_YO(w));
            box.extents.x2 = MIN(region->extents.x2, WIN_XO(w) + WIN_WO(w));
            box.extents.y2 = MIN(region->extents.y2, WIN_YO(w) + WIN_HO(w));
            if (box.extents.x1 < box.extents.x2
                  && box.extents.y1 < box.extents.y2)
            {
                  CompWindow *cw = malloc(sizeof(CompWindow));

                  memcpy(cw, w, sizeof(CompWindow));
                  cw->vertexSize = bw->decoArray.vertexSize;
                  cw->indexSize = bw->decoArray.indexSize;
                  cw->vertices = bw->decoArray.vertices;
                  cw->indices = bw->decoArray.indices;
                  cw->vCount = bw->decoArray.vCount;
                  cw->indexCount = bw->decoArray.indexCount;
                  UNWRAP(bs, w->screen, addWindowGeometry);
                  (*w->screen->addWindowGeometry) (cw, m, nM, &box, clip);
                  WRAP(bs, w->screen, addWindowGeometry, blurfxAddWindowGeometry);
                  bw->decoArray.vertexSize = cw->vertexSize;
                  bw->decoArray.indexSize = cw->indexSize;
                  bw->decoArray.vertices = cw->vertices;
                  bw->decoArray.indices = cw->indices;
                  bw->decoArray.vCount = cw->vCount;
                  bw->decoArray.indexCount = cw->indexCount;
                  free(cw);
            }
      }

      UNWRAP(bs, w->screen, addWindowGeometry);
      (*w->screen->addWindowGeometry) (w, m, nM, region, clip);
      WRAP(bs, w->screen, addWindowGeometry, blurfxAddWindowGeometry);
}


static Bool blurfxDamageWindowRect(CompWindow * w, Bool initial, BoxPtr box)
{
      Bool status;

      BLURFX_SCREEN(w->screen);
      BLURFX_WINDOW(w);

      XRectangle rect;

      // a bigger damage region is needed to have correct blur
      box->x1 -= 7;
      box->x2 += 7;
      box->y1 -= 7;
      box->y2 += 7;

      rect.x = w->serverX + box->x1;
      rect.y = w->serverY + box->y1;
      rect.width = box->x2 - box->x1;
      rect.height = box->y2 - box->y1;

      // store window damage
      if (bs->opt[BLURFX_SCREEN_OPTION_BLUR_CACHE_TEXTURES].value.b)
            XUnionRectWithRegion(&rect, bw->damageRegion, bw->damageRegion);


      UNWRAP(bs, w->screen, damageWindowRect);
      status = (*w->screen->damageWindowRect) (w, initial, box);
      WRAP(bs, w->screen, damageWindowRect, blurfxDamageWindowRect);

      return status;
}

static void
updateBlurTexture(CompWindow * w, CompScreen * s,
                          const WindowPaintAttrib * attrib, unsigned int mask,
                          CompTextureFilter filter)
{

      Region reblurRegion;
      Region blurPaintRegion;
      int stride, count, stop, vCount, iCount;
      CompMatrix mat;
      GLfloat *vertices, x1, x2, x3, x4, y1, y2, y3, y4, bx1, bx2, by1, by2;
      GLushort *indices;
      XRectangle rect;

      BLURFX_SCREEN(s);
      BLURFX_WINDOW(w);

      if (bw->bc_x != s->x || bw->bc_y != s->y)
      {
            bw->texUpdated = FALSE;
            return;
      }

      if (bs->
            opt[BLURFX_SCREEN_OPTION_NO_BLUR_CACHE_ON_TRANSFORMED_SCREEN].
            value.b && mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK)
      {
            bw->texUpdated = FALSE;
            return;
      }
      // Do we have an decoration vertex array thet does not contain shadows?
      if (mask & PAINT_WINDOW_DECORATION_MASK && bw->decoArray.vCount)
      {
            vertices = bw->decoArray.vertices + (w->texUnits * w->texCoordSize);
            indices = bw->decoArray.indices;
            vCount = bw->decoArray.vCount;
            iCount = bw->decoArray.indexCount;
      }
      else
      {
            vertices = w->vertices + (w->texUnits * w->texCoordSize);
            indices = w->indices;
            vCount = w->vCount;
            iCount = w->indexCount;
      }

      if (vCount <= 0)
            return;
      stride = (w->texUnits * w->texCoordSize) + 2;

      // get regions we need not to update
      reblurRegion = XCreateRegion();
      blurPaintRegion = XCreateRegion();

      count = 0;
      stop = (iCount) ? iCount : vCount;

      bx1 = 65535;
      bx2 = 0.0;
      by1 = 65535;
      by2 = 0.0;

      // generate region that needs blur
      while (count < stop)
      {
            if (iCount)
            {
                  x1 = vertices[indices[count] * stride];
                  y1 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x2 = vertices[indices[count] * stride];
                  y2 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x3 = vertices[indices[count] * stride];
                  y3 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x4 = vertices[indices[count] * stride];
                  y4 = vertices[(indices[count] * stride) + 1];
                  count++;

            }
            else
            {
                  x1 = vertices[0];
                  y1 = vertices[1];
                  vertices += stride;
                  x2 = vertices[0];
                  y2 = vertices[1];
                  vertices += stride;
                  x3 = vertices[0];
                  y3 = vertices[1];
                  vertices += stride;
                  x4 = vertices[0];
                  y4 = vertices[1];
                  vertices += stride;
                  count += 4;
            }

            if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK))
            {
                  bx1 = 65535;
                  bx2 = 0.0;
                  by1 = 65535;
                  by2 = 0.0;
            }

            bx1 = MIN(bx1, x1);
            bx2 = MAX(bx2, x1);
            bx1 = MIN(bx1, x2);
            bx2 = MAX(bx2, x2);
            bx1 = MIN(bx1, x3);
            bx2 = MAX(bx2, x3);
            bx1 = MIN(bx1, x4);
            bx2 = MAX(bx2, x4);

            by1 = MIN(by1, y1);
            by2 = MAX(by2, y1);
            by1 = MIN(by1, y2);
            by2 = MAX(by2, y2);
            by1 = MIN(by1, y3);
            by2 = MAX(by2, y3);
            by1 = MIN(by1, y4);
            by2 = MAX(by2, y4);

            if (bx2 - bx1 > 0 && by2 - by1 > 0
                  && !(mask & PAINT_WINDOW_TRANSFORMED_MASK))
            {
                  rect.x = attrib->xTranslate +
                              (((bx1 - 7) - w->attrib.x) * attrib->xScale) +
                              w->attrib.x;
                  rect.y = attrib->yTranslate +
                              (((by1 - 1) - w->attrib.y) * attrib->yScale) +
                              w->attrib.y;
                  rect.width = (bx2 - bx1 + 14) * attrib->xScale;
                  rect.height = (by2 - by1 + 2) * attrib->yScale;

                  XUnionRectWithRegion(&rect, reblurRegion, reblurRegion);
            }
      }

      if (bx2 - bx1 > 0 && by2 - by1 > 0
            && (mask & PAINT_WINDOW_TRANSFORMED_MASK))
      {
            rect.x = attrib->xTranslate +
                        (((bx1 - 7) - w->attrib.x) * attrib->xScale) + w->attrib.x;
            rect.y = attrib->yTranslate +
                        (((by1 - 1) - w->attrib.y) * attrib->yScale) + w->attrib.y;
            rect.width = (bx2 - bx1 + 14) * attrib->xScale;
            rect.height = (by2 - by1 + 2) * attrib->yScale;

            XUnionRectWithRegion(&rect, reblurRegion, reblurRegion);
      }

      XIntersectRegion(reblurRegion, bw->bTexRegion, blurPaintRegion);

      // get regions we need to update
      XIntersectRegion(reblurRegion, bw->paintRegion, reblurRegion);
      XIntersectRegion(reblurRegion, bw->texDamage, reblurRegion);
      XIntersectRegion(reblurRegion, bw->bTexRegion, reblurRegion);

      XIntersectRegion(reblurRegion, &s->outputDev[bs->output].region,
                               reblurRegion);

      // subtract occluded region
      if (bs->od_active)
            XSubtractRegion(reblurRegion, bw->clip, reblurRegion);


      stride = 4 * sizeof(GLfloat);

      if (screenGrabExist(s, "switcher", 0) || bw->isSwitcher)
      {
            bw->texUpdated = FALSE;
            XDestroyRegion(reblurRegion);
            XDestroyRegion(blurPaintRegion);
            return;
      }

      if (reblurRegion->numRects)
      {

            if (mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK)
            {

                  float bm[16] = { s->outputDev[bs->output].width / 2.0, 0, 0,
                        0,
                        0, s->outputDev[bs->output].height / 2.0,
                        0, 0,
                        0, 0, 1, 0,
                        s->outputDev[bs->output].width / 2.0 +
                                    s->outputDev[bs->output].region.extents.x1,
                        s->outputDev[bs->output].height / 2.0 +
                                    s->height -
                                    s->outputDev[bs->output].region.extents.y2, 1, 1
                  };
                  float bpm[16];
                  float tm[16];

                  if (!bw->mvm_updated)
                  {
                        bw->mvm_updated = TRUE;
                        glGetFloatv(GL_MODELVIEW_MATRIX, bw->mvm);
                  }

                  MULTM(bm, bs->pm, bpm);
                  MULTM(bpm, bw->mvm, tm);

                  XRectangle rect, outputRect;

                  XClipBox(reblurRegion, &rect);

                  // check region for visibility
                  float bbProj[4][2];

                  bbProj[0][0] = rect.x * tm[0] + rect.y * tm[4] + tm[12];
                  bbProj[0][0] /= rect.x * tm[3] + rect.y * tm[7] + tm[15];
                  bbProj[0][1] = rect.x * tm[1] + rect.y * tm[5] + tm[13];
                  bbProj[0][1] /= rect.x * tm[3] + rect.y * tm[7] + tm[15];
                  bbProj[1][0] =
                              (rect.x + rect.width) * tm[0] + rect.y * tm[4] + tm[12];
                  bbProj[1][0] /= (rect.x + rect.width) * tm[3] +
                              rect.y * tm[7] + tm[15];
                  bbProj[1][1] =
                              (rect.x + rect.width) * tm[1] + rect.y * tm[5] + tm[13];
                  bbProj[1][1] /= (rect.x + rect.width) * tm[3] +
                              rect.y * tm[7] + tm[15];
                  bbProj[2][0] =
                              rect.x * tm[0] + (rect.y + rect.height) * tm[4] + tm[12];
                  bbProj[2][0] /= rect.x * tm[3] + (rect.y +
                                                                    rect.height) * tm[7] + tm[15];
                  bbProj[2][1] =
                              rect.x * tm[1] + (rect.y + rect.height) * tm[5] + tm[13];
                  bbProj[2][1] /= rect.x * tm[3] + (rect.y +
                                                                    rect.height) * tm[7] + tm[15];
                  bbProj[3][0] =
                              (rect.x + rect.width) * tm[0] + (rect.y +
                                                                               rect.height) *
                              tm[4] + tm[12];
                  bbProj[3][0] /= (rect.x + rect.width) * tm[3] +
                              (rect.y + rect.height) * tm[7] + tm[15];
                  bbProj[3][1] =
                              (rect.x + rect.width) * tm[1] + (rect.y +
                                                                               rect.height) *
                              tm[5] + tm[13];
                  bbProj[3][1] /= (rect.x + rect.width) * tm[3] +
                              (rect.y + rect.height) * tm[7] + tm[15];

                  screenGetOutputDevRect(s, bs->output, &outputRect);
                  int s_x1 = outputRect.x;
                  int s_y1 = outputRect.y;
                  int s_x2 = s_x1 + outputRect.width;
                  int s_y2 = s_y1 + outputRect.height;

                  if (bbProj[0][0] >= bbProj[1][0]
                        || bbProj[2][0] >= bbProj[3][0]
                        || bbProj[2][1] >= bbProj[0][1]
                        || bbProj[3][1] >= bbProj[1][1]
                        || bbProj[1][0] - bbProj[0][0] <
                        rect.width * 0.5
                        || bbProj[3][0] - bbProj[2][0] <
                        rect.width * 0.5
                        || bbProj[0][1] - bbProj[2][1] <
                        rect.height * 0.5
                        || bbProj[1][1] - bbProj[3][1] <
                        rect.height * 0.5 || bbProj[0][0] < s_x1
                        || bbProj[1][0] > s_x2 || bbProj[2][0] < s_x1
                        || bbProj[3][0] > s_x2 || bbProj[0][1] < s_y1
                        || bbProj[2][1] > s_y2 || bbProj[1][1] < s_y1
                        || bbProj[3][1] > s_y2)
                  {
                        XDestroyRegion(reblurRegion);
                        XDestroyRegion(blurPaintRegion);

                        bw->texUpdated = FALSE;
                        return;
                  }
                  // enable projective texture coordinate generation
                  float s_gen[4] = { tm[0], tm[4], tm[8], tm[12] };
                  float t_gen[4] = { tm[1], tm[5], tm[9], tm[13] };
                  float r_gen[4] = { tm[2], tm[6], tm[10], tm[14] };
                  float q_gen[4] = { tm[3], tm[7], tm[11], tm[15] };
                  glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
                  glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
                  glTexGenfv(GL_R, GL_OBJECT_PLANE, r_gen);
                  glTexGenfv(GL_Q, GL_OBJECT_PLANE, q_gen);

                  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
                  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
                  glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
                  glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

                  glEnable(GL_TEXTURE_GEN_S);
                  glEnable(GL_TEXTURE_GEN_T);
                  glEnable(GL_TEXTURE_GEN_R);
                  glEnable(GL_TEXTURE_GEN_Q);
            }
            else
            {

                  // enable texture coordinate generation
                  float s_gen[4] = { 1.0, 0.0, 0.0, 0.0 };
                  float t_gen[4] = { 0.0, -1.0, 0.0, s->height };
                  glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
                  glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
                  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
                  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
                  glEnable(GL_TEXTURE_GEN_S);
                  glEnable(GL_TEXTURE_GEN_T);
            }

            // draw vertically blured region into temprorary texture
            (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                      GL_COLOR_ATTACHMENT0_EXT,
                                                      GL_TEXTURE_RECTANGLE_ARB,
                                                      bs->blurTempTexV.handle, 0);
            GLERR;

            // bind vertival blur shader
            glEnable(GL_FRAGMENT_PROGRAM_ARB);
            (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, bs->blurShaderV);

            // bind unblurred background
            enableBlurfxTexture(&bs->backTex, filter);

            mat.xx = 1.0;
            mat.yx = 0.0;
            mat.xy = 0.0;
            mat.yy = -1.0;
            mat.x0 = 0.0;
            mat.y0 = bs->backTex.height;

            genGeometry(&bw->vertArray, mat, 7, reblurRegion);
            glVertexPointer(2, GL_FLOAT, stride, bw->vertArray.vertices + 2);
            glTexCoordPointer(2, GL_FLOAT, stride, bw->vertArray.vertices);

            glDrawArrays(GL_QUADS, 0, bw->vertArray.vCount);

            // draw vertically blured region into blur cache texture
            (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                      GL_COLOR_ATTACHMENT0_EXT,
                                                      GL_TEXTURE_RECTANGLE_ARB,
                                                      bw->blurTex.handle, 0);
            GLERR;

            glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            glLoadIdentity();
            glDepthRange(0, 1);
            glViewport(-1, -1, 2, 2);
            glRasterPos2f(0, 0);
            glViewport(0, 0, bw->blurTex.width, bw->blurTex.height);

            glTranslatef(-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
            glScalef(1.0f / bw->blurTex.width, -1.0f / bw->blurTex.height, 1.0f);
            glTranslatef(0.0f, -bw->blurTex.height, 0.0f);


            // bind horizontal blur shader
            (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, bs->blurShaderH);

            // bind temprorary texture
            switchBlurfxTexture(&bs->backTex, &bs->blurTempTexV, filter);

            glTranslated(-bw->blurTex.x, -bw->blurTex.y, 0);

            genGeometry(&bw->vertArray, mat, 0, reblurRegion);
            glVertexPointer(2, GL_FLOAT, stride, bw->vertArray.vertices + 2);
            glTexCoordPointer(2, GL_FLOAT, stride, bw->vertArray.vertices);

            glDrawArrays(GL_QUADS, 0, bw->vertArray.vCount);
            GLERR;

            (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                      GL_COLOR_ATTACHMENT0_EXT,
                                                      GL_TEXTURE_RECTANGLE_ARB,
                                                      bs->backTex.handle, 0);
            GLERR;
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glDepthRange(0, 1);
            glViewport(-1, -1, 2, 2);
            glRasterPos2f(0, 0);
            s->rasterX = s->rasterY = 0;
            glViewport(s->outputDev[bs->output].region.extents.x1,
                           s->height -
                           s->outputDev[bs->output].region.extents.y2,
                           s->outputDev[bs->output].width,
                           s->outputDev[bs->output].height);
            glMatrixMode(GL_MODELVIEW);
            glPopMatrix();

            glDisable(GL_FRAGMENT_PROGRAM_ARB);
            disableBlurfxTexture(&bs->blurTempTexV);
            glDisable(GL_TEXTURE_GEN_S);
            glDisable(GL_TEXTURE_GEN_T);
            glDisable(GL_TEXTURE_GEN_R);
            glDisable(GL_TEXTURE_GEN_Q);

            // remove reblurred regions from blur cache texture damage
            XSubtractRegion(bw->texDamage, reblurRegion, bw->texDamage);

      }
      // if the screen is transformed draw blur cache texture into temporary blur texture because there could be some regions we still need a blur for
      if (blurPaintRegion->numRects && (mask & PAINT_WINDOW_TRANSFORMED_MASK))
      {

            (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                      GL_COLOR_ATTACHMENT0_EXT,
                                                      GL_TEXTURE_RECTANGLE_ARB,
                                                      bs->blurTempTexH.handle, 0);
            GLERR;

            mat.xx = 1.0;
            mat.yx = 0.0;
            mat.xy = 0.0;
            mat.yy = -1.0;
            mat.x0 = -bw->blurTex.x;
            mat.y0 = bw->blurTex.height + bw->blurTex.y;

            genGeometry(&bw->vertArray, mat, 0, blurPaintRegion);
            glVertexPointer(2, GL_FLOAT, stride, bw->vertArray.vertices + 2);
            glTexCoordPointer(2, GL_FLOAT, stride, bw->vertArray.vertices);

            enableBlurfxTexture(&bw->blurTex, filter);

            glDrawArrays(GL_QUADS, 0, bw->vertArray.vCount);
            GLERR;

            disableBlurfxTexture(&bw->blurTex);

            (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                      GL_COLOR_ATTACHMENT0_EXT,
                                                      GL_TEXTURE_RECTANGLE_ARB,
                                                      bs->backTex.handle, 0);
            GLERR;
      }
      // cleanup
      XDestroyRegion(reblurRegion);
      XDestroyRegion(blurPaintRegion);
}

static void
updateBlur(CompWindow * w, CompScreen * s,
               const WindowPaintAttrib * attrib, unsigned int mask,
               CompTextureFilter filter)
{

      Region reblurRegion;
      int stride, count, stop, vCount, iCount;
      CompMatrix mat;
      GLfloat *vertices, x1, x2, x3, x4, y1, y2, y3, y4, bx1, bx2, by1, by2;
      GLushort *indices;
      XRectangle rect;


      BLURFX_SCREEN(s);
      BLURFX_WINDOW(w);

      // Do we have an decoration vertex array thet does not contain shadows?
      if (mask & PAINT_WINDOW_DECORATION_MASK && bw->decoArray.vCount)
      {
            vertices = bw->decoArray.vertices + (w->texUnits * w->texCoordSize);
            indices = bw->decoArray.indices;
            vCount = bw->decoArray.vCount;
            iCount = bw->decoArray.indexCount;
      }
      else
      {
            vertices = w->vertices + (w->texUnits * w->texCoordSize);
            indices = w->indices;
            vCount = w->vCount;
            iCount = w->indexCount;
      }

      if (vCount <= 0)
            return;

      // get regions we need not to update
      reblurRegion = XCreateRegion();

      stride = (w->texUnits * w->texCoordSize) + 2;

      count = 0;
      stop = (iCount) ? iCount : vCount;

      bx1 = 65535;
      bx2 = 0.0;
      by1 = 65535;
      by2 = 0.0;

      // generate region that needs blur
      while (count < stop)
      {
            if (iCount)
            {
                  x1 = vertices[indices[count] * stride];
                  y1 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x2 = vertices[indices[count] * stride];
                  y2 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x3 = vertices[indices[count] * stride];
                  y3 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x4 = vertices[indices[count] * stride];
                  y4 = vertices[(indices[count] * stride) + 1];
                  count++;

            }
            else
            {
                  x1 = vertices[0];
                  y1 = vertices[1];
                  vertices += stride;
                  x2 = vertices[0];
                  y2 = vertices[1];
                  vertices += stride;
                  x3 = vertices[0];
                  y3 = vertices[1];
                  vertices += stride;
                  x4 = vertices[0];
                  y4 = vertices[1];
                  vertices += stride;
                  count += 4;
            }


            if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK))
            {
                  bx1 = 65535;
                  bx2 = 0.0;
                  by1 = 65535;
                  by2 = 0.0;
            }

            bx1 = MIN(bx1, x1);
            bx2 = MAX(bx2, x1);
            bx1 = MIN(bx1, x2);
            bx2 = MAX(bx2, x2);
            bx1 = MIN(bx1, x3);
            bx2 = MAX(bx2, x3);
            bx1 = MIN(bx1, x4);
            bx2 = MAX(bx2, x4);

            by1 = MIN(by1, y1);
            by2 = MAX(by2, y1);
            by1 = MIN(by1, y2);
            by2 = MAX(by2, y2);
            by1 = MIN(by1, y3);
            by2 = MAX(by2, y3);
            by1 = MIN(by1, y4);
            by2 = MAX(by2, y4);

            if (bx2 - bx1 > 0 && by2 - by1 > 0
                  && !(mask & PAINT_WINDOW_TRANSFORMED_MASK))
            {
                  rect.x = -attrib->xTranslate +
                              (((bx1 - 7) - w->attrib.x) * attrib->xScale) +
                              w->attrib.x;
                  rect.y = -attrib->yTranslate +
                              (((by1 - 1) - w->attrib.y) * attrib->yScale) +
                              w->attrib.y;
                  rect.width = (bx2 - bx1 + 14) * attrib->xScale;
                  rect.height = (by2 - by1 + 2) * attrib->yScale;

                  XUnionRectWithRegion(&rect, reblurRegion, reblurRegion);
            }
      }

      if (bx2 - bx1 > 0 && by2 - by1 > 0
            && (mask & PAINT_WINDOW_TRANSFORMED_MASK))
      {
            rect.x = attrib->xTranslate +
                        (((bx1 - 7) - w->attrib.x) * attrib->xScale) + w->attrib.x;
            rect.y = attrib->yTranslate +
                        (((by1 - 1) - w->attrib.y) * attrib->yScale) + w->attrib.y;
            rect.width = (bx2 - bx1 + 14) * attrib->xScale;
            rect.height = (by2 - by1 + 2) * attrib->yScale;

            XUnionRectWithRegion(&rect, reblurRegion, reblurRegion);
      }

      if (!(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK))
            XIntersectRegion(reblurRegion,
                                     &s->outputDev[bs->output].region, reblurRegion);

      XSubtractRegion(reblurRegion, bs->blurredRegion, reblurRegion);

      // subtract occluded region
      if (bs->od_active)
            XSubtractRegion(reblurRegion, bw->clip, reblurRegion);

      // subtract blur cache texture region
      if (bw->texUpdated)
            XSubtractRegion(reblurRegion, bw->bTexRegion, reblurRegion);

      if (!reblurRegion->numRects)
      {
            XDestroyRegion(reblurRegion);
            return;
      }

      XUnionRegion(reblurRegion, bs->blurredRegion, bs->blurredRegion);

      mat.xx = 1.0;
      mat.yx = 0.0;
      mat.xy = 0.0;
      mat.yy = -1.0;
      mat.x0 = 0.0;
      mat.y0 = bs->backTex.height;

      stride = 4 * sizeof(GLfloat);

      // draw vertically blured region into temprorary texture
      (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                GL_COLOR_ATTACHMENT0_EXT,
                                                GL_TEXTURE_RECTANGLE_ARB,
                                                bs->blurTempTexV.handle, 0);
      GLERR;

      glPushMatrix();

      // enable projective texture cooridinate generation
      float bm[16] = { s->outputDev[bs->output].width / 2.0, 0, 0, 0,
            0, s->outputDev[bs->output].height / 2.0, 0, 0,
            0, 0, 1, 0,
            s->outputDev[bs->output].width / 2.0 +
                        s->outputDev[bs->output].region.extents.x1,
            s->outputDev[bs->output].height / 2.0 + s->height -
                        s->outputDev[bs->output].region.extents.y2, 1, 1
      };
      float bpm[16];
      float tm[16];

      bw->mvm_updated = FALSE;
      glGetFloatv(GL_MODELVIEW_MATRIX, bw->mvm);

      MULTM(bm, bs->pm, bpm);
      MULTM(bpm, bw->mvm, tm);

      float s_gen[4] = { tm[0], tm[4], tm[8], tm[12] };
      float t_gen[4] = { tm[1], tm[5], tm[9], tm[13] };
      float r_gen[4] = { tm[2], tm[6], tm[10], tm[14] };
      float q_gen[4] = { tm[3], tm[7], tm[11], tm[15] };
      glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
      glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
      glTexGenfv(GL_R, GL_OBJECT_PLANE, r_gen);
      glTexGenfv(GL_Q, GL_OBJECT_PLANE, q_gen);

      glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
      glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
      glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
      glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
      glEnable(GL_TEXTURE_GEN_S);
      glEnable(GL_TEXTURE_GEN_T);
      glEnable(GL_TEXTURE_GEN_R);
      glEnable(GL_TEXTURE_GEN_Q);

      // bind vertival blur shader
      glEnable(GL_FRAGMENT_PROGRAM_ARB);
      GLERR;
      (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, bs->blurShaderV);
      GLERR;


      // bind unblurred background
      enableBlurfxTexture(&bs->backTex, filter);

      genGeometry(&bs->vertArray, mat, 0, reblurRegion);
      glVertexPointer(2, GL_FLOAT, stride, bs->vertArray.vertices + 2);
      GLERR;
      glTexCoordPointer(2, GL_FLOAT, stride, bs->vertArray.vertices);
      GLERR;

      glDrawArrays(GL_QUADS, 0, bs->vertArray.vCount);
      GLERR;

      // draw vertically blured region into temprorary texture
      (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                GL_COLOR_ATTACHMENT0_EXT,
                                                GL_TEXTURE_RECTANGLE_ARB,
                                                bs->blurTempTexH.handle, 0);
      GLERR;

      // bind horizontal blur shader
      (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, bs->blurShaderH);
      GLERR;

      // bind temprorary texture
      switchBlurfxTexture(&bs->backTex, &bs->blurTempTexV, filter);

      glDrawArrays(GL_QUADS, 0, bs->vertArray.vCount);
      GLERR;

      glPopMatrix();
      GLERR;
      (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                GL_COLOR_ATTACHMENT0_EXT,
                                                GL_TEXTURE_RECTANGLE_ARB,
                                                bs->backTex.handle, 0);
      GLERR;

      (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, 0);
      GLERR;
      glDisable(GL_FRAGMENT_PROGRAM_ARB);

      glDisable(GL_TEXTURE_GEN_S);
      glDisable(GL_TEXTURE_GEN_T);
      glDisable(GL_TEXTURE_GEN_R);
      glDisable(GL_TEXTURE_GEN_Q);

      disableBlurfxTexture(&bs->blurTempTexV);

      XDestroyRegion(reblurRegion);
}

static void
updateBlurTextureSize(CompWindow * w, CompScreen * s,
                                const WindowPaintAttrib * attrib, unsigned int mask)
{

      XRectangle box;
      int texCheck = 0;
      float div_w, div_h;

      BLURFX_SCREEN(s);
      BLURFX_WINDOW(w);

      // if the window does not have a blur cache texture create it
      if (!bw->hasTexture && !WINDOW_INPUT_INVISIBLE(w))
      {
            bw->hasTexture = TRUE;

            genBlurTexture(bs, &bw->blurTex,
                                 ceil((WIN_W(w) + 80) / bs->downSample),
                                 ceil((WIN_H(w) + 80) / bs->downSample), 0);

            bw->blurTex.x =
                        floor((WIN_X(w) - 40) / bs->downSample) * bs->downSample;
            bw->blurTex.y =
                        floor((WIN_Y(w) - 40) / bs->downSample) * bs->downSample;
            bw->blurTex.downSample = bs->downSample;
            box.x = bw->blurTex.x;
            box.y = bw->blurTex.y;
            box.width = bw->blurTex.width;
            box.height = bw->blurTex.height;

            bw->bc_x = s->x;
            bw->bc_y = s->y;

            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bw->texDamage);
            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bw->bTexRegion);
            XUnionRectWithRegion(&box, bw->texDamage, bw->texDamage);
            XUnionRectWithRegion(&box, bw->bTexRegion, bw->bTexRegion);
      }
      // if the window has moved out of his blur cache texture then update the blur cache texture
      if (bw->blurTex.x > WIN_X(w)
            || WIN_X(w) + WIN_W(w) > bw->blurTex.x + bw->blurTex.width)
            texCheck = 1;
      if (bw->blurTex.y > WIN_Y(w)
            || WIN_Y(w) + WIN_H(w) > bw->blurTex.y + bw->blurTex.height)
            texCheck = 1;

      // do not update if the window is still moving
      if ((mask & PAINT_WINDOW_TRANSFORMED_MASK) && texCheck
            && !(w->attrib.x == bw->lastX && w->attrib.y == bw->lastY))
            texCheck = 0;

      // do we need to resize the blur cache texture
      if (bw->blurTex.width < WIN_W(w) || bw->blurTex.height < WIN_H(w))
            texCheck = 2;
      if (bw->blurTex.width - WIN_W(w) > 160
            || bw->blurTex.height - WIN_H(w) > 160)
            texCheck = 2;

      if ((bw->bc_x != s->x || bw->bc_y != s->y)
            && !(mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK))
      {
            texCheck = 1;
      }
      // do not update blur cache texture size if window is transformed
      if ((mask & PAINT_WINDOW_TRANSFORMED_MASK) && texCheck == 2)
            texCheck = 0;

      if (bw->blurTex.downSample != bs->downSample)
            texCheck = 2;

      if (texCheck && (!WINDOW_INPUT_INVISIBLE(w) || w->shaded))
      {
            if (texCheck == 2)
            {
                  // update blur cache texture size
                  enableBlurfxTexture(&bw->blurTex, COMP_TEXTURE_FILTER_FAST);
                  glTexImage2D(bw->blurTex.target, 0, 3,
                                     ceil((WIN_W(w) +
                                             80) / bs->downSample),
                                     ceil((WIN_H(w) +
                                             80) / bs->downSample), 0,
                                     GL_RGB, GL_UNSIGNED_BYTE, NULL);
                  disableBlurfxTexture(&bw->blurTex);
                  bw->blurTex.width = WIN_W(w) + 80;
                  bw->blurTex.height = WIN_H(w) + 80;
            }
            // update blur cache texture position
            div_w = (bw->blurTex.width - WIN_W(w)) / 2;
            div_h = (bw->blurTex.height - WIN_H(w)) / 2;

            bw->blurTex.x =
                        floor((WIN_X(w) - div_w) / bs->downSample) * bs->downSample;
            bw->blurTex.y =
                        floor((WIN_Y(w) - div_h) / bs->downSample) * bs->downSample;
            bw->blurTex.downSample = bs->downSample;
            box.x = bw->blurTex.x;
            box.y = bw->blurTex.y;
            box.width = bw->blurTex.width;
            box.height = bw->blurTex.height;

            bw->bc_x = s->x;
            bw->bc_y = s->y;

            // update to new regions and add damage
            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bw->texDamage);
            XUnionRegion(getEmptyRegion(), getEmptyRegion(), bw->bTexRegion);
            XUnionRectWithRegion(&box, bw->texDamage, bw->texDamage);
            XUnionRectWithRegion(&box, bw->bTexRegion, bw->bTexRegion);
      }
}

static void
updateBlurTextureNoFBO(CompWindow * w, CompScreen * s,
                                 const WindowPaintAttrib * attrib, unsigned int mask)
{

      Region reblurRegion;
      Region blurPaintRegion;
      int stride, count, stop, vCount, iCount;
      GLfloat *vertices, x1, x2, x3, x4, y1, y2, y3, y4, bx1, bx2, by1, by2;
      GLushort *indices;
      XRectangle rect;

      BLURFX_SCREEN(s);
      BLURFX_WINDOW(w);

      if (bw->bc_x != s->x || bw->bc_y != s->y)
      {
            bw->texUpdated = FALSE;
            return;
      }

      if (screenGrabExist(s, "switcher", 0)
            || mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK
            || mask & PAINT_WINDOW_TRANSFORMED_MASK || bw->isSwitcher)
      {
            bw->texUpdated = FALSE;
            return;
      }
      // Do we have an decoration vertex array thet does not contain shadows?
      if (mask & PAINT_WINDOW_DECORATION_MASK && bw->decoArray.vCount)
      {
            vertices = bw->decoArray.vertices + (w->texUnits * w->texCoordSize);
            indices = bw->decoArray.indices;
            vCount = bw->decoArray.vCount;
            iCount = bw->decoArray.indexCount;
      }
      else
      {
            vertices = w->vertices + (w->texUnits * w->texCoordSize);
            indices = w->indices;
            vCount = w->vCount;
            iCount = w->indexCount;
      }

      if (vCount <= 0)
            return;
      stride = (w->texUnits * w->texCoordSize) + 2;

      // get regions we need not to update
      reblurRegion = XCreateRegion();
      blurPaintRegion = XCreateRegion();

      count = 0;
      stop = (iCount) ? iCount : vCount;

      bx1 = 65535;
      bx2 = 0.0;
      by1 = 65535;
      by2 = 0.0;

      // generate region that needs blur
      while (count < stop)
      {
            if (iCount)
            {
                  x1 = vertices[indices[count] * stride];
                  y1 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x2 = vertices[indices[count] * stride];
                  y2 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x3 = vertices[indices[count] * stride];
                  y3 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x4 = vertices[indices[count] * stride];
                  y4 = vertices[(indices[count] * stride) + 1];
                  count++;

            }
            else
            {
                  x1 = vertices[0];
                  y1 = vertices[1];
                  vertices += stride;
                  x2 = vertices[0];
                  y2 = vertices[1];
                  vertices += stride;
                  x3 = vertices[0];
                  y3 = vertices[1];
                  vertices += stride;
                  x4 = vertices[0];
                  y4 = vertices[1];
                  vertices += stride;
                  count += 4;
            }


            bx1 = 65535;
            bx2 = 0.0;
            by1 = 65535;
            by2 = 0.0;

            bx1 = MIN(bx1, x1);
            bx2 = MAX(bx2, x1);
            bx1 = MIN(bx1, x2);
            bx2 = MAX(bx2, x2);
            bx1 = MIN(bx1, x3);
            bx2 = MAX(bx2, x3);
            bx1 = MIN(bx1, x4);
            bx2 = MAX(bx2, x4);

            by1 = MIN(by1, y1);
            by2 = MAX(by2, y1);
            by1 = MIN(by1, y2);
            by2 = MAX(by2, y2);
            by1 = MIN(by1, y3);
            by2 = MAX(by2, y3);
            by1 = MIN(by1, y4);
            by2 = MAX(by2, y4);

            if (bx2 - bx1 > 0 && by2 - by1 > 0)
            {
                  rect.x = attrib->xTranslate +
                              (((bx1 - 7) - w->attrib.x) * attrib->xScale) +
                              w->attrib.x;
                  rect.y = attrib->yTranslate +
                              (((by1 - 1) - w->attrib.y) * attrib->yScale) +
                              w->attrib.y;
                  rect.width = (bx2 - bx1 + 14) * attrib->xScale;
                  rect.height = (by2 - by1 + 2) * attrib->yScale;

                  XUnionRectWithRegion(&rect, reblurRegion, reblurRegion);
            }
      }

      XIntersectRegion(reblurRegion, bw->bTexRegion, blurPaintRegion);

      // get regions we need to update
      XIntersectRegion(reblurRegion, bw->paintRegion, reblurRegion);
      XIntersectRegion(reblurRegion, bw->texDamage, reblurRegion);
      XIntersectRegion(reblurRegion, bw->bTexRegion, reblurRegion);

      XIntersectRegion(reblurRegion, &s->outputDev[bs->output].region,
                               reblurRegion);

      // subtract occluded region
      if (bs->od_active)
            XSubtractRegion(reblurRegion, bw->clip, reblurRegion);

      if (reblurRegion->numRects)
      {

            // enable projective texture cooridinate generation
            float bm[16] = { s->outputDev[bs->output].width / 2.0, 0, 0, 0,
                  0, s->outputDev[bs->output].height / -2.0, 0, 0,
                  0, 0, 1, 0,
                  s->outputDev[bs->output].width / 2.0 +
                              s->outputDev[bs->output].region.extents.x1,
                  s->outputDev[bs->output].height / 2.0 +
                              s->outputDev[bs->output].region.extents.y1, 1,
                  1
            };
            float bpm[16];
            float tm[16];

            if (!bw->mvm_updated)
            {
                  bw->mvm_updated = TRUE;
                  glGetFloatv(GL_MODELVIEW_MATRIX, bw->mvm);
            }

            MULTM(bm, bs->pm, bpm);
            MULTM(bpm, bw->mvm, tm);

            int i;
            XRectangle sRect, bRect;

            for (i = 0; i < reblurRegion->numRects; i++)
            {

                  sRect.x = floor(reblurRegion->rects[i].x1 / bs->downSample);
                  sRect.y = floor(reblurRegion->rects[i].y1 / bs->downSample);
                  sRect.width =
                              MAX(1.0,
                                    ceil(reblurRegion->rects[i].x2 /
                                           bs->downSample) - sRect.x);
                  sRect.height =
                              MAX(1.0,
                                    ceil(reblurRegion->rects[i].y2 /
                                           bs->downSample) - sRect.y);

                  bRect.x = sRect.x * bs->downSample;
                  bRect.y = sRect.y * bs->downSample;
                  bRect.width = sRect.width * bs->downSample;
                  bRect.height = sRect.height * bs->downSample;

                  // copy background into temporary texture
                  enableBlurfxTexture(&bs->blurTempTexV, COMP_TEXTURE_FILTER_GOOD);
                  glCopyTexSubImage2D(bs->blurTempTexV.target, 0, 0,
                                                0, bRect.x,
                                                s->height - bRect.y -
                                                bRect.height, bRect.width, bRect.height);

                  // draw downsampled texture

                  glBegin(GL_QUADS);
                  glTexCoord2f(0, 0);
                  glVertex2f(bRect.x, bRect.y);
                  glTexCoord2f(0, bRect.height);
                  glVertex2f(bRect.x, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width, bRect.height);
                  glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width, 0);
                  glVertex2f(bRect.x + sRect.width, bRect.y);
                  glEnd();

                  glEnable(GL_BLEND);
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


                  float shift = bs->downSample / 2.0;

                  glColor4f(1.0, 1.0, 1.0, 0.5);


                  glBegin(GL_QUADS);
                  glTexCoord2f(0 + shift, 0);
                  glVertex2f(bRect.x, bRect.y);
                  glTexCoord2f(0 + shift, bRect.height);
                  glVertex2f(bRect.x, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width + shift, bRect.height);
                  glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width + shift, 0);
                  glVertex2f(bRect.x + sRect.width, bRect.y);
                  glEnd();

                  glColor4f(1.0, 1.0, 1.0, 0.333);


                  glBegin(GL_QUADS);
                  glTexCoord2f(0 - shift, 0);
                  glVertex2f(bRect.x, bRect.y);
                  glTexCoord2f(0 - shift, bRect.height);
                  glVertex2f(bRect.x, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width - shift, bRect.height);
                  glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width - shift, 0);
                  glVertex2f(bRect.x + sRect.width, bRect.y);
                  glEnd();

                  glColor4f(1.0, 1.0, 1.0, 0.25);


                  glBegin(GL_QUADS);
                  glTexCoord2f(0, 0 - shift);
                  glVertex2f(bRect.x, bRect.y);
                  glTexCoord2f(0, bRect.height - shift);
                  glVertex2f(bRect.x, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width, bRect.height - shift);
                  glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width, 0 - shift);
                  glVertex2f(bRect.x + sRect.width, bRect.y);
                  glEnd();

                  glColor4f(1.0, 1.0, 1.0, 0.2);


                  glBegin(GL_QUADS);
                  glTexCoord2f(0, 0 + shift);
                  glVertex2f(bRect.x, bRect.y);
                  glTexCoord2f(0, bRect.height + shift);
                  glVertex2f(bRect.x, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width, bRect.height + shift);
                  glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
                  glTexCoord2f(bRect.width, 0 + shift);
                  glVertex2f(bRect.x + sRect.width, bRect.y);
                  glEnd();


                  glDisable(GL_BLEND);
                  // copy downsampled background into temporary texture
                  switchBlurfxTexture(&bs->blurTempTexV,
                                                &bw->blurTex, COMP_TEXTURE_FILTER_GOOD);
                  glCopyTexSubImage2D(bw->blurTex.target, 0,
                                                sRect.x -
                                                (bw->blurTex.x /
                                                 bs->downSample),
                                                sRect.y -
                                                (bw->blurTex.y /
                                                 bs->downSample), bRect.x,
                                                s->height - bRect.y -
                                                sRect.height, sRect.width, sRect.height);

                  // copy normal background back to screen
                  switchBlurfxTexture(&bw->blurTex,
                                                &bs->blurTempTexV, COMP_TEXTURE_FILTER_GOOD);

                  glBegin(GL_QUADS);
                  glTexCoord2f(0, bRect.height);
                  glVertex2f(bRect.x, bRect.y);
                  glTexCoord2f(0, 0);
                  glVertex2f(bRect.x, bRect.y + bRect.height);
                  glTexCoord2f(bRect.width, 0);
                  glVertex2f(bRect.x + bRect.width, bRect.y + bRect.height);
                  glTexCoord2f(bRect.width, bRect.height);
                  glVertex2f(bRect.x + bRect.width, bRect.y);
                  glEnd();

                  disableBlurfxTexture(&bs->blurTempTexV);


            }

            // remove reblurred regions from blur cache texture damage
            XSubtractRegion(bw->texDamage, reblurRegion, bw->texDamage);

      }
      // cleanup
      XDestroyRegion(reblurRegion);
      XDestroyRegion(blurPaintRegion);
}

static void
updateBlurNoFBO(CompWindow * w, CompScreen * s,
                        const WindowPaintAttrib * attrib, unsigned int mask)
{

      Region reblurRegion;
      int stride, count, stop, vCount, iCount;
      GLfloat *vertices, x1, x2, x3, x4, y1, y2, y3, y4, bx1, bx2, by1, by2;
      GLushort *indices;
      XRectangle rect;

      BLURFX_SCREEN(s);
      BLURFX_WINDOW(w);

      // Do we have an decoration vertex array thet does not contain shadows?
      if (mask & PAINT_WINDOW_DECORATION_MASK && bw->decoArray.vCount)
      {
            vertices = bw->decoArray.vertices + (w->texUnits * w->texCoordSize);
            indices = bw->decoArray.indices;
            vCount = bw->decoArray.vCount;
            iCount = bw->decoArray.indexCount;
      }
      else
      {
            vertices = w->vertices + (w->texUnits * w->texCoordSize);
            indices = w->indices;
            vCount = w->vCount;
            iCount = w->indexCount;
      }

      if (vCount <= 0)
            return;

      // get regions we need not to update
      reblurRegion = XCreateRegion();

      stride = (w->texUnits * w->texCoordSize) + 2;

      count = 0;
      stop = (iCount) ? iCount : vCount;

      bx1 = 65535;
      bx2 = 0.0;
      by1 = 65535;
      by2 = 0.0;

      // generate region that needs blur
      while (count < stop)
      {
            if (iCount)
            {
                  x1 = vertices[indices[count] * stride];
                  y1 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x2 = vertices[indices[count] * stride];
                  y2 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x3 = vertices[indices[count] * stride];
                  y3 = vertices[(indices[count] * stride) + 1];
                  count++;
                  x4 = vertices[indices[count] * stride];
                  y4 = vertices[(indices[count] * stride) + 1];
                  count++;

            }
            else
            {
                  x1 = vertices[0];
                  y1 = vertices[1];
                  vertices += stride;
                  x2 = vertices[0];
                  y2 = vertices[1];
                  vertices += stride;
                  x3 = vertices[0];
                  y3 = vertices[1];
                  vertices += stride;
                  x4 = vertices[0];
                  y4 = vertices[1];
                  vertices += stride;
                  count += 4;
            }


            if (!(mask & PAINT_WINDOW_TRANSFORMED_MASK))
            {
                  bx1 = 65535;
                  bx2 = 0.0;
                  by1 = 65535;
                  by2 = 0.0;
            }

            bx1 = MIN(bx1, x1);
            bx2 = MAX(bx2, x1);
            bx1 = MIN(bx1, x2);
            bx2 = MAX(bx2, x2);
            bx1 = MIN(bx1, x3);
            bx2 = MAX(bx2, x3);
            bx1 = MIN(bx1, x4);
            bx2 = MAX(bx2, x4);

            by1 = MIN(by1, y1);
            by2 = MAX(by2, y1);
            by1 = MIN(by1, y2);
            by2 = MAX(by2, y2);
            by1 = MIN(by1, y3);
            by2 = MAX(by2, y3);
            by1 = MIN(by1, y4);
            by2 = MAX(by2, y4);

            if (bx2 - bx1 > 0 && by2 - by1 > 0
                  && !(mask & PAINT_WINDOW_TRANSFORMED_MASK))
            {
                  rect.x = attrib->xTranslate +
                              (((bx1 - 7) - w->attrib.x) * attrib->xScale) +
                              w->attrib.x;
                  rect.y = attrib->yTranslate +
                              (((by1 - 1) - w->attrib.y) * attrib->yScale) +
                              w->attrib.y;
                  rect.width = (bx2 - bx1 + 14) * attrib->xScale;
                  rect.height = (by2 - by1 + 2) * attrib->yScale;

                  XUnionRectWithRegion(&rect, reblurRegion, reblurRegion);
            }
      }

      if (bx2 - bx1 > 0 && by2 - by1 > 0
            && (mask & PAINT_WINDOW_TRANSFORMED_MASK))
      {
            rect.x = attrib->xTranslate +
                        (((bx1 - 7) - w->attrib.x) * attrib->xScale) + w->attrib.x;
            rect.y = attrib->yTranslate +
                        (((by1 - 1) - w->attrib.y) * attrib->yScale) + w->attrib.y;
            rect.width = (bx2 - bx1 + 14) * attrib->xScale;
            rect.height = (by2 - by1 + 2) * attrib->yScale;

            XUnionRectWithRegion(&rect, reblurRegion, reblurRegion);
      }

      XIntersectRegion(reblurRegion, &s->region, reblurRegion);

      XSubtractRegion(reblurRegion, bs->blurredRegion, reblurRegion);

      // subtract occluded region
      if (bs->od_active)
            XSubtractRegion(reblurRegion, bw->clip, reblurRegion);

      // subtract blur cache texture region
      if (bw->texUpdated)
            XSubtractRegion(reblurRegion, bw->bTexRegion, reblurRegion);

      if (!reblurRegion->numRects)
      {
            XDestroyRegion(reblurRegion);
            return;
      }

      XUnionRegion(reblurRegion, bs->blurredRegion, bs->blurredRegion);

      glPushMatrix();

      // enable projective texture cooridinate generation
      float bm[16] = { s->outputDev[bs->output].width / 2.0, 0, 0, 0,
            0, s->outputDev[bs->output].height / -2.0, 0, 0,
            0, 0, 1, 0,
            s->outputDev[bs->output].width / 2.0 +
                        s->outputDev[bs->output].region.extents.x1,
            s->outputDev[bs->output].height / 2.0 +
                        s->outputDev[bs->output].region.extents.y1, 1, 1
      };
      float bpm[16];
      float tm[16];

      bw->mvm_updated = FALSE;
      glGetFloatv(GL_MODELVIEW_MATRIX, bw->mvm);

      MULTM(bm, bs->pm, bpm);
      MULTM(bpm, bw->mvm, tm);

      Bool enable_light = FALSE;

      if (glIsEnabled(GL_LIGHTING))
      {
            glDisable(GL_LIGHTING);
            enable_light = TRUE;
      }

      Bool enable_clipPlanes = FALSE;

      if (glIsEnabled(GL_CLIP_PLANE0))
      {
            glDisable (GL_CLIP_PLANE0);
            glDisable (GL_CLIP_PLANE1);
            glDisable (GL_CLIP_PLANE2);
            glDisable (GL_CLIP_PLANE3);
            enable_clipPlanes = TRUE;
      }

      int i;
      XRectangle sRect, bRect;

      for (i = 0; i < reblurRegion->numRects; i++)
      {

            rect.x = reblurRegion->rects[i].x1;
            rect.y = reblurRegion->rects[i].y1;
            rect.width = reblurRegion->rects[i].x2 - rect.x;
            rect.height = reblurRegion->rects[i].y2 - rect.y;

            // check region for visibility and project it to screen
            float bbProj[4][2];
            float bBox[4];

            bbProj[0][0] = rect.x * tm[0] + rect.y * tm[4] + tm[12];
            bbProj[0][0] /= rect.x * tm[3] + rect.y * tm[7] + tm[15];
            bbProj[0][1] = rect.x * tm[1] + rect.y * tm[5] + tm[13];
            bbProj[0][1] /= rect.x * tm[3] + rect.y * tm[7] + tm[15];
            bbProj[1][0] =
                        (rect.x + rect.width) * tm[0] + rect.y * tm[4] + tm[12];
            bbProj[1][0] /= (rect.x + rect.width) * tm[3] +
                        rect.y * tm[7] + tm[15];
            bbProj[1][1] =
                        (rect.x + rect.width) * tm[1] + rect.y * tm[5] + tm[13];
            bbProj[1][1] /= (rect.x + rect.width) * tm[3] +
                        rect.y * tm[7] + tm[15];
            bbProj[2][0] =
                        rect.x * tm[0] + (rect.y + rect.height) * tm[4] + tm[12];
            bbProj[2][0] /= rect.x * tm[3] + (rect.y +
                                                              rect.height) * tm[7] + tm[15];
            bbProj[2][1] =
                        rect.x * tm[1] + (rect.y + rect.height) * tm[5] + tm[13];
            bbProj[2][1] /= rect.x * tm[3] + (rect.y +
                                                              rect.height) * tm[7] + tm[15];
            bbProj[3][0] =
                        (rect.x + rect.width) * tm[0] + (rect.y +
                                                                         rect.height) * tm[4] +
                        tm[12];
            bbProj[3][0] /= (rect.x + rect.width) * tm[3] + (rect.y +
                                                                                     rect.height) *
                        tm[7] + tm[15];
            bbProj[3][1] =
                        (rect.x + rect.width) * tm[1] + (rect.y +
                                                                         rect.height) * tm[5] +
                        tm[13];
            bbProj[3][1] /= (rect.x + rect.width) * tm[3] + (rect.y +
                                                                                     rect.height) *
                        tm[7] + tm[15];

            // calculate a bounding box of the projected rectangle
            bBox[0] =
                        MIN(s->outputDev[bs->output].region.extents.x2, bbProj[0][0]);
            bBox[0] = MIN(bBox[0], bbProj[1][0]);
            bBox[0] = MIN(bBox[0], bbProj[2][0]);
            bBox[0] = MIN(bBox[0], bbProj[3][0]);
            bBox[0] = MAX(bBox[0], s->outputDev[bs->output].region.extents.x1);

            bBox[1] =
                        MIN(s->outputDev[bs->output].region.extents.y2, bbProj[0][1]);
            bBox[1] = MIN(bBox[1], bbProj[1][1]);
            bBox[1] = MIN(bBox[1], bbProj[2][1]);
            bBox[1] = MIN(bBox[1], bbProj[3][1]);
            bBox[1] = MAX(bBox[1], s->outputDev[bs->output].region.extents.y1);

            bBox[2] =
                        MAX(s->outputDev[bs->output].region.extents.x1, bbProj[0][0]);
            bBox[2] = MAX(bBox[2], bbProj[1][0]);
            bBox[2] = MAX(bBox[2], bbProj[2][0]);
            bBox[2] = MAX(bBox[2], bbProj[3][0]);
            bBox[2] = MIN(bBox[2], s->outputDev[bs->output].region.extents.x2);

            bBox[3] =
                        MAX(s->outputDev[bs->output].region.extents.y1, bbProj[0][1]);
            bBox[3] = MAX(bBox[3], bbProj[1][1]);
            bBox[3] = MAX(bBox[3], bbProj[2][1]);
            bBox[3] = MAX(bBox[3], bbProj[3][1]);
            bBox[3] = MIN(bBox[3], s->outputDev[bs->output].region.extents.y2);

            if (bBox[2] - bBox[0] <= 0 || bBox[3] - bBox[1] <= 0)
                  continue;

            sRect.x = floor(bBox[0] / bs->downSample);
            sRect.y = floor(bBox[1] / bs->downSample);
            sRect.width = MAX(1.0, ceil(bBox[2] / bs->downSample) - sRect.x);
            sRect.height = MAX(1.0, ceil(bBox[3] / bs->downSample) - sRect.y);


            bRect.x = sRect.x * bs->downSample;
            bRect.y = sRect.y * bs->downSample;
            bRect.width = sRect.width * bs->downSample;
            bRect.height = sRect.height * bs->downSample;

            glLoadIdentity();
            prepareXCoords(s, bs->output, -DEFAULT_Z_CAMERA);

            // copy background into temporary texture
            enableBlurfxTexture(&bs->blurTempTexV, COMP_TEXTURE_FILTER_GOOD);
            glCopyTexSubImage2D(bs->blurTempTexV.target, 0, 0, 0,
                                          bRect.x,
                                          s->height - bRect.y - bRect.height,
                                          bRect.width, bRect.height);

            // draw downsampled texture

            glBegin(GL_QUADS);
            glTexCoord2f(0, 0);
            glVertex2f(bRect.x, bRect.y);
            glTexCoord2f(0, bRect.height);
            glVertex2f(bRect.x, bRect.y + sRect.height);
            glTexCoord2f(bRect.width, bRect.height);
            glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
            glTexCoord2f(bRect.width, 0);
            glVertex2f(bRect.x + sRect.width, bRect.y);
            glEnd();

            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


            float shift = bs->downSample / 2.0;


            glColor4f(1.0, 1.0, 1.0, 0.5);


            glBegin(GL_QUADS);
            glTexCoord2f(0 + shift, 0);
            glVertex2f(bRect.x, bRect.y);
            glTexCoord2f(0 + shift, bRect.height);
            glVertex2f(bRect.x, bRect.y + sRect.height);
            glTexCoord2f(bRect.width + shift, bRect.height);
            glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
            glTexCoord2f(bRect.width + shift, 0);
            glVertex2f(bRect.x + sRect.width, bRect.y);
            glEnd();

            glColor4f(1.0, 1.0, 1.0, 0.333);


            glBegin(GL_QUADS);
            glTexCoord2f(0 - shift, 0);
            glVertex2f(bRect.x, bRect.y);
            glTexCoord2f(0 - shift, bRect.height);
            glVertex2f(bRect.x, bRect.y + sRect.height);
            glTexCoord2f(bRect.width - shift, bRect.height);
            glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
            glTexCoord2f(bRect.width - shift, 0);
            glVertex2f(bRect.x + sRect.width, bRect.y);
            glEnd();

            glColor4f(1.0, 1.0, 1.0, 0.25);


            glBegin(GL_QUADS);
            glTexCoord2f(0, 0 - shift);
            glVertex2f(bRect.x, bRect.y);
            glTexCoord2f(0, bRect.height - shift);
            glVertex2f(bRect.x, bRect.y + sRect.height);
            glTexCoord2f(bRect.width, bRect.height - shift);
            glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
            glTexCoord2f(bRect.width, 0 - shift);
            glVertex2f(bRect.x + sRect.width, bRect.y);
            glEnd();

            glColor4f(1.0, 1.0, 1.0, 0.2);


            glBegin(GL_QUADS);
            glTexCoord2f(0, 0 + shift);
            glVertex2f(bRect.x, bRect.y);
            glTexCoord2f(0, bRect.height + shift);
            glVertex2f(bRect.x, bRect.y + sRect.height);
            glTexCoord2f(bRect.width, bRect.height + shift);
            glVertex2f(bRect.x + sRect.width, bRect.y + sRect.height);
            glTexCoord2f(bRect.width, 0 + shift);
            glVertex2f(bRect.x + sRect.width, bRect.y);
            glEnd();


            glDisable(GL_BLEND);
            // copy downsampled background into temporary texture
            switchBlurfxTexture(&bs->blurTempTexV, &bs->blurTempTexH,
                                          COMP_TEXTURE_FILTER_GOOD);
            glCopyTexSubImage2D(bs->blurTempTexV.target, 0, sRect.x,
                                          sRect.y +
                                          ((s->height -
                                            s->outputDev[bs->output].region.
                                            extents.y2) / bs->downSample),
                                          bRect.x,
                                          s->height - bRect.y - sRect.height,
                                          sRect.width, sRect.height);

            // copy normal background back to screen
            switchBlurfxTexture(&bs->blurTempTexH, &bs->blurTempTexV,
                                          COMP_TEXTURE_FILTER_GOOD);

            glBegin(GL_QUADS);
            glTexCoord2f(0, bRect.height);
            glVertex2f(bRect.x, bRect.y);
            glTexCoord2f(0, 0);
            glVertex2f(bRect.x, bRect.y + bRect.height);
            glTexCoord2f(bRect.width, 0);
            glVertex2f(bRect.x + bRect.width, bRect.y + bRect.height);
            glTexCoord2f(bRect.width, bRect.height);
            glVertex2f(bRect.x + bRect.width, bRect.y);
            glEnd();

            disableBlurfxTexture(&bs->blurTempTexV);

      }

      glPopMatrix();

      if (enable_light)
            glEnable(GL_LIGHTING);

      if (enable_clipPlanes)
      {
            glEnable (GL_CLIP_PLANE0);
            glEnable (GL_CLIP_PLANE1);
            glEnable (GL_CLIP_PLANE2);
            glEnable (GL_CLIP_PLANE3);
      }

      XDestroyRegion(reblurRegion);
}

static void
drawBlur(CompWindow * w, CompScreen * s, CompTexture * texture,
             const WindowPaintAttrib * attrib, int mask, CompTextureFilter filter)
{

      int i, count, vCount, iCount, stride;
      GLfloat *vertices;
      GLushort *indices;
      GLfloat constant[4];

      unsigned int actTex = 0;

      BLURFX_SCREEN(s);
      BLURFX_WINDOW(w);

      glPushMatrix();

      if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
      {
            glTranslatef(w->attrib.x, w->attrib.y, 0.0f);
            glScalef(attrib->xScale, attrib->yScale, 0.0f);
            glTranslatef(attrib->xTranslate / attrib->xScale -
                               w->attrib.x,
                               attrib->yTranslate / attrib->yScale - w->attrib.y, 0.0f);
      }
      // Do we have an decoration vertex array thet does not contain shadows?
      if (mask & PAINT_WINDOW_DECORATION_MASK && bw->decoArray.vCount)
      {
            vertices = bw->decoArray.vertices + (w->texUnits * w->texCoordSize);
            indices = bw->decoArray.indices;
            vCount = bw->decoArray.vCount;
            iCount = bw->decoArray.indexCount;
      }
      else
      {
            vertices = w->vertices + (w->texUnits * w->texCoordSize);
            indices = w->indices;
            vCount = w->vCount;
            iCount = w->indexCount;
      }

      if (vCount <= 0)
            return;

      i = 0;
      count = 0;
      stride = (w->texUnits * w->texCoordSize + 2) * sizeof(GLfloat);

      // draw blur only for visible regions
      if (!(mask & PAINT_WINDOW_DECORATION_MASK) && !w->alpha
            && !(mask & PAINT_WINDOW_TRANSFORMED_MASK) && !w->shaded
            && bs->od_active)
      {
            Region drawBlurRegion = XCreateRegion();

            XIntersectRegion(w->region, bw->paintRegion, drawBlurRegion);
            if (bw->texUpdated)
                  XIntersectRegion(drawBlurRegion, bw->bTexRegion, drawBlurRegion);
            XSubtractRegion(drawBlurRegion, bw->clip, drawBlurRegion);

            CompMatrix mat;

            mat.xx = 0.0;
            mat.yx = 0.0;
            mat.xy = 0.0;
            mat.yy = 0.0;
            mat.x0 = 0.0;
            mat.y0 = 0.0;

            genGeometry(&bs->vertArray, mat, 0, drawBlurRegion);
            stride = 4 * sizeof(GLfloat);
            vCount = bs->vertArray.vCount;
            iCount = 0;
            vertices = bs->vertArray.vertices + 2;
            XDestroyRegion(drawBlurRegion);
      }

      glVertexPointer(2, GL_FLOAT, stride, vertices);
      GLERR;


      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      (*s->activeTexture) (GL_TEXTURE0_ARB);

      float tm[16];

      if ((mask & PAINT_WINDOW_TRANSFORMED_MASK) || !bw->texUpdated)
      {
            // enable projective texture cooridinate generation
            float bm[16] =
                        { s->outputDev[bs->output].width / (2.0 * bs->downSample), 0,
                  0, 0, 0,
                  s->outputDev[bs->output].height / (2.0 * bs->downSample),
                  0, 0, 0, 0, 1, 0,
                  s->outputDev[bs->output].width / (2.0 *
                                                                    bs->downSample) +
                              (s->outputDev[bs->output].region.extents.x1 /
                               bs->downSample),
                  s->outputDev[bs->output].height / (2.0 * bs->downSample) +
                              ((s->height -
                                s->outputDev[bs->output].region.extents.y2) /
                               bs->downSample), 1,
                  1
            };
            if (bs->downSample != 1.0)
                  bm[5] *= -1;
            float bpm[16];

            //if (!bw->mvm_updated)
            {
                  bw->mvm_updated = TRUE;
                  glGetFloatv(GL_MODELVIEW_MATRIX, bw->mvm);
            }

            MULTM(bm, bs->pm, bpm);
            MULTM(bpm, bw->mvm, tm);

            float s_gen[4] = { tm[0], tm[4], tm[8], tm[12] };
            float t_gen[4] = { tm[1], tm[5], tm[9], tm[13] };
            float r_gen[4] = { tm[2], tm[6], tm[10], tm[14] };
            float q_gen[4] = { tm[3], tm[7], tm[11], tm[15] };
            glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
            glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
            glTexGenfv(GL_R, GL_OBJECT_PLANE, r_gen);
            glTexGenfv(GL_Q, GL_OBJECT_PLANE, q_gen);

            glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glEnable(GL_TEXTURE_GEN_S);
            glEnable(GL_TEXTURE_GEN_T);
            glEnable(GL_TEXTURE_GEN_R);
            glEnable(GL_TEXTURE_GEN_Q);
            enableBlurfxTexture(&bs->blurTempTexH, filter);

      }
      else
      {
            // enable texture cooridinate generation
            float s_gen[4] = { 1.0 / bs->downSample, 0.0, 0.0,
                  -bw->blurTex.x / bs->downSample
            };

            if (bs->downSample != 1.0)
            {
                  float t_gen[4] = { 0.0, 1.0 / bs->downSample, 0.0,
                        -bw->blurTex.y / bs->downSample
                  };
                  glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
            }
            else
            {
                  float t_gen[4] = { 0.0, -1.0, 0.0,
                        bw->blurTex.height + bw->blurTex.y
                  };
                  glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
            }
            glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
            glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glEnable(GL_TEXTURE_GEN_S);
            glEnable(GL_TEXTURE_GEN_T);
            enableBlurfxTexture(&bw->blurTex, filter);
      }

      glDisableClientState(GL_TEXTURE_COORD_ARRAY);

      // simple switcher detection hack
      Bool switcher = FALSE;

      if (w->resName == 0 && w->resClass == 0
            && (mask & PAINT_WINDOW_DECORATION_MASK)
            && screenGrabExist(s, "switcher", 0))
            switcher = TRUE;

      // we need alpha dependend blur if window has alpha channel
      if (((mask & PAINT_WINDOW_DECORATION_MASK)
             && !bs->opt[BLURFX_SCREEN_OPTION_DISABLE_DECORATION_ALPHADEP].
             value.b) || switcher
            || (!(mask & PAINT_WINDOW_DECORATION_MASK) && w->alpha))
      {
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

            actTex++;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);
            glDisable(GL_TEXTURE_GEN_T);
            glDisable(GL_TEXTURE_GEN_S);
            enableTexture(s, texture, filter);
            GLERR;

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);


            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
            glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 4.0);

            constant[3] = attrib->opacity / 65535.0f;

            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);

            (*s->clientActiveTexture) (GL_TEXTURE1_ARB);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glTexCoordPointer(2, GL_FLOAT, stride,
                                      vertices - (w->texUnits * w->texCoordSize));
            GLERR;
      }
      else
      {
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
            constant[3] = MIN(1.0, (attrib->opacity / 65535.0f) * 4.0);

            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);

      }

      if (s->canDoSlightlySaturated
            && bs->opt[BLURFX_SCREEN_OPTION_BLUR_SATURATION].value.f < 100.0)
      {

            actTex++;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);
            enableBlurfxTexture(&bs->blurTempTexH, filter);

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PRIMARY_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

            glColor4f(1.0f, 1.0f, 1.0f, 0.5f);

            actTex++;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);
            enableBlurfxTexture(&bs->blurTempTexH, filter);

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

            constant[0] = 0.5f + 0.5f * RED_SATURATION_WEIGHT;
            constant[1] = 0.5f + 0.5f * GREEN_SATURATION_WEIGHT;
            constant[2] = 0.5f + 0.5f * BLUE_SATURATION_WEIGHT;
            constant[3] = 1.0;

            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);

            actTex++;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);
            enableBlurfxTexture(&bs->blurTempTexH, filter);

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

            constant[3] =
                        bs->opt[BLURFX_SCREEN_OPTION_BLUR_SATURATION].value.f / 100.0;

            glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
      }

      // draw blur
      if (iCount)
      {
            glDrawElements(GL_QUADS, iCount, GL_UNSIGNED_SHORT, indices);
            GLERR;
      }
      else
      {
            glDrawArrays(GL_QUADS, 0, vCount);
            GLERR;
      }

      // set all back to normal

      if (s->canDoSlightlySaturated
            && bs->opt[BLURFX_SCREEN_OPTION_BLUR_SATURATION].value.f < 100.0)
      {

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

            disableBlurfxTexture(&bs->blurTempTexH);
            actTex--;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

            glDisable(GL_TEXTURE_GEN_S);
            glDisable(GL_TEXTURE_GEN_T);
            glDisable(GL_TEXTURE_GEN_R);
            glDisable(GL_TEXTURE_GEN_Q);

            disableBlurfxTexture(&bs->blurTempTexH);
            actTex--;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

            disableBlurfxTexture(&bs->blurTempTexH);
            actTex--;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);

      }

      if (((mask & PAINT_WINDOW_DECORATION_MASK)
             && !bs->opt[BLURFX_SCREEN_OPTION_DISABLE_DECORATION_ALPHADEP].
             value.b) || switcher
            || (!(mask & PAINT_WINDOW_DECORATION_MASK) && w->alpha))
      {
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
            disableTexture(s, texture);
            GLERR;

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);


            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);

            glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1.0);

            (*s->clientActiveTexture) (GL_TEXTURE0_ARB);
            actTex--;
            (*s->activeTexture) (GL_TEXTURE0_ARB + actTex);

      }

      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);

      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
      glDisable(GL_TEXTURE_RECTANGLE_ARB);
      glDisable(GL_TEXTURE_GEN_S);
      glDisable(GL_TEXTURE_GEN_T);
      glDisable(GL_TEXTURE_GEN_R);
      glDisable(GL_TEXTURE_GEN_Q);
      glDisable(GL_BLEND);

      glPopMatrix();
      GLERR;

}

static void
drawReflection(CompWindow * w, CompScreen * s, CompTexture * texture,
                     const WindowPaintAttrib * attrib, int mask,
                     CompTextureFilter filter)
{

      int vCount, iCount;
      GLfloat *vertices;
      GLushort *indices;

      float dx, dy;

      BLURFX_SCREEN(w->screen);
      BLURFX_WINDOW(w);

      glPushMatrix();

      if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
      {
            glTranslatef(w->attrib.x, w->attrib.y, 0.0f);
            glScalef(attrib->xScale, attrib->yScale, 0.0f);
            glTranslatef(attrib->xTranslate / attrib->xScale -
                               w->attrib.x,
                               attrib->yTranslate / attrib->yScale - w->attrib.y, 0.0f);

      }
      // setup reflection texture scaling
      if (bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_SCALE].value.b)
      {
            if (bs->opt[BLURFX_SCREEN_OPTION_REFLECTION_PROPORTIONAL].value.b)
            {

                  dx = 1.0 /
                              (((s->width / bs->modTex.width) *
                                bs->modTex.height >
                                s->height) ? (s->height /
                                                      bs->modTex.height) *
                               bs->modTex.width : s->width);
                  dy = 1.0 /
                              (((s->width / bs->modTex.width) *
                                bs->modTex.height >
                                s->height) ? s->height : (s->width /
                                                                        bs->modTex.width) *
                               bs->modTex.height);
            }
            else
            {
                  dx = 1.0 / s->width;
                  dy = 1.0 / s->height;
            }
      }
      else
      {
            dx = 1.0 / bs->modTex.width;
            dy = 1.0 / bs->modTex.height;
      }


      // Do we have an decoration vertex array thet does not contain shadows?
      if (mask & PAINT_WINDOW_DECORATION_MASK && bw->decoArray.vCount)
      {
            vertices = bw->decoArray.vertices + (w->texUnits * w->texCoordSize);
            indices = bw->decoArray.indices;
            vCount = bw->decoArray.vCount;
            iCount = bw->decoArray.indexCount;
      }
      else
      {
            vertices = w->vertices + (w->texUnits * w->texCoordSize);
            indices = w->indices;
            vCount = w->vCount;
            iCount = w->indexCount;
      }

      if (vCount <= 0)
            return;

      int stride = (w->texUnits * w->texCoordSize + 2) * sizeof(GLfloat);

      // draw reflection only for visible regions
      if (!(mask & PAINT_WINDOW_DECORATION_MASK) && !w->alpha
            && !(mask & PAINT_WINDOW_TRANSFORMED_MASK) && !w->shaded)
      {
            Region drawBlurRegion = XCreateRegion();

            XIntersectRegion(w->region, bw->paintRegion, drawBlurRegion);
            XSubtractRegion(drawBlurRegion, bw->clip, drawBlurRegion);

            CompMatrix mat;

            mat.xx = 0.0;
            mat.yx = 0.0;
            mat.xy = 0.0;
            mat.yy = 0.0;
            mat.x0 = 0.0;
            mat.y0 = 0.0;

            genGeometry(&bs->vertArray, mat, 0, drawBlurRegion);
            stride = 4 * sizeof(GLfloat);
            vCount = bs->vertArray.vCount;
            iCount = 0;
            vertices = bs->vertArray.vertices + 2;
            XDestroyRegion(drawBlurRegion);
      }

      glVertexPointer(2, GL_FLOAT, stride, vertices);


      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


      (*s->activeTexture) (GL_TEXTURE0_ARB);
      enableBlurfxTexture(&bs->modTex, filter);

      if (mask &
            (PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK |
             PAINT_WINDOW_TRANSFORMED_MASK))
      {
            // enable projective texture cooridinate generation
            float bm[16] = { (s->width * dx) / 2.0, 0, 0, 0, 0,
                  (s->height * dy) / -2.0, 0,
                  0, 0, 0, 1, 0, (s->width * dx) / 2.0,
                  (s->height * dy) / 2.0, 1, 1
            };
            float bpm[16];
            float tm[16];
            float mvm[16];

            glPushMatrix();
            glLoadIdentity();
            glTranslatef(-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
            glScalef(1.0f / s->width, -1.0f / s->height, 1.0f);
            glTranslatef(0.0f, -s->height, 0.0f);

            if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
            {
                  glTranslatef(w->attrib.x, w->attrib.y, 0.0f);
                  glScalef(attrib->xScale, attrib->yScale, 0.0f);
                  glTranslatef(attrib->xTranslate / attrib->xScale -
                                     w->attrib.x,
                                     attrib->yTranslate / attrib->yScale -
                                     w->attrib.y, 0.0f);
            }
            glGetFloatv(GL_MODELVIEW_MATRIX, mvm);
            glPopMatrix();

            MULTM(bm, bs->pm, bpm);
            MULTM(bpm, mvm, tm);

            float s_gen[4] = { tm[0], tm[4], tm[8], tm[12] };
            float t_gen[4] = { tm[1], tm[5], tm[9], tm[13] };
            float r_gen[4] = { tm[2], tm[6], tm[10], tm[14] };
            float q_gen[4] = { tm[3], tm[7], tm[11], tm[15] };
            glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
            glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
            glTexGenfv(GL_R, GL_OBJECT_PLANE, r_gen);
            glTexGenfv(GL_Q, GL_OBJECT_PLANE, q_gen);

            glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

            glEnable(GL_TEXTURE_GEN_S);
            glEnable(GL_TEXTURE_GEN_T);
            glEnable(GL_TEXTURE_GEN_R);
            glEnable(GL_TEXTURE_GEN_Q);
      }
      else
      {
            // enable texture cooridinate generation
            float s_gen[4] = { dx, 0.0, 0.0, 0.0 };
            float t_gen[4] = { 0.0, dy, 0.0, 0.0 };
            glTexGenfv(GL_T, GL_OBJECT_PLANE, t_gen);
            glTexGenfv(GL_S, GL_OBJECT_PLANE, s_gen);
            glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
            glEnable(GL_TEXTURE_GEN_S);
            glEnable(GL_TEXTURE_GEN_T);
      }

      glDisableClientState(GL_TEXTURE_COORD_ARRAY);

      glColor4f(1.0, 1.0, 1.0, attrib->opacity / 65535.0f);

      // simple switcher detection hack
      Bool switcher = FALSE;

      if (w->resName == 0 && w->resClass == 0
            && (mask & PAINT_WINDOW_DECORATION_MASK)
            && screenGrabExist(s, "switcher", 0))
            switcher = TRUE;

      // we need alpha dependend reflection if window has alpha channel
      if (((mask & PAINT_WINDOW_DECORATION_MASK)
             && !bs->opt[BLURFX_SCREEN_OPTION_DISABLE_DECORATION_ALPHADEP].
             value.b) || switcher
            || (!(mask & PAINT_WINDOW_DECORATION_MASK) && w->alpha))
      {
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

            (*s->activeTexture) (GL_TEXTURE1_ARB);
            enableTexture(s, texture, filter);
            GLERR;

            glDisable(GL_TEXTURE_GEN_T);
            glDisable(GL_TEXTURE_GEN_S);

            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

            (*s->clientActiveTexture) (GL_TEXTURE1_ARB);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glTexCoordPointer(2, GL_FLOAT, stride,
                                      vertices - (w->texUnits * w->texCoordSize));
      }
      else
      {
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
      }

      // draw reflection
      if (iCount)
      {
            glDrawElements(GL_QUADS, iCount, GL_UNSIGNED_SHORT, indices);
            GLERR;
      }
      else
      {
            glDrawArrays(GL_QUADS, 0, vCount);
            GLERR;
      }

      // set all back to normal
      if (((mask & PAINT_WINDOW_DECORATION_MASK)
             && !bs->opt[BLURFX_SCREEN_OPTION_DISABLE_DECORATION_ALPHADEP].
             value.b) || switcher
            || (!(mask & PAINT_WINDOW_DECORATION_MASK) && w->alpha))
      {
            disableTexture(s, texture);
            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

            glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
            glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);

            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
            (*s->clientActiveTexture) (GL_TEXTURE0_ARB);
            (*s->activeTexture) (GL_TEXTURE0_ARB);
      }

      glEnableClientState(GL_TEXTURE_COORD_ARRAY);

      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
      glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
      glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
      glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

      glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
      glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
      glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);

      disableBlurfxTexture(&bs->modTex);

      glDisable(GL_TEXTURE_GEN_S);
      glDisable(GL_TEXTURE_GEN_T);
      glDisable(GL_TEXTURE_GEN_R);
      glDisable(GL_TEXTURE_GEN_Q);

      glPopMatrix();

      glDisable(GL_BLEND);

}

// activate/deactivate motion blur
static Bool
blurfxToggleMotionBlur(CompDisplay * d, CompAction * ac,
                                 CompActionState state, CompOption * option,
                                 int nOption)
{
      CompScreen *s;

      s = findScreenAtDisplay(d, getIntOptionNamed(option, nOption, "root", 0));
      if (s)
      {
            BLURFX_SCREEN(s);
            bs->mb_activated = !bs->mb_activated;
            bs->mb_activated &= bs->mblur_supported;
      }
      return FALSE;
}


// bind our fbo and bind the texture to it
static Bool bindFbo(CompScreen * s, BlurTexture tex)
{

      BLURFX_SCREEN(s);

      GLERR;

      (*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, bs->fbo);
      (*s->framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
                                                GL_COLOR_ATTACHMENT0_EXT,
                                                GL_TEXTURE_RECTANGLE_ARB, tex.handle, 0);

      if (!bs->fboStatus)
      {
            bs->fboStatus = (*s->checkFramebufferStatus) (GL_FRAMEBUFFER_EXT);
            if (bs->fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
            {
                  (*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
                  s->bindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
                  printf("Framebuffer attach failed\n");
                  bs->fboStatus = 0;
                  bs->fboActive = FALSE;

                  glMatrixMode(GL_PROJECTION);
                  glPushMatrix();
                  glLoadIdentity();
                  glMatrixMode(GL_MODELVIEW);
                  glPushMatrix();
                  glLoadIdentity();
                  glDepthRange(0, 1);
                  glViewport(-1, -1, 2, 2);
                  glRasterPos2f(0, 0);
                  s->rasterX = s->rasterY = 0;
                  glViewport(s->outputDev[bs->output].region.extents.x1,
                                 s->height - s->outputDev[bs->output].region.extents.y2,
                                 s->outputDev[bs->output].width,
                                 s->outputDev[bs->output].height);

                  glMatrixMode(GL_PROJECTION);
                  glPopMatrix();
                  glMatrixMode(GL_MODELVIEW);
                  glPopMatrix();

                  glDrawBuffer(GL_BACK);
                  glReadBuffer(GL_BACK);

                  return FALSE;
            }
      }
      //Set the draw  buffer
      glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
      glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);

      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glLoadIdentity();
      glDepthRange(0, 1);
      glViewport(-1, -1, 2, 2);
      glRasterPos2f(0, 0);
      glViewport(s->outputDev[bs->output].region.extents.x1,
                     s->height - s->outputDev[bs->output].region.extents.y2,
                     s->outputDev[bs->output].width,
                     s->outputDev[bs->output].height);

      prepareXCoords(s, bs->output, -DEFAULT_Z_CAMERA);

      bs->fboActive = TRUE;

      GLERR;

      return TRUE;
}

// unbind the fbo and set everything back to normal
static void unbindFbo(CompScreen * s)
{

      BLURFX_SCREEN(s);

      if (!bs->fboActive)
            return;

      GLERR;
      // unbind fbo
      (*s->bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);

      // set alles back to normal
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glDepthRange(0, 1);
      glViewport(-1, -1, 2, 2);
      glRasterPos2f(0, 0);
      s->rasterX = s->rasterY = 0;
      glViewport(s->outputDev[bs->output].region.extents.x1,
                     s->height - s->outputDev[bs->output].region.extents.y2,
                     s->outputDev[bs->output].width,
                     s->outputDev[bs->output].height);

      glMatrixMode(GL_PROJECTION);
      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
      glPopMatrix();

      glDrawBuffer(GL_BACK);
      glReadBuffer(GL_BACK);

      bs->fboActive = FALSE;

      GLERR;
}

// generate a vertex and coordinate aray for the given region
static void
genGeometry(BlurfxVertArray * vA, CompMatrix matrix, int xextend,
                  Region region)
{

      BoxPtr pBox;
      int nBox;
      int vSize;
      int n, x1, y1, x2, y2;
      GLfloat *d;

      pBox = region->rects;
      nBox = region->numRects;

      vSize = 4;

      n = 0;

      if (nBox * vSize * 4 > vA->vertexSize)
      {
            if (!moreVertices(vA, nBox * vSize * 4))
                  return;
      }

      d = vA->vertices;

      while (nBox--)
      {
            x1 = pBox->x1 - xextend;
            y1 = pBox->y1;
            x2 = pBox->x2 + xextend;
            y2 = pBox->y2;

            pBox++;

            if (x1 < x2 && y1 < y2)
            {
                  BFX_ADD_RECT(d, matrix, x1, y1, x2, y2);
                  n++;
            }
      }
      vA->vCount = n * 4;

}

// helper function for genGeometry
static Bool moreVertices(BlurfxVertArray * vA, int newSize)
{
      if (newSize > vA->vertexSize)
      {
            GLfloat *vertices;

            vertices = realloc(vA->vertices, sizeof(GLfloat) * newSize);
            if (!vertices)
                  return FALSE;

            vA->vertices = vertices;
            vA->vertexSize = newSize;
      }
      return TRUE;
}

// does opengl level iniliazation of the screen
static void
initBlurfxScreen(BlurfxScreen * bs, int Screenwidth, int Screenheight,
                         CompScreen * s)
{
      bs->blurShaderV = 0;
      bs->blurShaderH = 0;

      bs->backTex.handle = 0;
      bs->blurTempTexV.handle = 0;
      bs->blurTempTexH.handle = 0;
      bs->motionTex.handle = 0;

      bs->fbo = 0;

      if (bs->fboBlur_supported
            && !bs->opt[BLURFX_SCREEN_OPTION_FORCE_NON_FBO_BLUR].value.b)
      {
            // load shaders
            loadShader(GL_FRAGMENT_PROGRAM_ARB, s, &bs->blurShaderV,
                           blurShader[bs->blur_shader][0]);
            loadShader(GL_FRAGMENT_PROGRAM_ARB, s, &bs->blurShaderH,
                           blurShader[bs->blur_shader][1]);

            bs->downSample = 1.0;
      }

      if (bs->blur_supported)
      {
            genBlurTexture(bs, &bs->blurTempTexV, Screenwidth, Screenheight, 0);
            genBlurTexture(bs, &bs->blurTempTexH, Screenwidth, Screenheight, 0);
      }
      //Generate a fbo
      if (s->fbo)
      {
            (*s->genFramebuffers) (1, &bs->fbo);
            GLERR;
            bs->fboStatus = 0;

            // generate textures
            genBlurTexture(bs, &bs->backTex, Screenwidth, Screenheight, 1);
      }

      if (bs->mblur_supported && bs->mb_mode != 1)
      {
            // generate morion blur texture
            genBlurTexture(bs, &bs->motionTex, Screenwidth,
                                 Screenheight, bs->mb_mode);
      }

      bs->modTex.handle = 0;

      if (bs->reflection_supported)
      {
            // load reflection map
            loadPngToTexture2D(s, &bs->modTex,
                                       bs->
                                       opt[BLURFX_SCREEN_OPTION_REFLECTION_FILE].value.s);
      }

      bs->hasInit = 1;
}

// generate texture
static void
genBlurTexture(BlurfxScreen * bs, BlurTexture * tex, int width, int height,
                     int type)
{
      GLERR;

      //Enable texturing
      glEnable(GL_TEXTURE_RECTANGLE_ARB);
      //Generate the OpenGL textures
      if (!tex->handle)
            glGenTextures(1, &tex->handle);
      //Write important info into the structure
      tex->width = width;
      tex->height = height;
      //Bind the texture
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex->handle);
      //Load the parameters
      glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
                              GL_LINEAR);
      glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
                              GL_LINEAR);
      glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);

      tex->target = GL_TEXTURE_RECTANGLE_ARB;
      tex->active_filter = GL_LINEAR;

      //Generate a large image
      switch (type)
      {
      case 1:
            glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width,
                               height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
            break;
      case 2:
            glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB16F_ARB,
                               width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
            break;
      case 0:
      default:
            glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, width,
                               height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
            break;
      }
      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
      glDisable(GL_TEXTURE_RECTANGLE_ARB);

      GLERR;
}

// load shader
static void
loadShader(GLenum type, CompScreen * s, GLuint * shader, const char *prog)
{

      //Switch a bunch of strings
      char buffer[4096];

      sprintf(buffer, prog);
      int errorPos, errorNum;

      glGetError();

      //Load the fragment program
      if (*shader == 0)
            (*s->genPrograms) (1, shader);
      (*s->bindProgram) (type, *shader);

      (*s->programString) (type, GL_PROGRAM_FORMAT_ASCII_ARB,
                                     strlen(buffer), buffer);


      glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
      errorNum = glGetError();
      if (errorNum != GL_NO_ERROR || errorPos != -1)
      {
            fprintf(stderr,
                        "%s: (0x%X) error loading fragment program at line: %d\n",
                        getProgramName(), errorNum, errorPos);
            fprintf(stderr, "%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
            glGetIntegerv(GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &errorPos);
            if (*shader)
                  (*s->deletePrograms) (1, shader);
            *shader = 0;
      }
      (*s->bindProgram) (type, 0);
}

// load png
static void
loadPngToTexture2D(CompScreen * s, BlurTexture * tex, char *filename)
{

      int img_w = 0, img_h = 0, stride = 0;
      char *img_data;
      char *img_mod;
      struct stat fInfo;

      int i = 0;
      float Y, R, G, B;
      int pix;

      BLURFX_SCREEN(s);

      if (strlen(filename) == 0)
            return;

      GLERR;

      if (stat(filename, &fInfo) ||
            !S_ISREG(fInfo.st_mode) ||
            S_ISDIR(fInfo.st_mode) || access(filename, F_OK) != 0)
      {
            fprintf(stderr, "Unable to read image \"%s\" \n", filename);
            return;
      }
      fprintf(stderr, "Loading image \"%s\" \n", filename);

      // Was: readPng(filename, &img_data, &img_w, &img_h);
      if (!(*s->display->fileToImage)
            (s->display, NULL, filename, &img_w, &img_h, &stride,
             (void *)&img_data))
      {
            printf("Unable to load image \"%s\" \n", filename);
            return;
      }

      printf("%s loaded. w: %i; h: %i\n", filename, img_w, img_h);

      //Generate the OpenGL textures
      if (tex->handle == 0)
            glGenTextures(1, &tex->handle);

      glEnable(GL_TEXTURE_2D);
      //Bind the texture
      glBindTexture(GL_TEXTURE_2D, tex->handle);

      //Load the parameters
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

      tex->target = GL_TEXTURE_2D;
      tex->active_filter = GL_LINEAR;
      tex->width = img_w;
      tex->height = img_h;

      // merge all colors to an alpha texture if not disabled
      img_mod = malloc(img_w * img_h * 4);
      for (i = 0; i < img_w * img_h; i++)
      {
            R = img_data[(i * 4) + 2];
            G = img_data[(i * 4) + 1];
            B = img_data[i * 4];
            Y = (R * 0.299) + (G * 0.587) + (B * 0.114);
            pix = Y;
            img_mod[i * 4] =
                        (bs->
                         opt[BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_COLOR].
                         value.b) ? img_data[(i * 4) + 2] : (char)pix;
            img_mod[(i * 4) + 1] =
                        (bs->
                         opt[BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_COLOR].
                         value.b) ? img_data[(i * 4) + 1] : (char)pix;
            img_mod[(i * 4) + 2] =
                        (bs->
                         opt[BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_COLOR].
                         value.b) ? img_data[i * 4] : (char)pix;
            img_mod[(i * 4) + 3] =
                        (bs->
                         opt[BLURFX_SCREEN_OPTION_REFLECTION_USE_IMAGE_ALPHA].
                         value.b) ? img_data[(i * 4) + 3] : (char)pix;
      }

      glTexImage2D(GL_TEXTURE_2D, 0, 4, img_w, img_h, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, img_mod);
      GLERR;

      glBindTexture(GL_TEXTURE_2D, 0);
      glDisable(GL_TEXTURE_2D);
      free(img_mod);
      free(img_data);

}

// enable texture and set filter
static void enableBlurfxTexture(BlurTexture * tex, CompTextureFilter filter)
{
      glEnable(tex->target);
      glBindTexture(tex->target, tex->handle);
      GLERR;
      switch (filter)
      {
      case COMP_TEXTURE_FILTER_FAST:
            if (tex->active_filter != GL_NEAREST)
            {
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                  tex->active_filter = GL_NEAREST;
            }
            break;
      case COMP_TEXTURE_FILTER_GOOD:
      default:
            if (tex->active_filter != GL_LINEAR)
            {
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                  tex->active_filter = GL_LINEAR;
            }
            break;
      }
}

// disable texture
static void disableBlurfxTexture(BlurTexture * tex)
{
      glBindTexture(tex->target, 0);
      GLERR;
      glDisable(tex->target);
}

// switch to another texture and set filter
static void
switchBlurfxTexture(BlurTexture * from, BlurTexture * to,
                              CompTextureFilter filter)
{
      if (from->target != to->target)
      {
            disableBlurfxTexture(from);
            enableBlurfxTexture(to, filter);
      }
      glBindTexture(to->target, to->handle);
      GLERR;
      switch (filter)
      {
      case COMP_TEXTURE_FILTER_FAST:
            if (to->active_filter != GL_NEAREST)
            {
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                  to->active_filter = GL_NEAREST;
            }
            break;
      case COMP_TEXTURE_FILTER_GOOD:
      default:
            if (to->active_filter != GL_LINEAR)
            {
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                  to->active_filter = GL_LINEAR;
            }
            break;
      }
}

Generated by  Doxygen 1.6.0   Back to index