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 <compiz-cube.h>
34 
35 static CompMetadata cubeMetadata;
36 
37 static int cubeCorePrivateIndex;
38 static int cubeDisplayPrivateIndex;
39 
40 #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
41 
42 static void
cubeLoadImg(CompScreen * s,int n)43 cubeLoadImg (CompScreen *s,
44 	     int	n)
45 {
46     unsigned int    width, height;
47     int		    pw, ph;
48     CompOptionValue *imgFiles;
49     int		    imgNFile;
50 
51     CUBE_SCREEN (s);
52 
53     imgFiles = cs->opt[CUBE_SCREEN_OPTION_IMAGES].value.list.value;
54     imgNFile = cs->opt[CUBE_SCREEN_OPTION_IMAGES].value.list.nValue;
55 
56     if (!cs->fullscreenOutput)
57     {
58 	pw = s->width;
59 	ph = s->height;
60     }
61     else
62     {
63 	pw = s->outputDev[0].width;
64 	ph = s->outputDev[0].height;
65     }
66 
67     if (!imgNFile || cs->pw != pw || cs->ph != ph)
68     {
69 	finiTexture (s, &cs->texture);
70 	initTexture (s, &cs->texture);
71 
72 	if (!imgNFile)
73 	    return;
74     }
75 
76     cs->imgCurFile = n % imgNFile;
77 
78     if (!readImageToTexture (s, &cs->texture,
79 			    imgFiles[cs->imgCurFile].s,
80 			    &width, &height))
81     {
82 	compLogMessage ("cube", CompLogLevelWarn,
83 			"Failed to load slide: %s",
84 			imgFiles[cs->imgCurFile].s);
85 
86 	finiTexture (s, &cs->texture);
87 	initTexture (s, &cs->texture);
88 
89 	return;
90     }
91 
92     cs->tc[0] = COMP_TEX_COORD_X (&cs->texture.matrix, width / 2.0f);
93     cs->tc[1] = COMP_TEX_COORD_Y (&cs->texture.matrix, height / 2.0f);
94 
95     if (cs->opt[CUBE_SCREEN_OPTION_SCALE_IMAGE].value.b)
96     {
97 	cs->tc[2] = COMP_TEX_COORD_X (&cs->texture.matrix, width);
98 	cs->tc[3] = COMP_TEX_COORD_Y (&cs->texture.matrix, 0.0f);
99 
100 	cs->tc[4] = COMP_TEX_COORD_X (&cs->texture.matrix, 0.0f);
101 	cs->tc[5] = COMP_TEX_COORD_Y (&cs->texture.matrix, 0.0f);
102 
103 	cs->tc[6] = COMP_TEX_COORD_X (&cs->texture.matrix, 0.0f);
104 	cs->tc[7] = COMP_TEX_COORD_Y (&cs->texture.matrix, height);
105 
106 	cs->tc[8] = COMP_TEX_COORD_X (&cs->texture.matrix, width);
107 	cs->tc[9] = COMP_TEX_COORD_Y (&cs->texture.matrix, height);
108 
109 	cs->tc[10] = COMP_TEX_COORD_X (&cs->texture.matrix, width);
110 	cs->tc[11] = COMP_TEX_COORD_Y (&cs->texture.matrix, 0.0f);
111     }
112     else
113     {
114 	float x1 = width  / 2.0f - pw / 2.0f;
115 	float y1 = height / 2.0f - ph / 2.0f;
116 	float x2 = width  / 2.0f + pw / 2.0f;
117 	float y2 = height / 2.0f + ph / 2.0f;
118 
119 	cs->tc[2] = COMP_TEX_COORD_X (&cs->texture.matrix, x2);
120 	cs->tc[3] = COMP_TEX_COORD_Y (&cs->texture.matrix, y1);
121 
122 	cs->tc[4] = COMP_TEX_COORD_X (&cs->texture.matrix, x1);
123 	cs->tc[5] = COMP_TEX_COORD_Y (&cs->texture.matrix, y1);
124 
125 	cs->tc[6] = COMP_TEX_COORD_X (&cs->texture.matrix, x1);
126 	cs->tc[7] = COMP_TEX_COORD_Y (&cs->texture.matrix, y2);
127 
128 	cs->tc[8] = COMP_TEX_COORD_X (&cs->texture.matrix, x2);
129 	cs->tc[9] = COMP_TEX_COORD_Y (&cs->texture.matrix, y2);
130 
131 	cs->tc[10] = COMP_TEX_COORD_X (&cs->texture.matrix, x2);
132 	cs->tc[11] = COMP_TEX_COORD_Y (&cs->texture.matrix, y1);
133     }
134 }
135 
136 static Bool
cubeUpdateGeometry(CompScreen * s,int sides,Bool invert)137 cubeUpdateGeometry (CompScreen *s,
138 		    int	       sides,
139 		    Bool       invert)
140 {
141     GLfloat radius, distance;
142     GLfloat *v;
143     int     i, n;
144 
145     CUBE_SCREEN (s);
146 
147     sides *= cs->nOutput;
148 
149     distance = 0.5f / tanf (M_PI / sides);
150     radius   = 0.5f / sinf (M_PI / sides);
151 
152     n = (sides + 2) * 2;
153 
154     if (cs->nVertices != n)
155     {
156 	v = realloc (cs->vertices, sizeof (GLfloat) * n * 3);
157 	if (!v)
158 	    return FALSE;
159 
160 	cs->nVertices = n;
161 	cs->vertices  = v;
162     }
163     else
164 	v = cs->vertices;
165 
166     *v++ = 0.0f;
167     *v++ = 0.5 * invert;
168     *v++ = 0.0f;
169 
170     for (i = 0; i <= sides; i++)
171     {
172 	*v++ = radius * sinf (i * 2 * M_PI / sides + M_PI / sides);
173 	*v++ = 0.5 * invert;
174 	*v++ = radius * cosf (i * 2 * M_PI / sides + M_PI / sides);
175     }
176 
177     *v++ = 0.0f;
178     *v++ = -0.5 * invert;
179     *v++ = 0.0f;
180 
181     for (i = sides; i >= 0; i--)
182     {
183 	*v++ = radius * sinf (i * 2 * M_PI / sides + M_PI / sides);
184 	*v++ = -0.5 * invert;
185 	*v++ = radius * cosf (i * 2 * M_PI / sides + M_PI / sides);
186     }
187 
188     cs->invert	 = invert;
189     cs->distance = distance;
190 
191     return TRUE;
192 }
193 
194 static void
cubeUpdateOutputs(CompScreen * s)195 cubeUpdateOutputs (CompScreen *s)
196 {
197     BoxPtr pBox0, pBox1;
198     int    i, j, k, x;
199 
200     CUBE_SCREEN (s);
201 
202     k = 0;
203 
204     cs->fullscreenOutput = TRUE;
205 
206     for (i = 0; i < s->nOutputDev; i++)
207     {
208 	cs->outputMask[i] = -1;
209 
210 	/* dimensions must match first output */
211 	if (s->outputDev[i].width  != s->outputDev[0].width ||
212 	    s->outputDev[i].height != s->outputDev[0].height)
213 	    continue;
214 
215 	pBox0 = &s->outputDev[0].region.extents;
216 	pBox1 = &s->outputDev[i].region.extents;
217 
218 	/* top and bottom line must match first output */
219 	if (pBox0->y1 != pBox1->y1 || pBox0->y2 != pBox1->y2)
220 	    continue;
221 
222 	k++;
223 
224 	for (j = 0; j < s->nOutputDev; j++)
225 	{
226 	    pBox0 = &s->outputDev[j].region.extents;
227 
228 	    /* must not intersect other output region */
229 	    if (i != j && pBox0->x2 > pBox1->x1 && pBox0->x1 < pBox1->x2)
230 	    {
231 		k--;
232 		break;
233 	    }
234 	}
235     }
236 
237     if (cs->moMode == CUBE_MOMODE_ONE)
238     {
239 	cs->fullscreenOutput = FALSE;
240 	cs->nOutput = 1;
241 	return;
242     }
243 
244     if (cs->moMode == CUBE_MOMODE_MULTI)
245     {
246 	cs->fullscreenOutput = TRUE;
247 	cs->nOutput = 1;
248 	return;
249     }
250 
251     if (k != s->nOutputDev)
252     {
253 	cs->fullscreenOutput = FALSE;
254 	cs->nOutput = 1;
255 	return;
256     }
257 
258     /* add output indices from left to right */
259     j = 0;
260     for (;;)
261     {
262 	x = MAXSHORT;
263 	k = -1;
264 
265 	for (i = 0; i < s->nOutputDev; i++)
266 	{
267 	    if (cs->outputMask[i] != -1)
268 		continue;
269 
270 	    if (s->outputDev[i].region.extents.x1 < x)
271 	    {
272 		x = s->outputDev[i].region.extents.x1;
273 		k = i;
274 	    }
275 	}
276 
277 	if (k < 0)
278 	    break;
279 
280 	cs->outputMask[k] = j;
281 	cs->output[j]     = k;
282 
283 	j++;
284     }
285 
286     cs->nOutput = j;
287 
288     if (cs->nOutput == 1)
289     {
290 	if (s->outputDev[0].width  != s->width ||
291 	    s->outputDev[0].height != s->height)
292 	    cs->fullscreenOutput = FALSE;
293     }
294 }
295 
296 static CompOption *
cubeGetScreenOptions(CompPlugin * plugin,CompScreen * screen,int * count)297 cubeGetScreenOptions (CompPlugin *plugin,
298 		      CompScreen *screen,
299 		      int	 *count)
300 {
301     CUBE_SCREEN (screen);
302 
303     *count = NUM_OPTIONS (cs);
304     return cs->opt;
305 }
306 
307 static void
cubeUpdateSkyDomeTexture(CompScreen * screen)308 cubeUpdateSkyDomeTexture (CompScreen *screen)
309 {
310     CUBE_SCREEN (screen);
311 
312     finiTexture (screen, &cs->sky);
313     initTexture (screen, &cs->sky);
314 
315     if (!cs->opt[CUBE_SCREEN_OPTION_SKYDOME].value.b)
316 	return;
317 
318     if (strlen (cs->opt[CUBE_SCREEN_OPTION_SKYDOME_IMG].value.s) == 0 ||
319 	!readImageToTexture (screen,
320 			     &cs->sky,
321 			     cs->opt[CUBE_SCREEN_OPTION_SKYDOME_IMG].value.s,
322 			     &cs->skyW,
323 			     &cs->skyH))
324     {
325 	GLfloat aaafTextureData[128][128][3];
326 	GLfloat fRStart = (GLfloat)
327 	    cs->opt[CUBE_SCREEN_OPTION_SKYDOME_GRAD_START].value.c[0] / 0xffff;
328 	GLfloat fGStart = (GLfloat)
329 	    cs->opt[CUBE_SCREEN_OPTION_SKYDOME_GRAD_START].value.c[1] / 0xffff;
330 	GLfloat fBStart = (GLfloat)
331 	    cs->opt[CUBE_SCREEN_OPTION_SKYDOME_GRAD_START].value.c[2] / 0xffff;
332 	GLfloat fREnd = (GLfloat)
333 	    cs->opt[CUBE_SCREEN_OPTION_SKYDOME_GRAD_END].value.c[0] / 0xffff;
334 	GLfloat fGEnd = (GLfloat)
335 	    cs->opt[CUBE_SCREEN_OPTION_SKYDOME_GRAD_END].value.c[1] / 0xffff;
336 	GLfloat fBEnd = (GLfloat)
337 	    cs->opt[CUBE_SCREEN_OPTION_SKYDOME_GRAD_END].value.c[2] / 0xffff;
338 	GLfloat fRStep = (fREnd - fRStart) / 128.0f;
339 	GLfloat fGStep = (fGEnd - fGStart) / 128.0f;
340 	GLfloat fBStep = (fBStart - fBEnd) / 128.0f;
341 	GLfloat fR = fRStart;
342 	GLfloat fG = fGStart;
343 	GLfloat fB = fBStart;
344 
345 	int	iX, iY;
346 
347 	for (iX = 127; iX >= 0; iX--)
348 	{
349 	    fR += fRStep;
350 	    fG += fGStep;
351 	    fB -= fBStep;
352 
353 	    for (iY = 0; iY < 128; iY++)
354 	    {
355 		aaafTextureData[iX][iY][0] = fR;
356 		aaafTextureData[iX][iY][1] = fG;
357 		aaafTextureData[iX][iY][2] = fB;
358 	    }
359 	}
360 
361 	cs->sky.target = GL_TEXTURE_2D;
362 	cs->sky.filter = GL_LINEAR;
363 	cs->sky.wrap   = GL_CLAMP_TO_EDGE;
364 
365 	cs->sky.matrix.xx = 1.0 / 128.0;
366 	cs->sky.matrix.yy = -1.0 / 128.0;
367 	cs->sky.matrix.xy = 0;
368 	cs->sky.matrix.yx = 0;
369 	cs->sky.matrix.x0 = 0;
370 	cs->sky.matrix.y0 = 1.0;
371 
372 	cs->skyW = 128;
373 	cs->skyH = 128;
374 
375 	glGenTextures (1, &cs->sky.name);
376 	glBindTexture (cs->sky.target, cs->sky.name);
377 
378 	glTexParameteri (cs->sky.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
379 	glTexParameteri (cs->sky.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
380 
381 	glTexParameteri (cs->sky.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
382 	glTexParameteri (cs->sky.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
383 
384 	glTexImage2D (cs->sky.target,
385 		      0,
386 		      GL_RGB,
387 		      128,
388 		      128,
389 		      0,
390 		      GL_RGB,
391 		      GL_FLOAT,
392 		      aaafTextureData);
393 
394 	glBindTexture (cs->sky.target, 0);
395     }
396 }
397 
398 static Bool
fillCircleTable(GLfloat ** ppSint,GLfloat ** ppCost,const int n)399 fillCircleTable (GLfloat   **ppSint,
400 		 GLfloat   **ppCost,
401 		 const int n)
402 {
403     const GLfloat angle = 2 * M_PI / (GLfloat) ((n == 0) ? 1 : n);
404     const int	  size = abs (n);
405     int		  i;
406 
407     *ppSint = (GLfloat *) calloc (sizeof (GLfloat), size + 1);
408     *ppCost = (GLfloat *) calloc (sizeof (GLfloat), size + 1);
409 
410     if (!(*ppSint) || !(*ppCost))
411     {
412 	free (*ppSint);
413 	free (*ppCost);
414 
415 	return FALSE;
416     }
417 
418     (*ppSint)[0] = 0.0;
419     (*ppCost)[0] = 1.0;
420 
421     for (i = 1; i < size; i++)
422     {
423 	(*ppSint)[i] = sin (angle * i);
424 	(*ppCost)[i] = cos (angle * i);
425     }
426 
427     (*ppSint)[size] = (*ppSint)[0];
428     (*ppCost)[size] = (*ppCost)[0];
429 
430     return TRUE;
431 }
432 
433 static void
cubeUpdateSkyDomeList(CompScreen * s,GLfloat fRadius)434 cubeUpdateSkyDomeList (CompScreen *s,
435 		       GLfloat	  fRadius)
436 {
437     GLint   iSlices = 128;
438     GLint   iStacks = 64;
439     GLfloat afTexCoordX[4];
440     GLfloat afTexCoordY[4];
441     GLfloat *sint1;
442     GLfloat *cost1;
443     GLfloat *sint2;
444     GLfloat *cost2;
445     GLfloat r;
446     GLfloat x;
447     GLfloat y;
448     GLfloat z;
449     int	    i;
450     int	    j;
451     int	    iStacksStart;
452     int	    iStacksEnd;
453     int	    iSlicesStart;
454     int	    iSlicesEnd;
455     GLfloat fStepX;
456     GLfloat fStepY;
457 
458     CUBE_SCREEN (s);
459 
460     if (cs->opt[CUBE_SCREEN_OPTION_SKYDOME_ANIM].value.b)
461     {
462 	iStacksStart = 11; /* min.   0 */
463 	iStacksEnd = 53;   /* max.  64 */
464 	iSlicesStart = 0;  /* min.   0 */
465 	iSlicesEnd = 128;  /* max. 128 */
466     }
467     else
468     {
469 	iStacksStart = 21; /* min.   0 */
470 	iStacksEnd = 43;   /* max.  64 */
471 	iSlicesStart = 21; /* min.   0 */
472 	iSlicesEnd = 44;   /* max. 128 */
473     }
474 
475     fStepX = 1.0 / (GLfloat) (iSlicesEnd - iSlicesStart);
476     fStepY = 1.0 / (GLfloat) (iStacksEnd - iStacksStart);
477 
478     if (!fillCircleTable (&sint1, &cost1, -iSlices))
479 	return;
480 
481     if (!fillCircleTable (&sint2, &cost2, iStacks * 2))
482     {
483 	free (sint1);
484 	free (cost1);
485 	return;
486     }
487 
488     afTexCoordX[0] = 1.0f;
489     afTexCoordY[0] = 1.0f - fStepY;
490     afTexCoordX[1] = 1.0f - fStepX;
491     afTexCoordY[1] = 1.0f - fStepY;
492     afTexCoordX[2] = 1.0f - fStepX;
493     afTexCoordY[2] = 1.0f;
494     afTexCoordX[3] = 1.0f;
495     afTexCoordY[3] = 1.0f;
496 
497     if (!cs->skyListId)
498 	cs->skyListId = glGenLists (1);
499 
500     glNewList (cs->skyListId, GL_COMPILE);
501 
502     enableTexture (s, &cs->sky, COMP_TEXTURE_FILTER_GOOD);
503 
504     glBegin (GL_QUADS);
505 
506     for (i = iStacksStart; i < iStacksEnd; i++)
507     {
508 	afTexCoordX[0] = 1.0f;
509 	afTexCoordX[1] = 1.0f - fStepX;
510 	afTexCoordX[2] = 1.0f - fStepX;
511 	afTexCoordX[3] = 1.0f;
512 
513 	for (j = iSlicesStart; j < iSlicesEnd; j++)
514 	{
515 	    /* bottom-right */
516 	    z = cost2[i];
517 	    r = sint2[i];
518 	    x = cost1[j];
519 	    y = sint1[j];
520 
521 	    glTexCoord2f (
522 		COMP_TEX_COORD_X (&cs->sky.matrix, afTexCoordX[3] * cs->skyW),
523 		COMP_TEX_COORD_Y (&cs->sky.matrix, afTexCoordY[3] * cs->skyH));
524 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
525 
526 	    /* top-right */
527 	    z = cost2[i + 1];
528 	    r = sint2[i + 1];
529 	    x = cost1[j];
530 	    y = sint1[j];
531 
532 	    glTexCoord2f (
533 		COMP_TEX_COORD_X (&cs->sky.matrix, afTexCoordX[0] * cs->skyW),
534 		COMP_TEX_COORD_Y (&cs->sky.matrix, afTexCoordY[0] * cs->skyH));
535 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
536 
537 	    /* top-left */
538 	    z = cost2[i + 1];
539 	    r = sint2[i + 1];
540 	    x = cost1[j + 1];
541 	    y = sint1[j + 1];
542 
543 	    glTexCoord2f (
544 		COMP_TEX_COORD_X (&cs->sky.matrix, afTexCoordX[1] * cs->skyW),
545 		COMP_TEX_COORD_Y (&cs->sky.matrix, afTexCoordY[1] * cs->skyH));
546 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
547 
548 	    /* bottom-left */
549 	    z = cost2[i];
550 	    r = sint2[i];
551 	    x = cost1[j + 1];
552 	    y = sint1[j + 1];
553 
554 	    glTexCoord2f (
555 		COMP_TEX_COORD_X (&cs->sky.matrix, afTexCoordX[2] * cs->skyW),
556 		COMP_TEX_COORD_Y (&cs->sky.matrix, afTexCoordY[2] * cs->skyH));
557 	    glVertex3f (x * r * fRadius, y * r * fRadius, z * fRadius);
558 
559 	    afTexCoordX[0] -= fStepX;
560 	    afTexCoordX[1] -= fStepX;
561 	    afTexCoordX[2] -= fStepX;
562 	    afTexCoordX[3] -= fStepX;
563 	}
564 
565 	afTexCoordY[0] -= fStepY;
566 	afTexCoordY[1] -= fStepY;
567 	afTexCoordY[2] -= fStepY;
568 	afTexCoordY[3] -= fStepY;
569     }
570 
571     glEnd ();
572 
573     disableTexture (s, &cs->sky);
574 
575     glEndList ();
576 
577     free (sint1);
578     free (cost1);
579     free (sint2);
580     free (cost2);
581 }
582 
583 static Bool
cubeSetScreenOption(CompPlugin * plugin,CompScreen * screen,const char * name,CompOptionValue * value)584 cubeSetScreenOption (CompPlugin      *plugin,
585 		     CompScreen      *screen,
586 		     const char	     *name,
587 		     CompOptionValue *value)
588 {
589     CompOption *o;
590     int	       index;
591 
592     CUBE_SCREEN (screen);
593 
594     o = compFindOption (cs->opt, NUM_OPTIONS (cs), name, &index);
595     if (!o)
596 	return FALSE;
597 
598     switch (index) {
599     case CUBE_SCREEN_OPTION_COLOR:
600 	if (compSetColorOption (o, value))
601 	{
602 	    memcpy (cs->color, o->value.c, sizeof (cs->color));
603 	    damageScreen (screen);
604 	    return TRUE;
605 	}
606 	break;
607     case CUBE_SCREEN_OPTION_IN:
608 	if (compSetBoolOption (o, value))
609 	{
610 	    if (cubeUpdateGeometry (screen, screen->hsize, o->value.b ? -1 : 1))
611 		return TRUE;
612 	}
613 	break;
614     case CUBE_SCREEN_OPTION_SCALE_IMAGE:
615 	if (compSetBoolOption (o, value))
616 	{
617 	    cubeLoadImg (screen, cs->imgCurFile);
618 	    damageScreen (screen);
619 
620 	    return TRUE;
621 	}
622 	break;
623     case CUBE_SCREEN_OPTION_IMAGES:
624 	if (compSetOptionList (o, value))
625 	{
626 	    cubeLoadImg (screen, cs->imgCurFile);
627 	    damageScreen (screen);
628 
629 	    return TRUE;
630 	}
631 	break;
632     case CUBE_SCREEN_OPTION_SKYDOME:
633 	if (compSetBoolOption (o, value))
634 	{
635 	    cubeUpdateSkyDomeTexture (screen);
636 	    cubeUpdateSkyDomeList (screen, 1.0f);
637 	    damageScreen (screen);
638 	    return TRUE;
639 	}
640 	break;
641     case CUBE_SCREEN_OPTION_SKYDOME_IMG:
642 	if (compSetStringOption (o, value))
643 	{
644 	    cubeUpdateSkyDomeTexture (screen);
645 	    cubeUpdateSkyDomeList (screen, 1.0f);
646 	    damageScreen (screen);
647 	    return TRUE;
648 	}
649 	break;
650     case CUBE_SCREEN_OPTION_SKYDOME_ANIM:
651 	if (compSetBoolOption (o, value))
652 	{
653 	    cubeUpdateSkyDomeTexture (screen);
654 	    cubeUpdateSkyDomeList (screen, 1.0f);
655 	    damageScreen (screen);
656 	    return TRUE;
657 	}
658 	break;
659     case CUBE_SCREEN_OPTION_SKYDOME_GRAD_START:
660 	if (compSetColorOption (o, value))
661 	{
662 	    cubeUpdateSkyDomeTexture (screen);
663 	    cubeUpdateSkyDomeList (screen, 1.0f);
664 	    damageScreen (screen);
665 	    return TRUE;
666 	}
667 	break;
668     case CUBE_SCREEN_OPTION_SKYDOME_GRAD_END:
669 	if (compSetColorOption (o, value))
670 	{
671 	    cubeUpdateSkyDomeTexture (screen);
672 	    cubeUpdateSkyDomeList (screen, 1.0f);
673 	    damageScreen (screen);
674 	    return TRUE;
675 	}
676 	break;
677     case CUBE_SCREEN_OPTION_MULTIOUTPUT_MODE:
678 	if (compSetIntOption (o, value))
679 	{
680 	    cs->moMode = o->value.i;
681 	    cubeUpdateOutputs (screen);
682 	    cubeUpdateGeometry (screen, screen->hsize, cs->invert);
683 	    damageScreen (screen);
684 	    return TRUE;
685 	}
686 	break;
687     default:
688 	return compSetScreenOption (screen, o, value);
689     }
690 
691     return FALSE;
692 }
693 
694 static int
adjustVelocity(CubeScreen * cs)695 adjustVelocity (CubeScreen *cs)
696 {
697     float unfold, adjust, amount;
698 
699     if (cs->unfolded)
700 	unfold = 1.0f - cs->unfold;
701     else
702 	unfold = 0.0f - cs->unfold;
703 
704     adjust = unfold * 0.02f * cs->opt[CUBE_SCREEN_OPTION_ACCELERATION].value.f;
705     amount = fabs (unfold);
706     if (amount < 1.0f)
707 	amount = 1.0f;
708     else if (amount > 3.0f)
709 	amount = 3.0f;
710 
711     cs->unfoldVelocity = (amount * cs->unfoldVelocity + adjust) /
712 	(amount + 2.0f);
713 
714     return (fabs (unfold) < 0.002f && fabs (cs->unfoldVelocity) < 0.01f);
715 }
716 
717 static void
cubePreparePaintScreen(CompScreen * s,int msSinceLastPaint)718 cubePreparePaintScreen (CompScreen *s,
719 			int	   msSinceLastPaint)
720 {
721     int   opt;
722     float x, progress;
723 
724     CUBE_SCREEN (s);
725 
726     if (cs->grabIndex)
727     {
728 	int   steps;
729 	float amount, chunk;
730 
731 	amount = msSinceLastPaint * 0.2f *
732 	    cs->opt[CUBE_SCREEN_OPTION_SPEED].value.f;
733 	steps  = amount / (0.5f * cs->opt[CUBE_SCREEN_OPTION_TIMESTEP].value.f);
734 	if (!steps) steps = 1;
735 	chunk  = amount / (float) steps;
736 
737 	while (steps--)
738 	{
739 	    cs->unfold += cs->unfoldVelocity * chunk;
740 	    if (cs->unfold > 1.0f)
741 		cs->unfold = 1.0f;
742 
743 	    if (adjustVelocity (cs))
744 	    {
745 		if (cs->unfold < 0.5f)
746 		{
747 		    if (cs->grabIndex)
748 		    {
749 			removeScreenGrab (s, cs->grabIndex, NULL);
750 			cs->grabIndex = 0;
751 		    }
752 
753 		    cs->unfold = 0.0f;
754 		}
755 		break;
756 	    }
757 	}
758     }
759 
760     memset (cs->cleared, 0, sizeof (Bool) * s->nOutputDev);
761     memset (cs->capsPainted, 0, sizeof (Bool) * s->nOutputDev);
762 
763     /* Transparency handling */
764     if (cs->rotationState == RotationManual ||
765 	(cs->rotationState == RotationChange &&
766 	 !cs->opt[CUBE_SCREEN_OPTION_TRANSPARENT_MANUAL_ONLY].value.b))
767     {
768 	opt = cs->lastOpacityIndex = CUBE_SCREEN_OPTION_ACTIVE_OPACITY;
769     }
770     else if (cs->rotationState == RotationChange)
771     {
772 	opt = cs->lastOpacityIndex = CUBE_SCREEN_OPTION_INACTIVE_OPACITY;
773     }
774     else
775     {
776 	opt = CUBE_SCREEN_OPTION_INACTIVE_OPACITY;
777     }
778 
779     cs->toOpacity = (cs->opt[opt].value.f / 100.0f) * OPAQUE;
780 
781     (*cs->getRotation) (s, &x, &x, &progress);
782 
783     if (cs->desktopOpacity != cs->toOpacity ||
784 	(progress > 0.0 && progress < 1.0))
785     {
786 	cs->desktopOpacity =
787 	    (cs->opt[CUBE_SCREEN_OPTION_INACTIVE_OPACITY].value.f -
788 	    ((cs->opt[CUBE_SCREEN_OPTION_INACTIVE_OPACITY].value.f -
789 	    cs->opt[cs->lastOpacityIndex].value.f) * progress))
790 	    / 100.0f * OPAQUE;
791 
792     }
793 
794     cs->paintAllViewports = (cs->desktopOpacity != OPAQUE);
795 
796     UNWRAP (cs, s, preparePaintScreen);
797     (*s->preparePaintScreen) (s, msSinceLastPaint);
798     WRAP (cs, s, preparePaintScreen, cubePreparePaintScreen);
799 }
800 
801 static void
cubePaintScreen(CompScreen * s,CompOutput * outputs,int numOutputs,unsigned int mask)802 cubePaintScreen (CompScreen   *s,
803 		 CompOutput   *outputs,
804 		 int          numOutputs,
805 		 unsigned int mask)
806 {
807     float x, progress;
808 
809     CUBE_SCREEN (s);
810 
811     (*cs->getRotation) (s, &x, &x, &progress);
812 
813     UNWRAP (cs, s, paintScreen);
814     if (cs->moMode == CUBE_MOMODE_ONE && s->nOutputDev &&
815         (progress > 0.0f || cs->desktopOpacity != OPAQUE))
816 	(*s->paintScreen) (s, &s->fullscreenOutput, 1, mask);
817     else
818 	(*s->paintScreen) (s, outputs, numOutputs, mask);
819     WRAP (cs, s, paintScreen, cubePaintScreen);
820 }
821 
822 static Bool
cubePaintOutput(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)823 cubePaintOutput (CompScreen		 *s,
824 		 const ScreenPaintAttrib *sAttrib,
825 		 const CompTransform	*transform,
826 		 Region			 region,
827 		 CompOutput		 *output,
828 		 unsigned int		 mask)
829 {
830     Bool status;
831 
832     CUBE_SCREEN (s);
833 
834     if (cs->grabIndex || cs->desktopOpacity != OPAQUE)
835     {
836 	mask &= ~PAINT_SCREEN_REGION_MASK;
837 	mask |= PAINT_SCREEN_TRANSFORMED_MASK;
838     }
839 
840     cs->srcOutput = (output->id != ~0) ? output->id : 0;
841     /* Always use BTF painting on non-transformed screen */
842     cs->paintOrder = BTF;
843 
844     UNWRAP (cs, s, paintOutput);
845     status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
846     WRAP (cs, s, paintOutput, cubePaintOutput);
847 
848     return status;
849 }
850 
851 static void
cubeDonePaintScreen(CompScreen * s)852 cubeDonePaintScreen (CompScreen *s)
853 {
854     CUBE_SCREEN (s);
855 
856     if (cs->grabIndex || cs->desktopOpacity != cs->toOpacity)
857 	damageScreen (s);
858 
859     UNWRAP (cs, s, donePaintScreen);
860     (*s->donePaintScreen) (s);
861     WRAP (cs, s, donePaintScreen, cubeDonePaintScreen);
862 }
863 
864 static Bool
cubeCheckOrientation(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,CompOutput * outputPtr,CompVector * points)865 cubeCheckOrientation (CompScreen              *s,
866 		      const ScreenPaintAttrib *sAttrib,
867 		      const CompTransform     *transform,
868 		      CompOutput              *outputPtr,
869 		      CompVector              *points)
870 {
871     CompTransform sTransform = *transform;
872     CompTransform mvp, pm;
873     CompVector    pntA, pntB, pntC;
874     CompVector    vecA, vecB, ortho;
875     Bool          rv = FALSE;
876 
877     CUBE_SCREEN (s);
878 
879     (*s->applyScreenTransform) (s, sAttrib, outputPtr, &sTransform);
880     matrixTranslate (&sTransform, cs->outputXOffset, -cs->outputYOffset, 0.0f);
881     matrixScale (&sTransform, cs->outputXScale, cs->outputYScale, 1.0f);
882 
883     memcpy (pm.m, s->projection, sizeof (pm.m));
884     matrixMultiply (&mvp, &pm, &sTransform);
885 
886     matrixMultiplyVector (&pntA, &points[0], &mvp);
887 
888     if (pntA.w < 0.0f)
889 	rv = !rv;
890 
891     matrixVectorDiv (&pntA);
892 
893     matrixMultiplyVector (&pntB, &points[1], &mvp);
894 
895     if (pntB.w < 0.0f)
896 	rv = !rv;
897 
898     matrixVectorDiv (&pntB);
899     matrixMultiplyVector (&pntC, &points[2], &mvp);
900     matrixVectorDiv (&pntC);
901 
902     vecA.x = pntC.x - pntA.x;
903     vecA.y = pntC.y - pntA.y;
904     vecA.z = pntC.z - pntA.z;
905 
906     vecB.x = pntC.x - pntB.x;
907     vecB.y = pntC.y - pntB.y;
908     vecB.z = pntC.z - pntB.z;
909 
910     ortho.x = vecA.y * vecB.z - vecA.z * vecB.y;
911     ortho.y = vecA.z * vecB.x - vecA.x * vecB.z;
912     ortho.z = vecA.x * vecB.y - vecA.y * vecB.x;
913 
914     if (ortho.z > 0.0f)
915 	rv = !rv;
916 
917     return rv;
918 }
919 
920 static Bool
cubeShouldPaintViewport(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,CompOutput * outputPtr,PaintOrder order)921 cubeShouldPaintViewport (CompScreen              *s,
922 			 const ScreenPaintAttrib *sAttrib,
923 			 const CompTransform     *transform,
924 			 CompOutput              *outputPtr,
925 			 PaintOrder              order)
926 {
927     Bool  ftb;
928     float pointZ;
929 
930     CUBE_SCREEN (s);
931 
932     pointZ = cs->invert * cs->distance;
933     CompVector vPoints[3] = { {.v = { -0.5, 0.0, pointZ, 1.0 } },
934 			      {.v = {  0.0, 0.5, pointZ, 1.0 } },
935 			      {.v = {  0.0, 0.0, pointZ, 1.0 } } };
936 
937     ftb = (*cs->checkOrientation) (s, sAttrib, transform, outputPtr, vPoints);
938 
939     return (order == FTB && ftb) || (order == BTF && !ftb);
940 }
941 
942 static void
cubeMoveViewportAndPaint(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,CompOutput * outputPtr,unsigned int mask,PaintOrder paintOrder,int dx)943 cubeMoveViewportAndPaint (CompScreen		  *s,
944 			  const ScreenPaintAttrib *sAttrib,
945 			  const CompTransform	  *transform,
946 			  CompOutput		  *outputPtr,
947 			  unsigned int		  mask,
948 			  PaintOrder              paintOrder,
949 			  int			  dx)
950 {
951     int   output;
952 
953     CUBE_SCREEN (s);
954 
955     if (!(*cs->shouldPaintViewport) (s,
956 				     sAttrib,
957 				     transform,
958 				     outputPtr,
959 				     paintOrder))
960 	return;
961 
962     output = (outputPtr->id != ~0) ? outputPtr->id : 0;
963 
964     cs->paintOrder = paintOrder;
965 
966     if (cs->nOutput > 1)
967     {
968 	int cubeOutput, dView;
969 
970 	/* translate to cube output */
971 	cubeOutput = cs->outputMask[output];
972 
973 	/* convert from window movement to viewport movement */
974 	dView = -dx;
975 
976 	cubeOutput += dView;
977 
978 	dView      = cubeOutput / cs->nOutput;
979 	cubeOutput = cubeOutput % cs->nOutput;
980 
981 	if (cubeOutput < 0)
982 	{
983 	    cubeOutput += cs->nOutput;
984 	    dView--;
985 	}
986 
987 	/* translate back to compiz output */
988 	output = cs->srcOutput = cs->output[cubeOutput];
989 
990 	setWindowPaintOffset (s, -dView * s->width, 0);
991 	(*cs->paintViewport) (s, sAttrib, transform,
992 			      &s->outputDev[output].region,
993 			      &s->outputDev[output], mask);
994 	setWindowPaintOffset (s, 0, 0);
995     }
996     else
997     {
998 	Region region;
999 
1000 	setWindowPaintOffset (s, dx * s->width, 0);
1001 
1002 	if (cs->moMode == CUBE_MOMODE_MULTI)
1003 	    region = &outputPtr->region;
1004 	else
1005 	    region = &s->region;
1006 
1007 	(*cs->paintViewport) (s, sAttrib, transform, region, outputPtr, mask);
1008 
1009 	setWindowPaintOffset (s, 0, 0);
1010     }
1011 }
1012 
1013 static void
cubePaintAllViewports(CompScreen * s,ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * outputPtr,unsigned int mask,int xMove,float size,int hsize,PaintOrder paintOrder)1014 cubePaintAllViewports (CompScreen          *s,
1015 		       ScreenPaintAttrib   *sAttrib,
1016 		       const CompTransform *transform,
1017 		       Region              region,
1018 		       CompOutput          *outputPtr,
1019 		       unsigned int        mask,
1020 		       int                 xMove,
1021 		       float               size,
1022 		       int                 hsize,
1023 		       PaintOrder          paintOrder)
1024 {
1025     ScreenPaintAttrib sa = *sAttrib;
1026 
1027     int i;
1028     int xMoveAdd;
1029     int origXMoveAdd = 0; /* dx for the viewport we start
1030 			     painting with (back-most). */
1031     int iFirstSign;       /* 1 if we do xMove += i first and
1032 			     -1 if we do xMove -= i first. */
1033 
1034     CUBE_SCREEN (s);
1035 
1036     if (cs->invert == 1)
1037     {
1038 	/* xMove ==> dx for the viewport which is the
1039 	   nearest to the viewer in z axis.
1040 	   xMove +/- hsize / 2 ==> dx for the viewport
1041 	   which is the farthest to the viewer in z axis. */
1042 
1043 	if ((sa.xRotate < 0.0f && hsize % 2 == 1) ||
1044 	    (sa.xRotate > 0.0f && hsize % 2 == 0))
1045 	{
1046 	    origXMoveAdd = hsize / 2;
1047 	    iFirstSign = 1;
1048 	}
1049 	else
1050 	{
1051 	    origXMoveAdd = -hsize / 2;
1052 	    iFirstSign = -1;
1053 	}
1054     }
1055     else
1056     {
1057 	/* xMove is already the dx for farthest viewport. */
1058 	if (sa.xRotate > 0.0f)
1059 	    iFirstSign = -1;
1060 	else
1061 	    iFirstSign = 1;
1062     }
1063 
1064     for (i = 0; i <= hsize / 2; i++)
1065     {
1066 	/* move to the correct viewport (back to front). */
1067 	xMoveAdd = origXMoveAdd;	/* move to farthest viewport. */
1068 	xMoveAdd += iFirstSign * i;	/* move i more viewports to
1069 					   the right / left. */
1070 
1071 	/* Needed especially for unfold.
1072 	   We paint the viewports around xMove viewport.
1073 	   Adding or subtracting hsize from xMove has no effect on
1074 	   what viewport we paint, but can make shorter paths. */
1075 	if (xMoveAdd < -hsize / 2)
1076 	    xMoveAdd += hsize;
1077 	else if (xMoveAdd > hsize / 2)
1078 	    xMoveAdd -= hsize;
1079 
1080 	/* Paint the viewport. */
1081 	xMove += xMoveAdd;
1082 
1083 	sa.yRotate -= cs->invert * xMoveAdd * 360.0f / size;
1084 	cubeMoveViewportAndPaint (s, &sa, transform, outputPtr, mask,
1085 				  paintOrder, xMove);
1086 	sa.yRotate += cs->invert * xMoveAdd * 360.0f / size;
1087 
1088 	xMove -= xMoveAdd;
1089 
1090 	/* do the same for an equally far viewport. */
1091 	if (i == 0 || i * 2 == hsize)
1092 	    continue;
1093 
1094 	xMoveAdd = origXMoveAdd;	/* move to farthest viewport. */
1095 	xMoveAdd -= iFirstSign * i;	/* move i more viewports to the
1096 					   left / right (opposite side
1097 					   from the one chosen first) */
1098 
1099 	if (xMoveAdd < -hsize / 2)
1100 	    xMoveAdd += hsize;
1101 	else if (xMoveAdd > hsize / 2)
1102 	    xMoveAdd -= hsize;
1103 
1104 	xMove += xMoveAdd;
1105 
1106 	sa.yRotate -= cs->invert * xMoveAdd * 360.0f / size;
1107 	cubeMoveViewportAndPaint (s, &sa, transform, outputPtr, mask,
1108 				  paintOrder, xMove);
1109 	sa.yRotate += cs->invert * xMoveAdd * 360.0f / size;
1110 
1111 	xMove -= xMoveAdd;
1112     }
1113 }
1114 
1115 static void
cubeGetRotation(CompScreen * s,float * x,float * v,float * progress)1116 cubeGetRotation (CompScreen *s,
1117 		 float	    *x,
1118 		 float	    *v,
1119 		 float      *progress)
1120 {
1121     *x        = 0.0f;
1122     *v        = 0.0f;
1123     *progress = 0.0f;
1124 }
1125 
1126 static void
cubeClearTargetOutput(CompScreen * s,float xRotate,float vRotate)1127 cubeClearTargetOutput (CompScreen *s,
1128 		       float	  xRotate,
1129 		       float	  vRotate)
1130 {
1131     CUBE_SCREEN (s);
1132 
1133     if (cs->sky.name)
1134     {
1135 	screenLighting (s, FALSE);
1136 
1137 	glPushMatrix ();
1138 
1139 	if (cs->opt[CUBE_SCREEN_OPTION_SKYDOME_ANIM].value.b &&
1140 	    cs->grabIndex == 0)
1141 	{
1142 	    glRotatef (vRotate / 5.0f + 90.0f, 1.0f, 0.0f, 0.0f);
1143 	    glRotatef (xRotate, 0.0f, 0.0f, -1.0f);
1144 	}
1145 	else
1146 	{
1147 	    glRotatef (90.0f, 1.0f, 0.0f, 0.0f);
1148 	}
1149 
1150 	glCallList (cs->skyListId);
1151 	glPopMatrix ();
1152     }
1153     else
1154     {
1155 	clearTargetOutput (s->display, GL_COLOR_BUFFER_BIT);
1156     }
1157 }
1158 
1159 static void
cubePaintTop(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,CompOutput * output,int size)1160 cubePaintTop (CompScreen	      *s,
1161 	      const ScreenPaintAttrib *sAttrib,
1162 	      const CompTransform     *transform,
1163 	      CompOutput	      *output,
1164 	      int		      size)
1165 {
1166     ScreenPaintAttrib sa = *sAttrib;
1167     CompTransform     sTransform = *transform;
1168 
1169     CUBE_SCREEN (s);
1170 
1171     screenLighting (s, TRUE);
1172 
1173     glColor4us (cs->color[0], cs->color[1], cs->color[2], cs->desktopOpacity);
1174 
1175     glPushMatrix ();
1176 
1177     sa.yRotate += (360.0f / size) * (cs->xRotations + 1);
1178     if (!cs->opt[CUBE_SCREEN_OPTION_ADJUST_IMAGE].value.b)
1179 	sa.yRotate -= (360.0f / size) * s->x;
1180 
1181     (*s->applyScreenTransform) (s, &sa, output, &sTransform);
1182 
1183     glLoadMatrixf (sTransform.m);
1184     glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f);
1185     glScalef (cs->outputXScale, cs->outputYScale, 1.0f);
1186 
1187     if (cs->desktopOpacity != OPAQUE)
1188     {
1189 	screenTexEnvMode (s, GL_MODULATE);
1190 	glEnable (GL_BLEND);
1191 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1192     }
1193 
1194     glVertexPointer (3, GL_FLOAT, 0, cs->vertices);
1195 
1196     if (cs->invert == 1 && size == 4 && cs->texture.name)
1197     {
1198 	enableTexture (s, &cs->texture, COMP_TEXTURE_FILTER_GOOD);
1199 	glTexCoordPointer (2, GL_FLOAT, 0, cs->tc);
1200 	glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nVertices >> 1);
1201 	disableTexture (s, &cs->texture);
1202 	glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1203     }
1204     else
1205     {
1206 	glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1207 	glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nVertices >> 1);
1208     }
1209 
1210     glPopMatrix ();
1211 
1212     glColor4usv (defaultColor);
1213     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1214 
1215     screenTexEnvMode (s, GL_REPLACE);
1216     glDisable (GL_BLEND);
1217     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1218 }
1219 
1220 static void
cubePaintBottom(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,CompOutput * output,int size)1221 cubePaintBottom (CompScreen		 *s,
1222 		 const ScreenPaintAttrib *sAttrib,
1223 		 const CompTransform	 *transform,
1224 		 CompOutput		 *output,
1225 		 int			 size)
1226 {
1227     ScreenPaintAttrib sa = *sAttrib;
1228     CompTransform     sTransform = *transform;
1229 
1230     CUBE_SCREEN (s);
1231 
1232     screenLighting (s, TRUE);
1233 
1234     glColor4us (cs->color[0], cs->color[1], cs->color[2], cs->desktopOpacity);
1235 
1236     glPushMatrix ();
1237 
1238     sa.yRotate += (360.0f / size) * (cs->xRotations + 1);
1239     if (!cs->opt[CUBE_SCREEN_OPTION_ADJUST_IMAGE].value.b)
1240 	sa.yRotate -= (360.0f / size) * s->x;
1241 
1242     (*s->applyScreenTransform) (s, &sa, output, &sTransform);
1243 
1244     glLoadMatrixf (sTransform.m);
1245     glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f);
1246     glScalef (cs->outputXScale, cs->outputYScale, 1.0f);
1247 
1248     if (cs->desktopOpacity != OPAQUE)
1249     {
1250 	screenTexEnvMode (s, GL_MODULATE);
1251 	glEnable (GL_BLEND);
1252 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1253     }
1254 
1255     glVertexPointer (3, GL_FLOAT, 0, cs->vertices);
1256 
1257     glDrawArrays (GL_TRIANGLE_FAN, cs->nVertices >> 1,
1258 		  cs->nVertices >> 1);
1259 
1260     glPopMatrix ();
1261 
1262     glColor4usv (defaultColor);
1263     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1264 
1265     screenTexEnvMode (s, GL_REPLACE);
1266     glDisable (GL_BLEND);
1267     glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1268 }
1269 
1270 static void
cubePaintInside(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,CompOutput * output,int size)1271 cubePaintInside (CompScreen		 *s,
1272 		 const ScreenPaintAttrib *sAttrib,
1273 		 const CompTransform	 *transform,
1274 		 CompOutput		 *output,
1275 		 int			 size)
1276 {
1277 }
1278 
1279 static void
cubeEnableOutputClipping(CompScreen * s,const CompTransform * transform,Region region,CompOutput * output)1280 cubeEnableOutputClipping (CompScreen	      *s,
1281 			  const CompTransform *transform,
1282 			  Region	      region,
1283 			  CompOutput	      *output)
1284 {
1285     CUBE_SCREEN (s);
1286 
1287     if (cs->rotationState != RotationNone)
1288     {
1289 	glPushMatrix ();
1290 	glLoadMatrixf (transform->m);
1291 	glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f);
1292 	glScalef (cs->outputXScale, cs->outputYScale, 1.0f);
1293 
1294 	if (cs->invert == 1)
1295 	{
1296 	    GLdouble clipPlane0[] = {  1.0, 0.0, 0.5 / cs->distance, 0.0 };
1297 	    GLdouble clipPlane1[] = {  -1.0,  0.0, 0.5 / cs->distance, 0.0 };
1298 	    GLdouble clipPlane2[] = {  0.0,  -1.0, 0.5 / cs->distance, 0.0 };
1299 	    GLdouble clipPlane3[] = { 0.0,  1.0, 0.5 / cs->distance, 0.0 };
1300 	    glClipPlane (GL_CLIP_PLANE0, clipPlane0);
1301 	    glClipPlane (GL_CLIP_PLANE1, clipPlane1);
1302 	    glClipPlane (GL_CLIP_PLANE2, clipPlane2);
1303 	    glClipPlane (GL_CLIP_PLANE3, clipPlane3);
1304 	}
1305 	else
1306 	{
1307 	    GLdouble clipPlane0[] = {  -1.0, 0.0, -0.5 / cs->distance, 0.0 };
1308 	    GLdouble clipPlane1[] = {  1.0,  0.0, -0.5 / cs->distance, 0.0 };
1309 	    GLdouble clipPlane2[] = {  0.0,  1.0, -0.5 / cs->distance, 0.0 };
1310 	    GLdouble clipPlane3[] = { 0.0,  -1.0, -0.5 / cs->distance, 0.0 };
1311 	    glClipPlane (GL_CLIP_PLANE0, clipPlane0);
1312 	    glClipPlane (GL_CLIP_PLANE1, clipPlane1);
1313 	    glClipPlane (GL_CLIP_PLANE2, clipPlane2);
1314 	    glClipPlane (GL_CLIP_PLANE3, clipPlane3);
1315 	}
1316 
1317 	glEnable (GL_CLIP_PLANE0);
1318 	glEnable (GL_CLIP_PLANE1);
1319 	glEnable (GL_CLIP_PLANE2);
1320 	glEnable (GL_CLIP_PLANE3);
1321 
1322 	glPopMatrix ();
1323     }
1324     else
1325     {
1326 	UNWRAP (cs, s, enableOutputClipping);
1327 	(*s->enableOutputClipping) (s, transform, region, output);
1328 	WRAP (cs, s, enableOutputClipping, cubeEnableOutputClipping);
1329     }
1330 }
1331 
1332 static void
cubePaintViewport(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)1333 cubePaintViewport (CompScreen              *s,
1334 		   const ScreenPaintAttrib *sAttrib,
1335 		   const CompTransform     *transform,
1336 		   Region                  region,
1337 		   CompOutput              *output,
1338 		   unsigned int            mask)
1339 {
1340     (*s->paintTransformedOutput) (s, sAttrib, transform, region, output, mask);
1341 }
1342 
1343 static void
cubePaintTransformedOutput(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,Region region,CompOutput * outputPtr,unsigned int mask)1344 cubePaintTransformedOutput (CompScreen		    *s,
1345 			    const ScreenPaintAttrib *sAttrib,
1346 			    const CompTransform	    *transform,
1347 			    Region		    region,
1348 			    CompOutput		    *outputPtr,
1349 			    unsigned int	    mask)
1350 {
1351     ScreenPaintAttrib sa = *sAttrib;
1352     float	      xRotate, vRotate, progress;
1353     int		      hsize;
1354     float	      size;
1355     GLenum            filter = s->display->textureFilter;
1356     PaintOrder        paintOrder;
1357     Bool              wasCulled = FALSE;
1358     Bool              paintCaps;
1359     int               cullNorm, cullInv;
1360     int               output = 0;
1361 
1362     CUBE_SCREEN (s);
1363 
1364     output = (outputPtr->id != ~0) ? outputPtr->id : 0;
1365 
1366     if (((outputPtr->id != ~0) && cs->recalcOutput) ||
1367 	((outputPtr->id == ~0) && !cs->recalcOutput && cs->nOutput > 1))
1368     {
1369 	cs->recalcOutput = (outputPtr->id == ~0);
1370 	cs->nOutput      = 1;
1371 	cubeUpdateGeometry (s, s->hsize, cs->invert);
1372     }
1373 
1374     hsize = s->hsize * cs->nOutput;
1375     size  = hsize;
1376 
1377     glGetIntegerv (GL_CULL_FACE_MODE, &cullNorm);
1378     cullInv   = (cullNorm == GL_BACK)? GL_FRONT : GL_BACK;
1379     wasCulled = glIsEnabled (GL_CULL_FACE);
1380 
1381     if (!cs->fullscreenOutput)
1382     {
1383 	cs->outputXScale = (float) s->width / outputPtr->width;
1384 	cs->outputYScale = (float) s->height / outputPtr->height;
1385 
1386 	cs->outputXOffset =
1387 	    (s->width / 2.0f -
1388 	     (outputPtr->region.extents.x1 +
1389 	      outputPtr->region.extents.x2) / 2.0f) /
1390 	    (float) outputPtr->width;
1391 
1392 	cs->outputYOffset =
1393 	    (s->height / 2.0f -
1394 	     (outputPtr->region.extents.y1 +
1395 	      outputPtr->region.extents.y2) / 2.0f) /
1396 	    (float) outputPtr->height;
1397     }
1398     else
1399     {
1400 	cs->outputXScale  = 1.0f;
1401 	cs->outputYScale  = 1.0f;
1402 	cs->outputXOffset = 0.0f;
1403 	cs->outputYOffset = 0.0f;
1404     }
1405 
1406     (*cs->getRotation) (s, &xRotate, &vRotate, &progress);
1407 
1408     sa.xRotate += xRotate;
1409     sa.vRotate += vRotate;
1410 
1411     if (!cs->cleared[output])
1412     {
1413 	float rRotate;
1414 
1415 	rRotate = xRotate - ((s->x *360.0f) / s->hsize);
1416 
1417 	(*cs->clearTargetOutput) (s, rRotate, vRotate);
1418 	cs->cleared[output] = TRUE;
1419     }
1420 
1421     mask &= ~PAINT_SCREEN_CLEAR_MASK;
1422 
1423     UNWRAP (cs, s, paintTransformedOutput);
1424 
1425     if (cs->grabIndex)
1426     {
1427 	sa.vRotate = 0.0f;
1428 
1429 	size += cs->unfold * 8.0f;
1430 	size += powf (cs->unfold, 6) * 64.0;
1431 	size += powf (cs->unfold, 16) * 8192.0;
1432 
1433 	sa.zTranslate = -cs->invert * (0.5f / tanf (M_PI / size));
1434 
1435 	/* distance we move the camera back when unfolding the cube.
1436 	   currently hardcoded to 1.5 but it should probably be optional. */
1437 	sa.zCamera -= cs->unfold * 1.5f;
1438     }
1439     else
1440     {
1441 	if (vRotate > 100.0f)
1442 	    sa.vRotate = 100.0f;
1443 	else if (vRotate < -100.0f)
1444 	    sa.vRotate = -100.0f;
1445 	else
1446 	    sa.vRotate = vRotate;
1447 
1448 	sa.zTranslate = -cs->invert * cs->distance;
1449     }
1450 
1451     if (sa.xRotate > 0.0f)
1452 	cs->xRotations = (int) (hsize * sa.xRotate + 180.0f) / 360.0f;
1453     else
1454 	cs->xRotations = (int) (hsize * sa.xRotate - 180.0f) / 360.0f;
1455 
1456     sa.xRotate -= (360.0f * cs->xRotations) / hsize;
1457     sa.xRotate *= cs->invert;
1458 
1459     sa.xRotate = sa.xRotate / size * hsize;
1460 
1461     if (cs->grabIndex && cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b)
1462 	s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
1463 
1464     if (cs->invert == 1)
1465     {
1466 	/* Outside cube - start with FTB faces */
1467 	paintOrder = FTB;
1468 	glCullFace (cullInv);
1469     }
1470     else
1471     {
1472 	/* Inside cube - start with BTF faces */
1473 	paintOrder = BTF;
1474     }
1475 
1476     if (cs->invert == -1 || cs->paintAllViewports)
1477 	cubePaintAllViewports (s, &sa, transform, region, outputPtr,
1478 			       mask, cs->xRotations, size, hsize, paintOrder);
1479 
1480     glCullFace (cullNorm);
1481 
1482     if (wasCulled && cs->paintAllViewports)
1483 	glDisable (GL_CULL_FACE);
1484 
1485     paintCaps = !cs->grabIndex && (hsize > 2) && !cs->capsPainted[output] &&
1486 	        (cs->invert != 1 || cs->desktopOpacity != OPAQUE ||
1487 		 cs->paintAllViewports || sa.vRotate != 0.0f ||
1488 		 sa.yTranslate != 0.0f);
1489 
1490     if (paintCaps)
1491     {
1492 	Bool topDir, bottomDir, allCaps;
1493 
1494 	static CompVector top[3] = { { .v = { 0.5, 0.5,  0.0, 1.0} },
1495 				     { .v = { 0.0, 0.5, -0.5, 1.0} },
1496 				     { .v = { 0.0, 0.5,  0.0, 1.0} } };
1497 	static CompVector bottom[3] = { { .v = { 0.5, -0.5,  0.0, 1.0} },
1498 			                { .v = { 0.0, -0.5, -0.5, 1.0} },
1499 					{ .v = { 0.0, -0.5,  0.0, 1.0} } };
1500 
1501 	topDir    = (*cs->checkOrientation) (s, &sa, transform, outputPtr, top);
1502 	bottomDir = (*cs->checkOrientation) (s, &sa, transform,
1503 					     outputPtr, bottom);
1504 
1505 	cs->capsPainted[output] = TRUE;
1506 
1507 	allCaps = cs->paintAllViewports || cs->invert != 1;
1508 
1509 	if (topDir && bottomDir)
1510 	{
1511 	    glNormal3f (0.0f, -1.0f, 0.0f);
1512 	    if (allCaps)
1513 	    {
1514 		(*cs->paintBottom) (s, &sa, transform, outputPtr, hsize);
1515 		glNormal3f (0.0f, 0.0f, -1.0f);
1516 		(*cs->paintInside) (s, &sa, transform, outputPtr, hsize);
1517 		glNormal3f (0.0f, -1.0f, 0.0f);
1518 	    }
1519 	    (*cs->paintTop) (s, &sa, transform, outputPtr, hsize);
1520 	}
1521 	else if (!topDir && !bottomDir)
1522 	{
1523 	    glNormal3f (0.0f, 1.0f, 0.0f);
1524 	    if (allCaps)
1525 	    {
1526 		(*cs->paintTop) (s, &sa, transform, outputPtr, hsize);
1527 		glNormal3f (0.0f, 0.0f, -1.0f);
1528 		(*cs->paintInside) (s, &sa, transform, outputPtr, hsize);
1529 		glNormal3f (0.0f, 1.0f, 0.0f);
1530 	    }
1531 	    (*cs->paintBottom) (s, &sa, transform, outputPtr, hsize);
1532 	}
1533 	else if (allCaps)
1534 	{
1535 	    glNormal3f (0.0f, 1.0f, 0.0f);
1536 	    (*cs->paintTop) (s, &sa, transform, outputPtr, hsize);
1537 	    glNormal3f (0.0f, -1.0f, 0.0f);
1538 	    (*cs->paintBottom) (s, &sa, transform, outputPtr, hsize);
1539 	    glNormal3f (0.0f, 0.0f, -1.0f);
1540 	    (*cs->paintInside) (s, &sa, transform, outputPtr, hsize);
1541 	}
1542 	glNormal3f (0.0f, 0.0f, -1.0f);
1543     }
1544 
1545     if (wasCulled)
1546 	glEnable (GL_CULL_FACE);
1547 
1548     if (cs->invert == 1)
1549     {
1550 	/* Outside cube - continue with BTF faces */
1551 	paintOrder = BTF;
1552     }
1553     else
1554     {
1555 	/* Inside cube - continue with FTB faces */
1556 	paintOrder = FTB;
1557 	glCullFace (cullInv);
1558     }
1559 
1560     if (cs->invert == 1 || cs->paintAllViewports)
1561 	cubePaintAllViewports (s, &sa, transform, region,
1562 			       outputPtr, mask, cs->xRotations,
1563 			       size, hsize, paintOrder);
1564 
1565     glCullFace (cullNorm);
1566 
1567     s->display->textureFilter = filter;
1568 
1569     WRAP (cs, s, paintTransformedOutput, cubePaintTransformedOutput);
1570 }
1571 
1572 static Bool
cubePaintWindow(CompWindow * w,const WindowPaintAttrib * attrib,const CompTransform * transform,Region region,unsigned int mask)1573 cubePaintWindow (CompWindow		  *w,
1574 		 const WindowPaintAttrib  *attrib,
1575 		 const CompTransform	  *transform,
1576 		 Region			  region,
1577 		 unsigned int		  mask)
1578 {
1579     Bool       status;
1580     CompScreen *s = w->screen;
1581     CUBE_SCREEN (s);
1582 
1583     if ((w->type & CompWindowTypeDesktopMask) &&
1584 	(attrib->opacity != cs->desktopOpacity))
1585     {
1586 	WindowPaintAttrib wAttrib = *attrib;
1587 
1588 	wAttrib.opacity = cs->desktopOpacity;
1589 
1590 	UNWRAP (cs, s, paintWindow);
1591 	status = (*s->paintWindow) (w, &wAttrib, transform, region, mask);
1592 	WRAP (cs, s, paintWindow, cubePaintWindow);
1593     }
1594     else
1595     {
1596 	UNWRAP (cs, s, paintWindow);
1597 	status = (*s->paintWindow) (w, attrib, transform, region, mask);
1598 	WRAP (cs, s, paintWindow, cubePaintWindow);
1599     }
1600 
1601     return status;
1602 }
1603 
1604 static void
cubeInitWindowWalker(CompScreen * s,CompWalker * walker)1605 cubeInitWindowWalker (CompScreen *s, CompWalker* walker)
1606 {
1607     CUBE_SCREEN (s);
1608 
1609     UNWRAP (cs, s, initWindowWalker);
1610     (*s->initWindowWalker) (s, walker);
1611     WRAP (cs, s, initWindowWalker, cubeInitWindowWalker);
1612 
1613     if (cs->paintOrder == FTB)
1614     {
1615 	WalkInitProc tmpInit = walker->first;
1616 	WalkStepProc tmpStep = walker->next;
1617 
1618 	walker->first = walker->last;
1619 	walker->last = tmpInit;
1620 
1621 	walker->next = walker->prev;
1622 	walker->prev = tmpStep;
1623     }
1624 }
1625 
1626 static void
cubeApplyScreenTransform(CompScreen * s,const ScreenPaintAttrib * sAttrib,CompOutput * output,CompTransform * transform)1627 cubeApplyScreenTransform (CompScreen		  *s,
1628 			  const ScreenPaintAttrib *sAttrib,
1629 			  CompOutput		  *output,
1630 			  CompTransform	          *transform)
1631 {
1632     CUBE_SCREEN (s);
1633 
1634     matrixTranslate (transform, cs->outputXOffset, -cs->outputYOffset, 0.0f);
1635     matrixScale (transform, cs->outputXScale, cs->outputYScale, 1.0f);
1636 
1637     UNWRAP (cs, s, applyScreenTransform);
1638     (*s->applyScreenTransform) (s, sAttrib, output, transform);
1639     WRAP (cs, s, applyScreenTransform, cubeApplyScreenTransform);
1640 
1641     matrixScale (transform, 1.0f / cs->outputXScale,
1642 		 1.0f / cs->outputYScale, 1.0f);
1643     matrixTranslate (transform, -cs->outputXOffset, cs->outputYOffset, 0.0f);
1644 }
1645 
1646 static Bool
cubeUnfold(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1647 cubeUnfold (CompDisplay     *d,
1648 	    CompAction      *action,
1649 	    CompActionState state,
1650 	    CompOption      *option,
1651 	    int		    nOption)
1652 {
1653     CompScreen *s;
1654     Window     xid;
1655 
1656     xid = getIntOptionNamed (option, nOption, "root", 0);
1657 
1658     s = findScreenAtDisplay (d, xid);
1659     if (s)
1660     {
1661 	CUBE_SCREEN (s);
1662 
1663 	if (s->hsize * cs->nOutput < 4)
1664 	    return FALSE;
1665 
1666 	if (otherScreenGrabExist (s, "rotate", "switcher", "cube", NULL))
1667 	    return FALSE;
1668 
1669 	if (!cs->grabIndex)
1670 	    cs->grabIndex = pushScreenGrab (s, s->invisibleCursor, "cube");
1671 
1672 	if (cs->grabIndex)
1673 	{
1674 	    cs->unfolded = TRUE;
1675 	    damageScreen (s);
1676 	}
1677 
1678 	if (state & CompActionStateInitButton)
1679 	    action->state |= CompActionStateTermButton;
1680 
1681 	if (state & CompActionStateInitKey)
1682 	    action->state |= CompActionStateTermKey;
1683     }
1684 
1685     return FALSE;
1686 }
1687 
1688 static Bool
cubeFold(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1689 cubeFold (CompDisplay     *d,
1690 	  CompAction      *action,
1691 	  CompActionState state,
1692 	  CompOption      *option,
1693 	  int		  nOption)
1694 {
1695     CompScreen *s;
1696     Window     xid;
1697 
1698     xid = getIntOptionNamed (option, nOption, "root", 0);
1699 
1700     for (s = d->screens; s; s = s->next)
1701     {
1702 	CUBE_SCREEN (s);
1703 
1704 	if (xid && s->root != xid)
1705 	    continue;
1706 
1707 	if (cs->grabIndex)
1708 	{
1709 	    cs->unfolded = FALSE;
1710 	    damageScreen (s);
1711 	}
1712     }
1713 
1714     action->state &= ~(CompActionStateTermButton | CompActionStateTermKey);
1715 
1716     return FALSE;
1717 }
1718 
1719 static Bool
cubeNextImage(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1720 cubeNextImage (CompDisplay     *d,
1721 	       CompAction      *action,
1722 	       CompActionState state,
1723 	       CompOption      *option,
1724 	       int	       nOption)
1725 {
1726     CompScreen *s;
1727     Window     xid;
1728 
1729     xid = getIntOptionNamed (option, nOption, "root", 0);
1730 
1731     s = findScreenAtDisplay (d, xid);
1732     if (s)
1733     {
1734 	int imgNFile;
1735 
1736 	CUBE_SCREEN (s);
1737 
1738 	imgNFile = cs->opt[CUBE_SCREEN_OPTION_IMAGES].value.list.nValue;
1739 	if (imgNFile)
1740 	{
1741 	    cubeLoadImg (s, (cs->imgCurFile + 1) % imgNFile);
1742 	    damageScreen (s);
1743 	}
1744     }
1745 
1746     return FALSE;
1747 }
1748 
1749 static Bool
cubePrevImage(CompDisplay * d,CompAction * action,CompActionState state,CompOption * option,int nOption)1750 cubePrevImage (CompDisplay     *d,
1751 	       CompAction      *action,
1752 	       CompActionState state,
1753 	       CompOption      *option,
1754 	       int	       nOption)
1755 {
1756     CompScreen *s;
1757     Window     xid;
1758 
1759     xid = getIntOptionNamed (option, nOption, "root", 0);
1760 
1761     s = findScreenAtDisplay (d, xid);
1762     if (s)
1763     {
1764 	int imgNFile;
1765 
1766 	CUBE_SCREEN (s);
1767 
1768 	imgNFile = cs->opt[CUBE_SCREEN_OPTION_IMAGES].value.list.nValue;
1769 	if (imgNFile)
1770 	{
1771 	    cubeLoadImg (s, (cs->imgCurFile - 1 + imgNFile) % imgNFile);
1772 	    damageScreen (s);
1773 	}
1774     }
1775 
1776     return FALSE;
1777 }
1778 
1779 static void
cubeOutputChangeNotify(CompScreen * s)1780 cubeOutputChangeNotify (CompScreen *s)
1781 {
1782     CUBE_SCREEN (s);
1783 
1784     cubeUpdateOutputs (s);
1785     cubeUpdateGeometry (s, s->hsize, cs->invert);
1786 
1787     if (cs->opt[CUBE_SCREEN_OPTION_IMAGES].value.list.nValue)
1788 	cubeLoadImg (s, cs->imgCurFile);
1789 
1790     UNWRAP (cs, s, outputChangeNotify);
1791     (*s->outputChangeNotify) (s);
1792     WRAP (cs, s, outputChangeNotify, cubeOutputChangeNotify);
1793 }
1794 
1795 static Bool
cubeSetOptionForPlugin(CompObject * o,const char * plugin,const char * name,CompOptionValue * value)1796 cubeSetOptionForPlugin (CompObject      *o,
1797 			const char      *plugin,
1798 			const char      *name,
1799 			CompOptionValue *value)
1800 {
1801     Bool status;
1802 
1803     CUBE_CORE (&core);
1804 
1805     UNWRAP (cc, &core, setOptionForPlugin);
1806     status = (*core.setOptionForPlugin) (o, plugin, name, value);
1807     WRAP (cc, &core, setOptionForPlugin, cubeSetOptionForPlugin);
1808 
1809     if (status && o->type == COMP_OBJECT_TYPE_SCREEN)
1810     {
1811 	if (strcmp (plugin, "core") == 0 && strcmp (name, "hsize") == 0)
1812 	{
1813 	    CompScreen *s = (CompScreen *) o;
1814 
1815 	    CUBE_SCREEN (s);
1816 
1817 	    cubeUpdateGeometry (s, s->hsize, cs->invert);
1818 	}
1819     }
1820 
1821     return status;
1822 }
1823 
1824 static CompOption *
cubeGetDisplayOptions(CompPlugin * plugin,CompDisplay * display,int * count)1825 cubeGetDisplayOptions (CompPlugin  *plugin,
1826 		       CompDisplay *display,
1827 		       int	   *count)
1828 {
1829     CUBE_DISPLAY (display);
1830 
1831     *count = NUM_OPTIONS (cd);
1832     return cd->opt;
1833 }
1834 
1835 static Bool
cubeSetDisplayOption(CompPlugin * plugin,CompDisplay * display,const char * name,CompOptionValue * value)1836 cubeSetDisplayOption (CompPlugin      *plugin,
1837 		      CompDisplay     *display,
1838 		      const char      *name,
1839 		      CompOptionValue *value)
1840 {
1841     CompOption *o;
1842     int	       index;
1843 
1844     CUBE_DISPLAY (display);
1845 
1846     o = compFindOption (cd->opt, NUM_OPTIONS (cd), name, &index);
1847     if (!o)
1848 	return FALSE;
1849 
1850     switch (index) {
1851     case CUBE_DISPLAY_OPTION_ABI:
1852     case CUBE_DISPLAY_OPTION_INDEX:
1853 	break;
1854     default:
1855 	return compSetDisplayOption (display, o, value);
1856     }
1857 
1858     return FALSE;
1859 }
1860 
1861 static Bool
cubeInitCore(CompPlugin * p,CompCore * c)1862 cubeInitCore (CompPlugin *p,
1863 	      CompCore   *c)
1864 {
1865     CubeCore *cc;
1866 
1867     if (!checkPluginABI ("core", CORE_ABIVERSION))
1868 	return FALSE;
1869 
1870     cc = malloc (sizeof (CubeCore));
1871     if (!cc)
1872 	return FALSE;
1873 
1874     cubeDisplayPrivateIndex = allocateDisplayPrivateIndex ();
1875     if (cubeDisplayPrivateIndex < 0)
1876     {
1877 	free (cc);
1878 	return FALSE;
1879     }
1880 
1881     WRAP (cc, &core, setOptionForPlugin, cubeSetOptionForPlugin);
1882 
1883     c->base.privates[cubeCorePrivateIndex].ptr = cc;
1884 
1885     return TRUE;
1886 }
1887 
1888 static void
cubeFiniCore(CompPlugin * p,CompCore * c)1889 cubeFiniCore (CompPlugin *p,
1890 	      CompCore   *c)
1891 {
1892     CUBE_CORE (c);
1893 
1894     UNWRAP (cc, &core, setOptionForPlugin);
1895 
1896     freeDisplayPrivateIndex (cubeDisplayPrivateIndex);
1897 
1898     free (cc);
1899 }
1900 
1901 static const CompMetadataOptionInfo cubeDisplayOptionInfo[] = {
1902     { "abi", "int", 0, 0, 0 },
1903     { "index", "int", 0, 0, 0 },
1904     { "unfold_key", "key", 0, cubeUnfold, cubeFold },
1905     { "next_slide_key", "key", "<passive_grab>false</passive_grab>",
1906       cubeNextImage, 0 },
1907     { "prev_slide_key", "key", "<passive_grab>false</passive_grab>",
1908       cubePrevImage, 0 }
1909 };
1910 
1911 static Bool
cubeInitDisplay(CompPlugin * p,CompDisplay * d)1912 cubeInitDisplay (CompPlugin  *p,
1913 		 CompDisplay *d)
1914 {
1915     CubeDisplay *cd;
1916 
1917     cd = malloc (sizeof (CubeDisplay));
1918     if (!cd)
1919 	return FALSE;
1920 
1921     if (!compInitDisplayOptionsFromMetadata (d,
1922 					     &cubeMetadata,
1923 					     cubeDisplayOptionInfo,
1924 					     cd->opt,
1925 					     CUBE_DISPLAY_OPTION_NUM))
1926     {
1927 	free (cd);
1928 	return FALSE;
1929     }
1930 
1931     cd->opt[CUBE_DISPLAY_OPTION_ABI].value.i   = CUBE_ABIVERSION;
1932     cd->opt[CUBE_DISPLAY_OPTION_INDEX].value.i = cubeDisplayPrivateIndex;
1933 
1934     cd->screenPrivateIndex = allocateScreenPrivateIndex (d);
1935     if (cd->screenPrivateIndex < 0)
1936     {
1937 	compFiniDisplayOptions (d, cd->opt, CUBE_DISPLAY_OPTION_NUM);
1938 	free (cd);
1939 	return FALSE;
1940     }
1941 
1942     d->base.privates[cubeDisplayPrivateIndex].ptr = cd;
1943 
1944     return TRUE;
1945 }
1946 
1947 static void
cubeFiniDisplay(CompPlugin * p,CompDisplay * d)1948 cubeFiniDisplay (CompPlugin  *p,
1949 		 CompDisplay *d)
1950 {
1951     CUBE_DISPLAY (d);
1952 
1953     freeScreenPrivateIndex (d, cd->screenPrivateIndex);
1954 
1955     compFiniDisplayOptions (d, cd->opt, CUBE_DISPLAY_OPTION_NUM);
1956 
1957     free (cd);
1958 }
1959 
1960 static const CompMetadataOptionInfo cubeScreenOptionInfo[] = {
1961     { "color", "color", 0, 0, 0 },
1962     { "in", "bool", 0, 0, 0 },
1963     { "scale_image", "bool", 0, 0, 0 },
1964     { "images", "list", "<type>string</type>", 0, 0 },
1965     { "skydome", "bool", 0, 0, 0 },
1966     { "skydome_image", "string", 0, 0, 0 },
1967     { "skydome_animated", "bool", 0, 0, 0 },
1968     { "skydome_gradient_start_color", "color", 0, 0, 0 },
1969     { "skydome_gradient_end_color", "color", 0, 0, 0 },
1970     { "acceleration", "float", "<min>1.0</min>", 0, 0 },
1971     { "speed", "float", "<min>0.1</min>", 0, 0 },
1972     { "timestep", "float", "<min>0.1</min>", 0, 0 },
1973     { "mipmap", "bool", 0, 0, 0 },
1974     { "adjust_image", "bool", 0, 0, 0 },
1975     { "active_opacity", "float", "<min>0.0</min><max>100.0</max>", 0, 0 },
1976     { "inactive_opacity", "float", "<min>0.0</min><max>100.0</max>", 0, 0 },
1977     { "transparent_manual_only", "bool", 0, 0, 0 },
1978     { "multioutput_mode", "int", "<min>0</min><max>2</max>", 0, 0 }
1979 };
1980 
1981 static Bool
cubeInitScreen(CompPlugin * p,CompScreen * s)1982 cubeInitScreen (CompPlugin *p,
1983 		CompScreen *s)
1984 {
1985     CubeScreen *cs;
1986 
1987     CUBE_DISPLAY (s->display);
1988 
1989     cs = malloc (sizeof (CubeScreen));
1990     if (!cs)
1991 	return FALSE;
1992 
1993     if (!compInitScreenOptionsFromMetadata (s,
1994 					    &cubeMetadata,
1995 					    cubeScreenOptionInfo,
1996 					    cs->opt,
1997 					    CUBE_SCREEN_OPTION_NUM))
1998     {
1999 	free (cs);
2000 	return FALSE;
2001     }
2002 
2003     cs->pw = 0;
2004     cs->ph = 0;
2005 
2006     cs->invert = 1;
2007 
2008     cs->tc[0] = cs->tc[1] = cs->tc[2] = cs->tc[3] = 0.0f;
2009     cs->tc[4] = cs->tc[5] = cs->tc[6] = cs->tc[7] = 0.0f;
2010 
2011     memcpy (cs->color, cs->opt[CUBE_SCREEN_OPTION_COLOR].value.c,
2012 	    sizeof (cs->color));
2013 
2014     cs->nVertices = 0;
2015     cs->vertices  = NULL;
2016 
2017     cs->grabIndex = 0;
2018 
2019     cs->srcOutput = 0;
2020 
2021     cs->skyListId = 0;
2022 
2023     cs->getRotation	    = cubeGetRotation;
2024     cs->clearTargetOutput   = cubeClearTargetOutput;
2025     cs->paintTop            = cubePaintTop;
2026     cs->paintBottom         = cubePaintBottom;
2027     cs->paintInside         = cubePaintInside;
2028     cs->checkOrientation    = cubeCheckOrientation;
2029     cs->paintViewport       = cubePaintViewport;
2030     cs->shouldPaintViewport = cubeShouldPaintViewport;
2031 
2032     s->base.privates[cd->screenPrivateIndex].ptr = cs;
2033 
2034     initTexture (s, &cs->texture);
2035     initTexture (s, &cs->sky);
2036 
2037     cs->imgCurFile = 0;
2038 
2039     cs->unfolded = FALSE;
2040     cs->unfold   = 0.0f;
2041 
2042     cs->unfoldVelocity = 0.0f;
2043 
2044     cs->paintAllViewports = FALSE;
2045     cs->fullscreenOutput  = TRUE;
2046 
2047     cs->outputXScale  = 1.0f;
2048     cs->outputYScale  = 1.0f;
2049     cs->outputXOffset = 0.0f;
2050     cs->outputYOffset = 0.0f;
2051 
2052     cs->rotationState = RotationNone;
2053 
2054     cs->desktopOpacity = OPAQUE;
2055 
2056     cs->lastOpacityIndex = CUBE_SCREEN_OPTION_INACTIVE_OPACITY;
2057 
2058     cs->moMode = cs->opt[CUBE_SCREEN_OPTION_MULTIOUTPUT_MODE].value.i;
2059 
2060     cs->recalcOutput = FALSE;
2061 
2062     memset (cs->cleared, 0, sizeof (cs->cleared));
2063 
2064     cubeUpdateOutputs (s);
2065 
2066     if (!cubeUpdateGeometry (s, s->hsize, cs->invert))
2067     {
2068 	compFiniScreenOptions (s, cs->opt, CUBE_SCREEN_OPTION_NUM);
2069 	free (cs);
2070 	return FALSE;
2071     }
2072 
2073     if (cs->opt[CUBE_SCREEN_OPTION_IMAGES].value.list.nValue)
2074     {
2075 	cubeLoadImg (s, cs->imgCurFile);
2076 	damageScreen (s);
2077     }
2078 
2079     WRAP (cs, s, preparePaintScreen, cubePreparePaintScreen);
2080     WRAP (cs, s, donePaintScreen, cubeDonePaintScreen);
2081     WRAP (cs, s, paintScreen, cubePaintScreen);
2082     WRAP (cs, s, paintOutput, cubePaintOutput);
2083     WRAP (cs, s, paintTransformedOutput, cubePaintTransformedOutput);
2084     WRAP (cs, s, enableOutputClipping, cubeEnableOutputClipping);
2085     WRAP (cs, s, paintWindow, cubePaintWindow);
2086     WRAP (cs, s, applyScreenTransform, cubeApplyScreenTransform);
2087     WRAP (cs, s, outputChangeNotify, cubeOutputChangeNotify);
2088     WRAP (cs, s, initWindowWalker, cubeInitWindowWalker);
2089 
2090     return TRUE;
2091 }
2092 
2093 static void
cubeFiniScreen(CompPlugin * p,CompScreen * s)2094 cubeFiniScreen (CompPlugin *p,
2095 		CompScreen *s)
2096 {
2097     CUBE_SCREEN (s);
2098 
2099     if (cs->vertices)
2100 	free (cs->vertices);
2101 
2102     if (cs->skyListId)
2103 	glDeleteLists (cs->skyListId, 1);
2104 
2105     UNWRAP (cs, s, preparePaintScreen);
2106     UNWRAP (cs, s, donePaintScreen);
2107     UNWRAP (cs, s, paintScreen);
2108     UNWRAP (cs, s, paintOutput);
2109     UNWRAP (cs, s, paintTransformedOutput);
2110     UNWRAP (cs, s, enableOutputClipping);
2111     UNWRAP (cs, s, paintWindow);
2112     UNWRAP (cs, s, applyScreenTransform);
2113     UNWRAP (cs, s, outputChangeNotify);
2114     UNWRAP (cs, s, initWindowWalker);
2115 
2116     finiTexture (s, &cs->texture);
2117     finiTexture (s, &cs->sky);
2118 
2119     compFiniScreenOptions (s, cs->opt, CUBE_SCREEN_OPTION_NUM);
2120 
2121     free (cs);
2122 }
2123 
2124 static CompBool
cubeInitObject(CompPlugin * p,CompObject * o)2125 cubeInitObject (CompPlugin *p,
2126 		CompObject *o)
2127 {
2128     static InitPluginObjectProc dispTab[] = {
2129 	(InitPluginObjectProc) cubeInitCore,
2130 	(InitPluginObjectProc) cubeInitDisplay,
2131 	(InitPluginObjectProc) cubeInitScreen
2132     };
2133 
2134     RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
2135 }
2136 
2137 static void
cubeFiniObject(CompPlugin * p,CompObject * o)2138 cubeFiniObject (CompPlugin *p,
2139 		CompObject *o)
2140 {
2141     static FiniPluginObjectProc dispTab[] = {
2142 	(FiniPluginObjectProc) cubeFiniCore,
2143 	(FiniPluginObjectProc) cubeFiniDisplay,
2144 	(FiniPluginObjectProc) cubeFiniScreen
2145     };
2146 
2147     DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
2148 }
2149 
2150 static CompOption *
cubeGetObjectOptions(CompPlugin * plugin,CompObject * object,int * count)2151 cubeGetObjectOptions (CompPlugin *plugin,
2152 		      CompObject *object,
2153 		      int	 *count)
2154 {
2155     static GetPluginObjectOptionsProc dispTab[] = {
2156 	(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
2157 	(GetPluginObjectOptionsProc) cubeGetDisplayOptions,
2158 	(GetPluginObjectOptionsProc) cubeGetScreenOptions
2159     };
2160 
2161     *count = 0;
2162     RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
2163 		     (void *) count, (plugin, object, count));
2164 }
2165 
2166 static CompBool
cubeSetObjectOption(CompPlugin * plugin,CompObject * object,const char * name,CompOptionValue * value)2167 cubeSetObjectOption (CompPlugin      *plugin,
2168 		     CompObject      *object,
2169 		     const char      *name,
2170 		     CompOptionValue *value)
2171 {
2172     static SetPluginObjectOptionProc dispTab[] = {
2173 	(SetPluginObjectOptionProc) 0, /* SetCoreOption */
2174 	(SetPluginObjectOptionProc) cubeSetDisplayOption,
2175 	(SetPluginObjectOptionProc) cubeSetScreenOption
2176     };
2177 
2178     RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
2179 		     (plugin, object, name, value));
2180 }
2181 
2182 static Bool
cubeInit(CompPlugin * p)2183 cubeInit (CompPlugin *p)
2184 {
2185     if (!compInitPluginMetadataFromInfo (&cubeMetadata,
2186 					 p->vTable->name,
2187 					 cubeDisplayOptionInfo,
2188 					 CUBE_DISPLAY_OPTION_NUM,
2189 					 cubeScreenOptionInfo,
2190 					 CUBE_SCREEN_OPTION_NUM))
2191 	return FALSE;
2192 
2193     cubeCorePrivateIndex = allocateCorePrivateIndex ();
2194     if (cubeCorePrivateIndex < 0)
2195     {
2196 	compFiniMetadata (&cubeMetadata);
2197 	return FALSE;
2198     }
2199 
2200     compAddMetadataFromFile (&cubeMetadata, p->vTable->name);
2201 
2202     return TRUE;
2203 }
2204 
2205 static void
cubeFini(CompPlugin * p)2206 cubeFini (CompPlugin *p)
2207 {
2208     freeCorePrivateIndex (cubeCorePrivateIndex);
2209     compFiniMetadata (&cubeMetadata);
2210 }
2211 
2212 static CompMetadata *
cubeGetMetadata(CompPlugin * plugin)2213 cubeGetMetadata (CompPlugin *plugin)
2214 {
2215     return &cubeMetadata;
2216 }
2217 
2218 CompPluginVTable cubeVTable = {
2219     "cube",
2220     cubeGetMetadata,
2221     cubeInit,
2222     cubeFini,
2223     cubeInitObject,
2224     cubeFiniObject,
2225     cubeGetObjectOptions,
2226     cubeSetObjectOption
2227 };
2228 
2229 CompPluginVTable *
getCompPluginInfo20070830(void)2230 getCompPluginInfo20070830 (void)
2231 {
2232     return &cubeVTable;
2233 }
2234