1  /*
   2  * Copyright �� 2005 Novell, Inc.
   3  *
   4  * Permission to use, copy, modify, distribute, and sell this software
   5  * and its documentation for any purpose is hereby granted without
   6  * fee, provided that the above copyright notice appear in all copies
   7  * and that both that copyright notice and this permission notice
   8  * appear in supporting documentation, and that the name of
   9  * Novell, Inc. not be used in advertising or publicity pertaining to
  10  * distribution of the software without specific, written prior permission.
  11  * Novell, Inc. makes no representations about the suitability of this
  12  * software for any purpose. It is provided "as is" without express or
  13  * implied warranty.
  14  *
  15  * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
  17  * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  19  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  21  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22  *
  23  * Author: David Reveman <davidr@novell.com>
  24  *         Mirco M��ller <macslow@bangang.de> (Skydome support)
  25  */
  26 
  27 #include <string.h>
  28 #include <math.h>
  29 
  30 #include <X11/Xatom.h>
  31 #include <X11/Xproto.h>
  32 
  33 #include <privates.h>
  34 
  35 class CubePluginVTable :
  36     public CompPlugin::VTableForScreenAndWindow<CubeScreen, PrivateCubeWindow>
  37 {
  38     public:
  39 
  40 	bool init ();
  41 	void fini ();
  42 };
  43 
  44 COMPIZ_PLUGIN_20090315 (cube, CubePluginVTable)
  45 
  46 void
  47 CubeScreenInterface::cubeGetRotation (float &x, float &v, float &progress)
  48     WRAPABLE_DEF (cubeGetRotation, x, v, progress);
  49 
  50 void
  51 CubeScreenInterface::cubeClearTargetOutput (float xRotate, float vRotate)
  52     WRAPABLE_DEF (cubeClearTargetOutput, xRotate, vRotate);
  53 
  54 void
  55 CubeScreenInterface::cubePaintTop (const GLScreenPaintAttrib &sAttrib,
  56 		                   const GLMatrix            &transform,
  57 		                   CompOutput                *output,
  58 				   int                       size,
  59 				   const GLVector            &normal)
  60     WRAPABLE_DEF (cubePaintTop, sAttrib, transform, output, size, normal)
  61     
  62 void
  63 CubeScreenInterface::cubePaintBottom (const GLScreenPaintAttrib &sAttrib,
  64 				      const GLMatrix            &transform,
  65 				      CompOutput                *output,
  66 				      int                       size,
  67 				      const GLVector            &normal)
  68     WRAPABLE_DEF (cubePaintBottom, sAttrib, transform, output, size, normal)
  69 
  70 void
  71 CubeScreenInterface::cubePaintInside (const GLScreenPaintAttrib &sAttrib,
  72 				      const GLMatrix            &transform,
  73 				      CompOutput                *output,
  74 				      int                       size,
  75 				      const GLVector            &normal)
  76     WRAPABLE_DEF (cubePaintInside, sAttrib, transform, output, size, normal)
  77 
  78 bool
  79 CubeScreenInterface::cubeCheckOrientation (const GLScreenPaintAttrib &sAttrib,
  80 					   const GLMatrix            &transform,
  81 					   CompOutput                *output,
  82 					   std::vector<GLVector>     &points)
  83     WRAPABLE_DEF (cubeCheckOrientation, sAttrib, transform, output, points)
  84 
  85 void
  86 CubeScreenInterface::cubePaintViewport (const GLScreenPaintAttrib &sAttrib,
  87 					const GLMatrix            &transform,
  88 					const CompRegion          &region,
  89 					CompOutput                *output,
  90 					unsigned int              mask)
  91     WRAPABLE_DEF (cubePaintViewport, sAttrib, transform, region, output, mask)
  92 
  93 bool
  94 CubeScreenInterface::cubeShouldPaintViewport (const GLScreenPaintAttrib &sAttrib,
  95 					      const GLMatrix            &transform,
  96 					      CompOutput                *output,
  97 					      PaintOrder                order)
  98     WRAPABLE_DEF (cubeShouldPaintViewport, sAttrib, transform, output, order)
  99     
 100 bool
 101 CubeScreenInterface::cubeShouldPaintAllViewports ()
 102     WRAPABLE_DEF (cubeShouldPaintAllViewports);
 103 
 104 int 
 105 CubeScreen::invert () const
 106 {
 107     return priv->mInvert;
 108 }
 109 
 110 unsigned short* 
 111 CubeScreen::topColor () const
 112 {
 113     return priv->optionGetTopColor ();
 114 }
 115 
 116 unsigned short*  
 117 CubeScreen::bottomColor () const
 118 {
 119     return priv->optionGetBottomColor ();
 120 }
 121 
 122 bool 
 123 CubeScreen::unfolded () const
 124 {
 125     return priv->mUnfolded;
 126 }
 127 
 128 CubeScreen::RotationState 
 129 CubeScreen::rotationState () const
 130 {
 131     return priv->mRotationState;
 132 }
 133 
 134 void 
 135 CubeScreen::rotationState (CubeScreen::RotationState state)
 136 {
 137     priv->mRotationState = state;
 138 }
 139 
 140 int 
 141 CubeScreen::xRotations () const
 142 {
 143     return priv->mXRotations;
 144 }
 145 
 146 int 
 147 CubeScreen::nOutput () const
 148 {
 149     return priv->mNOutput;
 150 }
 151 
 152 float
 153 CubeScreen::outputXScale () const
 154 {
 155     return priv->mOutputXScale;
 156 }
 157 
 158 float
 159 CubeScreen::outputYScale () const
 160 {
 161     return priv->mOutputYScale;
 162 }
 163 
 164 float
 165 CubeScreen::outputXOffset () const
 166 {
 167     return priv->mOutputXOffset;
 168 }
 169 
 170 float
 171 CubeScreen::outputYOffset () const
 172 {
 173     return priv->mOutputYOffset;
 174 }
 175 
 176 float
 177 CubeScreen::distance () const
 178 {
 179     return priv->mDistance;
 180 }
 181 
 182 float
 183 CubeScreen::desktopOpacity () const
 184 {
 185     return priv->mDesktopOpacity;
 186 }
 187 
 188 CubeScreen::MultioutputMode 
 189 CubeScreen::multioutputMode () const
 190 {
 191     switch (priv->optionGetMultioutputMode ())
 192     {
 193 	case CubeOptions::MultioutputModeOneBigCube:
 194 	    return OneBigCube;
 195 	case CubeOptions::MultioutputModeMultipleCubes:
 196 	    return MultipleCubes;
 197 	default:
 198 	    break;
 199     }
 200 
 201     return Automatic;
 202 }
 203 
 204 int 
 205 CubeScreen::sourceOutput () const
 206 {
 207     return priv->mSrcOutput;
 208 }
 209 
 210 PaintOrder 
 211 CubeScreen::paintOrder () const
 212 {
 213     return priv->mPaintOrder;
 214 }
 215 
 216 bool
 217 CubeScreen::cubeShouldPaintAllViewports ()
 218 {
 219     WRAPABLE_HND_FUNCTN_RETURN (bool, cubeShouldPaintAllViewports);
 220     
 221     return priv->mPaintAllViewports;
 222 }
 223 
 224 void
 225 CubeScreen::repaintCaps ()
 226 {
 227     memset (priv->mCapsPainted, 0, sizeof (Bool) * screen->outputDevs ().size ());
 228 }
 229 
 230 bool
 231 PrivateCubeScreen::updateGeometry (int sides, int invert)
 232 {
 233     GLfloat radius, distance;
 234     GLfloat *v;
 235     int     i, n;
 236 
 237     sides *= mNOutput;
 238 
 239     distance = 0.5f / tanf (M_PI / sides);
 240     radius   = 0.5f / sinf (M_PI / sides);
 241 
 242     n = (sides + 2) * 2;
 243 
Condition "this->mNVertices != n", taking true branch
Condition "this->mNVertices != n", taking true branch
Condition "this->mNVertices != n", taking true branch
Condition "this->mNVertices != n", taking true branch
 244     if (mNVertices != n)
 245     {
 246 	v = (GLfloat *) realloc (mVertices, sizeof (GLfloat) * n * 3);
Condition "!v", taking false branch
Condition "!v", taking false branch
Condition "!v", taking false branch
Condition "!v", taking false branch
 247 	if (!v)
 248 	    return false;
 249 
 250 	mNVertices = n;
 251 	mVertices  = v;
Falling through to end of if statement
Falling through to end of if statement
Falling through to end of if statement
Falling through to end of if statement
 252     }
 253     else
 254 	v = mVertices;
 255 
 256     *v++ = 0.0f;
 257     *v++ = 0.5 * invert;
 258     *v++ = 0.0f;
 259 
Condition "i <= sides", taking true branch
Jumped back to beginning of loop
Condition "i <= sides", taking false branch
Condition "i <= sides", taking true branch
Jumped back to beginning of loop
Condition "i <= sides", taking false branch
Condition "i <= sides", taking true branch
Jumped back to beginning of loop
Condition "i <= sides", taking false branch
Condition "i <= sides", taking true branch
Jumped back to beginning of loop
Condition "i <= sides", taking false branch
 260     for (i = 0; i <= sides; i++)
 261     {
 262 	*v++ = radius * sinf (i * 2 * M_PI / sides + M_PI / sides);
 263 	*v++ = 0.5 * invert;
 264 	*v++ = radius * cosf (i * 2 * M_PI / sides + M_PI / sides);
Jumping back to the beginning of the loop
Reached end of loop
Jumping back to the beginning of the loop
Reached end of loop
Jumping back to the beginning of the loop
Reached end of loop
Jumping back to the beginning of the loop
Reached end of loop
 265     }
 266 
 267     *v++ = 0.0f;
 268     *v++ = -0.5 * invert;
 269     *v++ = 0.0f;
 270 
Condition "i >= 0", taking true branch
Condition "i >= 0", taking true branch
Condition "i >= 0", taking true branch
Condition "i >= 0", taking true branch
 271     for (i = sides; i >= 0; i--)
 272     {
CID 12435 - DIVIDE_BY_ZERO
In expression "3.14159 / sides", division by expression "sides" which may be zero has undefined behavior.
In expression "i * 2 * 3.14159 / sides", division by expression "sides" which may be zero has undefined behavior.
 273 	*v++ = radius * sinf (i * 2 * M_PI / sides + M_PI / sides);
 274 	*v++ = -0.5 * invert;
CID 12435 - DIVIDE_BY_ZERO
In expression "3.14159 / sides", division by expression "sides" which may be zero has undefined behavior.
In expression "i * 2 * 3.14159 / sides", division by expression "sides" which may be zero has undefined behavior.
 275 	*v++ = radius * cosf (i * 2 * M_PI / sides + M_PI / sides);
 276     }
 277 
 278     mInvert   = invert;
 279     mDistance = distance;
 280 
 281     return true;
 282 }
 283 
 284 void
 285 PrivateCubeScreen::updateOutputs ()
 286 {
 287     CompOutput *pBox0, *pBox1;
 288     unsigned int i, j;
 289     int    k, x;
 290 
 291     k = 0;
 292 
 293     mFullscreenOutput = true;
 294 
 295     for (i = 0; i < screen->outputDevs ().size (); i++)
 296     {
 297 	mOutputMask[i] = -1;
 298 
 299 	/* dimensions must match first output */
 300 	if (screen->outputDevs ()[i].width ()  != screen->outputDevs ()[0].width () ||
 301 	    screen->outputDevs ()[i].height () != screen->outputDevs ()[0].height ())
 302 	    continue;
 303 
 304 	pBox0 = &screen->outputDevs ()[0];
 305 	pBox1 = &screen->outputDevs ()[i];
 306 
 307 	/* top and bottom line must match first output */
 308 	if (pBox0->y1 () != pBox1->y1 () || pBox0->y2 () != pBox1->y2 ())
 309 	    continue;
 310 
 311 	k++;
 312 
 313 	for (j = 0; j < screen->outputDevs ().size (); j++)
 314 	{
 315 	    pBox0 = &screen->outputDevs ()[j];
 316 
 317 	    /* must not intersect other output region */
 318 	    if (i != j && pBox0->x2 () > pBox1->x1 () && pBox0->x1 () < pBox1->x2 ())
 319 	    {
 320 		k--;
 321 		break;
 322 	    }
 323 	}
 324     }
 325 
 326     if (optionGetMultioutputMode () == CubeOptions::MultioutputModeOneBigCube)
 327     {
 328 	mFullscreenOutput = false;
 329 	mNOutput = 1;
 330 	return;
 331     }
 332 
 333     if (optionGetMultioutputMode () == CubeOptions::MultioutputModeMultipleCubes)
 334     {
 335 	mFullscreenOutput = true;
 336 	mNOutput = 1;
 337 	return;
 338     }
 339 
 340     if ((unsigned int) k != screen->outputDevs ().size ())
 341     {
 342 	mFullscreenOutput = false;
 343 	mNOutput = 1;
 344 	return;
 345     }
 346 
 347     /* add output indices from left to right */
 348     j = 0;
 349     for (;;)
 350     {
 351 	x = MAXSHORT;
 352 	k = -1;
 353 
 354 	for (i = 0; i < screen->outputDevs ().size (); i++)
 355 	{
 356 	    if (mOutputMask[i] != -1)
 357 		continue;
 358 
 359 	    if (screen->outputDevs ()[i].x1 () < x)
 360 	    {
 361 		x = screen->outputDevs ()[i].x1 ();
 362 		k = i;
 363 	    }
 364 	}
 365 
 366 	if (k < 0)
 367 	    break;
 368 
 369 	mOutputMask[k] = j;
 370 	mOutput[j]     = k;
 371 
 372 	j++;
 373     }
 374 
 375     mNOutput = j;
 376 
 377     if (mNOutput == 1)
 378     {
 379 	if (screen->outputDevs ()[0].width ()  != screen->width () ||
 380 	    screen->outputDevs ()[0].height () != screen->height ())
 381 	    mFullscreenOutput = true;
 382     }
 383 }
 384 
 385 void
 386 PrivateCubeScreen::updateSkydomeTexture ()
 387 {
 388     mSky.clear ();
 389 
 390     if (!optionGetSkydome ())
 391 	return;
 392 
 393     CompString imgName = optionGetSkydomeImage ();
 394     CompString pname = "cube";
 395 
 396     if (optionGetSkydomeImage ().empty () ||
 397 	(mSky = GLTexture::readImageToTexture (imgName, pname, mSkySize)).empty ())
 398     {
 399 	GLfloat aaafTextureData[128][128][3];
 400 	GLfloat fRStart = (GLfloat) optionGetSkydomeGradientStartColorRed () / 0xffff;
 401 	GLfloat fGStart = (GLfloat) optionGetSkydomeGradientStartColorGreen () / 0xffff;
 402 	GLfloat fBStart = (GLfloat) optionGetSkydomeGradientStartColorBlue () / 0xffff;
 403 	GLfloat fREnd = (GLfloat) optionGetSkydomeGradientEndColorRed () / 0xffff;
 404 	GLfloat fGEnd = (GLfloat) optionGetSkydomeGradientEndColorGreen () / 0xffff;
 405 	GLfloat fBEnd = (GLfloat) optionGetSkydomeGradientEndColorBlue () / 0xffff;
 406 	GLfloat fRStep = (fREnd - fRStart) / 128.0f;
 407 	GLfloat fGStep = (fGEnd - fGStart) / 128.0f;
 408 	GLfloat fBStep = (fBStart - fBEnd) / 128.0f;
 409 	GLfloat fR = fRStart;
 410 	GLfloat fG = fGStart;
 411 	GLfloat fB = fBStart;
 412 
 413 	int	iX, iY;
 414 
 415 	for (iX = 127; iX >= 0; iX--)
 416 	{
 417 	    fR += fRStep;
 418 	    fG += fGStep;
 419 	    fB -= fBStep;
 420 
 421 	    for (iY = 0; iY < 128; iY++)
 422 	    {
 423 		aaafTextureData[iX][iY][0] = fR;
 424 		aaafTextureData[iX][iY][1] = fG;
 425 		aaafTextureData[iX][iY][2] = fB;
 426 	    }
 427 	}
 428 
 429 	mSkySize = CompSize (128, 128);
 430 
 431 	mSky = GLTexture::imageDataToTexture ((char *) aaafTextureData,
 432 					      mSkySize, GL_RGB, GL_FLOAT);
 433 
 434 	mSky[0]->setFilter (GL_LINEAR);
 435 	mSky[0]->setWrap (GL_CLAMP_TO_EDGE);
 436     }
 437 }
 438 
 439 #ifndef USE_GLES
 440 static bool
 441 fillCircleTable (GLfloat   **ppSint,
 442 		 GLfloat   **ppCost,
 443 		 const int n)
 444 {
 445     const GLfloat angle = 2 * M_PI / (GLfloat) ((n == 0) ? 1 : n);
 446     const int	  size = abs (n);
 447 
 448     *ppSint = (GLfloat *) calloc (sizeof (GLfloat), size + 1);
 449     *ppCost = (GLfloat *) calloc (sizeof (GLfloat), size + 1);
 450 
 451     if (!(*ppSint) || !(*ppCost))
 452     {
 453 	free (*ppSint);
 454 	free (*ppCost);
 455 
 456 	return false;
 457     }
 458 
 459     (*ppSint)[0] = 0.0;
 460     (*ppCost)[0] = 1.0;
 461 
 462     for (int i = 1; i < size; i++)
 463     {
 464 	(*ppSint)[i] = sin (angle * i);
 465 	(*ppCost)[i] = cos (angle * i);
 466     }
 467 
 468     (*ppSint)[size] = (*ppSint)[0];
 469     (*ppCost)[size] = (*ppCost)[0];
 470 
 471     return true;
 472 }
 473 #endif
 474 
 475 void
 476 PrivateCubeScreen::updateSkydomeList (GLfloat fRadius)
 477 {
 478 #ifndef USE_GLES
 479     GLint   iSlices = 128;
 480     GLint   iStacks = 64;
 481     GLfloat afTexCoordX[4];
 482     GLfloat afTexCoordY[4];
 483     GLfloat *sint1;
 484     GLfloat *cost1;
 485     GLfloat *sint2;
 486     GLfloat *cost2;
 487     GLfloat r;
 488     GLfloat x;
 489     GLfloat y;
 490     GLfloat z;
 491     int	    iStacksStart;
 492     int	    iStacksEnd;
 493     int	    iSlicesStart;
 494     int	    iSlicesEnd;
 495     GLfloat fStepX;
 496     GLfloat fStepY;
 497 
 498     if (optionGetSkydomeAnimated ())
 499     {
 500 	iStacksStart = 11; /* min.   0 */
 501 	iStacksEnd = 53;   /* max.  64 */
 502 	iSlicesStart = 0;  /* min.   0 */
 503 	iSlicesEnd = 128;  /* max. 128 */
 504     }
 505     else
 506     {
 507 	iStacksStart = 21; /* min.   0 */
 508 	iStacksEnd = 43;   /* max.  64 */
 509 	iSlicesStart = 21; /* min.   0 */
 510 	iSlicesEnd = 44;   /* max. 128 */
 511     }
 512 
 513     fStepX = 1.0 / (GLfloat) (iSlicesEnd - iSlicesStart);
 514     fStepY = 1.0 / (GLfloat) (iStacksEnd - iStacksStart);
 515 
 516     if (!mSky.size ())
 517 	return;
 518 
 519     if (!fillCircleTable (&sint1, &cost1, -iSlices))
 520 	return;
 521 
 522     if (!fillCircleTable (&sint2, &cost2, iStacks * 2))
 523     {
 524 	free (sint1);
 525 	free (cost1);
 526 	return;
 527     }
 528 
 529     afTexCoordX[0] = 1.0f;
 530     afTexCoordY[0] = 1.0f - fStepY;
 531     afTexCoordX[1] = 1.0f - fStepX;
 532     afTexCoordY[1] = 1.0f - fStepY;
 533     afTexCoordX[2] = 1.0f - fStepX;
 534     afTexCoordY[2] = 1.0f;
 535     afTexCoordX[3] = 1.0f;
 536     afTexCoordY[3] = 1.0f;
 537 
 538 
 539     if (!mSkyListId)
 540 	mSkyListId = glGenLists (1);
 541 
 542     glNewList (mSkyListId, GL_COMPILE);
 543 
 544     mSky[0]->enable (GLTexture::Good);
 545 
 546     glBegin (GL_QUADS);
 547 
 548     for (int i = iStacksStart; i < iStacksEnd; i++)
 549     {
 550 	afTexCoordX[0] = 1.0f;
 551 	afTexCoordX[1] = 1.0f - fStepX;
 552 	afTexCoordX[2] = 1.0f - fStepX;
 553 	afTexCoordX[3] = 1.0f;
 554 
 555 	for (int j = iSlicesStart; j < iSlicesEnd; j++)
 556 	{
 557 	    /* bottom-right */
 558 	    z = cost2[i];
 559 	    r = sint2[i];
 560 	    x = cost1[j];
 561 	    y = sint1[j];
 562 
 563 	    glTexCoord2f (
 564 		COMP_TEX_COORD_X (mSky[0]->matrix (), afTexCoordX[3] * mSkySize.width ()),
 565 		COMP_TEX_COORD_Y (mSky[0]->matrix (), afTexCoordY[3] * mSkySize.height ()));
 566 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
 567 
 568 	    /* top-right */
 569 	    z = cost2[i + 1];
 570 	    r = sint2[i + 1];
 571 	    x = cost1[j];
 572 	    y = sint1[j];
 573 
 574 	    glTexCoord2f (
 575                 COMP_TEX_COORD_X (mSky[0]->matrix (), afTexCoordX[0] * mSkySize.width ()),
 576 		COMP_TEX_COORD_Y (mSky[0]->matrix (), afTexCoordY[0] * mSkySize.height ()));
 577 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
 578 
 579 	    /* top-left */
 580 	    z = cost2[i + 1];
 581 	    r = sint2[i + 1];
 582 	    x = cost1[j + 1];
 583 	    y = sint1[j + 1];
 584 
 585 	    glTexCoord2f (
 586                 COMP_TEX_COORD_X (mSky[0]->matrix (), afTexCoordX[1] * mSkySize.width ()),
 587 		COMP_TEX_COORD_Y (mSky[0]->matrix (), afTexCoordY[1] * mSkySize.height ()));
 588 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
 589 
 590 	    /* bottom-left */
 591 	    z = cost2[i];
 592 	    r = sint2[i];
 593 	    x = cost1[j + 1];
 594 	    y = sint1[j + 1];
 595 
 596 	    glTexCoord2f (
 597                 COMP_TEX_COORD_X (mSky[0]->matrix (), afTexCoordX[2] * mSkySize.width ()),
 598 		COMP_TEX_COORD_Y (mSky[0]->matrix (), afTexCoordY[2] * mSkySize.height ()));
 599 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
 600 
 601 	    afTexCoordX[0] -= fStepX;
 602 	    afTexCoordX[1] -= fStepX;
 603 	    afTexCoordX[2] -= fStepX;
 604 	    afTexCoordX[3] -= fStepX;
 605 	}
 606 
 607 	afTexCoordY[0] -= fStepY;
 608 	afTexCoordY[1] -= fStepY;
 609 	afTexCoordY[2] -= fStepY;
 610 	afTexCoordY[3] -= fStepY;
 611     }
 612 
 613     glEnd ();
 614 
 615     mSky[0]->disable ();
 616 
 617     glEndList ();
 618 
 619     free (sint1);
 620     free (cost1);
 621     free (sint2);
 622     free (cost2);
 623 
 624 #endif
 625 }
 626 
 627 bool
 628 PrivateCubeScreen::setOption (const CompString &name, CompOption::Value &value)
 629 {
 630 
 631     unsigned int index;
 632 
 633     bool rv = CubeOptions::setOption (name, value);
 634 
 635     if (!rv || !CompOption::findOption (getOptions (), name, &index))
 636         return false;
 637 
 638     switch (index) {
 639 	case CubeOptions::In:
 640 	    rv = updateGeometry (screen->vpSize ().width (), value.b () ? -1 : 1);
 641 	    break;
 642 	case CubeOptions::Skydome:
 643 	case CubeOptions::SkydomeImage:
 644 	case CubeOptions::SkydomeAnimated:
 645 	case CubeOptions::SkydomeGradientStartColor:
 646 	case CubeOptions::SkydomeGradientEndColor:
 647 	    updateSkydomeTexture ();
 648 	    updateSkydomeList (1.0f);
 649 	    cScreen->damageScreen ();
 650 	    break;
 651 	case CubeOptions::MultioutputMode:
 652 	    updateOutputs ();
 653 	    updateGeometry (screen->vpSize ().width (), mInvert);
 654 	    cScreen->damageScreen ();
 655 	    break;
 656 	default:
 657 	    break;
 658     }
 659 
 660     return rv;
 661 }
 662 
 663 bool
 664 PrivateCubeScreen::adjustVelocity ()
 665 {
 666     float unfold, adjust, amount;
 667 
 668     if (mUnfolded)
 669 	unfold = 1.0f - mUnfold;
 670     else
 671 	unfold = 0.0f - mUnfold;
 672 
 673     adjust = unfold * 0.02f * optionGetAcceleration ();
 674     amount = fabs (unfold);
 675     if (amount < 1.0f)
 676 	amount = 1.0f;
 677     else if (amount > 3.0f)
 678 	amount = 3.0f;
 679 
 680     mUnfoldVelocity = (amount * mUnfoldVelocity + adjust) /
 681 	(amount + 2.0f);
 682 
 683     return (fabs (unfold) < 0.002f && fabs (mUnfoldVelocity) < 0.01f);
 684 }
 685 
 686 void
 687 PrivateCubeScreen::preparePaint (int msSinceLastPaint)
 688 {
 689     int   opt;
 690     float x, progress;
 691     unsigned short *topColor, *bottomColor;
 692 
 693     if (mGrabIndex)
 694     {
 695 	int   steps;
 696 	float amount, chunk;
 697 
 698 	amount = msSinceLastPaint * 0.2f *
 699 	    optionGetSpeed ();
 700 	steps  = amount / (0.5f * optionGetTimestep ());
 701 	if (!steps) steps = 1;
 702 	chunk  = amount / (float) steps;
 703 
 704 	while (steps--)
 705 	{
 706 	    mUnfold += mUnfoldVelocity * chunk;
 707 	    if (mUnfold > 1.0f)
 708 		mUnfold = 1.0f;
 709 
 710 	    if (adjustVelocity ())
 711 	    {
 712 		if (mUnfold < 0.5f)
 713 		{
 714 		    if (mGrabIndex)
 715 		    {
 716 			screen->removeGrab (mGrabIndex, NULL);
 717 			mGrabIndex = 0;
 718 		    }
 719 
 720 		    mUnfold = 0.0f;
 721 		}
 722 		break;
 723 	    }
 724 	}
 725     }
 726 
 727     memset (mCleared, 0, sizeof (Bool) * screen->outputDevs ().size ());
 728     memset (mCapsPainted, 0, sizeof (Bool) * screen->outputDevs ().size ());
 729 
 730     /* Transparency handling */
 731     if (mRotationState == CubeScreen::RotationManual ||
 732 	(mRotationState == CubeScreen::RotationChange &&
 733 	 !optionGetTransparentManualOnly ()))
 734     {
 735 	opt = mLastOpacityIndex = CubeOptions::ActiveOpacity;
 736     }
 737     else if (mRotationState == CubeScreen::RotationChange)
 738     {
 739 	opt = mLastOpacityIndex = CubeOptions::InactiveOpacity;
 740     }
 741     else
 742     {
 743 	opt = CubeOptions::InactiveOpacity;
 744     }
 745 
 746     mToOpacity = (mOptions[opt].value ().f () / 100.0f) * OPAQUE;
 747 
 748     cubeScreen->cubeGetRotation (x, x, progress);
 749 
 750     if (mDesktopOpacity != mToOpacity ||
 751 	(progress > 0.0 && progress < 1.0))
 752     {
 753 	mDesktopOpacity = 
 754 	    (optionGetInactiveOpacity () - 
 755 	    ((optionGetInactiveOpacity () -
 756 	     mOptions[mLastOpacityIndex].value ().f ()) * progress))
 757 	    / 100.0f * OPAQUE;
 758 
 759     }
 760 
 761     topColor	= optionGetTopColor ();
 762     bottomColor	= optionGetBottomColor ();
 763 
 764     mPaintAllViewports = (mDesktopOpacity != OPAQUE ||
 765 			  topColor[3] != OPAQUE ||
 766 			  bottomColor[3] != OPAQUE);
 767  
 768     cScreen->preparePaint (msSinceLastPaint);
 769 }
 770 
 771 void
 772 PrivateCubeScreen::paint (CompOutput::ptrList &outputs, unsigned int mask)
 773 {
 774     float x, progress;
 775 
 776     cubeScreen->cubeGetRotation (x, x, progress);
 777 
 778     if (optionGetMultioutputMode () == MultioutputModeOneBigCube && 
 779 	screen->outputDevs ().size () &&
 780         (progress > 0.0f || mDesktopOpacity != OPAQUE))
 781     {
 782 	outputs.clear ();
 783 	outputs.push_back (&screen->fullscreenOutput ());
 784     }
 785 
 786     cScreen->paint (outputs, mask);
 787 }
 788 
 789 bool
 790 PrivateCubeScreen::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
 791 				  const GLMatrix            &transform,
 792 				  const CompRegion          &region,
 793 				  CompOutput                *output,
 794 				  unsigned int              mask)
 795 {
 796     if (mGrabIndex || mDesktopOpacity != OPAQUE)
 797     {
 798 	mask &= ~PAINT_SCREEN_REGION_MASK;
 799 	mask |= PAINT_SCREEN_TRANSFORMED_MASK;
 800     }
 801 
 802     mSrcOutput = ((unsigned int) output->id () != (unsigned int) ~0) ?
 803     							      output->id () : 0;
 804     /* Always use BTF painting on non-transformed screen */
 805     mPaintOrder = BTF;
 806 
 807     return gScreen->glPaintOutput (sAttrib, transform, region, output, mask);
 808 }
 809 
 810 void
 811 PrivateCubeScreen::donePaint ()
 812 {
 813     if (mGrabIndex || mDesktopOpacity != mToOpacity)
 814 	cScreen->damageScreen ();
 815 
 816     cScreen->donePaint ();
 817 }
 818 
 819 bool
 820 CubeScreen::cubeCheckOrientation (const GLScreenPaintAttrib &sAttrib,
 821 				  const GLMatrix            &transform,
 822 				  CompOutput                *output,
 823 				  std::vector<GLVector>     &points)
 824 {
 825     WRAPABLE_HND_FUNCTN_RETURN (bool, cubeCheckOrientation, sAttrib, transform, output, points)
 826     GLMatrix sTransform = transform;
 827     GLMatrix mvp, pm (priv->gScreen->projectionMatrix ()->getMatrix ());
 828     GLVector pntA, pntB, pntC;
 829     GLVector vecA, vecB, ortho;
 830     bool     rv = false;
 831 
 832     priv->gScreen->glApplyTransform (sAttrib, output, &sTransform);
 833     sTransform.translate (priv->mOutputXOffset, -priv->mOutputYOffset, 0.0f);
 834     sTransform.scale (priv->mOutputXScale, priv->mOutputYScale, 1.0f);
 835 
 836     mvp = pm * sTransform;
 837 
 838     pntA = mvp * points[0];
 839 
 840     if (pntA[3] < 0.0f)
 841 	rv = !rv;
 842 
 843     pntA.homogenize ();
 844 
 845     pntB = mvp * points[1];
 846 
 847     if (pntB[3] < 0.0f)
 848 	rv = !rv;
 849 
 850     pntB.homogenize ();
 851 
 852     pntC = mvp * points[2];
 853     pntC.homogenize ();
 854 
 855     vecA = pntC - pntA;
 856     vecB = pntC - pntB;
 857 
 858     ortho = vecA ^ vecB;
 859 
 860     if (ortho[2] > 0.0f)
 861 	rv = !rv;
 862 
 863     return rv;
 864 }
 865 
 866 bool
 867 CubeScreen::cubeShouldPaintViewport (const GLScreenPaintAttrib &sAttrib,
 868 				     const GLMatrix            &transform,
 869 				     CompOutput                *output,
 870 				     PaintOrder                order)
 871 {
 872     WRAPABLE_HND_FUNCTN_RETURN (bool, cubeShouldPaintViewport, sAttrib, transform, output, order)
 873 
 874     bool  ftb;
 875     float pointZ;
 876 
 877     pointZ = priv->mInvert * priv->mDistance;
 878     std::vector<GLVector> vPoints;
 879     vPoints.push_back (GLVector (-0.5, 0.0, pointZ, 1.0));
 880     vPoints.push_back (GLVector (0.0, 0.5, pointZ, 1.0));
 881     vPoints.push_back (GLVector (0.0, 0.0, pointZ, 1.0));
 882 
 883     ftb = cubeCheckOrientation (sAttrib, transform, output, vPoints);
 884 
 885     return (order == FTB && ftb) || (order == BTF && !ftb);
 886 }
 887 
 888 void
 889 PrivateCubeScreen::moveViewportAndPaint (const GLScreenPaintAttrib &sAttrib,
 890 					 const GLMatrix            &transform,
 891 					 CompOutput                *outputPtr,
 892 					 unsigned int              mask,
 893 					 PaintOrder                paintOrder,
 894 					 int                       dx)
 895 {
 896     if (!cubeScreen->cubeShouldPaintViewport (sAttrib, transform, outputPtr, 
 897 					      paintOrder))
 898 	return;
 899 
 900     int output = ((unsigned int) outputPtr->id () != (unsigned int) ~0)
 901     							 ? outputPtr->id () : 0;
 902 
 903     mPaintOrder = paintOrder;
 904 
 905     if (mNOutput > 1)
 906     {
 907 	int cubeOutput, dView;
 908 
 909 	/* translate to cube output */
 910 	cubeOutput = mOutputMask[output];
 911 
 912 	/* convert from window movement to viewport movement */
 913 	dView = -dx;
 914 
 915 	cubeOutput += dView;
 916 
 917 	dView      = cubeOutput / mNOutput;
 918 	cubeOutput = cubeOutput % mNOutput;
 919 
 920 	if (cubeOutput < 0)
 921 	{
 922 	    cubeOutput += mNOutput;
 923 	    dView--;
 924 	}
 925 
 926 	/* translate back to compiz output */
 927 	output = mSrcOutput = mOutput[cubeOutput];
 928 
 929 	cScreen->setWindowPaintOffset (-dView * screen->width (), 0);
 930 	
 931 	CompRegion reg (screen->outputDevs () [output]);
 932 	cubeScreen->cubePaintViewport (sAttrib, transform, reg, 
 933 			               &screen->outputDevs () [output], mask);
 934 	cScreen->setWindowPaintOffset (0, 0);
 935     }
 936     else
 937     {
 938 	CompRegion region;
 939 
 940 	cScreen->setWindowPaintOffset (dx * screen->width (), 0);
 941 
 942 	if (optionGetMultioutputMode () == MultioutputModeMultipleCubes)
 943 	    region = CompRegion (*outputPtr);
 944 	else
 945 	    region = screen->region ();
 946 
 947 	cubeScreen->cubePaintViewport (sAttrib, transform, region, outputPtr, mask);
 948 
 949 	cScreen->setWindowPaintOffset (0, 0);
 950     }
 951 }
 952 
 953 void
 954 PrivateCubeScreen::paintAllViewports (const GLScreenPaintAttrib &sAttrib,
 955 				      const GLMatrix            &transform,
 956 				      const CompRegion          &region,
 957 				      CompOutput                *outputPtr,
 958 				      unsigned int              mask,
 959 				      int                       xMove,
 960 				      float                     size,
 961 				      int                       hsize,
 962 				      PaintOrder                paintOrder)
 963 {
 964     GLScreenPaintAttrib sa = sAttrib;
 965 
 966     int xMoveAdd;
 967     int origXMoveAdd = 0; /* dx for the viewport we start
 968 			     painting with (back-most). */
 969     int iFirstSign;       /* 1 if we do xMove += i first and
 970 			     -1 if we do xMove -= i first. */
 971 
 972     if (mInvert == 1)
 973     {
 974 	/* xMove ==> dx for the viewport which is the
 975 	   nearest to the viewer in z axis.
 976 	   xMove +/- hsize / 2 ==> dx for the viewport
 977 	   which is the farthest to the viewer in z axis. */
 978 
 979 	if ((sa.xRotate < 0.0f && hsize % 2 == 1) ||
 980 	    (sa.xRotate > 0.0f && hsize % 2 == 0))
 981 	{
 982 	    origXMoveAdd = hsize / 2;
 983 	    iFirstSign = 1;
 984 	}
 985 	else
 986 	{
 987 	    origXMoveAdd = -hsize / 2;
 988 	    iFirstSign = -1;
 989 	}
 990     }
 991     else
 992     {
 993 	/* xMove is already the dx for farthest viewport. */
 994 	if (sa.xRotate > 0.0f)
 995 	    iFirstSign = -1;
 996 	else
 997 	    iFirstSign = 1;
 998     }
 999 
1000     for (int i = 0; i <= hsize / 2; i++)
1001     {
1002 	/* move to the correct viewport (back to front). */
1003 	xMoveAdd = origXMoveAdd;	/* move to farthest viewport. */
1004 	xMoveAdd += iFirstSign * i;	/* move i more viewports to
1005 					   the right / left. */
1006 
1007 	/* Needed especially for unfold.
1008 	   We paint the viewports around xMove viewport.
1009 	   Adding or subtracting hsize from xMove has no effect on
1010 	   what viewport we paint, but can make shorter paths. */
1011 	if (xMoveAdd < -hsize / 2)
1012 	    xMoveAdd += hsize;
1013 	else if (xMoveAdd > hsize / 2)
1014 	    xMoveAdd -= hsize;
1015 
1016 	/* Paint the viewport. */
1017 	xMove += xMoveAdd;
1018 
1019 	sa.yRotate -= mInvert * xMoveAdd * 360.0f / size;
1020 	moveViewportAndPaint (sa, transform, outputPtr, mask,
1021 			      paintOrder, xMove);
1022 	sa.yRotate += mInvert * xMoveAdd * 360.0f / size;
1023 
1024 	xMove -= xMoveAdd;
1025 
1026 	/* do the same for an equally far viewport. */
1027 	if (i == 0 || i * 2 == hsize)
1028 	    continue;
1029 
1030 	xMoveAdd = origXMoveAdd;	/* move to farthest viewport. */
1031 	xMoveAdd -= iFirstSign * i;	/* move i more viewports to the
1032 					   left / right (opposite side
1033 					   from the one chosen first) */
1034 
1035 	if (xMoveAdd < -hsize / 2)
1036 	    xMoveAdd += hsize;
1037 	else if (xMoveAdd > hsize / 2)
1038 	    xMoveAdd -= hsize;
1039 
1040 	xMove += xMoveAdd;
1041 
1042 	sa.yRotate -= mInvert * xMoveAdd * 360.0f / size;
1043 	moveViewportAndPaint (sa, transform, outputPtr, mask,
1044 			      paintOrder, xMove);
1045 	sa.yRotate += mInvert * xMoveAdd * 360.0f / size;
1046 
1047 	xMove -= xMoveAdd;
1048     }
1049 }
1050 
1051 void
1052 CubeScreen::cubeGetRotation (float &x, float &v, float &progress)
1053 {
1054     WRAPABLE_HND_FUNCTN (cubeGetRotation, x, v, progress)
1055 
1056     x        = 0.0f;
1057     v        = 0.0f;
1058     progress = 0.0f;
1059 }
1060 
1061 void
1062 CubeScreen::cubeClearTargetOutput (float xRotate, float vRotate)
1063 {
1064     WRAPABLE_HND_FUNCTN (cubeClearTargetOutput, xRotate, vRotate)
1065 
1066     if (priv->mSky.size () > 0)
1067     {
1068 	priv->gScreen->setLighting (false);
1069 #ifndef USE_GLES
1070 	glPushMatrix ();
1071 
1072 	if (priv->optionGetSkydomeAnimated () &&
1073 	    priv->mGrabIndex == 0)
1074 	{
1075 	    glRotatef (vRotate / 5.0f + 90.0f, 1.0f, 0.0f, 0.0f);
1076 	    glRotatef (xRotate, 0.0f, 0.0f, -1.0f);
1077 	}
1078 	else
1079 	{
1080 	    glRotatef (90.0f, 1.0f, 0.0f, 0.0f);
1081 	}
1082 
1083 	glCallList (priv->mSkyListId);
1084 	glPopMatrix ();
1085 #endif
1086     }
1087     else
1088     {
1089 	priv->gScreen->clearTargetOutput (GL_COLOR_BUFFER_BIT);
1090     }
1091 }
1092 
1093 void 
1094 CubeScreen::cubePaintTop (const GLScreenPaintAttrib &sAttrib,
1095 			  const GLMatrix            &transform,
1096 			  CompOutput                *output,
1097 			  int                       size,
1098 			  const GLVector            &normal)
1099 {
1100     WRAPABLE_HND_FUNCTN (cubePaintTop, sAttrib, transform, output, size, normal)
1101 
1102     GLScreenPaintAttrib sa = sAttrib;
1103     GLMatrix            sTransform = transform;
1104 
1105     unsigned short*	color;
1106     int			opacity;
1107 
1108     priv->gScreen->setLighting (true);
1109 
1110     color = priv->optionGetTopColor ();
1111     opacity = priv->mDesktopOpacity * color[3] / 0xffff;
1112 
1113     GLVertexBuffer	  *streamingBuffer = GLVertexBuffer::streamingBuffer ();
1114     std::vector <GLushort> colorData;
1115 
1116     colorData.push_back (color[0] * opacity / 0xffff);
1117     colorData.push_back (color[1] * opacity / 0xffff);
1118     colorData.push_back (color[2] * opacity / 0xffff);
1119     colorData.push_back (opacity);
1120 
1121     sa.yRotate += (360.0f / size) * (priv->mXRotations + 1);
1122 
1123     priv->gScreen->glApplyTransform (sa, output, &sTransform);
1124 
1125     sTransform.translate (priv->mOutputXOffset, -priv->mOutputYOffset, 0.0f);
1126     sTransform.scale (priv->mOutputXScale, priv->mOutputYScale, 1.0f);
1127 
1128     if ((priv->mDesktopOpacity != OPAQUE) || (color[3] != OPAQUE))
1129     {
1130 #ifndef USE_GLES
1131 	priv->gScreen->setTexEnvMode (GL_MODULATE);
1132 #endif
1133 	glEnable (GL_BLEND);
1134 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1135     }
1136 
1137     bool withTexture = priv->mInvert == 1 && size == 4 && priv->mTexture.size ();
1138 
1139     if (withTexture)
1140 	priv->mTexture[0]->enable (GLTexture::Good);
1141 
1142     streamingBuffer->begin (GL_TRIANGLE_FAN);
1143     streamingBuffer->addColors (1, &(colorData[0]));
1144     streamingBuffer->addVertices (priv->mNVertices >> 1, priv->mVertices);
1145     streamingBuffer->addNormals (1, const_cast <GLfloat *> (&normal[0]));
1146 
1147     if (withTexture)
1148 	streamingBuffer->addTexCoords (0, 2, priv->mTc);
1149 
1150     streamingBuffer->end ();
1151     streamingBuffer->render (sTransform);
1152 
1153     if (withTexture)
1154 	priv->mTexture[0]->disable ();
1155 
1156     priv->gScreen->setTexEnvMode (GL_REPLACE);
1157     glDisable (GL_BLEND);
1158     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1159 }
1160 
1161 void 
1162 CubeScreen::cubePaintBottom (const GLScreenPaintAttrib &sAttrib,
1163 			     const GLMatrix            &transform,
1164 			     CompOutput                *output,
1165 			     int                       size,
1166 			     const GLVector            &normal)
1167 {
1168     WRAPABLE_HND_FUNCTN (cubePaintBottom, sAttrib, transform, output, size, normal)
1169 
1170     GLScreenPaintAttrib sa = sAttrib;
1171     GLMatrix            sTransform = transform;
1172 
1173     unsigned short*	color;
1174     int			opacity;
1175 
1176     priv->gScreen->setLighting (true);
1177 
1178     color   = priv->optionGetBottomColor ();
1179     opacity = priv->mDesktopOpacity * color[3] / 0xffff;
1180 
1181     GLVertexBuffer	  *streamingBuffer = GLVertexBuffer::streamingBuffer ();
1182     std::vector <GLushort> colorData;
1183 
1184     colorData.push_back (color[0] * opacity / 0xffff);
1185     colorData.push_back (color[1] * opacity / 0xffff);
1186     colorData.push_back (color[2] * opacity / 0xffff);
1187     colorData.push_back (opacity);
1188 
1189     sa.yRotate += (360.0f / size) * (priv->mXRotations + 1);
1190 
1191     priv->gScreen->glApplyTransform (sa, output, &sTransform);
1192 
1193     sTransform.translate (priv->mOutputXOffset, -priv->mOutputYOffset, 0.0f);
1194     sTransform.scale (priv->mOutputXScale, priv->mOutputYScale, 1.0f);
1195 
1196     if ((priv->mDesktopOpacity != OPAQUE) || (color[3] != OPAQUE))
1197     {
1198 #ifndef USE_GLES
1199 	priv->gScreen->setTexEnvMode (GL_MODULATE);
1200 #endif
1201 	glEnable (GL_BLEND);
1202 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1203     }
1204 
1205     streamingBuffer->begin (GL_TRIANGLE_FAN);
1206     streamingBuffer->addColors (1, &(colorData[0]));
1207     streamingBuffer->addVertices (priv->mNVertices, priv->mVertices);
1208     streamingBuffer->addNormals (1, const_cast <GLfloat *> (&normal[0]));
1209     streamingBuffer->setVertexOffset (priv->mNVertices >> 1);
1210     streamingBuffer->setMaxVertices (priv->mNVertices >> 1);
1211 
1212     streamingBuffer->end ();
1213     streamingBuffer->render (sTransform);
1214 
1215     priv->gScreen->setTexEnvMode (GL_REPLACE);
1216     glDisable (GL_BLEND);
1217     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1218 }
1219 
1220 void
1221 CubeScreen::cubePaintInside (const GLScreenPaintAttrib &sAttrib,
1222 			     const GLMatrix            &transform,
1223 			     CompOutput                *output,
1224 			     int                       size,
1225 			     const GLVector            &normal)
1226 {
1227     WRAPABLE_HND_FUNCTN (cubePaintInside, sAttrib, transform, output, size, normal)
1228 }
1229 
1230 void 
1231 PrivateCubeScreen::glEnableOutputClipping (const GLMatrix &transform, 
1232 					   const CompRegion &region,
1233 					   CompOutput *output)
1234 {
1235     if (mRotationState != CubeScreen::RotationNone)
1236     {
1237 	/* FIXME: No output clipping in OpenGL|ES yet */
1238 	#ifndef USE_GLES
1239 	glPushMatrix ();
1240 	glLoadMatrixf (transform.getMatrix ());
1241 	glTranslatef (mOutputXOffset, -mOutputYOffset, 0.0f);
1242 	glScalef (mOutputXScale, mOutputYScale, 1.0f);
1243 
1244 	if (mInvert == 1)
1245 	{
1246 	    GLdouble clipPlane0[] = {  1.0, 0.0, 0.5 / mDistance, 0.0 };
1247 	    GLdouble clipPlane1[] = {  -1.0,  0.0, 0.5 / mDistance, 0.0 };
1248 	    GLdouble clipPlane2[] = {  0.0,  -1.0, 0.5 / mDistance, 0.0 };
1249 	    GLdouble clipPlane3[] = { 0.0,  1.0, 0.5 / mDistance, 0.0 };
1250 	    glClipPlane (GL_CLIP_PLANE0, clipPlane0);
1251 	    glClipPlane (GL_CLIP_PLANE1, clipPlane1);
1252 	    glClipPlane (GL_CLIP_PLANE2, clipPlane2);
1253 	    glClipPlane (GL_CLIP_PLANE3, clipPlane3);
1254 	}
1255 	else
1256 	{
1257 	    GLdouble clipPlane0[] = {  -1.0, 0.0, -0.5 / mDistance, 0.0 };
1258 	    GLdouble clipPlane1[] = {  1.0,  0.0, -0.5 / mDistance, 0.0 };
1259 	    GLdouble clipPlane2[] = {  0.0,  1.0, -0.5 / mDistance, 0.0 };
1260 	    GLdouble clipPlane3[] = { 0.0,  -1.0, -0.5 / mDistance, 0.0 };
1261 	    glClipPlane (GL_CLIP_PLANE0, clipPlane0);
1262 	    glClipPlane (GL_CLIP_PLANE1, clipPlane1);
1263 	    glClipPlane (GL_CLIP_PLANE2, clipPlane2);
1264 	    glClipPlane (GL_CLIP_PLANE3, clipPlane3);
1265 	}
1266 
1267 	glEnable (GL_CLIP_PLANE0);
1268 	glEnable (GL_CLIP_PLANE1);
1269 	glEnable (GL_CLIP_PLANE2);
1270 	glEnable (GL_CLIP_PLANE3);
1271 
1272 	glPopMatrix ();
1273 	#endif
1274     }
1275     else
1276 	gScreen->glEnableOutputClipping (transform, region, output);
1277 }
1278 
1279 void 
1280 CubeScreen::cubePaintViewport (const GLScreenPaintAttrib &sAttrib,
1281 			       const GLMatrix            &transform,
1282 			       const CompRegion          &region,
1283 			       CompOutput                *output,
1284 			       unsigned int              mask)
1285 {
1286     WRAPABLE_HND_FUNCTN (cubePaintViewport, sAttrib, transform, region, output, mask)
1287 
1288     priv->gScreen->glPaintTransformedOutput (sAttrib, transform, region, 
1289 					     output, mask);
1290 }
1291 
1292 void 
1293 PrivateCubeScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &sAttrib,
1294 					     const GLMatrix            &transform, 
1295 					     const CompRegion          &region,
1296 					     CompOutput                *outputPtr, 
1297 					     unsigned int              mask)
1298 {
1299     GLScreenPaintAttrib sa = sAttrib;
1300     float               xRotate, vRotate, progress;
1301     int                 hsize;
1302     float               size;
1303     GLenum              filter = gScreen->textureFilter ();
1304     PaintOrder          paintOrder;
1305     bool                wasCulled = false;
1306     bool                paintCaps;
1307     int                 cullNorm, cullInv;
1308     int                 output = 0;
1309 
1310     output = ((unsigned int) outputPtr->id () != (unsigned int) ~0) ?
1311     							   outputPtr->id () : 0;
1312 
1313     mReversedWindowList = cScreen->getWindowPaintList ();
1314     mReversedWindowList.reverse ();
1315 
1316     if ((((unsigned int) outputPtr->id () != (unsigned int) ~0) && mRecalcOutput) ||
1317 	(((unsigned int) outputPtr->id () == (unsigned int) ~0) && !mRecalcOutput &&
1318 	 mNOutput > 1))
1319     {
1320 	mRecalcOutput = ((unsigned int) outputPtr->id () == (unsigned int) ~0);
1321 	mNOutput      = 1;
1322 	updateGeometry (screen->vpSize ().width (), mInvert);
1323     }
1324 
1325     hsize = screen->vpSize ().width () * mNOutput;
1326     size  = hsize;
1327 
1328     glGetIntegerv (GL_CULL_FACE_MODE, &cullNorm);
1329     cullInv   = (cullNorm == GL_BACK)? GL_FRONT : GL_BACK;
1330     wasCulled = glIsEnabled (GL_CULL_FACE);
1331 
1332     if (!mFullscreenOutput)
1333     {
1334 	mOutputXScale = (float) screen->width () / outputPtr->width ();
1335 	mOutputYScale = (float) screen->height () / outputPtr->height ();
1336 
1337 	mOutputXOffset =
1338 	    (screen->width () / 2.0f -
1339 	     (outputPtr->x1 () + outputPtr->x2 ()) / 2.0f) /
1340 	    (float) outputPtr->width ();
1341 
1342 	mOutputYOffset =
1343 	    (screen->height () / 2.0f -
1344 	     (outputPtr->y1 () +
1345 	      outputPtr->y2 ()) / 2.0f) /
1346 	    (float) outputPtr->height ();
1347     }
1348     else
1349     {
1350 	mOutputXScale  = 1.0f;
1351 	mOutputYScale  = 1.0f;
1352 	mOutputXOffset = 0.0f;
1353 	mOutputYOffset = 0.0f;
1354     }
1355 
1356     cubeScreen->cubeGetRotation (xRotate, vRotate, progress);
1357 
1358     sa.xRotate += xRotate;
1359     sa.vRotate += vRotate;
1360 
1361     if (!mCleared[output])
1362     {
1363 	float rRotate;
1364 
1365 	rRotate = xRotate - ((screen->vp ().x () *360.0f) / screen->vpSize ().width ());
1366 
1367 	cubeScreen->cubeClearTargetOutput (rRotate, vRotate);
1368 	mCleared[output] = true;
1369     }
1370 
1371     mask &= ~PAINT_SCREEN_CLEAR_MASK;
1372 
1373     if (mGrabIndex)
1374     {
1375 	sa.vRotate = 0.0f;
1376 
1377 	size += mUnfold * 8.0f;
1378 	size += powf (mUnfold, 6) * 64.0;
1379 	size += powf (mUnfold, 16) * 8192.0;
1380 
1381 	sa.zTranslate = -mInvert * (0.5f / tanf (M_PI / size));
1382 
1383 	/* distance we move the camera back when unfolding the cube.
1384 	   currently hardcoded to 1.5 but it should probably be optional. */
1385 	sa.zCamera -= mUnfold * 1.5f;
1386     }
1387     else
1388     {
1389 	if (vRotate > 100.0f)
1390 	    sa.vRotate = 100.0f;
1391 	else if (vRotate < -100.0f)
1392 	    sa.vRotate = -100.0f;
1393 	else
1394 	    sa.vRotate = vRotate;
1395 
1396 	sa.zTranslate = -mInvert * mDistance;
1397     }
1398 
1399     if (sa.xRotate > 0.0f)
1400 	mXRotations = (int) (hsize * sa.xRotate + 180.0f) / 360.0f;
1401     else
1402 	mXRotations = (int) (hsize * sa.xRotate - 180.0f) / 360.0f;
1403 
1404     sa.xRotate -= (360.0f * mXRotations) / hsize;
1405     sa.xRotate *= mInvert;
1406 
1407     sa.xRotate = sa.xRotate / size * hsize;
1408 
1409     if (mGrabIndex && optionGetMipmap ())
1410 	gScreen->setTextureFilter (GL_LINEAR_MIPMAP_LINEAR);
1411 
1412     if (mInvert == 1)
1413     {
1414 	/* Outside cube - start with FTB faces */
1415 	paintOrder = FTB;
1416 	glCullFace (cullInv);
1417     }
1418     else
1419     {
1420 	/* Inside cube - start with BTF faces */
1421 	paintOrder = BTF;
1422     }
1423 
1424     if (mInvert == -1 || cubeScreen->cubeShouldPaintAllViewports ())
1425 	paintAllViewports (sa, transform, region, outputPtr,
1426 			   mask, mXRotations, size, hsize, paintOrder);
1427 
1428     glCullFace (cullNorm);
1429 
1430     if (wasCulled && cubeScreen->cubeShouldPaintAllViewports ())
1431 	glDisable (GL_CULL_FACE);
1432 
1433     paintCaps = !mGrabIndex && (hsize > 2) && !mCapsPainted[output] &&
1434 	        (mInvert != 1 || mDesktopOpacity != OPAQUE ||
1435 		 cubeScreen->cubeShouldPaintAllViewports () || sa.vRotate != 0.0f ||
1436 		 sa.yTranslate != 0.0f);
1437 
1438     if (paintCaps)
1439     {
1440 	Bool topDir, bottomDir, allCaps;
1441 
1442 	std::vector<GLVector> top;
1443 	top.push_back (GLVector (0.5, 0.5,  0.0, 1.0));
1444 	top.push_back (GLVector (0.0, 0.5, -0.5, 1.0));
1445 	top.push_back (GLVector (0.0, 0.5,  0.0, 1.0));
1446 
1447 	std::vector<GLVector> bottom;
1448 	bottom.push_back (GLVector (0.5, -0.5,  0.0, 1.0));
1449 	bottom.push_back (GLVector (0.0, -0.5, -0.5, 1.0));
1450 	bottom.push_back (GLVector (0.0, -0.5,  0.0, 1.0));
1451 
1452 	topDir    = cubeScreen->cubeCheckOrientation (sa, transform, outputPtr, top);
1453 	bottomDir = cubeScreen->cubeCheckOrientation (sa, transform, outputPtr, bottom);
1454 
1455 	mCapsPainted[output] = TRUE;
1456 
1457 	allCaps = cubeScreen->cubeShouldPaintAllViewports () || mInvert != 1;
1458 
1459 	if (topDir && bottomDir)
1460 	{
1461 	    if (allCaps)
1462 	    {
1463 		cubeScreen->cubePaintBottom (sa, transform, outputPtr, hsize, GLVector (0.0f, -1.0f, 0.0f, 1.0f));
1464 		cubeScreen->cubePaintInside (sa, transform, outputPtr, hsize, GLVector (0.0f, 0.0f, -1.0f, 1.0f));
1465 	    }
1466 	    cubeScreen->cubePaintTop (sa, transform, outputPtr, hsize, GLVector (0.0f, -1.0f, 0.0f, 1.0f));
1467 	}
1468 	else if (!topDir && !bottomDir)
1469 	{
1470 	    if (allCaps)
1471 	    {
1472 		cubeScreen->cubePaintTop (sa, transform, outputPtr, hsize, GLVector (0.0f, 1.0f, 0.0f, 1.0f));
1473 		cubeScreen->cubePaintInside (sa, transform, outputPtr, hsize, GLVector (0.0f, 0.0f, -1.0f, 1.0f));
1474 	    }
1475 	    cubeScreen->cubePaintBottom (sa, transform, outputPtr, hsize, GLVector (0.0f, -1.0f, 0.0f, 1.0f));
1476 	}
1477 	else if (allCaps)
1478 	{
1479 	    cubeScreen->cubePaintTop (sa, transform, outputPtr, hsize, GLVector (0.0f, 1.0f, 0.0f, 1.0f));
1480 	    cubeScreen->cubePaintBottom (sa, transform, outputPtr, hsize, GLVector (0.0f, -1.0f, 0.0f, 1.0f));
1481 	    cubeScreen->cubePaintInside (sa, transform, outputPtr, hsize, GLVector (0.0f, 0.0f, -1.0f, 1.0f));
1482 	}
1483     }
1484 
1485     if (wasCulled)
1486 	glEnable (GL_CULL_FACE);
1487 
1488     if (mInvert == 1)
1489     {
1490 	/* Outside cube - continue with BTF faces */
1491 	paintOrder = BTF;
1492     }
1493     else
1494     {
1495 	/* Inside cube - continue with FTB faces */
1496 	paintOrder = FTB;
1497 	glCullFace (cullInv);
1498     }
1499 
1500     if (mInvert == 1 || cubeScreen->cubeShouldPaintAllViewports ())
1501 	paintAllViewports (sa, transform, region, outputPtr, mask, mXRotations,
1502 			   size, hsize, paintOrder);
1503 
1504     glCullFace (cullNorm);
1505 
1506     gScreen->setTextureFilter (filter);
1507 }
1508 
1509 bool 
1510 PrivateCubeWindow::glPaint (const GLWindowPaintAttrib &attrib, 
1511 			    const GLMatrix            &transform,
1512                             const CompRegion          &region, 
1513 			    unsigned int              mask)
1514 {
1515 
1516     if ((window->type () & CompWindowTypeDesktopMask) &&
1517 	(attrib.opacity != cubeScreen->priv->mDesktopOpacity))
1518     {
1519 	GLWindowPaintAttrib wAttrib = attrib;
1520 
1521 	wAttrib.opacity = cubeScreen->priv->mDesktopOpacity;
1522 
1523 	return gWindow->glPaint (wAttrib, transform, region, mask);
1524     }
1525     else
1526 	return gWindow->glPaint (attrib, transform, region, mask);
1527 
1528 }
1529 
1530 const CompWindowList &
1531 PrivateCubeScreen::getWindowPaintList ()
1532 {
1533     if (mPaintOrder == FTB)
1534 	return mReversedWindowList;
1535     else
1536         return cScreen->getWindowPaintList ();
1537 }
1538 
1539 void 
1540 PrivateCubeScreen::glApplyTransform (const GLScreenPaintAttrib &sAttrib,
1541 				     CompOutput                *output, 
1542 				     GLMatrix                  *transform)
1543 {
1544     transform->translate (mOutputXOffset, -mOutputYOffset, 0.0f);
1545     transform->scale (mOutputXScale, mOutputYScale, 1.0f);
1546 
1547     gScreen->glApplyTransform (sAttrib, output, transform);
1548 
1549     transform->scale (1.0f / mOutputXScale, 1.0 / mOutputYScale, 1.0f);
1550     transform->translate (-mOutputXOffset, mOutputYOffset, 0.0f);
1551 }
1552 
1553 bool
1554 PrivateCubeScreen::unfold (CompAction         *action,
1555 		           CompAction::State  state,
1556 			   CompOption::Vector &options)
1557 {
1558     Window     xid;
1559 
1560     xid = CompOption::getIntOptionNamed (options, "root");
1561 
1562     if (::screen->root () == xid)
1563     {
1564 	CUBE_SCREEN (screen);
1565 
1566 	if (screen->vpSize ().width () * cs->priv->mNOutput < 4)
1567 	    return false;
1568 
1569 	if (screen->otherGrabExist ("rotate", "switcher", "cube", NULL))
1570 	    return false;
1571 
1572 	if (!cs->priv->mGrabIndex)
1573 	    cs->priv->mGrabIndex = screen->pushGrab (screen->invisibleCursor (), "cube");
1574 
1575 	if (cs->priv->mGrabIndex)
1576 	{
1577 	    cs->priv->mUnfolded = true;
1578 	    cs->priv->cScreen->damageScreen ();
1579 	}
1580 
1581 	if (state & CompAction::StateInitButton)
1582 	    action->setState (action->state () | CompAction::StateTermButton);
1583 
1584 	if (state & CompAction::StateInitKey)
1585 	    action->setState (action->state () | CompAction::StateTermKey);
1586     }
1587 
1588     return false;
1589 }
1590 
1591 bool
1592 PrivateCubeScreen::fold (CompAction         *action,
1593 			 CompAction::State  state,
1594 			 CompOption::Vector &options)
1595 {
1596     Window     xid;
1597     xid = CompOption::getIntOptionNamed (options, "root");
1598 
1599     if (!xid || ::screen->root () == xid)
1600     {
1601 	CUBE_SCREEN (screen);
1602 	
1603 	if (cs->priv->mGrabIndex)
1604 	{
1605 	    cs->priv->mUnfolded = false;
1606 	    cs->priv->cScreen->damageScreen ();
1607 	}
1608     }
1609 
1610     action->setState (action->state () & ~(CompAction::StateTermButton | CompAction::StateTermKey));
1611 
1612     return false;
1613 }
1614 
1615 void
1616 PrivateCubeScreen::outputChangeNotify ()
1617 {
1618     updateOutputs ();
1619     updateGeometry (screen->vpSize ().width (), mInvert);
1620 
1621     screen->outputChangeNotify ();
1622 }
1623 
1624 bool 
1625 PrivateCubeScreen::setOptionForPlugin (const char *plugin,
1626 				       const char *name,
1627 				       CompOption::Value &v)
1628 {
1629     bool status;
1630 
1631     status = screen->setOptionForPlugin (plugin, name, v);
1632 
1633     if (status)
1634     {
1635 	if (strcmp (plugin, "core") == 0 && strcmp (name, "hsize") == 0)
1636 	    updateGeometry (screen->vpSize ().width (), mInvert);
1637     }
1638 
1639     return status;
1640 }
1641 
1642 PrivateCubeScreen::PrivateCubeScreen (CompScreen *s) :
1643     cScreen (CompositeScreen::get (s)),
1644     gScreen (GLScreen::get (s)),
1645     cubeScreen (CubeScreen::get (s))
1646 {
1647 
1648     mPw = 0;
1649     mPh = 0;
1650 
1651     mInvert = 1;
1652 
1653     for (int i = 0; i < 8; i++)
1654 	mTc[i] = 0.0f;
1655 
1656     mNVertices = 0;
1657     mVertices  = NULL;
1658 
1659     mGrabIndex = 0;
1660 
1661     mSrcOutput = 0;
1662 
1663     mSkyListId = 0;
1664 
1665     mImgCurFile = 0;
1666 
1667     mUnfolded = false;
1668     mUnfold   = 0.0f;
1669 
1670     mUnfoldVelocity = 0.0f;
1671 
1672     mPaintAllViewports = false;
1673     mFullscreenOutput  = true;
1674 
1675     mOutputXScale  = 1.0f;
1676     mOutputYScale  = 1.0f;
1677     mOutputXOffset = 0.0f;
1678     mOutputYOffset = 0.0f;
1679 
1680     mRotationState = CubeScreen::RotationNone;
1681 
1682     mDesktopOpacity = OPAQUE;
1683     mPaintOrder = BTF;
1684 
1685     mLastOpacityIndex = CubeOptions::InactiveOpacity;
1686 
1687 
1688     mRecalcOutput = false;
1689 
1690     memset (mCleared, 0, sizeof (mCleared));
1691 
1692     updateOutputs ();
1693 
1694     updateGeometry (screen->vpSize ().width (), mInvert);
1695 
1696     optionSetUnfoldKeyInitiate (PrivateCubeScreen::unfold);
1697     optionSetUnfoldKeyTerminate (PrivateCubeScreen::fold);
1698 
1699     ScreenInterface::setHandler (s);
1700     CompositeScreenInterface::setHandler (cScreen);
1701     GLScreenInterface::setHandler (gScreen);
1702 }
1703 
1704 PrivateCubeScreen::~PrivateCubeScreen ()
1705 {
1706     if (mVertices)
1707 	free (mVertices);
1708 
1709 #ifndef USE_GLES
1710     if (mSkyListId)
1711 	glDeleteLists (mSkyListId, 1);
1712 #endif
1713 }
1714 
1715 
1716 template class PluginClassHandler<PrivateCubeWindow, CompWindow, COMPIZ_CUBE_ABI>;
1717 
1718 PrivateCubeWindow::PrivateCubeWindow (CompWindow *w) :
1719     PluginClassHandler<PrivateCubeWindow, CompWindow, COMPIZ_CUBE_ABI> (w),
1720     window (w),
1721     cWindow (CompositeWindow::get (w)),
1722     gWindow (GLWindow::get (w)),
1723     cubeScreen (CubeScreen::get (screen))
1724 {
1725     GLWindowInterface::setHandler (gWindow, true);
1726 }
1727 
1728 PrivateCubeWindow::~PrivateCubeWindow ()
1729 {
1730 }
1731 
1732 template class PluginClassHandler<CubeScreen, CompScreen, COMPIZ_CUBE_ABI>;
1733 
1734 CubeScreen::CubeScreen (CompScreen *s) :
1735     PluginClassHandler<CubeScreen, CompScreen, COMPIZ_CUBE_ABI> (s),
1736     priv (new PrivateCubeScreen (s))
1737 {
1738 }
1739 
1740 CubeScreen::~CubeScreen ()
1741 {
1742     delete priv;
1743 }
1744 
1745 
1746 CompOption::Vector &
1747 CubeScreen::getOptions ()
1748 {
1749     return priv->getOptions ();
1750 }
1751 
1752 bool
1753 CubeScreen::setOption (const CompString  &name,
1754 		       CompOption::Value &value)
1755 {
1756     return priv->setOption (name, value);
1757 }
1758 
1759 bool
1760 CubePluginVTable::init ()
1761 {
1762     if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
1763         !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
1764         !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
1765 	return false;
1766 
1767     CompPrivate p;
1768     p.uval = COMPIZ_CUBE_ABI;
1769     screen->storeValue ("cube_ABI", p);
1770 
1771     return true;
1772 }
1773 
1774 void
1775 CubePluginVTable::fini ()
1776 {
1777     screen->eraseValue ("cube_ABI");
1778 }