/* * 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 #include #include #include #include #include #include #include #include #include #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; } }