All pastes #476654 Raw Edit

Anonymous

public text v1 · immutable
·published 2007-05-08 07:55 UTC
rendered paste body
From 5b0a8bc553cbe50bac8b202d229c605c86914da8 Mon Sep 17 00:00:00 2001
From: Roi Cohen <roico@roico-desktop.(none)>
Date: Tue, 8 May 2007 10:34:28 +0300
Subject: [PATCH] cube painting order

---
 plugins/cube.c |  643 +++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 423 insertions(+), 220 deletions(-)

diff --git a/plugins/cube.c b/plugins/cube.c
index 9ba05e1..5617c82 100644
--- a/plugins/cube.c
+++ b/plugins/cube.c
@@ -87,6 +87,43 @@ typedef struct _CubeDisplay {
 #define CUBE_SCREEN_OPTION_ADJUST_IMAGE	      14
 #define CUBE_SCREEN_OPTION_NUM                15
 
+#define MULTM(x, y, z) \
+z[0] = x[0] * y[0] + x[4] * y[1] + x[8] * y[2] + x[12] * y[3]; \
+z[1] = x[1] * y[0] + x[5] * y[1] + x[9] * y[2] + x[13] * y[3]; \
+z[2] = x[2] * y[0] + x[6] * y[1] + x[10] * y[2] + x[14] * y[3]; \
+z[3] = x[3] * y[0] + x[7] * y[1] + x[11] * y[2] + x[15] * y[3]; \
+z[4] = x[0] * y[4] + x[4] * y[5] + x[8] * y[6] + x[12] * y[7]; \
+z[5] = x[1] * y[4] + x[5] * y[5] + x[9] * y[6] + x[13] * y[7]; \
+z[6] = x[2] * y[4] + x[6] * y[5] + x[10] * y[6] + x[14] * y[7]; \
+z[7] = x[3] * y[4] + x[7] * y[5] + x[11] * y[6] + x[15] * y[7]; \
+z[8] = x[0] * y[8] + x[4] * y[9] + x[8] * y[10] + x[12] * y[11]; \
+z[9] = x[1] * y[8] + x[5] * y[9] + x[9] * y[10] + x[13] * y[11]; \
+z[10] = x[2] * y[8] + x[6] * y[9] + x[10] * y[10] + x[14] * y[11]; \
+z[11] = x[3] * y[8] + x[7] * y[9] + x[11] * y[10] + x[15] * y[11]; \
+z[12] = x[0] * y[12] + x[4] * y[13] + x[8] * y[14] + x[12] * y[15]; \
+z[13] = x[1] * y[12] + x[5] * y[13] + x[9] * y[14] + x[13] * y[15]; \
+z[14] = x[2] * y[12] + x[6] * y[13] + x[10] * y[14] + x[14] * y[15]; \
+z[15] = x[3] * y[12] + x[7] * y[13] + x[11] * y[14] + x[15] * y[15];
+
+#define MULTMV(m, v) { \
+float v0 = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; \
+float v1 = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; \
+float v2 = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; \
+float v3 = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; \
+v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
+
+#define DIVV(v) \
+v[0] /= v[3]; \
+v[1] /= v[3]; \
+v[2] /= v[3]; \
+v[3] /= v[3];
+
+typedef enum _PaintOrder
+{
+    BTF = 0,
+    FTB
+} PaintOrder;
+
 typedef struct _CubeScreen {
     PreparePaintScreenProc     preparePaintScreen;
     DonePaintScreenProc	       donePaintScreen;
@@ -97,15 +134,19 @@ typedef struct _CubeScreen {
     SetScreenOptionProc	       setScreenOption;
     OutputChangeNotifyProc     outputChangeNotify;
     SetClipPlanesProc          setClipPlanes;
+    StackFirstProc             stackFirst;
+    StackLastProc              stackLast;
+    StackNextProc              stackNext;
+    StackPrevProc              stackPrev;
 
     CompOption opt[CUBE_SCREEN_OPTION_NUM];
 
-    int      invert;
-    int      xrotations;
-    GLfloat  distance;
-    Bool     paintTopBottom;
-    GLushort color[3];
-    GLfloat  tc[12];
+    int        invert;
+    int        xrotations;
+    PaintOrder paintOrder;
+    GLfloat    distance;
+    GLushort   color[3];
+    GLfloat    tc[12];
 
     int grabIndex;
 
@@ -1075,6 +1116,8 @@ cubePaintScreen (CompScreen		 *s,
 	mask |= PAINT_SCREEN_TRANSFORMED_MASK;
     }
 
+    cs->paintOrder = BTF;	// Always use BTF painting on non-transformed screen.
+
     UNWRAP (cs, s, paintScreen);
     status = (*s->paintScreen) (s, sAttrib, transform, region, output, mask);
     WRAP (cs, s, paintScreen, cubePaintScreen);
@@ -1095,16 +1138,78 @@ cubeDonePaintScreen (CompScreen *s)
     WRAP (cs, s, donePaintScreen, cubeDonePaintScreen);
 }
 
+static Bool
+cubeCheckFTB (CompScreen *s, 
+              const ScreenPaintAttrib *sAttrib, 
+              const CompTransform  *transform,
+              int output)
+{
+    float mvp[16];
+    CompTransform sTransform = *transform;
+    
+    (*s->applyScreenTransform) (s, sAttrib, output, &sTransform);
+    transformToScreenSpace (s, output, -sAttrib->zTranslate, &sTransform);
+
+    MULTM(s->projection, sTransform.m, mvp);
+
+    float pntA[4] = { s->outputDev[output].region.extents.x1,
+                      s->outputDev[output].region.extents.y1,
+                      0, 1};
+
+    float pntB[4] = { s->outputDev[output].region.extents.x2,
+                      s->outputDev[output].region.extents.y1,
+                      0, 1};
+
+    float pntC[4] = { s->outputDev[output].region.extents.x1 + s->outputDev[output].width / 2.0f,
+                      s->outputDev[output].region.extents.y1 + s->outputDev[output].height / 2.0f,
+                      0, 1};
+
+    MULTMV(mvp, pntA);
+    DIVV(pntA);
+
+    MULTMV(mvp, pntB);
+    DIVV(pntB);
+
+    MULTMV(mvp, pntC);
+    DIVV(pntC);
+
+    float vecA[3] = { pntC[0] - pntA[0],
+                      pntC[1] - pntA[1],
+                      pntC[2] - pntA[2]};
+    
+    float vecB[3] = { pntC[0] - pntB[0], 
+                      pntC[1] - pntB[1],
+                      pntC[2] - pntB[2]};
+
+    float ortho[3] = { vecA[1] * vecB[2] - vecA[2] * vecB[1],
+	               vecA[2] * vecB[0] - vecA[0] * vecB[2],
+	               vecA[0] * vecB[1] - vecA[1] * vecB[0]};
+
+    if (ortho[2] > 0.0f)	//The viewport is reversed, should be painted front to back.
+	return TRUE;
+    
+    return FALSE;
+}
+
 static void
 cubeMoveViewportAndPaint (CompScreen		  *s,
 			  const ScreenPaintAttrib *sAttrib,
 			  const CompTransform	  *transform,
 			  int			  output,
 			  unsigned int		  mask,
+			  PaintOrder              paintOrder,
 			  int			  dx)
 {
     CUBE_SCREEN (s);
+    
+    Bool ftb = cubeCheckFTB(s, sAttrib, transform, output);
 
+    if ((paintOrder == FTB && !ftb) ||
+        (paintOrder == BTF && ftb))
+	return;
+    
+    cs->paintOrder = paintOrder;
+    
     if (cs->nOutput > 1)
     {
 	int cubeOutput, dView;
@@ -1145,49 +1250,105 @@ cubeMoveViewportAndPaint (CompScreen		  *s,
 }
 
 static void
-cubePaintTransformedScreen (CompScreen		    *s,
-			    const ScreenPaintAttrib *sAttrib,
-			    const CompTransform	    *transform,
-			    Region		    region,
-			    int			    output,
-			    unsigned int	    mask)
+cubePaintAllViewports (CompScreen              *s,
+                       ScreenPaintAttrib       *sAttrib,
+	               const CompTransform     *transform,
+                       Region		       region,
+                       int                     output,
+                       unsigned int            mask,
+                       int                     xMove,
+                       float                   size, 
+                       int                     hsize,
+                       PaintOrder              paintOrder)
 {
-    ScreenPaintAttrib sa = *sAttrib;
-    int		      hsize, xMove = 0;
-    float	      size;
-    Bool	      clear;
-
-    CUBE_SCREEN (s);
+    CUBE_SCREEN(s);
 
-    hsize = s->hsize * cs->nOutput;
-    size  = hsize;
+    ScreenPaintAttrib sa = *sAttrib;
 
-    if (!cs->fullscreenOutput)
+    int i;
+    int xMoveAdd;
+    int origXMoveAdd = 0;
+    int iFirstSign;	// 1 if we do xMove += i first and -1 if we do xMove -= i first.
+    
+    if (cs->invert == 1)
     {
-	cs->outputXScale = (float) s->width / s->outputDev[output].width;
-	cs->outputYScale = (float) s->height / s->outputDev[output].height;
-
-	cs->outputXOffset =
-	    (s->width / 2.0f -
-	     (s->outputDev[output].region.extents.x1 +
-	      s->outputDev[output].region.extents.x2) / 2.0f) /
-	    (float) s->outputDev[output].width;
-
-	cs->outputYOffset =
-	    (s->height / 2.0f -
-	     (s->outputDev[output].region.extents.y1 +
-	      s->outputDev[output].region.extents.y2) / 2.0f) /
-	    (float) s->outputDev[output].height;
+	// xMove ==> dx for the viewport which is the nearest to the viewer in z axis.
+	// xMove +/- hsize / 2 ==> dx for the viewport which is the farest to the viewer in z axis.
+    
+	if ((sa.xRotate < 0.0f && hsize % 2 == 1) ||
+	    (sa.xRotate > 0.0f && hsize % 2 == 0))
+	{
+	    origXMoveAdd = hsize / 2;
+	    iFirstSign = 1;
+	}
+        
+	else
+	{
+	    origXMoveAdd -= hsize / 2;
+	    iFirstSign = -1;
+	}
     }
+    
     else
     {
-	cs->outputXScale  = 1.0f;
-	cs->outputYScale  = 1.0f;
-	cs->outputXOffset = 0.0f;
-	cs->outputYOffset = 0.0f;
+    	// xMove is already the dx for farest viewport.
+    
+	if (sa.xRotate > 0.0f)
+	    iFirstSign = -1;
+	else
+	    iFirstSign = 1;
     }
+    
+    for (i = 0; i <= hsize / 2; i++)
+    {
+	xMoveAdd = origXMoveAdd;
+    
+	xMoveAdd += iFirstSign * i;
+	
+	if (xMoveAdd < -hsize / 2)
+	    xMoveAdd += hsize;
+	else if (xMoveAdd > hsize / 2)
+	    xMoveAdd -= hsize;
+	
+	xMove += xMoveAdd;
+	
+	sa.yRotate -= cs->invert * xMoveAdd * 360.0f / size;
+	cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
+	                          paintOrder, xMove);
+	sa.yRotate += cs->invert * xMoveAdd * 360.0f / size;
+	
+	xMove -= xMoveAdd;
 
-    clear = cs->cleared[output];
+	if (i == 0 || i * 2 == hsize)	// same viewport.
+	    continue;
+	
+	xMoveAdd = origXMoveAdd;
+	
+	xMoveAdd -= iFirstSign * i;
+	
+	if (xMoveAdd < -hsize / 2)
+	    xMoveAdd += hsize;
+	else if (xMoveAdd > hsize / 2)
+	    xMoveAdd -= hsize;
+	
+	xMove += xMoveAdd;
+
+	sa.yRotate -= cs->invert * xMoveAdd * 360.0f / size;
+	cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
+	                          paintOrder, xMove);
+	sa.yRotate += cs->invert * xMoveAdd * 360.0f / size;
+	
+	xMove -= xMoveAdd;
+    }
+}
+
+static void
+cubePaintSkydome (CompScreen        *s,
+                  ScreenPaintAttrib *sAttrib,
+                  Bool              clear)
+{
+    CUBE_SCREEN(s);
+    
     if (!clear)
     {
 	if (cs->sky.name)
@@ -1214,77 +1375,24 @@ cubePaintTransformedScreen (CompScreen		    *s,
 	{
 	    clearTargetOutput (s->display, GL_COLOR_BUFFER_BIT);
 	}
-
-	cs->cleared[output] = TRUE;
-    }
-
-    mask &= ~PAINT_SCREEN_CLEAR_MASK;
-
-    UNWRAP (cs, s, paintTransformedScreen);
-
-    sa.xTranslate = sAttrib->xTranslate;
-    sa.yTranslate = sAttrib->yTranslate;
-
-    if (cs->grabIndex)
-    {
-	sa.vRotate = 0.0f;
-
-	size += cs->unfold * 8.0f;
-	size += powf (cs->unfold, 6) * 64.0;
-	size += powf (cs->unfold, 16) * 8192.0;
-
-	sa.zTranslate = -cs->invert * (0.5f / tanf (M_PI / size));
-
-	/* distance we move the camera back when unfolding the cube.
-	   currently hardcoded to 1.5 but it should probably be optional. */
-	sa.zCamera -= cs->unfold * 1.5f;
-
-	sa.xRotate = sAttrib->xRotate * cs->invert;
-	if (sa.xRotate > 0.0f)
-	{
-	    cs->xrotations = (int) (hsize * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate - (360.0f * cs->xrotations) / hsize;
-	}
-	else
-	{
-	    cs->xrotations = (int) (hsize * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate -
-		(360.0f * cs->xrotations) / hsize + 360.0f / hsize;
-	    cs->xrotations--;
-	}
-
-	sa.xRotate = sa.xRotate / size * hsize;
     }
-    else
-    {
-	if (sAttrib->vRotate > 100.0f)
-	    sa.vRotate = 100.0f;
-	else if (sAttrib->vRotate < -100.0f)
-	    sa.vRotate = -100.0f;
-	else
-	    sa.vRotate = sAttrib->vRotate;
+}
 
-	sa.zTranslate = -cs->invert * cs->distance;
-	sa.xRotate = sAttrib->xRotate * cs->invert;
-	if (sa.xRotate > 0.0f)
-	{
-	    cs->xrotations = (int) (size * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate - (360.0f * cs->xrotations) / size;
-	}
-	else
-	{
-	    cs->xrotations = (int) (size * sa.xRotate) / 360;
-	    sa.xRotate = sa.xRotate -
-		(360.0f * cs->xrotations) / size + 360.0f / size;
-	    cs->xrotations--;
-	}
-    }
+static void
+cubePaintCaps (CompScreen          *s,
+               ScreenPaintAttrib   *sAttrib,
+               const CompTransform *transform,
+               Bool                clear,
+               int                 output,
+               int                 hsize)
+{
+    CUBE_SCREEN(s);
 
     if (!clear && cs->grabIndex == 0 && hsize > 2 &&
-	(cs->invert != 1 || sa.vRotate != 0.0f || sa.yTranslate != 0.0f))
+	(cs->invert != 1 || sAttrib->vRotate != 0.0f || sAttrib->yTranslate != 0.0f))
     {
 	CompTransform sTransform = *transform;
-	float	      yRotate = (360.0f / size) * (cs->xrotations + 1);
+	float	      yRotate = (360.0f / hsize) * (cs->xrotations + 1);
 
 	screenLighting (s, TRUE);
 
@@ -1293,155 +1401,244 @@ cubePaintTransformedScreen (CompScreen		    *s,
 	glPushMatrix ();
 
 	if (cs->opt[CUBE_SCREEN_OPTION_ADJUST_IMAGE].value.b)
-	{
-	    if (sAttrib->xRotate > 0.0f)
-		yRotate = 360.0f / size;
-	    else
-		yRotate = 0.0f;
-	}
+		yRotate = 360.0f / hsize;
 
-	sa.yRotate += yRotate;
+	sAttrib->yRotate += yRotate;
 
-	(*s->applyScreenTransform) (s, &sa, output, &sTransform);
+	(*s->applyScreenTransform) (s, sAttrib, output, &sTransform);
 	glLoadMatrixf (sTransform.m);
 	glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f);
 	glScalef (cs->outputXScale, cs->outputYScale, 1.0f);
 
-	sa.yRotate -= yRotate;
+	sAttrib->yRotate -= yRotate;
 
 	glVertexPointer (3, GL_FLOAT, 0, cs->vertices);
-
-	glNormal3f (0.0f, -1.0f, 0.0f);
-
-	if (cs->invert == 1 && hsize == 4 && cs->texture.name)
-	{
-	    enableTexture (s, &cs->texture, COMP_TEXTURE_FILTER_GOOD);
-	    glTexCoordPointer (2, GL_FLOAT, 0, cs->tc);
-	    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
-	    disableTexture (s, &cs->texture);
-	    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-	}
-	else
+	
+	int i;
+	for (i = 0; i < 2; i++)
 	{
-	    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
-	    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
+	    if ((i == 0 && sAttrib->vRotate <= 0.0f) ||
+	        (i == 1 && sAttrib->vRotate > 0.0f))
+	    {
+		glNormal3f (0.0f, -1.0f, 0.0f);
+		if (cs->invert == 1 && hsize == 4 && cs->texture.name)
+		{
+		    enableTexture (s, &cs->texture, COMP_TEXTURE_FILTER_GOOD);
+		    glTexCoordPointer (2, GL_FLOAT, 0, cs->tc);
+		    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
+		    disableTexture (s, &cs->texture);
+		    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+		}
+		else
+		{
+		    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+		    glDrawArrays (GL_TRIANGLE_FAN, 0, cs->nvertices >> 1);
+		}
+	    }
+	    else
+	    {
+		glNormal3f (0.0f, 1.0f, 0.0f);
+	        glDrawArrays (GL_TRIANGLE_FAN, cs->nvertices >> 1,
+		              cs->nvertices >> 1);
+	    }
 	}
-
-	glNormal3f (0.0f, 1.0f, 0.0f);
-
-	glDrawArrays (GL_TRIANGLE_FAN, cs->nvertices >> 1,
-		      cs->nvertices >> 1);
-
+	
 	glNormal3f (0.0f, 0.0f, -1.0f);
-
+	
 	glPopMatrix ();
-
+	
 	glColor4usv (defaultColor);
 	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
     }
+}
 
-    /* outside cube */
-    if (cs->invert == 1)
-    {
-	if (cs->grabIndex || hsize > 4)
-	{
-	    GLenum filter;
-	    int    i;
-
-	    xMove = cs->xrotations - ((hsize >> 1) - 1);
-	    sa.yRotate += (360.0f / size) * ((hsize >> 1) - 1);
-
-	    filter = s->display->textureFilter;
-	    if (cs->grabIndex && cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b)
-		s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
-
-	    for (i = 0; i < hsize; i++)
-	    {
-		cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
-					  xMove);
-
-		sa.yRotate -= 360.0f / size;
-		xMove++;
-	    }
-
-	    s->display->textureFilter = filter;
-	}
-	else
-	{
-	    if (sAttrib->xRotate != 0.0f)
-	    {
-		xMove = cs->xrotations;
+static void
+cubePaintTransformedScreen (CompScreen		    *s,
+			    const ScreenPaintAttrib *sAttrib,
+			    const CompTransform	    *transform,
+			    Region		    region,
+			    int			    output,
+			    unsigned int	    mask)
+{
+    ScreenPaintAttrib sa = *sAttrib;
+    int		      hsize, xMove = 0;
+    float	      size;
+    GLenum            filter = s->display->textureFilter;
+    PaintOrder        paintOrder;
+    Bool              clear;
+    
+    CUBE_SCREEN (s);
+    
+    clear = cs->cleared[output];
+    cs->cleared[output] = TRUE;
 
-		cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
-					  xMove);
+    hsize = s->hsize * cs->nOutput;
+    size  = hsize;
 
-		xMove++;
-	    }
+    if (!cs->fullscreenOutput)
+    {
+	cs->outputXScale = (float) s->width / s->outputDev[output].width;
+	cs->outputYScale = (float) s->height / s->outputDev[output].height;
 
-	    sa.yRotate -= 360.0f / size;
+	cs->outputXOffset =
+	    (s->width / 2.0f -
+	     (s->outputDev[output].region.extents.x1 +
+	      s->outputDev[output].region.extents.x2) / 2.0f) /
+	    (float) s->outputDev[output].width;
 
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
-	}
+	cs->outputYOffset =
+	    (s->height / 2.0f -
+	     (s->outputDev[output].region.extents.y1 +
+	      s->outputDev[output].region.extents.y2) / 2.0f) /
+	    (float) s->outputDev[output].height;
     }
     else
     {
-	if (sa.xRotate > 180.0f / size)
-	{
-	    sa.yRotate -= 360.0f / size;
-	    cs->xrotations++;
-	}
+	cs->outputXScale  = 1.0f;
+	cs->outputYScale  = 1.0f;
+	cs->outputXOffset = 0.0f;
+	cs->outputYOffset = 0.0f;
+    }
 
-	sa.yRotate -= 360.0f / size;
-	xMove = -1 - cs->xrotations;
+    cubePaintSkydome (s, &sa, clear);	// Paint skydome first.
 
-	if (cs->grabIndex)
-	{
-	    GLenum filter;
-	    int    i;
+    mask &= ~PAINT_SCREEN_CLEAR_MASK;
 
-	    filter = s->display->textureFilter;
-	    if (cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b)
-		s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
+    UNWRAP (cs, s, paintTransformedScreen);
 
-	    if (sa.xRotate > 180.0f / size)
-	    {
-		xMove -= ((hsize >> 1) - 2);
-		sa.yRotate -= (360.0f / size) * ((hsize >> 1) - 2);
-	    }
-	    else
-	    {
-		xMove -= ((hsize >> 1) - 1);
-		sa.yRotate -= (360.0f / size) * ((hsize >> 1) - 1);
-	    }
+    sa.xTranslate = sAttrib->xTranslate;
+    sa.yTranslate = sAttrib->yTranslate;
 
-	    for (i = 0; i < hsize; i++)
-	    {
-		cubeMoveViewportAndPaint (s, &sa, transform, output, mask,
-					  xMove);
+    if (cs->grabIndex)
+    {
+	sa.vRotate = 0.0f;
 
-		sa.yRotate += 360.0f / size;
-		xMove++;
-	    }
+	size += cs->unfold * 8.0f;
+	size += powf (cs->unfold, 6) * 64.0;
+	size += powf (cs->unfold, 16) * 8192.0;
 
-	    s->display->textureFilter = filter;
-	}
+	sa.zTranslate = -cs->invert * (0.5f / tanf (M_PI / size));
+
+	/* distance we move the camera back when unfolding the cube.
+	   currently hardcoded to 1.5 but it should probably be optional. */
+	sa.zCamera -= cs->unfold * 1.5f;
+    }
+    else
+    {
+	if (sAttrib->vRotate > 100.0f)
+	    sa.vRotate = 100.0f;
+	else if (sAttrib->vRotate < -100.0f)
+	    sa.vRotate = -100.0f;
 	else
-	{
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
+	    sa.vRotate = sAttrib->vRotate;
+
+	sa.zTranslate = -cs->invert * cs->distance;
+    }
+    
+    sa.xRotate = sAttrib->xRotate;
+
+    if (sa.xRotate > 0.0f)
+	cs->xrotations = (int) (hsize * sa.xRotate + 180) / 360;
+    else
+	cs->xrotations = (int) (hsize * sa.xRotate - 180) / 360;
+    
+    sa.xRotate -= (360.0f * cs->xrotations) / hsize;
+    sa.xRotate *= cs->invert;
+    
+    sa.xRotate = sa.xRotate / size * hsize;
+   
+    xMove = cs->xrotations;
+    
+    if (cs->grabIndex && cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b)
+	s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;
+    
+    if (cs->invert == 1)
+	paintOrder = FTB;	// Outside cube - start with FTB faces.
+    else
+	paintOrder = BTF;	// Inside cube -  start with BTF faces.
+    
+    if (cs->paintAllViewports || cs->invert == -1)
+	cubePaintAllViewports(s, &sa, transform, region, output, mask, xMove, size, hsize, paintOrder);
+    
+    cubePaintCaps (s, &sa, transform, clear, output, hsize);	// Paint caps between BTF faces and FTB faces.
+    
+    if (cs->invert == 1)
+	paintOrder = BTF;	// Outside cube - continue with BTF faces.
+    else
+	paintOrder = FTB;	// Inside cube -  continue with FTB faces.	
+    
+    if (cs->paintAllViewports || cs->invert == 1)
+	cubePaintAllViewports(s, &sa, transform, region, output, mask, xMove, size, hsize, paintOrder);
+    
+    s->display->textureFilter = filter;
 
-	    sa.yRotate += 360.0f / size;
-	    xMove = -cs->xrotations;
+    WRAP (cs, s, paintTransformedScreen, cubePaintTransformedScreen);
+}
 
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
+static CompWindow*
+cubeStackFirst (CompScreen* screen)
+{
+    CompWindow* status;
+    CUBE_SCREEN (screen);
+    
+    if (cs->paintOrder == FTB)
+	return screen->reverseWindows;
+    
+    UNWRAP (cs, screen, stackFirst);
+    status = (*screen->stackFirst) (screen);
+    WRAP (cs, screen, stackFirst, cubeStackFirst);
+    
+    return status;
+}
 
-	    sa.yRotate += 360.0f / size;
-	    xMove = 1 - cs->xrotations;
+static CompWindow*
+cubeStackLast (CompScreen* screen)
+{
+    CompWindow* status;
+    CUBE_SCREEN (screen);
+    
+    if (cs->paintOrder == FTB)
+	return screen->windows;
+    
+    UNWRAP (cs, screen, stackLast);
+    status = (*screen->stackLast) (screen);
+    WRAP (cs, screen, stackLast, cubeStackLast);
+    
+    return status;
+}
 
-	    cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove);
-	}
-    }
+static CompWindow*
+cubeStackNext (CompWindow* window)
+{
+    CompWindow* status;
+    CompScreen *screen = window->screen;
+    CUBE_SCREEN (screen);
+    
+    if (cs->paintOrder == FTB)
+	return window->prev;
+    
+    UNWRAP (cs, screen, stackNext);
+    status = (*screen->stackNext) (window);
+    WRAP (cs, screen, stackNext, cubeStackNext);
+    
+    return status;
+}
 
-    WRAP (cs, s, paintTransformedScreen, cubePaintTransformedScreen);
+static CompWindow*
+cubeStackPrev (CompWindow* window)
+{
+    CompWindow *status;
+    CompScreen *screen = window->screen;
+    CUBE_SCREEN (screen);
+    
+    if (cs->paintOrder == FTB)
+	return window->next;
+    
+    UNWRAP (cs, screen, stackPrev);
+    status = (*screen->stackPrev) (window);
+    WRAP (cs, screen, stackPrev, cubeStackPrev);
+    
+    return status;
 }
 
 static void
@@ -1991,8 +2188,6 @@ cubeInitScreen (CompPlugin *p,
 
     s->privates[cd->screenPrivateIndex].ptr = cs;
 
-    cs->paintTopBottom = FALSE;
-
     initTexture (s, &cs->texture);
     initTexture (s, &cs->sky);
 
@@ -2040,6 +2235,10 @@ cubeInitScreen (CompPlugin *p,
     WRAP (cs, s, setScreenOption, cubeSetGlobalScreenOption);
     WRAP (cs, s, outputChangeNotify, cubeOutputChangeNotify);
     WRAP (cs, s, setClipPlanes, cubeSetClipPlanes);
+    WRAP (cs, s, stackFirst, cubeStackFirst);
+    WRAP (cs, s, stackLast, cubeStackLast);
+    WRAP (cs, s, stackNext, cubeStackNext);
+    WRAP (cs, s, stackPrev, cubeStackPrev);
 
     return TRUE;
 }
@@ -2062,6 +2261,10 @@ cubeFiniScreen (CompPlugin *p,
     UNWRAP (cs, s, setScreenOption);
     UNWRAP (cs, s, outputChangeNotify);
     UNWRAP (cs, s, setClipPlanes);
+    UNWRAP (cs, s, stackFirst);
+    UNWRAP (cs, s, stackLast);
+    UNWRAP (cs, s, stackNext);
+    UNWRAP (cs, s, stackPrev);
 
     finiTexture (s, &cs->texture);
     finiTexture (s, &cs->sky);
-- 
1.4.4.2