summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Spilsbury <smspillaz@XPS-FEDORA.(none)>2009-08-02 15:21:04 +0800
committerSam Spilsbury <smspillaz@XPS-FEDORA.(none)>2009-08-02 15:21:04 +0800
commit312c3e3fdda4f2532316a4d8fafb70f85e448045 (patch)
tree4ccbc5c553bc010d6608f028a3b1fab34707126b
parentfd3d7459a75591782dc18d5e357af93682f14f55 (diff)
downloadmag-312c3e3fdda4f2532316a4d8fafb70f85e448045.tar.gz
mag-312c3e3fdda4f2532316a4d8fafb70f85e448045.tar.bz2
Added relevant files
-rw-r--r--src/mag.cpp1007
-rw-r--r--src/mag.h175
2 files changed, 1182 insertions, 0 deletions
diff --git a/src/mag.cpp b/src/mag.cpp
new file mode 100644
index 0000000..80a607a
--- /dev/null
+++ b/src/mag.cpp
@@ -0,0 +1,1007 @@
+/*
+ *
+ * Compiz magnifier plugin
+ *
+ * mag.c
+ *
+ * Copyright : (C) 2008 by Dennis Kasprzyk
+ * E-mail : onestone@opencompositing.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 "mag.h"
+
+COMPIZ_PLUGIN_20090315 (mag, MagPluginVTable);
+
+void
+MagScreen::cleanup ()
+{
+ if (overlay.size ())
+ {
+ overlay.clear ();
+ }
+ if (mask.size ())
+ {
+ mask.clear ();
+ }
+
+ if (program)
+ {
+ GL::deletePrograms (1, &program);
+ program = 0;
+ }
+}
+
+bool
+MagScreen::loadFragmentProgram ()
+{
+ char buffer[1024];
+ GLsizei bufSize;
+ GLint errorPos;
+
+ if (!GL::fragmentProgram)
+ return false;
+
+ if (target == GL_TEXTURE_2D)
+ sprintf (buffer, fisheyeFpString, "2D");
+ else
+ sprintf (buffer, fisheyeFpString, "RECT");
+
+ /* clear errors */
+ glGetError ();
+
+ if (!program)
+ GL::genPrograms (1, &program);
+
+ bufSize = (GLsizei) strlen (buffer);
+
+ GL::bindProgram (GL_FRAGMENT_PROGRAM_ARB, program);
+ GL::programString (GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ bufSize, buffer);
+
+ glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError () != GL_NO_ERROR || errorPos != -1)
+ {
+ compLogMessage ("mag", CompLogLevelError,
+ "failed to load fisheye fragment program");
+
+ GL::deletePrograms (1, &program);
+ program = 0;
+
+ return false;
+ }
+ GL::bindProgram (GL_FRAGMENT_PROGRAM_ARB, 0);
+
+ return true;
+}
+
+bool
+MagScreen::loadImages ()
+{
+ CompString overlay_s = optionGetOverlay ();
+ CompString mask_s = optionGetMask ();
+ if (!GL::multiTexCoord2f)
+ return false;
+
+ overlay = GLTexture::readImageToTexture (overlay_s,
+ overlaySize);
+
+ if (!overlay.size ())
+ {
+ compLogMessage ("mag", CompLogLevelWarn,
+ "Could not load magnifier overlay image \"%s\"!",
+ overlay_s.c_str ());
+ return false;
+ }
+
+ mask = GLTexture::readImageToTexture (mask_s,
+ maskSize);
+
+ if (!mask.size ())
+ {
+ compLogMessage ("mag", CompLogLevelWarn,
+ "Could not load magnifier mask image \"%s\"!",
+ mask_s.c_str ());
+ overlay.clear ();
+ return false;
+ }
+
+ if (overlaySize.width () != maskSize.width () ||
+ overlaySize.height () != maskSize.height ())
+ {
+ compLogMessage ("mag", CompLogLevelWarn,
+ "Image dimensions do not match!");
+ overlay.clear ();
+ mask.clear ();
+ return false;
+ }
+
+ return true;
+}
+
+void
+MagScreen::optionChanged (CompOption *opt,
+ MagOptions::Options num)
+{
+ cleanup ();
+
+ switch (optionGetMode ())
+ {
+ case ModeImageOverlay:
+ if (loadImages ())
+ mode = MagOptions::ModeImageOverlay;
+ else
+ mode = MagOptions::ModeSimple;
+ break;
+ case MagOptions::ModeFisheye:
+ if (loadFragmentProgram ())
+ mode = MagOptions::ModeFisheye;
+ else
+ mode = MagOptions::ModeSimple;
+ break;
+ default:
+ mode = MagOptions::ModeSimple;
+ }
+
+ if (zoom != 1.0)
+ cScreen->damageScreen ();
+}
+
+void
+MagScreen::damageRegion ()
+{
+ CompRegion region;
+
+ int w, h, x, y;
+
+ switch (mode)
+ {
+ case MagOptions::ModeSimple:
+ {
+ int b;
+ w = optionGetBoxWidth ();
+ h = optionGetBoxHeight ();
+ b = optionGetBorder ();
+ w += 2 * b;
+ h += 2 * b;
+ x = MAX (0, MIN (posX - (w / 2), screen->width () - w));
+ y = MAX (0, MIN (posY - (h / 2), screen->height () - h));
+
+ CompRegion tmpRegion (x, y, w, h);
+
+ region = tmpRegion;
+ }
+ break;
+ case MagOptions::ModeImageOverlay:
+ {
+ x = posX - optionGetXOffset ();
+ y = posY - optionGetYOffset ();
+ w = overlaySize.width ();
+ h = overlaySize.height ();
+
+ CompRegion tmpRegion (x, y, w, h);
+
+ region = tmpRegion;
+ }
+ break;
+ case MagOptions::ModeFisheye:
+ {
+ int radius = optionGetRadius ();
+ int x2, y2;
+
+ x = MAX (0.0, posX - radius);
+ y = MAX (0.0, posY - radius);
+ x2 = MIN (screen->width (), posX + radius);
+ y2 = MIN (screen->height (), posY + radius);
+ w = x2 - x;
+ h = y2 - y;
+
+ CompRegion tmpRegion (x, y, w, h);
+
+ region = tmpRegion;
+ }
+ break;
+ default:
+ break;
+ }
+
+ cScreen->damageRegion (region);
+}
+
+void
+MagScreen::positionUpdate (const CompPoint &pos)
+{
+ damageRegion ();
+
+ posX = pos.x ();
+ posY = pos.y ();
+
+ damageRegion ();
+}
+
+int
+MagScreen::adjustZoom (float chunk)
+{
+ float dx, adjust, amount;
+ float change;
+
+ dx = zTarget - zoom;
+
+ adjust = dx * 0.15f;
+ amount = fabs(dx) * 1.5f;
+ if (amount < 0.2f)
+ amount = 0.2f;
+ else if (amount > 2.0f)
+ amount = 2.0f;
+
+ zVelocity = (amount * zVelocity + adjust) / (amount + 1.0f);
+
+ if (fabs (dx) < 0.002f && fabs (zVelocity) < 0.004f)
+ {
+ zVelocity = 0.0f;
+ zoom = zTarget;
+ return false;
+ }
+
+ change = zVelocity * chunk;
+ if (!change)
+ {
+ if (zVelocity)
+ change = (dx > 0) ? 0.01 : -0.01;
+ }
+
+ zoom += change;
+
+ return true;
+}
+
+void
+MagScreen::preparePaint (int time)
+{
+ if (adjust)
+ {
+ int steps;
+ float amount, chunk;
+
+ amount = time * 0.35f * optionGetSpeed ();
+ steps = amount / (0.5f * optionGetTimestep ());
+
+ if (!steps)
+ steps = 1;
+
+ chunk = amount / (float) steps;
+
+ while (steps--)
+ {
+ adjust = adjustZoom (chunk);
+ if (adjust)
+ break;
+ }
+ }
+
+ if (zoom != 1.0)
+ {
+ if (!poller.active ())
+ {
+ CompPoint pos;
+ pos = poller.getCurrentPosition ();
+ posX = pos.x ();
+ posY = pos.y ();
+ poller.start ();
+ }
+ damageRegion ();
+ }
+
+ cScreen->preparePaint (time);
+}
+
+void
+MagScreen::donePaint ()
+{
+
+ if (adjust)
+ damageRegion ();
+
+ if (!adjust && zoom == 1.0 && (width || height))
+ {
+ glEnable (target);
+
+ glBindTexture (target, texture);
+
+ glTexImage2D (target, 0, GL_RGB, 0, 0, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+ width = 0;
+ height = 0;
+
+ glBindTexture (target, 0);
+
+ glDisable (target);
+ }
+
+ if (zoom == 1.0 && !adjust && poller.active ())
+ {
+ poller.stop ();
+ }
+
+ cScreen->donePaint ();
+}
+
+void
+MagScreen::paintSimple ()
+{
+ float pw, ph, bw, bh;
+ int x1, x2, y1, y2;
+ float vc[4];
+ float tc[4];
+ int w, h, cw, ch, cx, cy;
+ bool kScreen;
+ unsigned short *color;
+ float tmp;
+
+ w = optionGetBoxWidth ();
+ h = optionGetBoxHeight ();
+
+ kScreen = optionGetKeepScreen ();
+
+ x1 = posX - (w / 2);
+ if (kScreen)
+ x1 = MAX (0, MIN (x1, screen->width () - w));
+ x2 = x1 + w;
+ y1 = posY - (h / 2);
+ if (kScreen)
+ y1 = MAX (0, MIN (y1, screen->height () - h));
+ y2 = y1 + h;
+
+ cw = ceil ((float)w / (zoom * 2.0)) * 2.0;
+ ch = ceil ((float)h / (zoom * 2.0)) * 2.0;
+ cw = MIN (w, cw + 2);
+ ch = MIN (h, ch + 2);
+ cx = (w - cw) / 2;
+ cy = (h - ch) / 2;
+
+ cx = MAX (0, MIN (w - cw, cx));
+ cy = MAX (0, MIN (h - ch, cy));
+
+ if (x1 != (posX - (w / 2)))
+ {
+ cx = 0;
+ cw = w;
+ }
+ if (y1 != (posY - (h / 2)))
+ {
+ cy = 0;
+ ch = h;
+ }
+
+ glEnable (target);
+
+ glBindTexture (target, texture);
+
+ if (width != w || height != h)
+ {
+ glCopyTexImage2D(target, 0, GL_RGB, x1, screen->height () - y2,
+ w, h, 0);
+ width = w;
+ height = h;
+ }
+ else
+ glCopyTexSubImage2D (target, 0, cx, cy,
+ x1 + cx, screen->height () - y2 + cy, cw, ch);
+
+ if (target == GL_TEXTURE_2D)
+ {
+ pw = 1.0 / width;
+ ph = 1.0 / height;
+ }
+ else
+ {
+ pw = 1.0;
+ ph = 1.0;
+ }
+
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix ();
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix ();
+ glLoadIdentity ();
+
+ vc[0] = ((x1 * 2.0) / screen->width ()) - 1.0;
+ vc[1] = ((x2 * 2.0) / screen->width ()) - 1.0;
+ vc[2] = ((y1 * -2.0) / screen->height ()) + 1.0;
+ vc[3] = ((y2 * -2.0) / screen->height ()) + 1.0;
+
+ tc[0] = 0.0;
+ tc[1] = w * pw;
+ tc[2] = h * ph;
+ tc[3] = 0.0;
+
+ glColor4usv (defaultColor);
+
+ glPushMatrix ();
+
+ glTranslatef ((float)(posX - (screen->width () / 2)) * 2 / screen->width (),
+ (float)(posY - (screen->height () / 2)) * 2 / -screen->height (), 0.0);
+
+ glScalef (zoom, zoom, 1.0);
+
+ glTranslatef ((float)((screen->width () / 2) - posX) * 2 / screen->width (),
+ (float)((screen->height () / 2) - posY) * 2 / -screen->height (), 0.0);
+
+ glScissor (x1, screen->height () - y2, w, h);
+
+ glEnable (GL_SCISSOR_TEST);
+
+ glBegin (GL_QUADS);
+ glTexCoord2f (tc[0], tc[2]);
+ glVertex2f (vc[0], vc[2]);
+ glTexCoord2f (tc[0], tc[3]);
+ glVertex2f (vc[0], vc[3]);
+ glTexCoord2f (tc[1], tc[3]);
+ glVertex2f (vc[1], vc[3]);
+ glTexCoord2f (tc[1], tc[2]);
+ glVertex2f (vc[1], vc[2]);
+ glEnd ();
+
+ glDisable (GL_SCISSOR_TEST);
+
+ glPopMatrix ();
+
+ glBindTexture (target, 0);
+
+ glDisable (target);
+
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ tmp = MIN (1.0, (zoom - 1) * 3.0);
+
+ bw = bh = optionGetBorder ();
+
+ bw = bw * 2.0 / screen->width ();
+ bh = bh * 2.0 / screen->height ();
+
+ bw = bh = optionGetBorder ();
+
+ bw *= 2.0 / (float)screen->width ();
+ bh *= 2.0 / (float)screen->height ();
+
+ color = optionGetBoxColor ();
+
+ glColor4us (color[0], color[1], color[2], color[3] * tmp);
+
+ glBegin (GL_QUADS);
+ glVertex2f (vc[0] - bw, vc[2] + bh);
+ glVertex2f (vc[0] - bw, vc[2]);
+ glVertex2f (vc[1] + bw, vc[2]);
+ glVertex2f (vc[1] + bw, vc[2] + bh);
+ glVertex2f (vc[0] - bw, vc[3]);
+ glVertex2f (vc[0] - bw, vc[3] - bh);
+ glVertex2f (vc[1] + bw, vc[3] - bh);
+ glVertex2f (vc[1] + bw, vc[3]);
+ glVertex2f (vc[0] - bw, vc[2]);
+ glVertex2f (vc[0] - bw, vc[3]);
+ glVertex2f (vc[0], vc[3]);
+ glVertex2f (vc[0], vc[2]);
+ glVertex2f (vc[1], vc[2]);
+ glVertex2f (vc[1], vc[3]);
+ glVertex2f (vc[1] + bw, vc[3]);
+ glVertex2f (vc[1] + bw, vc[2]);
+ glEnd();
+
+ glColor4usv (defaultColor);
+ glDisable (GL_BLEND);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glPopMatrix();
+ glMatrixMode (GL_PROJECTION);
+ glPopMatrix ();
+ glMatrixMode (GL_MODELVIEW);
+}
+
+void
+MagScreen::paintImage ()
+{
+ float pw, ph;
+ int x1, x2, y1, y2;
+ float vc[4];
+ float tc[4];
+ int w, h, cw, ch, cx, cy;
+ float tmp, xOff, yOff;
+
+ w = overlaySize.width ();
+ h = overlaySize.height ();
+
+ xOff = MIN (w, optionGetXOffset ());
+ yOff = MIN (h, optionGetYOffset ());
+
+ x1 = posX - xOff;
+ x2 = x1 + w;
+ y1 = posY - yOff;
+ y2 = y1 + h;
+
+ cw = ceil ((float)w / (zoom * 2.0)) * 2.0;
+ ch = ceil ((float)h / (zoom * 2.0)) * 2.0;
+ cw = MIN (w, cw + 2);
+ ch = MIN (h, ch + 2);
+ cx = floor (xOff - (xOff / zoom));
+ cy = h - ch - floor (yOff - (yOff / zoom));
+
+ cx = MAX (0, MIN (w - cw, cx));
+ cy = MAX (0, MIN (h - ch, cy));
+
+ glPushAttrib (GL_TEXTURE_BIT);
+
+ glEnable (target);
+
+ glBindTexture (target, texture);
+
+ if (width != w || height != h)
+ {
+ glCopyTexImage2D(target, 0, GL_RGB, x1, screen->height () - y2,
+ w, h, 0);
+ width = w;
+ height = h;
+ }
+ else
+ glCopyTexSubImage2D (target, 0, cx, cy,
+ x1 + cx, screen->height () - y2 + cy, cw, ch);
+
+ if (target == GL_TEXTURE_2D)
+ {
+ pw = 1.0 / width;
+ ph = 1.0 / height;
+ }
+ else
+ {
+ pw = 1.0;
+ ph = 1.0;
+ }
+
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix ();
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix ();
+ glLoadIdentity ();
+
+ vc[0] = ((x1 * 2.0) / screen->width ()) - 1.0;
+ vc[1] = ((x2 * 2.0) / screen->width ()) - 1.0;
+ vc[2] = ((y1 * -2.0) / screen->height ()) + 1.0;
+ vc[3] = ((y2 * -2.0) / screen->height ()) + 1.0;
+
+ tc[0] = xOff - (xOff / zoom);
+ tc[1] = tc[0] + (w / zoom);
+
+ tc[2] = h - (yOff - (yOff / zoom));
+ tc[3] = tc[2] - (h / zoom);
+
+ tc[0] *= pw;
+ tc[1] *= pw;
+ tc[2] *= ph;
+ tc[3] *= ph;
+
+ glEnable (GL_BLEND);
+
+ glColor4usv (defaultColor);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ GL::activeTexture (GL_TEXTURE1_ARB);
+ foreach (GLTexture *tex, mask)
+ {
+ tex->enable (GLTexture::Good);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glBegin (GL_QUADS);
+ GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[0], tc[2]);
+ GL::multiTexCoord2f (GL_TEXTURE1_ARB,
+ COMP_TEX_COORD_X (tex->matrix (), 0),
+ COMP_TEX_COORD_Y (tex->matrix (), 0));
+ glVertex2f (vc[0], vc[2]);
+ GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[0], tc[3]);
+ GL::multiTexCoord2f (GL_TEXTURE1_ARB,
+ COMP_TEX_COORD_X (tex->matrix (), 0),
+ COMP_TEX_COORD_Y (tex->matrix (), h));
+ glVertex2f (vc[0], vc[3]);
+ GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[1], tc[3]);
+ GL::multiTexCoord2f (GL_TEXTURE1_ARB,
+ COMP_TEX_COORD_X (tex->matrix (), w),
+ COMP_TEX_COORD_Y (tex->matrix (), h));
+ glVertex2f (vc[1], vc[3]);
+ GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[1], tc[2]);
+ GL::multiTexCoord2f (GL_TEXTURE1_ARB,
+ COMP_TEX_COORD_X (tex->matrix (), w),
+ COMP_TEX_COORD_Y (tex->matrix (), 0));
+ glVertex2f (vc[1], vc[2]);
+ glEnd ();
+
+ tex->disable ();
+ }
+ GL::activeTexture (GL_TEXTURE0_ARB);
+
+ glBindTexture (target, 0);
+
+ glDisable (target);
+
+ tmp = MIN (1.0, (zoom - 1) * 3.0);
+
+ glColor4f (tmp, tmp, tmp, tmp);
+
+ foreach (GLTexture *tex, overlay)
+ {
+ tex->enable (GLTexture::Fast);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glBegin (GL_QUADS);
+ glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), 0),
+ COMP_TEX_COORD_Y (tex->matrix (), 0));
+ glVertex2f (vc[0], vc[2]);
+ glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), 0),
+ COMP_TEX_COORD_Y (tex->matrix (), h));
+ glVertex2f (vc[0], vc[3]);
+ glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), w),
+ COMP_TEX_COORD_Y (tex->matrix (), h));
+ glVertex2f (vc[1], vc[3]);
+ glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), w),
+ COMP_TEX_COORD_Y (tex->matrix (), 0));
+ glVertex2f (vc[1], vc[2]);
+ glEnd ();
+
+ tex->disable ();
+ }
+
+ glColor4usv (defaultColor);
+ glDisable (GL_BLEND);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glPopMatrix();
+ glMatrixMode (GL_PROJECTION);
+ glPopMatrix ();
+ glMatrixMode (GL_MODELVIEW);
+
+ glPopAttrib ();
+
+}
+
+void
+MagScreen::paintFisheye ()
+{
+ float pw, ph;
+ float radius, fZoom, base; // fZoom is the local zoom variable
+ int x1, x2, y1, y2;
+ float vc[4];
+ int size;
+
+ radius = optionGetRadius ();
+ base = 0.5 + (0.0015 * radius);
+ fZoom = (zoom * base) + 1.0 - base;
+
+ size = radius + 1;
+
+ x1 = MAX (0.0, posX - size);
+ x2 = MIN (screen->width (), posX + size);
+ y1 = MAX (0.0, posY - size);
+ y2 = MIN (screen->height (), posY + size);
+
+ glEnable (target);
+
+ glBindTexture (target, texture);
+
+ if (width != 2 * size || height != 2 * size)
+ {
+ glCopyTexImage2D(target, 0, GL_RGB, x1, screen->height () - y2,
+ size * 2, size * 2, 0);
+ width = height = 2 * size;
+ }
+ else
+ glCopyTexSubImage2D (target, 0, 0, 0,
+ x1, screen->height () - y2, x2 - x1, y2 - y1);
+
+ if (target == GL_TEXTURE_2D)
+ {
+ pw = 1.0 / width;
+ ph = 1.0 / height;
+ }
+ else
+ {
+ pw = 1.0;
+ ph = 1.0;
+ }
+
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix ();
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix ();
+ glLoadIdentity ();
+
+ glColor4usv (defaultColor);
+
+ glEnable (GL_FRAGMENT_PROGRAM_ARB);
+ GL::bindProgram (GL_FRAGMENT_PROGRAM_ARB, program);
+
+ GL::programEnvParameter4f (GL_FRAGMENT_PROGRAM_ARB, 0,
+ posX, screen->height () - posY,
+ 1.0 / radius, 0.0f);
+ GL::programEnvParameter4f (GL_FRAGMENT_PROGRAM_ARB, 1,
+ pw, ph, M_PI / radius,
+ (fZoom - 1.0) * fZoom);
+ GL::programEnvParameter4f (GL_FRAGMENT_PROGRAM_ARB, 2,
+ -x1 * pw, -(screen->height () - y2) * ph,
+ -M_PI / 2.0, 0.0);
+
+ x1 = MAX (0.0, posX - radius);
+ x2 = MIN (screen->width (), posX + radius);
+ y1 = MAX (0.0, posY - radius);
+ y2 = MIN (screen->height (), posY + radius);
+
+ vc[0] = ((x1 * 2.0) / screen->width ()) - 1.0;
+ vc[1] = ((x2 * 2.0) / screen->width ()) - 1.0;
+ vc[2] = ((y1 * -2.0) / screen->height ()) + 1.0;
+ vc[3] = ((y2 * -2.0) / screen->height ()) + 1.0;
+
+ y1 = screen->height () - y1;
+ y2 = screen->height () - y2;
+
+ glBegin (GL_QUADS);
+ glTexCoord2f (x1, y1);
+ glVertex2f (vc[0], vc[2]);
+ glTexCoord2f (x1, y2);
+ glVertex2f (vc[0], vc[3]);
+ glTexCoord2f (x2, y2);
+ glVertex2f (vc[1], vc[3]);
+ glTexCoord2f (x2, y1);
+ glVertex2f (vc[1], vc[2]);
+ glEnd ();
+
+ glDisable (GL_FRAGMENT_PROGRAM_ARB);
+
+ glColor4usv (defaultColor);
+
+ glPopMatrix();
+ glMatrixMode (GL_PROJECTION);
+ glPopMatrix ();
+ glMatrixMode (GL_MODELVIEW);
+
+ glBindTexture (target, 0);
+
+ glDisable (target);
+}
+
+
+bool
+MagScreen::glPaintOutput (GLScreenPaintAttrib &attrib,
+ GLMatrix &transform,
+ CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ bool status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
+
+ if (zoom == 1.0)
+ return status;
+
+ /* Temporarily set the viewport to fullscreen */
+
+ glViewport (0, 0, screen->width (), screen->height ());
+
+ switch (mode)
+ {
+ case MagOptions::ModeImageOverlay:
+ paintImage ();
+ break;
+ case MagOptions::ModeFisheye:
+ paintFisheye ();
+ break;
+ default:
+ paintSimple ();
+ }
+
+ gScreen->setDefaultViewport ();
+
+ return status;
+}
+
+bool
+MagScreen::terminate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options)
+{
+ zTarget = 1.0;
+ adjust = true;
+ cScreen->damageScreen ();
+ return true;
+}
+
+bool
+MagScreen::initiate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options)
+{
+ float factor;
+ factor = CompOption::getFloatOptionNamed (options, "factor", 0);
+
+ if (factor == 0.0 && zTarget != 1.0)
+ return terminate (action, state, options);
+
+ if (mode == MagOptions::ModeFisheye)
+ {
+ if (factor != 1.0)
+ factor = optionGetZoomFactor () * 3;
+
+ zTarget = MAX (1.0, MIN (10.0, factor));
+
+ }
+ else
+ {
+ if (factor != 1.0)
+ factor = optionGetZoomFactor ();
+ }
+ adjust = true;
+ cScreen->damageScreen ();
+
+ return true;
+}
+
+bool
+MagScreen::zoomIn (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options)
+{
+ if (mode == MagOptions::ModeFisheye)
+ zTarget = MIN (10.0, zTarget + 1.0);
+ else
+ zTarget = MIN (64.0, zTarget * 1.2);
+ adjust = true;
+ cScreen->damageScreen ();
+
+ return true;
+}
+
+bool
+MagScreen::zoomOut (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options)
+{
+ if (mode == MagOptions::ModeFisheye)
+ zTarget = MAX (1.0, zTarget - 1.0);
+ else
+ zTarget = MAX (1.0, zTarget / 1.2);
+ adjust = true;
+ cScreen->damageScreen ();
+
+ return true;
+}
+
+
+
+MagScreen::MagScreen (CompScreen *screen) :
+ PluginClassHandler <MagScreen, CompScreen> (screen),
+ cScreen (CompositeScreen::get (screen)),
+ gScreen (GLScreen::get (screen)),
+ posX (0),
+ posY (0),
+ adjust (false),
+ zVelocity (0.0f),
+ zTarget (1.0f),
+ zoom (1.0f),
+ program (0)
+{
+ ScreenInterface::setHandler (screen);
+ CompositeScreenInterface::setHandler (cScreen);
+ GLScreenInterface::setHandler (gScreen);
+
+ poller.setCallback (boost::bind (&MagScreen::positionUpdate, this, _1));
+
+ glGenTextures (1, &texture);
+
+ if (GL::textureNonPowerOfTwo)
+ target = GL_TEXTURE_2D;
+ else
+ target = GL_TEXTURE_RECTANGLE_ARB;
+
+ glEnable (target);
+
+ /* Bind the texture */
+ glBindTexture (target, texture);
+
+ /* Load the parameters */
+ glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ glTexImage2D (target, 0, GL_RGB, 0, 0, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+ width = 0;
+ height = 0;
+
+ glBindTexture (target, 0);
+
+ glDisable (target);
+
+#define optionNotify(name) \
+ optionSet##name##Notify (boost::bind (&MagScreen::optionChanged, \
+ this, _1, _2))
+
+ optionNotify (Overlay);
+ optionNotify (Mask);
+ optionNotify (Mode);
+
+#undef optionNotify
+
+ optionSetInitiateInitiate (boost::bind (&MagScreen::initiate, this, _1, _2,
+ _3));
+ optionSetInitiateTerminate (boost::bind (&MagScreen::initiate, this, _1, _2,
+ _3));
+
+ optionSetZoomInButtonInitiate (boost::bind (&MagScreen::zoomIn, this, _1, _2,
+ _3));
+
+ optionSetZoomOutButtonInitiate (boost::bind (&MagScreen::zoomOut, this, _1, _2,
+ _3));
+
+ switch (optionGetMode ())
+ {
+ case MagOptions::ModeImageOverlay:
+ if (loadImages ())
+ mode = MagOptions::ModeImageOverlay;
+ else
+ mode = MagOptions::ModeSimple;
+ break;
+ case MagOptions::ModeFisheye:
+ if (loadFragmentProgram ())
+ mode = MagOptions::ModeFisheye;
+ else
+ mode = MagOptions::ModeSimple;
+ break;
+ default:
+ mode = MagOptions::ModeSimple;
+ }
+
+ if (!GL::fragmentProgram)
+ compLogMessage ("mag", CompLogLevelWarn,
+ "GL_ARB_fragment_program not supported. "
+ "Fisheye mode will not work.");
+}
+
+MagScreen::~MagScreen ()
+{
+ poller.stop ();
+
+ if (zoom)
+ cScreen->damageScreen ();
+
+ glDeleteTextures (1, &target);
+
+ cleanup ();
+}
+
+bool
+MagPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
+ return false;
+ if (!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI))
+ return false;
+ if (!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
+ return false;
+ if (!CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI))
+ return false;
+
+ return true;
+}
diff --git a/src/mag.h b/src/mag.h
new file mode 100644
index 0000000..c973bd2
--- /dev/null
+++ b/src/mag.h
@@ -0,0 +1,175 @@
+/*
+ *
+ * Compiz magnifier plugin
+ *
+ * mag.h
+ *
+ * Copyright : (C) 2008 by Dennis Kasprzyk
+ * E-mail : onestone@opencompositing.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 <cmath>
+
+#include <core/core.h>
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+#include <mousepoll/mousepoll.h>
+
+#include "mag_options.h"
+
+#define MAG_SCREEN(s) \
+ MagScreen *ms = MagScreen::get (s)
+
+class MagScreen :
+ public PluginClassHandler <MagScreen, CompScreen>,
+ public MagOptions,
+ public ScreenInterface,
+ public CompositeScreenInterface,
+ public GLScreenInterface
+{
+ public:
+ MagScreen (CompScreen *screen);
+ ~MagScreen ();
+
+ CompositeScreen *cScreen;
+ GLScreen *gScreen;
+
+ int posX;
+ int posY;
+
+ Bool adjust;
+
+ GLfloat zVelocity;
+ GLfloat zTarget;
+ GLfloat zoom;
+
+ enum MagOptions::Mode mode;
+
+ GLuint texture;
+ GLenum target;
+
+ int width;
+ int height;
+
+ GLTexture::List overlay;
+ GLTexture::List mask;
+ CompSize overlaySize, maskSize;
+
+ GLuint program;
+
+ MousePoller poller;
+
+ void
+ preparePaint (int ms);
+
+ bool
+ glPaintOutput (GLScreenPaintAttrib &attrib,
+ GLMatrix &transform,
+ CompRegion &region,
+ CompOutput *output,
+ unsigned int mask);
+
+ void
+ donePaint ();
+
+ void
+ cleanup ();
+
+ bool
+ loadFragmentProgram ();
+
+ bool
+ loadImages ();
+
+ void
+ optionChanged (CompOption *opt,
+ MagOptions::Options num);
+
+ void
+ damageRegion ();
+
+ void
+ positionUpdate (const CompPoint &pos);
+
+ int
+ adjustZoom (float chunk);
+
+ void
+ paintSimple ();
+
+ void
+ paintImage ();
+
+ void
+ paintFisheye ();
+
+ bool
+ terminate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options);
+
+ bool
+ initiate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options);
+
+ bool
+ zoomIn (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options);
+
+ bool
+ zoomOut (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options);
+
+};
+
+class MagPluginVTable :
+ public CompPlugin::VTableForScreen <MagScreen>
+{
+ public:
+ bool init ();
+};
+
+static const char *fisheyeFpString =
+ "!!ARBfp1.0"
+
+ "PARAM p0 = program.env[0];"
+ "PARAM p1 = program.env[1];"
+ "PARAM p2 = program.env[2];"
+
+ "TEMP t0, t1, t2, t3;"
+
+ "SUB t1, p0.xyww, fragment.texcoord[0];"
+ "DP3 t2, t1, t1;"
+ "RSQ t2, t2.x;"
+ "SUB t0, t2, p0;"
+
+ "RCP t3, t2.x;"
+ "MAD t3, t3, p1.z, p2.z;"
+ "COS t3, t3.x;"
+
+ "MUL t3, t3, p1.w;"
+
+ "MUL t1, t2, t1;"
+ "MAD t1, t1, t3, fragment.texcoord[0];"
+
+ "CMP t1, t0.z, fragment.texcoord[0], t1;"
+
+ "MAD t1, t1, p1, p2;"
+ "TEX result.color, t1, texture[0], %s;"
+
+ "END";