summaryrefslogtreecommitdiff
path: root/src/vignetting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vignetting.cpp')
-rw-r--r--src/vignetting.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/vignetting.cpp b/src/vignetting.cpp
new file mode 100644
index 0000000..be8d1d4
--- /dev/null
+++ b/src/vignetting.cpp
@@ -0,0 +1,238 @@
+#include "vignetting.h"
+
+COMPIZ_PLUGIN_20090315 (vignetting, VigPluginVTable);
+
+void
+VigScreen::cairoClear (cairo_t *cr)
+{
+ if (pixmap)
+ {
+ XFreePixmap (screen->dpy (), pixmap);
+ pixmap = None;
+ }
+ if (surface)
+ {
+ cairo_surface_destroy (surface);
+ surface = NULL;
+ }
+ if (cairo)
+ {
+ cairo_destroy (cairo);
+ cairo = NULL;
+ }
+
+ cairo = cairoContext ();
+
+ if (cairo)
+ {
+ cairo_save (cairo);
+ cairo_set_operator (cairo, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cairo);
+ cairo_restore (cairo);
+ }
+}
+
+cairo_t *
+VigScreen::cairoContext ()
+{
+ if (!cairo)
+ {
+ XRenderPictFormat *format;
+ Screen *xScreen;
+ int w, h;
+
+ xScreen = ScreenOfDisplay (screen->dpy (), screen->screenNum ());
+
+ w = optionGetQuality () * 50;
+ h = optionGetQuality () * 50;
+
+ format = XRenderFindStandardFormat (screen->dpy (),
+ PictStandardARGB32);
+
+ pixmap = XCreatePixmap (screen->dpy (), screen->root (), w, h, 32);
+
+ texture = GLTexture::bindPixmapToTexture (pixmap, w, h, 32);
+
+ if (texture.empty ())
+ {
+ compLogMessage ("annotate", CompLogLevelError,
+ "Couldn't bind pixmap 0x%x to texture",
+ (int) pixmap);
+
+ XFreePixmap (screen->dpy (), pixmap);
+
+ return NULL;
+ }
+
+ damage = XDamageCreate (screen->dpy (), pixmap,
+ XDamageReportRawRectangles);
+
+ surface =
+ cairo_xlib_surface_create_with_xrender_format (screen->dpy (),
+ pixmap, xScreen,
+ format, w, h);
+
+ cairo = cairo_create (surface);
+ }
+
+ return cairo;
+}
+
+void
+VigScreen::renderVignette ()
+{
+ cairo_pattern_t *pat;
+ cairoClear (cairo);
+
+ unsigned int size = optionGetQuality () * 50;
+
+ /* Radial gradient - transparent center, opaque black outside */
+ pat = cairo_pattern_create_radial (size / 2, size / 2, size / 20,
+ size / 2, size / 2, size / 2);
+
+ /* Transparent */
+ cairo_pattern_add_color_stop_rgba (pat, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+ /* Black */
+ cairo_pattern_add_color_stop_rgba (pat, 1.0f, 0.0f, 0.0f, 0.0f, 0.9f);
+ /* Drawing over whatever was there */
+ cairo_set_operator (cairo, CAIRO_OPERATOR_OVER);
+ /* Copy the size of the rectangle to the surface from the gradient
+ */
+ cairo_rectangle (cairo, 0, 0, (optionGetQuality () * 50),
+ (optionGetQuality () * 50));
+ cairo_set_source (cairo, pat);
+ cairo_fill (cairo);
+
+ cairo_pattern_destroy (pat);
+
+}
+
+/* Draw the window */
+
+bool
+VigWindow::glDraw (const GLMatrix &transform,
+ GLFragment::Attrib &fragment,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ /* Save the brightness, we will be using it later */
+ float brightness = fragment.getBrightness ();
+
+ /* We want to set the geometry of the vignette to the window
+ * region */
+ CompRegion reg = CompRegion (window->inputRect ());
+
+ /* Draw the window on the bottom, we will be drawing the
+ * vignette render on top */
+ bool status = gWindow->glDraw (transform, fragment, region, mask);
+
+ VIG_SCREEN (screen);
+
+ foreach (GLTexture *tex, vs->texture)
+ {
+ GLTexture::MatrixList matl;
+ GLTexture::Matrix mat = tex->matrix ();
+
+ /* We can reset the window geometry since it will be
+ * re-added later */
+ gWindow->geometry ().reset ();
+
+ /* Scale the vignette render by the ratio of vignette size
+ * to window size */
+ mat.xx *= (vs->optionGetQuality () * 50.0f) / window->inputRect ().width ();
+ mat.yy *= (vs->optionGetQuality () * 50.0f) / window->inputRect ().height ();
+
+ /* Not sure what this does, but it is necessary
+ * (adjusts for scale?) */
+ mat.x0 -= mat.xx * reg.boundingRect ().x1 ();
+ mat.y0 -= mat.yy * reg.boundingRect ().y1 ();
+
+ matl.push_back (mat);
+
+ /* Now allow plugins to mess with the geometry of our
+ * vignette (so we get a nice render for things like
+ * wobbly etc etc */
+ gWindow->glAddGeometry (matl, reg, infiniteRegion);
+
+ /* Did it succeed? */
+ if (gWindow->geometry ().vertices)
+ {
+ /* Set the opacity of the vignette render to
+ * the opposite of the real brightness of the window */
+ fragment.setOpacity (OPAQUE - brightness);
+ /* Texture rendering set-up */
+ vs->gScreen->setTexEnvMode (GL_MODULATE);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ /* Draw the vignette texture with all of it's modified
+ * geometry glory */
+ gWindow->glDrawTexture (tex, fragment, mask | PAINT_WINDOW_BLEND_MASK
+ | PAINT_WINDOW_TRANSLUCENT_MASK |
+ PAINT_WINDOW_TRANSFORMED_MASK);
+ /* Texture rendering tear-down */
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ vs->gScreen->setTexEnvMode (GL_REPLACE);
+ }
+ }
+
+ return status;
+}
+
+void
+VigScreen::optionChanged (CompOption *opt,
+ Options num)
+{
+ switch (num)
+ {
+ case VignettingOptions::Quality:
+ renderVignette ();
+ default:
+ break;
+ }
+}
+
+
+
+/* Constructors */
+
+VigWindow::VigWindow (CompWindow *w) :
+ PluginClassHandler <VigWindow, CompWindow> (w),
+ window (w),
+ cWindow (CompositeWindow::get (w)),
+ gWindow (GLWindow::get (w))
+{
+ GLWindowInterface::setHandler (gWindow);
+}
+
+VigWindow::~VigWindow ()
+{
+}
+
+VigScreen::VigScreen (CompScreen *s) :
+ PluginClassHandler <VigScreen, CompScreen> (s),
+ cScreen (CompositeScreen::get (s)),
+ gScreen (GLScreen::get (s)),
+ pixmap (None),
+ surface (NULL),
+ cairo (NULL)
+{
+ renderVignette ();
+
+ optionSetQualityNotify (boost::bind (&VigScreen::optionChanged, this,
+ _1, _2));
+};
+
+VigScreen::~VigScreen ()
+{
+ cairoClear (cairo);
+}
+
+bool
+VigPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
+ !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
+ !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
+ return false;
+
+ return true;
+}