Logo Search packages:      
Sourcecode: beryl-plugins version File versions

3d.c

/**
 *
 * Beryl 3d plugin
 *
 * 3d.c
 *
 * Copyright : (C) 2006 by Roi Cohen
 * E-mail    : roico12@gmail.com
 *
 * Modified and maintained by : Robert Carr <racarr@beryl-project.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 **/

/**
TODO:
        1. Add 3d shadows / projections.
        3. Add an option to select z-order of windows not only by viewports but also by screens.
        4. Fix 3d for inside cube and planed / unfolded cube.
        5. Find a better solution for blur cache + 3d.
        6. Fix bugs with 3d + animations / wobbly.
            - Wobbly will draw the window twice if its in 2 different viewports.
            - Many Bugs with animations, some are solvable by changing the load order, but it will result with clipping when animations are done.
*/

#define _GNU_SOURCE

#include <stdlib.h>
#include <math.h>

#include <beryl.h>
#include <beryl_helpers.h>

#define PI 3.14159265359f

#define TD_SPACE_DEFAULT    0.04f
#define TD_SPACE_MIN        0.0f
#define TD_SPACE_MAX        1.0f
#define TD_SPACE_PRECISION  0.01f

#define TD_WIDTH_DEFAULT    0.29f
#define TD_WIDTH_MIN        0.0f
#define TD_WIDTH_MAX        0.01f
#define TD_WIDTH_PRECISION  0.001f

#define TD_SPEED_DEFAULT    0.005f
#define TD_SPEED_MIN        0.0f
#define TD_SPEED_MAX        1.0f
#define TD_SPEED_PRECISION  0.001f

#define TD_BEVEL_DEFAULT 0
#define TD_BEVEL_MIN    0
#define TD_BEVEL_MAX    20
#define TD_BEVEL_PRECISION 1

#define TD_DEPTH_DEFAULT TRUE

#define TD_TOPLEFT_DEFAULT TRUE
#define TD_TOPRIGHT_DEFAULT TRUE
#define TD_BOTTOMLEFT_DEFAULT FALSE
#define TD_BOTTOMRIGHT_DEFAULT FALSE

#define TD_CREATE_MIPMAPS_DEFAULT FALSE

#define TD_DISABLE_BACKFACE_CULLING_DEFAULT TRUE

#define TD_DISABLE_CAPS_IN_INSIDE_CUBE_DEFAULT TRUE

#define TD_SCREEN_OPTION_MANUAL_ONLY_DEFAULT TRUE

#define TD_SCREEN_OPTION_SPACE                        0
#define TD_SCREEN_OPTION_SPEED                        1
#define TD_SCREEN_OPTION_CREATE_MIPMAPS               2
#define TD_SCREEN_OPTION_DISABLE_BACKFACE_CULLING     3
#define TD_SCREEN_OPTION_DISABLE_CAPS_IN_INSIDE_CUBE  4
#define TD_SCREEN_OPTION_MANUAL_ONLY                  5
#define TD_SCREEN_OPTION_WIDTH                        6
#define TD_SCREEN_OPTION_BEVEL                        7
#define     TD_SCREEN_OPTION_BEVEL_TOPRIGHT                 8
#define     TD_SCREEN_OPTION_BEVEL_TOPLEFT                  9
#define     TD_SCREEN_OPTION_BEVEL_BOTTOMRIGHT        10
#define TD_SCREEN_OPTION_BEVEL_BOTTOMLEFT       11
#define TD_SCREEN_OPTION_DEPTH                        12
#define TD_SCREEN_OPTION_NUM                    13

