3
* Compiz magnifier plugin
7
* Copyright : (C) 2008 by Dennis Kasprzyk
8
* E-mail : onestone@opencompositing.org
11
* This program is free software; you can redistribute it and/or
12
* modify it under the terms of the GNU General Public License
13
* as published by the Free Software Foundation; either version 2
14
* of the License, or (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
25
COMPIZ_PLUGIN_20090315 (mag, MagPluginVTable);
41
GL::deletePrograms (1, &program);
47
MagScreen::loadFragmentProgram ()
53
if (!GL::fragmentProgram)
56
if (target == GL_TEXTURE_2D)
57
sprintf (buffer, fisheyeFpString, "2D");
59
sprintf (buffer, fisheyeFpString, "RECT");
65
GL::genPrograms (1, &program);
67
bufSize = (GLsizei) strlen (buffer);
69
GL::bindProgram (GL_FRAGMENT_PROGRAM_ARB, program);
70
GL::programString (GL_FRAGMENT_PROGRAM_ARB,
71
GL_PROGRAM_FORMAT_ASCII_ARB,
74
glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
75
if (glGetError () != GL_NO_ERROR || errorPos != -1)
77
compLogMessage ("mag", CompLogLevelError,
78
"failed to load fisheye fragment program");
80
GL::deletePrograms (1, &program);
85
GL::bindProgram (GL_FRAGMENT_PROGRAM_ARB, 0);
91
MagScreen::loadImages ()
93
CompString overlay_s = optionGetOverlay ();
94
CompString mask_s = optionGetMask ();
95
CompString pname ("mag");
96
if (!GL::multiTexCoord2f)
99
overlay = GLTexture::readImageToTexture (overlay_s, pname,
102
if (!overlay.size ())
104
compLogMessage ("mag", CompLogLevelWarn,
105
"Could not load magnifier overlay image \"%s\"!",
110
mask = GLTexture::readImageToTexture (mask_s, pname,
115
compLogMessage ("mag", CompLogLevelWarn,
116
"Could not load magnifier mask image \"%s\"!",
122
if (overlaySize.width () != maskSize.width () ||
123
overlaySize.height () != maskSize.height ())
125
compLogMessage ("mag", CompLogLevelWarn,
126
"Image dimensions do not match!");
136
MagScreen::optionChanged (CompOption *opt,
137
MagOptions::Options num)
141
switch (optionGetMode ())
143
case ModeImageOverlay:
145
mode = MagOptions::ModeImageOverlay;
147
mode = MagOptions::ModeSimple;
149
case MagOptions::ModeFisheye:
150
if (loadFragmentProgram ())
151
mode = MagOptions::ModeFisheye;
153
mode = MagOptions::ModeSimple;
156
mode = MagOptions::ModeSimple;
160
cScreen->damageScreen ();
164
MagScreen::damageRegion ()
172
case MagOptions::ModeSimple:
175
w = optionGetBoxWidth ();
176
h = optionGetBoxHeight ();
177
b = optionGetBorder ();
180
x = MAX (0, MIN (posX - (w / 2), screen->width () - w));
181
y = MAX (0, MIN (posY - (h / 2), screen->height () - h));
183
CompRegion tmpRegion (x, y, w, h);
188
case MagOptions::ModeImageOverlay:
190
x = posX - optionGetXOffset ();
191
y = posY - optionGetYOffset ();
192
w = overlaySize.width ();
193
h = overlaySize.height ();
195
CompRegion tmpRegion (x, y, w, h);
200
case MagOptions::ModeFisheye:
202
int radius = optionGetRadius ();
205
x = MAX (0.0, posX - radius);
206
y = MAX (0.0, posY - radius);
207
x2 = MIN (screen->width (), posX + radius);
208
y2 = MIN (screen->height (), posY + radius);
212
CompRegion tmpRegion (x, y, w, h);
221
cScreen->damageRegion (region);
225
MagScreen::positionUpdate (const CompPoint &pos)
236
MagScreen::adjustZoom (float chunk)
238
float dx, adjust, amount;
244
amount = fabs(dx) * 1.5f;
247
else if (amount > 2.0f)
250
zVelocity = (amount * zVelocity + adjust) / (amount + 1.0f);
252
if (fabs (dx) < 0.002f && fabs (zVelocity) < 0.004f)
259
change = zVelocity * chunk;
263
change = (dx > 0) ? 0.01 : -0.01;
272
MagScreen::preparePaint (int time)
279
amount = time * 0.35f * optionGetSpeed ();
280
steps = amount / (0.5f * optionGetTimestep ());
285
chunk = amount / (float) steps;
289
adjust = adjustZoom (chunk);
297
if (!poller.active ())
300
pos = poller.getCurrentPosition ();
308
cScreen->preparePaint (time);
312
MagScreen::donePaint ()
318
if (!adjust && zoom == 1.0 && (width || height))
322
glBindTexture (target, texture);
324
glTexImage2D (target, 0, GL_RGB, 0, 0, 0,
325
GL_RGB, GL_UNSIGNED_BYTE, NULL);
330
glBindTexture (target, 0);
335
if (zoom == 1.0 && !adjust)
337
// Mag mode has ended
338
cScreen->preparePaintSetEnabled (this, false);
339
cScreen->donePaintSetEnabled (this, false);
340
gScreen->glPaintOutputSetEnabled (this, false);
342
if (poller.active ())
346
cScreen->donePaint ();
350
MagScreen::paintSimple ()
352
float pw, ph, bw, bh;
356
int w, h, cw, ch, cx, cy;
358
unsigned short *color;
361
w = optionGetBoxWidth ();
362
h = optionGetBoxHeight ();
364
kScreen = optionGetKeepScreen ();
368
x1 = MAX (0, MIN (x1, screen->width () - w));
372
y1 = MAX (0, MIN (y1, screen->height () - h));
375
cw = ceil ((float)w / (zoom * 2.0)) * 2.0;
376
ch = ceil ((float)h / (zoom * 2.0)) * 2.0;
377
cw = MIN (w, cw + 2);
378
ch = MIN (h, ch + 2);
382
cx = MAX (0, MIN (w - cw, cx));
383
cy = MAX (0, MIN (h - ch, cy));
385
if (x1 != (posX - (w / 2)))
390
if (y1 != (posY - (h / 2)))
398
glBindTexture (target, texture);
400
if (width != w || height != h)
402
glCopyTexImage2D(target, 0, GL_RGB, x1, screen->height () - y2,
408
glCopyTexSubImage2D (target, 0, cx, cy,
409
x1 + cx, screen->height () - y2 + cy, cw, ch);
411
if (target == GL_TEXTURE_2D)
422
glMatrixMode (GL_PROJECTION);
425
glMatrixMode (GL_MODELVIEW);
429
vc[0] = ((x1 * 2.0) / screen->width ()) - 1.0;
430
vc[1] = ((x2 * 2.0) / screen->width ()) - 1.0;
431
vc[2] = ((y1 * -2.0) / screen->height ()) + 1.0;
432
vc[3] = ((y2 * -2.0) / screen->height ()) + 1.0;
439
glColor4usv (defaultColor);
443
glTranslatef ((float)(posX - (screen->width () / 2)) * 2 / screen->width (),
444
(float)(posY - (screen->height () / 2)) * 2 / -screen->height (), 0.0);
446
glScalef (zoom, zoom, 1.0);
448
glTranslatef ((float)((screen->width () / 2) - posX) * 2 / screen->width (),
449
(float)((screen->height () / 2) - posY) * 2 / -screen->height (), 0.0);
451
glScissor (x1, screen->height () - y2, w, h);
453
glEnable (GL_SCISSOR_TEST);
456
glTexCoord2f (tc[0], tc[2]);
457
glVertex2f (vc[0], vc[2]);
458
glTexCoord2f (tc[0], tc[3]);
459
glVertex2f (vc[0], vc[3]);
460
glTexCoord2f (tc[1], tc[3]);
461
glVertex2f (vc[1], vc[3]);
462
glTexCoord2f (tc[1], tc[2]);
463
glVertex2f (vc[1], vc[2]);
466
glDisable (GL_SCISSOR_TEST);
470
glBindTexture (target, 0);
475
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
477
tmp = MIN (1.0, (zoom - 1) * 3.0);
479
bw = bh = optionGetBorder ();
481
bw = bw * 2.0 / screen->width ();
482
bh = bh * 2.0 / screen->height ();
484
bw = bh = optionGetBorder ();
486
bw *= 2.0 / (float)screen->width ();
487
bh *= 2.0 / (float)screen->height ();
489
color = optionGetBoxColor ();
491
glColor4us (color[0], color[1], color[2], color[3] * tmp);
494
glVertex2f (vc[0] - bw, vc[2] + bh);
495
glVertex2f (vc[0] - bw, vc[2]);
496
glVertex2f (vc[1] + bw, vc[2]);
497
glVertex2f (vc[1] + bw, vc[2] + bh);
498
glVertex2f (vc[0] - bw, vc[3]);
499
glVertex2f (vc[0] - bw, vc[3] - bh);
500
glVertex2f (vc[1] + bw, vc[3] - bh);
501
glVertex2f (vc[1] + bw, vc[3]);
502
glVertex2f (vc[0] - bw, vc[2]);
503
glVertex2f (vc[0] - bw, vc[3]);
504
glVertex2f (vc[0], vc[3]);
505
glVertex2f (vc[0], vc[2]);
506
glVertex2f (vc[1], vc[2]);
507
glVertex2f (vc[1], vc[3]);
508
glVertex2f (vc[1] + bw, vc[3]);
509
glVertex2f (vc[1] + bw, vc[2]);
512
glColor4usv (defaultColor);
513
glDisable (GL_BLEND);
514
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
517
glMatrixMode (GL_PROJECTION);
519
glMatrixMode (GL_MODELVIEW);
523
MagScreen::paintImage ()
529
int w, h, cw, ch, cx, cy;
530
float tmp, xOff, yOff;
532
w = overlaySize.width ();
533
h = overlaySize.height ();
535
xOff = MIN (w, optionGetXOffset ());
536
yOff = MIN (h, optionGetYOffset ());
543
cw = ceil ((float)w / (zoom * 2.0)) * 2.0;
544
ch = ceil ((float)h / (zoom * 2.0)) * 2.0;
545
cw = MIN (w, cw + 2);
546
ch = MIN (h, ch + 2);
547
cx = floor (xOff - (xOff / zoom));
548
cy = h - ch - floor (yOff - (yOff / zoom));
550
cx = MAX (0, MIN (w - cw, cx));
551
cy = MAX (0, MIN (h - ch, cy));
553
glPushAttrib (GL_TEXTURE_BIT);
557
glBindTexture (target, texture);
559
if (width != w || height != h)
561
glCopyTexImage2D(target, 0, GL_RGB, x1, screen->height () - y2,
567
glCopyTexSubImage2D (target, 0, cx, cy,
568
x1 + cx, screen->height () - y2 + cy, cw, ch);
570
if (target == GL_TEXTURE_2D)
581
glMatrixMode (GL_PROJECTION);
584
glMatrixMode (GL_MODELVIEW);
588
vc[0] = ((x1 * 2.0) / screen->width ()) - 1.0;
589
vc[1] = ((x2 * 2.0) / screen->width ()) - 1.0;
590
vc[2] = ((y1 * -2.0) / screen->height ()) + 1.0;
591
vc[3] = ((y2 * -2.0) / screen->height ()) + 1.0;
593
tc[0] = xOff - (xOff / zoom);
594
tc[1] = tc[0] + (w / zoom);
596
tc[2] = h - (yOff - (yOff / zoom));
597
tc[3] = tc[2] - (h / zoom);
606
glColor4usv (defaultColor);
607
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
609
GL::activeTexture (GL_TEXTURE1_ARB);
610
foreach (GLTexture *tex, mask)
612
tex->enable (GLTexture::Good);
613
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
616
GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[0], tc[2]);
617
GL::multiTexCoord2f (GL_TEXTURE1_ARB,
618
COMP_TEX_COORD_X (tex->matrix (), 0),
619
COMP_TEX_COORD_Y (tex->matrix (), 0));
620
glVertex2f (vc[0], vc[2]);
621
GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[0], tc[3]);
622
GL::multiTexCoord2f (GL_TEXTURE1_ARB,
623
COMP_TEX_COORD_X (tex->matrix (), 0),
624
COMP_TEX_COORD_Y (tex->matrix (), h));
625
glVertex2f (vc[0], vc[3]);
626
GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[1], tc[3]);
627
GL::multiTexCoord2f (GL_TEXTURE1_ARB,
628
COMP_TEX_COORD_X (tex->matrix (), w),
629
COMP_TEX_COORD_Y (tex->matrix (), h));
630
glVertex2f (vc[1], vc[3]);
631
GL::multiTexCoord2f (GL_TEXTURE0_ARB, tc[1], tc[2]);
632
GL::multiTexCoord2f (GL_TEXTURE1_ARB,
633
COMP_TEX_COORD_X (tex->matrix (), w),
634
COMP_TEX_COORD_Y (tex->matrix (), 0));
635
glVertex2f (vc[1], vc[2]);
640
GL::activeTexture (GL_TEXTURE0_ARB);
642
glBindTexture (target, 0);
646
tmp = MIN (1.0, (zoom - 1) * 3.0);
648
glColor4f (tmp, tmp, tmp, tmp);
650
foreach (GLTexture *tex, overlay)
652
tex->enable (GLTexture::Fast);
653
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
656
glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), 0),
657
COMP_TEX_COORD_Y (tex->matrix (), 0));
658
glVertex2f (vc[0], vc[2]);
659
glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), 0),
660
COMP_TEX_COORD_Y (tex->matrix (), h));
661
glVertex2f (vc[0], vc[3]);
662
glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), w),
663
COMP_TEX_COORD_Y (tex->matrix (), h));
664
glVertex2f (vc[1], vc[3]);
665
glTexCoord2f (COMP_TEX_COORD_X (tex->matrix (), w),
666
COMP_TEX_COORD_Y (tex->matrix (), 0));
667
glVertex2f (vc[1], vc[2]);
673
glColor4usv (defaultColor);
674
glDisable (GL_BLEND);
675
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
678
glMatrixMode (GL_PROJECTION);
680
glMatrixMode (GL_MODELVIEW);
687
MagScreen::paintFisheye ()
690
float radius, fZoom, base; // fZoom is the local zoom variable
695
radius = optionGetRadius ();
696
base = 0.5 + (0.0015 * radius);
697
fZoom = (zoom * base) + 1.0 - base;
701
x1 = MAX (0.0, posX - size);
702
x2 = MIN (screen->width (), posX + size);
703
y1 = MAX (0.0, posY - size);
704
y2 = MIN (screen->height (), posY + size);
708
glBindTexture (target, texture);
710
if (width != 2 * size || height != 2 * size)
712
glCopyTexImage2D(target, 0, GL_RGB, x1, screen->height () - y2,
713
size * 2, size * 2, 0);
714
width = height = 2 * size;
717
glCopyTexSubImage2D (target, 0, 0, 0,
718
x1, screen->height () - y2, x2 - x1, y2 - y1);
720
if (target == GL_TEXTURE_2D)
731
glMatrixMode (GL_PROJECTION);
734
glMatrixMode (GL_MODELVIEW);
738
glColor4usv (defaultColor);
740
glEnable (GL_FRAGMENT_PROGRAM_ARB);
741
GL::bindProgram (GL_FRAGMENT_PROGRAM_ARB, program);
743
GL::programEnvParameter4f (GL_FRAGMENT_PROGRAM_ARB, 0,
744
posX, screen->height () - posY,
746
GL::programEnvParameter4f (GL_FRAGMENT_PROGRAM_ARB, 1,
747
pw, ph, M_PI / radius,
748
(fZoom - 1.0) * fZoom);
749
GL::programEnvParameter4f (GL_FRAGMENT_PROGRAM_ARB, 2,
750
-x1 * pw, -(screen->height () - y2) * ph,
753
x1 = MAX (0.0, posX - radius);
754
x2 = MIN (screen->width (), posX + radius);
755
y1 = MAX (0.0, posY - radius);
756
y2 = MIN (screen->height (), posY + radius);
758
vc[0] = ((x1 * 2.0) / screen->width ()) - 1.0;
759
vc[1] = ((x2 * 2.0) / screen->width ()) - 1.0;
760
vc[2] = ((y1 * -2.0) / screen->height ()) + 1.0;
761
vc[3] = ((y2 * -2.0) / screen->height ()) + 1.0;
763
y1 = screen->height () - y1;
764
y2 = screen->height () - y2;
767
glTexCoord2f (x1, y1);
768
glVertex2f (vc[0], vc[2]);
769
glTexCoord2f (x1, y2);
770
glVertex2f (vc[0], vc[3]);
771
glTexCoord2f (x2, y2);
772
glVertex2f (vc[1], vc[3]);
773
glTexCoord2f (x2, y1);
774
glVertex2f (vc[1], vc[2]);
777
glDisable (GL_FRAGMENT_PROGRAM_ARB);
779
glColor4usv (defaultColor);
782
glMatrixMode (GL_PROJECTION);
784
glMatrixMode (GL_MODELVIEW);
786
glBindTexture (target, 0);
793
MagScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
794
const GLMatrix &transform,
795
const CompRegion ®ion,
799
bool status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
804
/* Temporarily set the viewport to fullscreen */
806
glViewport (0, 0, screen->width (), screen->height ());
810
case MagOptions::ModeImageOverlay:
813
case MagOptions::ModeFisheye:
820
gScreen->setDefaultViewport ();
826
MagScreen::terminate (CompAction *action,
827
CompAction::State state,
828
CompOption::Vector options)
832
cScreen->damageScreen ();
837
MagScreen::initiate (CompAction *action,
838
CompAction::State state,
839
CompOption::Vector options)
842
factor = CompOption::getFloatOptionNamed (options, "factor", 0);
844
if (factor == 0.0 && zTarget != 1.0)
845
return terminate (action, state, options);
847
if (mode == MagOptions::ModeFisheye)
850
factor = optionGetZoomFactor () * 3;
852
zTarget = MAX (1.0, MIN (10.0, factor));
858
factor = optionGetZoomFactor ();
860
zTarget = MAX (1.0, MIN (64.0, factor));
863
cScreen->damageScreen ();
865
// Mag mode is starting
866
cScreen->preparePaintSetEnabled (this, true);
867
cScreen->donePaintSetEnabled (this, true);
868
gScreen->glPaintOutputSetEnabled (this, true);
874
MagScreen::zoomIn (CompAction *action,
875
CompAction::State state,
876
CompOption::Vector options)
878
if (mode == MagOptions::ModeFisheye)
879
zTarget = MIN (10.0, zTarget + 1.0);
881
zTarget = MIN (64.0, zTarget * 1.2);
883
cScreen->damageScreen ();
885
// Mag mode is starting
886
cScreen->preparePaintSetEnabled (this, true);
887
cScreen->donePaintSetEnabled (this, true);
888
gScreen->glPaintOutputSetEnabled (this, true);
894
MagScreen::zoomOut (CompAction *action,
895
CompAction::State state,
896
CompOption::Vector options)
898
if (mode == MagOptions::ModeFisheye)
899
zTarget = MAX (1.0, zTarget - 1.0);
901
zTarget = MAX (1.0, zTarget / 1.2);
903
cScreen->damageScreen ();
909
MagScreen::postLoad ()
911
if (zTarget != 1.0f || zVelocity != 0.0f || zoom != 1.0f)
913
cScreen->preparePaintSetEnabled (this, true);
914
cScreen->donePaintSetEnabled (this, true);
915
gScreen->glPaintOutputSetEnabled (this, true);
917
cScreen->damageScreen ();
921
MagScreen::MagScreen (CompScreen *screen) :
922
PluginClassHandler <MagScreen, CompScreen> (screen),
923
PluginStateWriter <MagScreen> (this, screen->root ()),
924
cScreen (CompositeScreen::get (screen)),
925
gScreen (GLScreen::get (screen)),
934
ScreenInterface::setHandler (screen, false);
935
CompositeScreenInterface::setHandler (cScreen, false);
936
GLScreenInterface::setHandler (gScreen, false);
938
poller.setCallback (boost::bind (&MagScreen::positionUpdate, this, _1));
940
glGenTextures (1, &texture);
942
if (GL::textureNonPowerOfTwo)
943
target = GL_TEXTURE_2D;
945
target = GL_TEXTURE_RECTANGLE_ARB;
949
/* Bind the texture */
950
glBindTexture (target, texture);
952
/* Load the parameters */
953
glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
954
glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
955
glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP);
956
glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP);
958
glTexImage2D (target, 0, GL_RGB, 0, 0, 0,
959
GL_RGB, GL_UNSIGNED_BYTE, NULL);
964
glBindTexture (target, 0);
968
#define optionNotify(name) \
969
optionSet##name##Notify (boost::bind (&MagScreen::optionChanged, \
972
optionNotify (Overlay);
978
optionSetInitiateInitiate (boost::bind (&MagScreen::initiate, this, _1, _2,
980
optionSetInitiateTerminate (boost::bind (&MagScreen::initiate, this, _1, _2,
983
optionSetZoomInButtonInitiate (boost::bind (&MagScreen::zoomIn, this, _1, _2,
986
optionSetZoomOutButtonInitiate (boost::bind (&MagScreen::zoomOut, this, _1, _2,
989
switch (optionGetMode ())
991
case MagOptions::ModeImageOverlay:
993
mode = MagOptions::ModeImageOverlay;
995
mode = MagOptions::ModeSimple;
997
case MagOptions::ModeFisheye:
998
if (loadFragmentProgram ())
999
mode = MagOptions::ModeFisheye;
1001
mode = MagOptions::ModeSimple;
1004
mode = MagOptions::ModeSimple;
1007
if (!GL::fragmentProgram)
1008
compLogMessage ("mag", CompLogLevelWarn,
1009
"GL_ARB_fragment_program not supported. "
1010
"Fisheye mode will not work.");
1013
MagScreen::~MagScreen ()
1015
writeSerializedData ();
1020
cScreen->damageScreen ();
1022
glDeleteTextures (1, &target);
1028
MagPluginVTable::init ()
1030
if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
1032
if (!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI))
1034
if (!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
1036
if (!CompPlugin::checkPluginABI ("mousepoll", COMPIZ_MOUSEPOLL_ABI))