diff --git a/plugins/cube.c b/plugins/cube.c index f7c2e12..06effb2 100644 --- a/plugins/cube.c +++ b/plugins/cube.c @@ -134,6 +134,37 @@ typedef struct _CubeDisplay { #define CUBE_SCREEN_OPTION_MIPMAP 12 #define CUBE_SCREEN_OPTION_NUM 13 +#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 struct _CubeScreen { PreparePaintScreenProc preparePaintScreen; DonePaintScreenProc donePaintScreen; @@ -1230,6 +1261,59 @@ 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, @@ -1240,6 +1324,13 @@ cubeMoveViewportAndPaint (CompScreen *s, { CUBE_SCREEN (s); + Bool ftb = cubeCheckFTB(s, sAttrib, transform, output); + + if (ftb && !(mask & PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK)) + return; + if (!ftb && (mask & PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK)) + return; + if (cs->nOutput > 1) { int cubeOutput, dView; @@ -1279,6 +1370,76 @@ cubeMoveViewportAndPaint (CompScreen *s, } } +void +cubePaintAllViewports (CompScreen *s, + ScreenPaintAttrib *sAttrib, + const CompTransform *transform, + Region region, + int output, + unsigned int mask, + int xMove, + int size, + int hsize) +{ + CUBE_SCREEN(s); + + ScreenPaintAttrib sa = *sAttrib; + + int i; + int iFirstSign; // 1 if we do xMove += i first and -1 if we do xMove -= i first. + + if (cs->invert == 1) + { + // 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)) + { + xMove += hsize / 2; + sa.yRotate -= (hsize / 2) * 360.0f / size; + iFirstSign = 1; + } + + else + { + xMove -= hsize / 2; + sa.yRotate += (hsize / 2) * 360.0f / size; + iFirstSign = -1; + } + } + + else + { + // 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++) + { + xMove += iFirstSign * i; + sa.yRotate -= cs->invert * iFirstSign * i * 360.0f / size; + cubeMoveViewportAndPaint (s, &sa, transform, output, mask, + xMove); + sa.yRotate += cs->invert * iFirstSign * i * 360.0f / size; + xMove -= iFirstSign * i; + + if (i == 0 || i * 2 == hsize) // same viewport. + continue; + + xMove -= iFirstSign * i; + sa.yRotate += cs->invert * iFirstSign * i * 360.0f / size; + cubeMoveViewportAndPaint (s, &sa, transform, output, mask, + xMove); + sa.yRotate -= cs->invert * iFirstSign * i * 360.0f / size; + xMove += iFirstSign * i; + } +} + static void cubePaintTransformedScreen (CompScreen *s, const ScreenPaintAttrib *sAttrib, @@ -1291,6 +1452,7 @@ cubePaintTransformedScreen (CompScreen *s, int hsize, xMove = 0; float size; Bool clear; + GLenum filter = s->display->textureFilter; CUBE_SCREEN (s); @@ -1372,22 +1534,6 @@ cubePaintTransformedScreen (CompScreen *s, /* 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 { @@ -1399,20 +1545,34 @@ cubePaintTransformedScreen (CompScreen *s, 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--; - } } + + 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) / size; + sa.xRotate *= cs->invert; + + 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) + mask |= PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK; // Outside cube - start with FTB faces. + // Inside cube - start with BTF faces. + + if (cs->paintAllViewports || cs->invert == -1) + cubePaintAllViewports(s, &sa, transform, region, output, mask, xMove, size, hsize); + + if (cs->invert == 1) + mask &= ~PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK; // Outside cube - continue with caps and then BTF faces. + else + mask |= PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK; // Inside cube - continue with caps and then FTB faces. if (!clear && cs->grabIndex == 0 && hsize > 2 && (cs->invert != 1 || sa.vRotate != 0.0f || sa.yTranslate != 0.0f)) @@ -1425,39 +1585,40 @@ cubePaintTransformedScreen (CompScreen *s, glPushMatrix (); - if (sAttrib->xRotate > 0.0f) - { - sa.yRotate += 360.0f / size; - (*s->applyScreenTransform) (s, &sa, output, &sTransform); - glLoadMatrixf (sTransform.m); - glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f); - glScalef (cs->outputXScale, cs->outputYScale, 1.0f); - sa.yRotate -= 360.0f / size; - } - else - { - (*s->applyScreenTransform) (s, &sa, output, &sTransform); - glLoadMatrixf (sTransform.m); - glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f); - glScalef (cs->outputXScale, cs->outputYScale, 1.0f); - } + (*s->applyScreenTransform) (s, &sa, output, &sTransform); + glLoadMatrixf (sTransform.m); + glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f); + glScalef (cs->outputXScale, cs->outputYScale, 1.0f); glVertexPointer (3, GL_FLOAT, 0, cs->vertices); - glNormal3f (0.0f, -1.0f, 0.0f); - - if (cs->invert == 1 && hsize == 4 && cs->texture.name) + int i; + for (i = 0; i < 2; i++) { - 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); + 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); @@ -1473,108 +1634,12 @@ cubePaintTransformedScreen (CompScreen *s, 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; - - cubeMoveViewportAndPaint (s, &sa, transform, output, mask, - xMove); - - xMove++; - } - - sa.yRotate -= 360.0f / size; - - cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove); - } - } - else - { - if (sa.xRotate > 180.0f / size) - { - sa.yRotate -= 360.0f / size; - cs->xrotations++; - } - - sa.yRotate -= 360.0f / size; - xMove = -1 - cs->xrotations; - - if (cs->grabIndex) - { - GLenum filter; - int i; - - filter = s->display->textureFilter; - if (cs->opt[CUBE_SCREEN_OPTION_MIPMAP].value.b) - s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR; - - 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); - } - - for (i = 0; i < hsize; i++) - { - cubeMoveViewportAndPaint (s, &sa, transform, output, mask, - xMove); - - sa.yRotate += 360.0f / size; - xMove++; - } - - s->display->textureFilter = filter; - } - else - { - cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove); - - sa.yRotate += 360.0f / size; - xMove = -cs->xrotations; - - cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove); - - sa.yRotate += 360.0f / size; - xMove = 1 - cs->xrotations; - - cubeMoveViewportAndPaint (s, &sa, transform, output, mask, xMove); - } - } + if (cs->paintAllViewports || cs->invert == 1) + cubePaintAllViewports(s, &sa, transform, region, output, mask, xMove, size, hsize); WRAP (cs, s, paintTransformedScreen, cubePaintTransformedScreen); + + s->display->textureFilter = filter; } static void cubeSetClipPlanes (CompScreen *s, Region region, int output)