#define GETBEVEL(corner) \
      tds->opt[TD_SCREEN_OPTION_BEVEL_##corner].value.b

#define SPEED (tds->opt[TD_SCREEN_OPTION_SPEED].value.f)
#define SPACE (tds->opt[TD_SCREEN_OPTION_SPACE].value.f)
#define CREATE_MIPMAPS (tds->opt[TD_SCREEN_OPTION_CREATE_MIPMAPS].value.b)
#define DISABLE_BACKFACE_CULLING (tds->opt[TD_SCREEN_OPTION_DISABLE_BACKFACE_CULLING].value.b)
#define DISABLE_CAPS (tds->opt[TD_SCREEN_OPTION_DISABLE_CAPS_IN_INSIDE_CUBE].value.b)
#define MANUAL_ONLY (tds->opt[TD_SCREEN_OPTION_MANUAL_ONLY].value.b)

static int displayPrivateIndex;

typedef struct _revertReorder
{
      struct _revertReorder *next;
      struct _revertReorder *prev;

      CompWindow *window;

      CompWindow *nextWindow;
      CompWindow *prevWindow;
} RevertReorder;


typedef enum _MultiMonitorMode
{
      Multiple,
      OneBig,
} MultiMonitorMode;


typedef struct _tdDisplay
{
      int screenPrivateIndex;
} tdDisplay;



typedef struct _tdScreen
{

      int windowPrivateIndex;
      CompOption opt[TD_SCREEN_OPTION_NUM];

      Bool tdWindowExists;
      //Bool reorder;

      PreparePaintScreenProc preparePaintScreen;

      PaintTransformedScreenProc paintTransformedScreen;
      PaintScreenProc paintScreen;

      DonePaintScreenProc donePaintScreen;

      PaintWindowProc paintWindow;

      RevertReorder *revertReorder;

      float maxZ;

      int currentViewportNum;
      float xMove;

      int mmModeAtom;
      MultiMonitorMode currentMmMode;

      int insideAtom;
      int manualAtom;
      Bool currentDifferentResolutions;

      int currentScreenNum;

      float mvm[16];                      //ModelView Matrix.
      float pm[16];                       //Projection Matrix.
      float pmvm[16];                     //Projection * ModelView matrix.

      Bool reorderWindowPainting;
      int tmpOutput;
      int unfoldedAtom;
} tdScreen;

typedef struct _tdWindow
{
      float z;
      float currentZ;
} tdWindow;


#define GET_TD_DISPLAY(d)       \
        ((tdDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define TD_DISPLAY(d)   \
        tdDisplay *tdd = GET_TD_DISPLAY (d)

#define GET_TD_SCREEN(s, tdd)   \
        ((tdScreen *) (s)->privates[(tdd)->screenPrivateIndex].ptr)

#define TD_SCREEN(s)    \
        tdScreen *tds = GET_TD_SCREEN (s, GET_TD_DISPLAY (s->display))

#define GET_TD_WINDOW(w, tds)                                     \
        ((tdWindow *) (w)->privates[(tds)->windowPrivateIndex].ptr)

#define TD_WINDOW(w)    \
        tdWindow *tdw = GET_TD_WINDOW  (w,                     \
                GET_TD_SCREEN  (w->screen,             \
                        GET_TD_DISPLAY (w->screen->display)))



#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))

static Bool windowIs3D(CompWindow * w)
{
      if (w->attrib.override_redirect)
            return FALSE;

      if (!(w->shaded || w->attrib.map_state == IsViewable))
            return FALSE;

      if (w->wmType & (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
            return FALSE;

      if (w->type & (CompWindowTypeDialogMask |
                           CompWindowTypeModalDialogMask |
                           CompWindowTypeUtilMask | CompWindowTypeNormalMask))
            return TRUE;

      return FALSE;
}

static Bool differentResolutions(CompScreen * s)
{
      //This code is taken from cube plugin... thanks for whoever wrote it (davidr i guess).

      BoxPtr pBox0, pBox1;
      int i, j, k;

      k = 0;

      for (i = 0; i < s->nOutputDev; i++)
      {
            /* dimensions must match first output */
            if (s->outputDev[i].width != s->outputDev[0].width ||
                  s->outputDev[i].height != s->outputDev[0].height)
                  continue;

            pBox0 = &s->outputDev[0].region.extents;
            pBox1 = &s->outputDev[i].region.extents;

            /* top and bottom line must match first output */
            if (pBox0->y1 != pBox1->y1 || pBox0->y2 != pBox1->y2)
                  continue;

            k++;

            for (j = 0; j < s->nOutputDev; j++)
            {
                  pBox0 = &s->outputDev[j].region.extents;

                  /* must not intersect other output region */
                  if (i != j && pBox0->x2 > pBox1->x1 && pBox0->x1 < pBox1->x2)
                  {
                        k--;
                        break;
                  }
            }
      }

      if (k != s->nOutputDev)
            return TRUE;

      return FALSE;
}

#define REAL_POSITION(x, s) ( (x >= 0)? x: x + (s)->hsize * (s)->width )

#define VIEWPORT(x, s) ( ( REAL_POSITION(x, s) / (s)->width ) % (s)->hsize )
#define SCREEN(x, s)   ( ( REAL_POSITION(x, s) % (s)->width ) / (s)->outputDev[0].width )

#define RIGHT_VIEWPORT(w) VIEWPORT( (w)->attrib.x + (w)->attrib.width + (w)->input.right -1, (w)->screen)
#define LEFT_VIEWPORT(w) VIEWPORT( (w)->attrib.x + 1 - (w)->input.left, (w)->screen)

#define RIGHT_SCREEN(w) SCREEN( (w)->attrib.x + (w)->attrib.width -1+w->input.right, (w)->screen)
#define LEFT_SCREEN(w) SCREEN( (w)->attrib.x + 1-w->input.left , (w)->screen)

#define IS_IN_VIEWPORT(w, i) ( ( LEFT_VIEWPORT(w) > RIGHT_VIEWPORT(w) && !(LEFT_VIEWPORT(w) > i && i > RIGHT_VIEWPORT(w)) ) \
                                || ( LEFT_VIEWPORT(w) <= i && i <= RIGHT_VIEWPORT(w) ) )

#define DO_3D(d,s) (compDisplayGetRequestFlagForAny (d, "ENABLE_3D") && !(tds->opt[TD_SCREEN_OPTION_MANUAL_ONLY].value.b && \
 !IPCS_GetBool(IPCS_OBJECT(s),tds->manualAtom)))

static void reorder(CompScreen * screen)
{
      CompWindow *firstReordered = NULL;
      CompWindow *next;
      CompWindow *w;

      TD_SCREEN(screen);

      for (w = screen->windows; w && w != firstReordered; w = next)
      {
            next = w->next;

            if (!windowIs3D(w))
                  continue;

            if (!firstReordered)
                  firstReordered = w;

            if (tds->revertReorder)
            {
                  tds->revertReorder->next =
                              (RevertReorder *) malloc(sizeof(RevertReorder));
                  tds->revertReorder->next->prev = tds->revertReorder;

                  tds->revertReorder = tds->revertReorder->next;
            }

            else
            {
                  tds->revertReorder =
                              (RevertReorder *) malloc(sizeof(RevertReorder));
                  tds->revertReorder->prev = NULL;
            }

            tds->revertReorder->next = NULL;

            tds->revertReorder->window = w;
            tds->revertReorder->nextWindow = w->next;
            tds->revertReorder->prevWindow = w->prev;

            unhookWindowFromScreen(screen, w);

            /*This is a faster replacement to insertWindowIntoScreen (screen, w, screen->reverseWindows->id)
               The original function will go through all the windows until it finds screen->reverseWindows->id
               But we already know where that window is, so it's unnecessary to go through all the windows. */
            if (screen->windows)
            {
                  screen->reverseWindows->next = w;
                  w->next = NULL;
                  w->prev = screen->reverseWindows;
                  screen->reverseWindows = w;
            }

            else
            {
                  screen->reverseWindows = screen->windows = w;
                  w->prev = w->next = NULL;
            }
      }
}

static void revertReorder(CompScreen * screen)
{
      TD_SCREEN(screen);

      while (tds->revertReorder)
      {
            unhookWindowFromScreen(screen, tds->revertReorder->window);

            tds->revertReorder->window->next = tds->revertReorder->nextWindow;
            tds->revertReorder->window->prev = tds->revertReorder->prevWindow;

            if (tds->revertReorder->nextWindow)
                  tds->revertReorder->nextWindow->prev = tds->revertReorder->window;
            else
                  screen->reverseWindows = tds->revertReorder->window;

            if (tds->revertReorder->prevWindow)
                  tds->revertReorder->prevWindow->next = tds->revertReorder->window;
            else
                  screen->windows = tds->revertReorder->window;

            if (tds->revertReorder->prev)
            {
                  tds->revertReorder = tds->revertReorder->prev;

                  free(tds->revertReorder->next);
                  tds->revertReorder->next = NULL;
            }

            else
            {
                  free(tds->revertReorder);
                  tds->revertReorder = NULL;
            }
      }
}

static void tdPreparePaintScreen(CompScreen * screen, int msSinceLastPaint)
{
      tdWindow **lastInViewport;

      CompWindow *w;

      tdWindow *tdw;

      int i;

      float maxZoom;

      TD_SCREEN(screen);

      if (tds->currentMmMode !=
            IPCS_GetInt(IPCS_OBJECT(screen), tds->mmModeAtom)
            || tds->currentViewportNum != screen->hsize
            || tds->currentScreenNum != screen->nOutputDev
            || tds->currentDifferentResolutions != differentResolutions(screen))
      {
            tds->currentViewportNum = screen->hsize;
            tds->currentMmMode =
                        IPCS_GetInt(IPCS_OBJECT(screen), tds->mmModeAtom);
            tds->currentScreenNum = screen->nOutputDev;
            tds->currentDifferentResolutions = differentResolutions(screen);

            if (tds->currentViewportNum > 2
                  && (tds->currentMmMode != Multiple || screen->nOutputDev == 1))
                  tds->xMove =
                              1.0f /
                              (tan
                               (PI * (tds->currentViewportNum - 2.0f) /
                                (2.0f * tds->currentViewportNum)));
            else
                  tds->xMove = 0.0f;
      }

      if (!DO_3D(screen->display, screen))
      {
            //tds->reorder = TRUE;

            if (tds->tdWindowExists)
                  reorder(screen);

            UNWRAP(tds, screen, preparePaintScreen);
            (*screen->preparePaintScreen) (screen, msSinceLastPaint);
            WRAP(tds, screen, preparePaintScreen, tdPreparePaintScreen);

            return;
      }

      compDisplaySetRequestFlagForPlugin(screen->display, "3d",
                                                         "DRAW_ALL_FACES");

      lastInViewport = (tdWindow **) malloc(sizeof(tdWindow *) * screen->hsize);

      for (i = 0; i < screen->hsize; i++)
            lastInViewport[i] = NULL;

      tds->maxZ = 0.0f;

      for (w = screen->windows; w; w = w->next)
      {
            if (!windowIs3D(w))
                  continue;

            tdw = GET_TD_WINDOW(w, tds);
            maxZoom = 0.0f;

            for (i = 0; i < screen->hsize; i++)
            {
                  if (IS_IN_VIEWPORT(w, i))
                  {
                        if (lastInViewport[i] && lastInViewport[i]->z > maxZoom)
                              maxZoom = lastInViewport[i]->z;

                        lastInViewport[i] = tdw;
                  }
            }

            tdw->z = maxZoom + SPACE;

            if (tdw->z > tds->maxZ)
                  tds->maxZ = tdw->z;
      }

      if (tds->maxZ > 0.0f
            && IPCS_GetBool(IPCS_OBJECT(screen), tds->insideAtom) && DISABLE_CAPS)
            compDisplaySetRequestFlagForPlugin(screen->display, "3d",
                                                               "NO_CUBE_CAPS");

      reorder(screen);

      //tds->reorder = FALSE;

      free(lastInViewport);

      UNWRAP(tds, screen, preparePaintScreen);
      (*screen->preparePaintScreen) (screen, msSinceLastPaint);
      WRAP(tds, screen, preparePaintScreen, tdPreparePaintScreen);
}

static Bool
tdPaintWindow(CompWindow * w,
                    const WindowPaintAttrib * attrib,
                    Region region, unsigned int mask)
{
      Bool status;
      Bool wasCulled = glIsEnabled(GL_CULL_FACE);

      TD_SCREEN(w->screen);
      TD_WINDOW(w);

      int output = tds->tmpOutput;
      int width;

      width = w->screen->width;

      if (DO_3D(w->screen->display, w->screen) && tds->reorderWindowPainting && !(w->state & CompWindowStateOffscreenMask))
      {
            //Window painting is done twice, once in reverse mode and one in normal.
            //We should paint it only in the needed mode.

            if (((w->attrib.y + w->attrib.height) > w->screen->workArea.height)
                  && (w->attrib.x > w->screen->workArea.x) &&
                  ((w->attrib.x + w->attrib.width) < w->screen->workArea.width))

                  mask |= PAINT_WINDOW_TRANSFORMED_MASK;


            float pntA[4] = { w->screen->outputDev[output].region.extents.x1,
                  w->screen->outputDev[output].region.extents.y1,
                  tdw->currentZ, 1
            };

            float pntB[4] = { w->screen->outputDev[output].region.extents.x2,
                  w->screen->outputDev[output].region.extents.y1,
                  tdw->currentZ, 1
            };

            float pntC[4] =
                        { w->screen->outputDev[output].region.extents.x1 +
                  w->screen->outputDev[output].width / 2.0f,
                  w->screen->outputDev[output].region.extents.y1 +
                              w->screen->outputDev[output].height / 2.0f,
                  tdw->currentZ, 1
            };

            MULTMV(tds->pmvm, pntA);
            DIVV(pntA);

            MULTMV(tds->pmvm, pntB);
            DIVV(pntB);

            MULTMV(tds->pmvm, 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 window is reversed, should be painted front to back.
            {
                  if (mask & PAINT_WINDOW_BACK_TO_FRONT_MASK)
                        return TRUE;
            }

            else
            {
                  if (mask & PAINT_WINDOW_FRONT_TO_BACK_MASK)
                        return TRUE;
            }
      }

      glPushMatrix();

      if (tdw->currentZ != 0.0f)
      {
            if (mask & PAINT_WINDOW_FRONT_TO_BACK_MASK)
                  glNormal3f(0.0, 0.0, 1.0);
            else
                  glNormal3f(0.0, 0.0, -1.0);

            glTranslatef(0.0f, 0.0f, tdw->currentZ);

            if (wasCulled && DISABLE_BACKFACE_CULLING)
                  glDisable(GL_CULL_FACE);

            if (!IS_IN_VIEWPORT(w, 0))
            {
                  float angle = 360 / tds->currentViewportNum;

                  glScalef(1.0f, 1.0f, 1.0f / width);

                  if (RIGHT_VIEWPORT(w) == w->screen->hsize - 1)
                  {
                        glTranslatef(-width * tdw->currentZ * tds->xMove, 0.0f, 0.0f);
                        glRotatef(-angle, 0.0f, 1.0f, 0.0f);
                        glTranslatef(-width * tdw->currentZ * tds->xMove, 0.0f, 0.0f);
                  }

                  else if (LEFT_VIEWPORT(w) == 1)
                  {
                        glTranslatef(width +
                                           width * tdw->currentZ * tds->xMove, 0.0f, 0.0f);
                        glRotatef(angle, 0.0f, 1.0f, 0.0f);
                        glTranslatef(width * tdw->currentZ *
                                           tds->xMove - width, 0.0f, 0.0f);
                  }
            }

            if ((LEFT_VIEWPORT(w) != RIGHT_VIEWPORT(w)) && !IPCS_GetBool(IPCS_OBJECT(w->screen),tds->unfoldedAtom))
            {
                  if (LEFT_VIEWPORT(w) == 0 && 1)
                  {
                        glTranslatef(width * tdw->currentZ * tds->xMove, 0.0f, 0.0f);
                  }

                  if (RIGHT_VIEWPORT(w) == 0 && 1)
                  {
                        glTranslatef(-width * tdw->currentZ * tds->xMove, 0.0f, 0.0f);
                  }
            }

            int wx, wy, wx2, wy2, ww, wh;

            wx = w->attrib.x - w->input.left;
            wy = w->attrib.y - w->input.top;
            wx2 = wx + w->attrib.width + w->input.left + w->input.right;
            wy2 = wy + w->attrib.height + w->input.top + w->input.bottom;

            wx = MIN(w->screen->width,wx);
            wx = MAX(0,wx);
            wx2 = MIN(w->screen->width,wx2);
            wx2 = MAX(0,wx2);

            wy = MIN(w->screen->height,wy);
            wy = MAX(0,wy);
            wy2 = MIN(w->screen->height,wy2);
            wy2 = MAX(0,wy2);

            ww = wx2 - wx;
            wh = wy2 - wy;

            float wwidth = -(tds->opt[TD_SCREEN_OPTION_WIDTH].value.f) / 30;
            int bevel = tds->opt[TD_SCREEN_OPTION_BEVEL].value.i;


            if (tds->opt[TD_SCREEN_OPTION_DEPTH].value.b && ww && wh)
            {
                  if (mask & PAINT_WINDOW_BACK_TO_FRONT_MASK)
                  {
                        glEnable(GL_CULL_FACE); // Make sure culling is on.
                        glCullFace(GL_FRONT);

                        glTranslatef(0.0f, 0.0f, wwidth);

                        UNWRAP(tds, w->screen, paintWindow);
                        status = (*w->screen->paintWindow) (w, attrib, region, mask);
                        WRAP(tds, w->screen, paintWindow, tdPaintWindow);

                        glTranslatef(0.0f, 0.0f, -wwidth);
                  }

                  else
                  {
                        glEnable(GL_CULL_FACE); // Make sure culling is on.
                        glCullFace(GL_BACK);

                        UNWRAP(tds, w->screen, paintWindow);
                        status = (*w->screen->paintWindow) (w, attrib, region, mask);
                        WRAP(tds, w->screen, paintWindow, tdPaintWindow);
                  }

                  /* Paint window depth. */
                  glDisable(GL_CULL_FACE);
                  glEnable(GL_BLEND);

                  glBegin(GL_QUADS);
                  glColor4f(.90f, .90f, .90f, w->paint.opacity/OPAQUE);

      #define DOBEVEL(corner) (GETBEVEL(corner) ? bevel : 0)

                  /* Top */
                  glVertex3f(wx + DOBEVEL(TOPLEFT), wy, 0);
                  glVertex3f(wx + ww - DOBEVEL(TOPRIGHT), wy, 0);
                  glVertex3f(wx + ww - DOBEVEL(TOPRIGHT), wy, (wwidth));
                  glVertex3f(wx + DOBEVEL(TOPLEFT), wy, (wwidth));

                  /* Bottom */
                  glVertex3f(wx + DOBEVEL(BOTTOMLEFT), wy + wh, 0);
                  glVertex3f(wx + ww - DOBEVEL(BOTTOMRIGHT), wy + wh, 0);
                  glVertex3f(wx + ww - DOBEVEL(BOTTOMRIGHT), wy + wh, wwidth);
                  glVertex3f(wx + DOBEVEL(BOTTOMLEFT), wy + wh, wwidth);


                  glColor4f(.70f, .70f, .70f,  w->paint.opacity/OPAQUE);

                  /* Left */
                  if (!(w->attrib.x < w->screen->workArea.x))
                  {
                        glVertex3f(wx, wy + DOBEVEL(TOPLEFT), 0);
                        glVertex3f(wx, wy + wh - DOBEVEL(BOTTOMLEFT), 0);
                        glVertex3f(wx, wy + wh - DOBEVEL(BOTTOMLEFT), wwidth);
                        glVertex3f(wx, wy + DOBEVEL(TOPLEFT), wwidth);
                  }


                  /* Right */
                  if (!
                        ((w->attrib.x + w->attrib.width + w->input.left +
                          w->input.right) > w->screen->workArea.width))
                  {
                        glVertex3f(wx + ww, wy + DOBEVEL(TOPRIGHT), 0);
                        glVertex3f(wx + ww, wy + wh - DOBEVEL(BOTTOMRIGHT), 0);
                        glVertex3f(wx + ww, wy + wh - DOBEVEL(BOTTOMRIGHT), wwidth);
                        glVertex3f(wx + ww, wy + DOBEVEL(TOPRIGHT), wwidth);
                  }

                  glColor4f(.95f, .95f, .95f,  w->paint.opacity/OPAQUE);

                  if (!(w->attrib.x < w->screen->workArea.x))
                  {
                        /* Top left bevel */
                        if (GETBEVEL(TOPLEFT))
                        {
                              glVertex3f(wx, wy + bevel, wwidth);
                              glVertex3f(wx, wy + bevel, 0);
                              glVertex3f(wx + bevel / 2.0f, wy + bevel - bevel / 1.2f, 0);
                              glVertex3f(wx + bevel / 2.0f, wy + bevel - bevel / 1.2f,
                                             wwidth);

                              glColor4f(1.0f, 1.0f, 1.0f,  w->paint.opacity/OPAQUE);

                              glVertex3f(wx + bevel / 2.0f, wy + bevel - bevel / 1.2f, 0);
                              glVertex3f(wx + bevel / 2.0f, wy + bevel - bevel / 1.2f,
                                             wwidth);
                              glVertex3f(wx + bevel, wy, wwidth);
                              glVertex3f(wx + bevel, wy, 0);

                              glColor4f(.95f, .95f, .95f,  w->paint.opacity/OPAQUE);
                        }
                        /* Bottom left bevel */
                        if (GETBEVEL(BOTTOMLEFT))
                        {
                              glVertex3f(wx, wy + wh - bevel, 0);
                              glVertex3f(wx, wy + wh - bevel, wwidth);
                              glVertex3f(wx + bevel / 2.0f, wy + wh - bevel + bevel / 1.2f,
                                             wwidth);
                              glVertex3f(wx + bevel / 2.0f, wy + wh - bevel + bevel / 1.2f,
                                             0);

                              glColor4f(1.0f, 1.0f, 1.0f,  w->paint.opacity/OPAQUE);

                              glVertex3f(wx + bevel / 2.0f, wy + wh - bevel + bevel / 1.2f,
                                             wwidth);
                              glVertex3f(wx + bevel / 2.0f, wy + wh - bevel + bevel / 1.2f,
                                             0);
                              glVertex3f(wx + bevel, wy + wh, 0);
                              glVertex3f(wx + bevel, wy + wh, wwidth);
                        }
                  }

                  glColor4f(.95f, .95f, .95f,  w->paint.opacity/OPAQUE);


                  if (!
                        ((w->attrib.x + w->attrib.width + w->input.left +
                          w->input.right) > w->screen->workArea.width))
                  {

                        /* Bottom right bevel */
                        if (GETBEVEL(BOTTOMRIGHT))
                        {
                              glVertex3f(wx + ww - bevel, wy + wh, 0);
                              glVertex3f(wx + ww - bevel, wy + wh, wwidth);
                              glVertex3f(wx + ww - bevel / 2.0f,
                                             wy + wh - bevel + bevel / 1.2f, wwidth);
                              glVertex3f(wx + ww - bevel / 2.0f,
                                             wy + wh - bevel + bevel / 1.2f, 0);

                              glColor4f(1.0f, 1.0f, 1.0f,  w->paint.opacity/OPAQUE);

                              glVertex3f(wx + ww - bevel / 2.0f,
                                             wy + wh - bevel + bevel / 1.2f, wwidth);
                              glVertex3f(wx + ww - bevel / 2.0f,
                                             wy + wh - bevel + bevel / 1.2f, 0);
                              glVertex3f(wx + ww, wy + wh - bevel, 0);
                              glVertex3f(wx + ww, wy + wh - bevel, wwidth);

                              glColor4f(.95f, .95f, .95f,  w->paint.opacity/OPAQUE);
                        }
                        /* Top right bevel */
                        if (GETBEVEL(TOPRIGHT))
                        {
                              glVertex3f(wx + ww - bevel, wy, 0);
                              glVertex3f(wx + ww - bevel, wy, wwidth);
                              glVertex3f(wx + ww - bevel / 2.0f, wy + bevel - bevel / 1.2f,
                                             wwidth);
                              glVertex3f(wx + ww - bevel / 2.0f, wy + bevel - bevel / 1.2f,
                                             0);

                              glColor4f(1.0f, 1.0f, 1.0f,  w->paint.opacity/OPAQUE);

                              glVertex3f(wx + ww - bevel / 2.0f, wy + bevel - bevel / 1.2f,
                                             wwidth);
                              glVertex3f(wx + ww - bevel / 2.0f, wy + bevel - bevel / 1.2f,
                                             0);
                              glVertex3f(wx + ww, wy + bevel, 0);
                              glVertex3f(wx + ww, wy + bevel, wwidth);
                        }
                  }

                  glEnd();

                  if (mask & PAINT_WINDOW_FRONT_TO_BACK_MASK)
                  {
                        glEnable(GL_CULL_FACE); // Re-enable culling.
                        glCullFace(GL_FRONT);



                        glTranslatef(0.0f, 0.0f, wwidth);

                        UNWRAP(tds, w->screen, paintWindow);
                        status = (*w->screen->paintWindow) (w, attrib, region, mask);
                        WRAP(tds, w->screen, paintWindow, tdPaintWindow);

                        glTranslatef(0.0f, 0.0f, -wwidth);
                  }

                  else
                  {
                        glEnable(GL_CULL_FACE); // Re-enable culling.
                        glCullFace(GL_BACK);

                        UNWRAP(tds, w->screen, paintWindow);
                        status = (*w->screen->paintWindow) (w, attrib, region, mask);
                        WRAP(tds, w->screen, paintWindow, tdPaintWindow);
                  }

                  glCullFace(GL_BACK);

                  glPopMatrix();

                  if (!wasCulled)
                        glDisable(GL_CULL_FACE);

                  glNormal3f(0.0, 0.0, -1.0);

                  return status;
            }
      }

      UNWRAP(tds, w->screen, paintWindow);
      status = (*w->screen->paintWindow) (w, attrib, region, mask);
      WRAP(tds, w->screen, paintWindow, tdPaintWindow);


      if (wasCulled)
            glEnable(GL_CULL_FACE);
      else
            glDisable(GL_CULL_FACE);

      glPopMatrix();

      return status;
}

static void
tdPaintTransformedScreen(CompScreen * s,
                                     const ScreenPaintAttrib * sAttrib,
                                     Region region, int output, unsigned int mask)
{
      TD_SCREEN(s);

      tds->reorderWindowPainting = FALSE;

      tds->tmpOutput = output;

      if (DO_3D(s->display, s))
      {
            if (CREATE_MIPMAPS)
                  s->display->textureFilter = GL_LINEAR_MIPMAP_LINEAR;

            /*Front to back should always be done.
               If FTB is already in mask, then the viewport is reversed, and all windows should be reversed.
               If BTF is in mask, the viewport isn't reversed, but some of the windows there might be, so we set FTB in addition to BTF, and check for each window what mode it should use... */

            if ((mask & PAINT_SCREEN_ORDER_BACK_TO_FRONT_MASK)
                  && !IPCS_GetBool(IPCS_OBJECT(s), tds->insideAtom))
            {
                  tds->reorderWindowPainting = TRUE;
                  mask |= PAINT_SCREEN_ORDER_FRONT_TO_BACK_MASK;

                  glPushMatrix();         //Get the matrices.

                  (s->applyScreenTransform) (s, sAttrib, output);
                  prepareXCoords(s, output, -sAttrib->zTranslate);

                  glGetFloatv(GL_MODELVIEW_MATRIX, tds->mvm);
                  glGetFloatv(GL_PROJECTION_MATRIX, tds->pm);

                  MULTM(tds->pm, tds->mvm, tds->pmvm);

                  glPopMatrix();
            }
      }

      UNWRAP(tds, s, paintTransformedScreen);
      (*s->paintTransformedScreen) (s, sAttrib, region, output, mask);
      WRAP(tds, s, paintTransformedScreen, tdPaintTransformedScreen);
}

static Bool
tdPaintScreen(CompScreen * s,
                    const ScreenPaintAttrib * sAttrib,
                    Region region, int output, unsigned int mask)
{
      Bool status;

      TD_SCREEN(s);

      if ((DO_3D(s->display, s)) || tds->tdWindowExists)
      {
            mask |= PAINT_SCREEN_TRANSFORMED_MASK;
      }

      UNWRAP(tds, s, paintScreen);
      status = (*s->paintScreen) (s, sAttrib, region, output, mask);
      WRAP(tds, s, paintScreen, tdPaintScreen);

      return status;
}

static void tdDonePaintScreen(CompScreen * s)
{
      CompWindow *w;
      tdWindow *tdw;

      TD_SCREEN(s);

      compDisplayClearRequestFlagForPlugin(s->display, "3d", "DRAW_ALL_FACES");
      compDisplayClearRequestFlagForPlugin(s->display, "3d", "NO_CUBE_CAPS");

      if (DO_3D(s->display, s) || tds->tdWindowExists)
      {
            float aim = 0.0f;

            damageScreen(s);

            tds->tdWindowExists = FALSE;

            for (w = s->windows; w; w = w->next)
            {
                  tdw = GET_TD_WINDOW(w,
                                                GET_TD_SCREEN(w->screen,
                                                                    GET_TD_DISPLAY(w->
                                                                                           screen->
                                                                                           display)));

                  if (DO_3D(s->display, s))
                  {
                        if (IPCS_GetBool(IPCS_OBJECT(s), tds->insideAtom))
                              aim = tdw->z - tds->maxZ;

                        else
                              aim = tdw->z;
                  }

                  if (fabs(tdw->currentZ - aim) < SPEED)
                        tdw->currentZ = aim;

                  else if (tdw->currentZ < aim)
                        tdw->currentZ += SPEED;

                  else if (tdw->currentZ > aim)
                        tdw->currentZ -= SPEED;

                  if (tdw->currentZ)
                        tds->tdWindowExists = TRUE;
            }
      }

      revertReorder(s);

      UNWRAP(tds, s, donePaintScreen);
      (*s->donePaintScreen) (s);
      WRAP(tds, s, donePaintScreen, tdDonePaintScreen);
}

static void tdScreenInitOptions(tdScreen * tds)
{
      CompOption *o;

      o = &tds->opt[TD_SCREEN_OPTION_SPACE];
      o->name = "space";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = False;
      o->shortDesc = N_("Space Between Windows");
      o->longDesc = N_("Change the amount of space between the windows.");
      o->displayHints = "";
      o->type = CompOptionTypeFloat;
      o->value.f = TD_SPACE_DEFAULT;
      o->rest.f.min = TD_SPACE_MIN;
      o->rest.f.max = TD_SPACE_MAX;
      o->rest.f.precision = TD_SPACE_PRECISION;

      o = &tds->opt[TD_SCREEN_OPTION_WIDTH];
      o->name = "width";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = False;
      o->shortDesc = N_("Window width");
      o->longDesc = N_("Window width");
      o->displayHints = "";
      o->type = CompOptionTypeFloat;
      o->value.f = TD_WIDTH_DEFAULT;
      o->rest.f.min = TD_SPACE_MIN;
      o->rest.f.max = TD_SPACE_MAX;
      o->rest.f.precision = TD_WIDTH_PRECISION;

      o = &tds->opt[TD_SCREEN_OPTION_SPEED];
      o->name = "speed";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = False;
      o->shortDesc = N_("3D Animation Speed");
      o->longDesc = N_("Change the speed of the 3D animation.");
      o->displayHints = "";
      o->type = CompOptionTypeFloat;
      o->value.f = TD_SPEED_DEFAULT;
      o->rest.f.min = TD_SPEED_MIN;
      o->rest.f.max = TD_SPEED_MAX;
      o->rest.f.precision = TD_SPEED_PRECISION;

      o = &tds->opt[TD_SCREEN_OPTION_BEVEL];
      o->name = "bevel";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = False;
      o->shortDesc = N_("Bevel corners");
      o->longDesc =
                  N_("Roundoff corners for consistency with rounded decorations");
      o->displayHints = "";
      o->type = CompOptionTypeInt;
      o->value.i = TD_BEVEL_DEFAULT;
      o->rest.i.min = TD_BEVEL_MIN;
      o->rest.i.max = TD_BEVEL_MAX;

      o = &tds->opt[TD_SCREEN_OPTION_CREATE_MIPMAPS];
      o->name = "mipmaps";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = True;
      o->shortDesc = N_("Create Mipmaps (for better texture quality)");
      o->longDesc =
                  N_
                  ("This will create mipmaps which improve overall texture appearence, and reduce jagged edges.");
      o->displayHints = "";
      o->type = CompOptionTypeBool;
      o->value.b = TD_CREATE_MIPMAPS_DEFAULT;

      o = &tds->opt[TD_SCREEN_OPTION_DISABLE_BACKFACE_CULLING];
      o->name = "noculling";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = True;
      o->shortDesc = N_("Draw backsides of windows");
      o->longDesc = N_("Enables the drawing of the backside of windows.");
      o->displayHints = "";
      o->type = CompOptionTypeBool;
      o->value.b = TD_DISABLE_BACKFACE_CULLING_DEFAULT;

      o = &tds->opt[TD_SCREEN_OPTION_DISABLE_CAPS_IN_INSIDE_CUBE];
      o->name = "nocaps";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = True;
      o->shortDesc = N_("Disable Caps in Cube");
      o->longDesc =
                  N_
                  ("Disables the drawing of the cube caps when the inside cube mode is set.");
      o->displayHints = "";
      o->type = CompOptionTypeBool;
      o->value.b = TD_DISABLE_CAPS_IN_INSIDE_CUBE_DEFAULT;

      o = &tds->opt[TD_SCREEN_OPTION_MANUAL_ONLY];
      o->name = "manual_only";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = True;
      o->shortDesc = N_("3D Only on Mouse Rotate");
      o->longDesc =
                  N_
                  ("Initiates the 3D display only if rotate is mouse driven. (Ex. You rotate the cube via the mouse)");
      o->displayHints = "";
      o->type = CompOptionTypeBool;
      o->value.b = TD_SCREEN_OPTION_MANUAL_ONLY_DEFAULT;

      o = &tds->opt[TD_SCREEN_OPTION_DEPTH];
      o->name = "enableDepth";
      o->group = N_("Misc. Settings");
      o->subGroup = N_("");
      o->advanced = False;
      o->shortDesc = N_("Enable window depth");
      o->longDesc = N_("Enable a window 'depth' or 'width'");
      o->displayHints = "";
      o->type = CompOptionTypeBool;
      o->value.b = TD_DEPTH_DEFAULT;

#define BEVELOPTION(CORNER) \
      o = &tds->opt[TD_SCREEN_OPTION_BEVEL_##CORNER]; \
      o->name = "bevel_"#CORNER; \
      o->group = N_("Misc. Settings"); \
      o->subGroup = N_("Corners"); \
      o->shortDesc = N_("Bevel "#CORNER); \
      o->longDesc = N_("Bevel "#CORNER); \
      o->displayHints = ""; \
      o->type = CompOptionTypeBool; \
      o->value.b = TD_##CORNER##_DEFAULT

      BEVELOPTION(TOPRIGHT);
      BEVELOPTION(TOPLEFT);
      BEVELOPTION(BOTTOMRIGHT);
      BEVELOPTION(BOTTOMLEFT);
}

static CompOption *tdGetScreenOptions(CompScreen * s, int *count)
{
      if (s)
      {
            TD_SCREEN(s);

            *count = NUM_OPTIONS(tds);

            return tds->opt;
      }

      else
      {
            tdScreen *tds = malloc(sizeof(tdScreen));

            tdScreenInitOptions(tds);
            *count = NUM_OPTIONS(tds);

            return tds->opt;
      }
}

static Bool
tdSetScreenOption(CompScreen * screen, char *name, CompOptionValue * value)
{
      CompOption *o;
      int index;

      TD_SCREEN(screen);

      o = compFindOption(tds->opt, NUM_OPTIONS(tds), name, &index);
      if (!o)
            return FALSE;

      switch (index)
      {
      case TD_SCREEN_OPTION_SPACE:
      case TD_SCREEN_OPTION_SPEED:
      case TD_SCREEN_OPTION_WIDTH:
            if (compSetFloatOption(o, value))
                  return TRUE;
            break;

      case TD_SCREEN_OPTION_CREATE_MIPMAPS:
      case TD_SCREEN_OPTION_DEPTH:
            if (compSetBoolOption(o, value))
                  return TRUE;
            break;

      case TD_SCREEN_OPTION_DISABLE_BACKFACE_CULLING:
      case TD_SCREEN_OPTION_DISABLE_CAPS_IN_INSIDE_CUBE:
            if (compSetBoolOption(o, value))
                  return TRUE;
            break;
      case TD_SCREEN_OPTION_MANUAL_ONLY:
      case TD_SCREEN_OPTION_BEVEL_TOPRIGHT:
      case TD_SCREEN_OPTION_BEVEL_TOPLEFT:
      case TD_SCREEN_OPTION_BEVEL_BOTTOMRIGHT:
      case TD_SCREEN_OPTION_BEVEL_BOTTOMLEFT:



            if (compSetBoolOption(o, value))
                  return TRUE;
            break;
      case TD_SCREEN_OPTION_BEVEL:
            if (compSetIntOption(o, value))
                  return TRUE;
            break;


      default:
            break;
      }

      return FALSE;
}

static Bool tdInitDisplay(CompPlugin * p, CompDisplay * d)
{
      tdDisplay *tdd;

      tdd = malloc(sizeof(tdDisplay));
      if (!tdd)
            return FALSE;

      tdd->screenPrivateIndex = allocateScreenPrivateIndex(d);
      if (tdd->screenPrivateIndex < 0)
      {
            free(tdd);
            return FALSE;
      }

      d->privates[displayPrivateIndex].ptr = tdd;

      return TRUE;
}

static void tdFiniDisplay(CompPlugin * p, CompDisplay * d)
{
      TD_DISPLAY(d);

      freeScreenPrivateIndex(d, tdd->screenPrivateIndex);

      free(tdd);
}

static Bool tdInitScreen(CompPlugin * p, CompScreen * s)
{
      TD_DISPLAY(s->display);

      tdScreen *tds;

      tds = malloc(sizeof(tdScreen));
      if (!tds)
            return FALSE;

      tds->windowPrivateIndex = allocateWindowPrivateIndex(s);
      if (tds->windowPrivateIndex < 0)
      {
            free(tds);
            free(tdd);
            return FALSE;
      }

      tdScreenInitOptions(tds);

      tds->tdWindowExists = FALSE;
      //tds->reorder = TRUE;
      tds->revertReorder = NULL;

      tds->mmModeAtom = IPCS_GetAtom(IPCS_OBJECT(s), IPCS_INT, "MM_MODE", TRUE);
      tds->manualAtom =
                  IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "MOUSE_INITIATED_ROTATE",
                                     TRUE);
      tds->insideAtom = IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "INSIDE", TRUE);
      tds->unfoldedAtom = IPCS_GetAtom(IPCS_OBJECT(s), IPCS_BOOL, "CUBE_UNFOLDED", TRUE);

      tds->currentViewportNum = s->hsize;
      tds->currentMmMode = IPCS_GetInt(IPCS_OBJECT(s), tds->mmModeAtom);
      tds->currentScreenNum = s->nOutputDev;
      tds->currentDifferentResolutions = differentResolutions(s);

      if (tds->currentViewportNum > 2 && tds->currentMmMode != Multiple)
            tds->xMove =
                        1.0f /
                        (tan
                         (PI * (tds->currentViewportNum - 2.0f) /
                          (2.0f * tds->currentViewportNum)));
      else
            tds->xMove = 0.0f;

      WRAP(tds, s, paintTransformedScreen, tdPaintTransformedScreen);
      WRAP(tds, s, paintWindow, tdPaintWindow);
      WRAP(tds, s, paintScreen, tdPaintScreen);
      WRAP(tds, s, donePaintScreen, tdDonePaintScreen);
      WRAP(tds, s, preparePaintScreen, tdPreparePaintScreen);

      s->privates[tdd->screenPrivateIndex].ptr = tds;

      return TRUE;
}

static void tdFiniScreen(CompPlugin * p, CompScreen * s)
{
      TD_SCREEN(s);

      freeWindowPrivateIndex(s, tds->windowPrivateIndex);

      UNWRAP(tds, s, paintTransformedScreen);
      UNWRAP(tds, s, paintWindow);
      UNWRAP(tds, s, paintScreen);
      UNWRAP(tds, s, donePaintScreen);
      UNWRAP(tds, s, preparePaintScreen);

      free(tds);
}

static Bool tdInitWindow(CompPlugin * p, CompWindow * w)
{
      tdWindow *tdw;

      TD_SCREEN(w->screen);

      tdw = malloc(sizeof(tdWindow));
      if (!tdw)
            return FALSE;

      tdw->z = 0.0f;
      tdw->currentZ = 0.0f;

      w->privates[tds->windowPrivateIndex].ptr = tdw;

      return TRUE;
}

static void tdFiniWindow(CompPlugin * p, CompWindow * w)
{
      TD_WINDOW(w);

      free(tdw);
}

static Bool tdInit(CompPlugin * p)
{
      displayPrivateIndex = allocateDisplayPrivateIndex();
      if (displayPrivateIndex < 0)
            return FALSE;

      return TRUE;
}

static void tdFini(CompPlugin * p)
{
      if (displayPrivateIndex >= 0)
            freeDisplayPrivateIndex(displayPrivateIndex);
}

CompPluginDep tdDeps[] = {
      {CompPluginRuleAfter, "decoration"}
      ,
};

static CompPluginVTable tdVTable = {
      "3d",
      N_("3D Effects"),
      N_("Windows aquire 3D Effects"),
      tdInit,
      tdFini,
      tdInitDisplay,
      tdFiniDisplay,
      tdInitScreen,
      tdFiniScreen,
      tdInitWindow,
      tdFiniWindow,
      /*tdGetDisplayOptions */ 0,
      /*tdSetDisplayOption */ 0,
      tdGetScreenOptions,
      tdSetScreenOption,
      tdDeps,
      sizeof(tdDeps) / sizeof(tdDeps[0]),
      0,
      0,
      BERYL_ABI_INFO,
      "beryl-plugins",
      "effects",
      0,
      0,
      False,
};

CompPluginVTable *getCompPluginInfo(void)
{
      return &tdVTable;
}

Generated by  Doxygen 1.6.0   Back to index