You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1268 lines
30 KiB

/*
* Copyright © 2005 Novell, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of
* Novell, Inc. not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
* Novell, Inc. makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: David Reveman <davidr@novell.com>
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <compiz-core.h>
ScreenPaintAttrib defaultScreenPaintAttrib = {
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -DEFAULT_Z_CAMERA
};
WindowPaintAttrib defaultWindowPaintAttrib = {
OPAQUE, BRIGHT, COLOR, 1.0f, 1.0f, 0.0f, 0.0f
};
void
preparePaintScreen (CompScreen *screen,
int msSinceLastPaint)
{
}
void
donePaintScreen (CompScreen *screen)
{
}
void
applyScreenTransform (CompScreen *screen,
const ScreenPaintAttrib *sAttrib,
CompOutput *output,
CompTransform *transform)
{
matrixTranslate (transform,
sAttrib->xTranslate,
sAttrib->yTranslate,
sAttrib->zTranslate + sAttrib->zCamera);
matrixRotate (transform,
sAttrib->xRotate, 0.0f, 1.0f, 0.0f);
matrixRotate (transform,
sAttrib->vRotate,
cosf (sAttrib->xRotate * DEG2RAD),
0.0f,
sinf (sAttrib->xRotate * DEG2RAD));
matrixRotate (transform,
sAttrib->yRotate, 0.0f, 1.0f, 0.0f);
}
void
transformToScreenSpace (CompScreen *screen,
CompOutput *output,
float z,
CompTransform *transform)
{
matrixTranslate (transform, -0.5f, -0.5f, z);
matrixScale (transform,
1.0f / output->width,
-1.0f / output->height,
1.0f);
matrixTranslate (transform,
-output->region.extents.x1,
-output->region.extents.y2,
0.0f);
}
void
prepareXCoords (CompScreen *screen,
CompOutput *output,
float z)
{
glTranslatef (-0.5f, -0.5f, z);
glScalef (1.0f / output->width,
-1.0f / output->height,
1.0f);
glTranslatef (-output->region.extents.x1,
-output->region.extents.y2,
0.0f);
}
void
paintCursor (CompCursor *c,
const CompTransform *transform,
Region region,
unsigned int mask)
{
int x1, y1, x2, y2;
if (!c->image)
return;
x1 = c->x;
y1 = c->y;
x2 = c->x + c->image->width;
y2 = c->y + c->image->height;
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
glEnable (GL_BLEND);
enableTexture (c->screen, &c->image->texture, COMP_TEXTURE_FILTER_FAST);
glBegin (GL_QUADS);
glTexCoord2f (COMP_TEX_COORD_X (&c->matrix, x1),
COMP_TEX_COORD_Y (&c->matrix, y2));
glVertex2i (x1, y2);
glTexCoord2f (COMP_TEX_COORD_X (&c->matrix, x2),
COMP_TEX_COORD_Y (&c->matrix, y2));
glVertex2i (x2, y2);
glTexCoord2f (COMP_TEX_COORD_X (&c->matrix, x2),
COMP_TEX_COORD_Y (&c->matrix, y1));
glVertex2i (x2, y1);
glTexCoord2f (COMP_TEX_COORD_X (&c->matrix, x1),
COMP_TEX_COORD_Y (&c->matrix, y1));
glVertex2i (x1, y1);
glEnd ();
disableTexture (c->screen, &c->image->texture);
glDisable (GL_BLEND);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
}
static void
paintBackground (CompScreen *s,
Region region,
Bool transformed)
{
CompTexture *bg = &s->backgroundTexture;
BoxPtr pBox = region->rects;
int n, nBox = region->numRects;
GLfloat *d, *data;
if (!nBox)
return;
if (s->desktopWindowCount)
{
if (bg->name)
{
finiTexture (s, bg);
initTexture (s, bg);
}
s->backgroundLoaded = FALSE;
return;
}
else
{
if (!s->backgroundLoaded)
updateScreenBackground (s, bg);
s->backgroundLoaded = TRUE;
}
data = malloc (sizeof (GLfloat) * nBox * 16);
if (!data)
return;
d = data;
n = nBox;
while (n--)
{
*d++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x1);
*d++ = COMP_TEX_COORD_Y (&bg->matrix, pBox->y2);
*d++ = pBox->x1;
*d++ = pBox->y2;
*d++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x2);
*d++ = COMP_TEX_COORD_Y (&bg->matrix, pBox->y2);
*d++ = pBox->x2;
*d++ = pBox->y2;
*d++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x2);
*d++ = COMP_TEX_COORD_Y (&bg->matrix, pBox->y1);
*d++ = pBox->x2;
*d++ = pBox->y1;
*d++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x1);
*d++ = COMP_TEX_COORD_Y (&bg->matrix, pBox->y1);
*d++ = pBox->x1;
*d++ = pBox->y1;
pBox++;
}
glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data);
glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data + 2);
if (bg->name)
{
if (transformed)
enableTexture (s, bg, COMP_TEXTURE_FILTER_GOOD);
else
enableTexture (s, bg, COMP_TEXTURE_FILTER_FAST);
glDrawArrays (GL_QUADS, 0, nBox * 4);
disableTexture (s, bg);
}
else
{
glColor4us (0, 0, 0, 0);
glDrawArrays (GL_QUADS, 0, nBox * 4);
glColor4usv (defaultColor);
}
free (data);
}
/* This function currently always performs occlusion detection to
minimize paint regions. OpenGL precision requirements are no good
enough to guarantee that the results from using occlusion detection
is the same as without. It's likely not possible to see any
difference with most hardware but occlusion detection in the
transformed screen case should be made optional for those who do
see a difference. */
static void
paintOutputRegion (CompScreen *screen,
const CompTransform *transform,
Region region,
CompOutput *output,
unsigned int mask)
{
static Region tmpRegion = NULL;
CompWindow *w;
CompCursor *c;
int count, windowMask, odMask, i;
CompWindow *fullscreenWindow = NULL;
CompWalker walk;
Bool status;
Bool withOffset = FALSE;
CompTransform vTransform;
int offX, offY;
Region clip = region;
if (!tmpRegion)
{
tmpRegion = XCreateRegion ();
if (!tmpRegion)
return;
}
if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
{
windowMask = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
count = 1;
}
else
{
windowMask = 0;
count = 0;
}
XSubtractRegion (region, &emptyRegion, tmpRegion);
(*screen->initWindowWalker) (screen, &walk);
if (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK))
{
/* detect occlusions */
for (w = (*walk.last) (screen); w; w = (*walk.prev) (w))
{
if (w->destroyed)
continue;
if (!w->shaded)
{
if (w->attrib.map_state != IsViewable || !w->damaged)
continue;
}
/* copy region */
XSubtractRegion (tmpRegion, &emptyRegion, w->clip);
odMask = PAINT_WINDOW_OCCLUSION_DETECTION_MASK;
if ((screen->windowOffsetX != 0 || screen->windowOffsetY != 0) &&
!windowOnAllViewports (w))
{
withOffset = TRUE;
getWindowMovementForOffset (w, screen->windowOffsetX,
screen->windowOffsetY,
&offX, &offY);
vTransform = *transform;
matrixTranslate (&vTransform, offX, offY, 0);
XOffsetRegion (w->clip, -offX, -offY);
odMask |= PAINT_WINDOW_WITH_OFFSET_MASK;
status = (*screen->paintWindow) (w, &w->paint, &vTransform,
tmpRegion, odMask);
}
else
{
withOffset = FALSE;
status = (*screen->paintWindow) (w, &w->paint, transform, tmpRegion,
odMask);
}
if (status)
{
if (withOffset)
{
XOffsetRegion (w->region, offX, offY);
XSubtractRegion (tmpRegion, w->region, tmpRegion);
XOffsetRegion (w->region, -offX, -offY);
}
else
XSubtractRegion (tmpRegion, w->region, tmpRegion);
/* unredirect top most fullscreen windows. */
if (count == 0 &&
screen->opt[COMP_SCREEN_OPTION_UNREDIRECT_FS].value.b)
{
if (XEqualRegion (w->region, &screen->region) &&
!REGION_NOT_EMPTY (tmpRegion))
{
fullscreenWindow = w;
}
else
{
for (i = 0; i < screen->nOutputDev; i++)
if (XEqualRegion (w->region,
&screen->outputDev[i].region))
fullscreenWindow = w;
}
}
}
if (!w->invisible)
count++;
}
}
if (fullscreenWindow)
unredirectWindow (fullscreenWindow);
if (!(mask & PAINT_SCREEN_NO_BACKGROUND_MASK))
paintBackground (screen, tmpRegion,
(mask & PAINT_SCREEN_TRANSFORMED_MASK));
/* paint all windows from bottom to top */
for (w = (*walk.first) (screen); w; w = (*walk.next) (w))
{
if (w->destroyed)
continue;
if (w == fullscreenWindow)
continue;
if (!w->shaded)
{
if (w->attrib.map_state != IsViewable || !w->damaged)
continue;
}
if (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK))
clip = w->clip;
if ((screen->windowOffsetX != 0 || screen->windowOffsetY != 0) &&
!windowOnAllViewports (w))
{
getWindowMovementForOffset (w, screen->windowOffsetX,
screen->windowOffsetY, &offX, &offY);
vTransform = *transform;
matrixTranslate (&vTransform, offX, offY, 0);
(*screen->paintWindow) (w, &w->paint, &vTransform, clip,
windowMask | PAINT_WINDOW_WITH_OFFSET_MASK);
}
else
{
(*screen->paintWindow) (w, &w->paint, transform, clip,
windowMask);
}
}
if (walk.fini)
(*walk.fini) (screen, &walk);
/* paint cursors */
for (c = screen->cursors; c; c = c->next)
(*screen->paintCursor) (c, transform, tmpRegion, 0);
}
void
enableOutputClipping (CompScreen *screen,
const CompTransform *transform,
Region region,
CompOutput *output)
{
GLdouble h = screen->height;
GLdouble p1[2] = { region->extents.x1, h - region->extents.y2 };
GLdouble p2[2] = { region->extents.x2, h - region->extents.y1 };
GLdouble halfW = output->width / 2.0;
GLdouble halfH = output->height / 2.0;
GLdouble cx = output->region.extents.x1 + halfW;
GLdouble cy = (h - output->region.extents.y2) + halfH;
GLdouble top[4] = { 0.0, halfH / (cy - p1[1]), 0.0, 0.5 };
GLdouble bottom[4] = { 0.0, halfH / (cy - p2[1]), 0.0, 0.5 };
GLdouble left[4] = { halfW / (cx - p1[0]), 0.0, 0.0, 0.5 };
GLdouble right[4] = { halfW / (cx - p2[0]), 0.0, 0.0, 0.5 };
glPushMatrix ();
glLoadMatrixf (transform->m);
glClipPlane (GL_CLIP_PLANE0, top);
glClipPlane (GL_CLIP_PLANE1, bottom);
glClipPlane (GL_CLIP_PLANE2, left);
glClipPlane (GL_CLIP_PLANE3, right);
glEnable (GL_CLIP_PLANE0);
glEnable (GL_CLIP_PLANE1);
glEnable (GL_CLIP_PLANE2);
glEnable (GL_CLIP_PLANE3);
glPopMatrix ();
}
void
disableOutputClipping (CompScreen *screen)
{
glDisable (GL_CLIP_PLANE0);
glDisable (GL_CLIP_PLANE1);
glDisable (GL_CLIP_PLANE2);
glDisable (GL_CLIP_PLANE3);
}
#define CLIP_PLANE_MASK (PAINT_SCREEN_TRANSFORMED_MASK | \
PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
void
paintTransformedOutput (CompScreen *screen,
const ScreenPaintAttrib *sAttrib,
const CompTransform *transform,
Region region,
CompOutput *output,
unsigned int mask)
{
CompTransform sTransform = *transform;
if (mask & PAINT_SCREEN_CLEAR_MASK)
clearTargetOutput (screen->display, GL_COLOR_BUFFER_BIT);
screenLighting (screen, TRUE);
(*screen->applyScreenTransform) (screen, sAttrib, output, &sTransform);
if ((mask & CLIP_PLANE_MASK) == CLIP_PLANE_MASK)
{
screen->enableOutputClipping (screen, &sTransform, region, output);
transformToScreenSpace (screen, output, -sAttrib->zTranslate,
&sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
paintOutputRegion (screen, &sTransform, region, output, mask);
glPopMatrix ();
screen->disableOutputClipping (screen);
}
else
{
transformToScreenSpace (screen, output, -sAttrib->zTranslate,
&sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
paintOutputRegion (screen, &sTransform, region, output, mask);
glPopMatrix ();
}
}
Bool
paintOutput (CompScreen *screen,
const ScreenPaintAttrib *sAttrib,
const CompTransform *transform,
Region region,
CompOutput *output,
unsigned int mask)
{
CompTransform sTransform = *transform;
if (mask & PAINT_SCREEN_REGION_MASK)
{
if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
{
if (mask & PAINT_SCREEN_FULL_MASK)
{
region = &output->region;
(*screen->paintTransformedOutput) (screen, sAttrib,
&sTransform, region,
output, mask);
return TRUE;
}
return FALSE;
}
/* fall through and redraw region */
}
else if (mask & PAINT_SCREEN_FULL_MASK)
{
(*screen->paintTransformedOutput) (screen, sAttrib, &sTransform,
&output->region,
output, mask);
return TRUE;
}
else
return FALSE;
screenLighting (screen, FALSE);
transformToScreenSpace (screen, output, -DEFAULT_Z_CAMERA, &sTransform);
glPushMatrix ();
glLoadMatrixf (sTransform.m);
paintOutputRegion (screen, &sTransform, region, output, mask);
glPopMatrix ();
return TRUE;
}
#define ADD_RECT(data, m, n, x1, y1, x2, y2) \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_X (&m[it], x1); \
*(data)++ = COMP_TEX_COORD_Y (&m[it], y1); \
} \
*(data)++ = (x1); \
*(data)++ = (y1); \
*(data)++ = 0.0; \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_X (&m[it], x1); \
*(data)++ = COMP_TEX_COORD_Y (&m[it], y2); \
} \
*(data)++ = (x1); \
*(data)++ = (y2); \
*(data)++ = 0.0; \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_X (&m[it], x2); \
*(data)++ = COMP_TEX_COORD_Y (&m[it], y2); \
} \
*(data)++ = (x2); \
*(data)++ = (y2); \
*(data)++ = 0.0; \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_X (&m[it], x2); \
*(data)++ = COMP_TEX_COORD_Y (&m[it], y1); \
} \
*(data)++ = (x2); \
*(data)++ = (y1); \
*(data)++ = 0.0
#define ADD_QUAD(data, m, n, x1, y1, x2, y2) \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_XY (&m[it], x1, y1); \
*(data)++ = COMP_TEX_COORD_YX (&m[it], x1, y1); \
} \
*(data)++ = (x1); \
*(data)++ = (y1); \
*(data)++ = 0.0; \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_XY (&m[it], x1, y2); \
*(data)++ = COMP_TEX_COORD_YX (&m[it], x1, y2); \
} \
*(data)++ = (x1); \
*(data)++ = (y2); \
*(data)++ = 0.0; \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_XY (&m[it], x2, y2); \
*(data)++ = COMP_TEX_COORD_YX (&m[it], x2, y2); \
} \
*(data)++ = (x2); \
*(data)++ = (y2); \
*(data)++ = 0.0; \
for (it = 0; it < n; it++) \
{ \
*(data)++ = COMP_TEX_COORD_XY (&m[it], x2, y1); \
*(data)++ = COMP_TEX_COORD_YX (&m[it], x2, y1); \
} \
*(data)++ = (x2); \
*(data)++ = (y1); \
*(data)++ = 0.0;
Bool
moreWindowVertices (CompWindow *w,
int newSize)
{
if (newSize > w->vertexSize)
{
GLfloat *vertices;
vertices = realloc (w->vertices, sizeof (GLfloat) * newSize);
if (!vertices)
return FALSE;
w->vertices = vertices;
w->vertexSize = newSize;
}
return TRUE;
}
Bool
moreWindowIndices (CompWindow *w,
int newSize)
{
if (newSize > w->indexSize)
{
GLushort *indices;
indices = realloc (w->indices, sizeof (GLushort) * newSize);
if (!indices)
return FALSE;
w->indices = indices;
w->indexSize = newSize;
}
return TRUE;
}
static void
drawWindowGeometry (CompWindow *w)
{
int texUnit = w->texUnits;
int currentTexUnit = 0;
int stride = w->vertexStride;
GLfloat *vertices = w->vertices + (stride - 3);
stride *= sizeof (GLfloat);
glVertexPointer (3, GL_FLOAT, stride, vertices);
while (texUnit--)
{
if (texUnit != currentTexUnit)
{
(*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
currentTexUnit = texUnit;
}
vertices -= w->texCoordSize;
glTexCoordPointer (w->texCoordSize, GL_FLOAT, stride, vertices);
}
glDrawArrays (GL_QUADS, 0, w->vCount);
/* disable all texture coordinate arrays except 0 */
texUnit = w->texUnits;
if (texUnit > 1)
{
while (--texUnit)
{
(*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
}
(*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB);
}
}
void
addWindowGeometry (CompWindow *w,
CompMatrix *matrix,
int nMatrix,
Region region,
Region clip)
{
BoxRec full;
w->texUnits = nMatrix;
full = clip->extents;
if (region->extents.x1 > full.x1)
full.x1 = region->extents.x1;
if (region->extents.y1 > full.y1)
full.y1 = region->extents.y1;
if (region->extents.x2 < full.x2)
full.x2 = region->extents.x2;
if (region->extents.y2 < full.y2)
full.y2 = region->extents.y2;
if (full.x1 < full.x2 && full.y1 < full.y2)
{
BoxPtr pBox;
int nBox;
BoxPtr pClip;
int nClip;
BoxRec cbox;
int vSize;
int n, it, x1, y1, x2, y2;
GLfloat *d;
Bool rect = TRUE;
for (it = 0; it < nMatrix; it++)
{
if (matrix[it].xy != 0.0f || matrix[it].yx != 0.0f)
{
rect = FALSE;
break;
}
}
pBox = region->rects;
nBox = region->numRects;
vSize = 3 + nMatrix * 2;
n = w->vCount / 4;
if ((n + nBox) * vSize * 4 > w->vertexSize)
{
if (!moreWindowVertices (w, (n + nBox) * vSize * 4))
return;
}
d = w->vertices + (w->vCount * vSize);
while (nBox--)
{
x1 = pBox->x1;
y1 = pBox->y1;
x2 = pBox->x2;
y2 = pBox->y2;
pBox++;
if (x1 < full.x1)
x1 = full.x1;
if (y1 < full.y1)
y1 = full.y1;
if (x2 > full.x2)
x2 = full.x2;
if (y2 > full.y2)
y2 = full.y2;
if (x1 < x2 && y1 < y2)
{
nClip = clip->numRects;
if (nClip == 1)
{
if (rect)
{
ADD_RECT (d, matrix, nMatrix, x1, y1, x2, y2);
}
else
{
ADD_QUAD (d, matrix, nMatrix, x1, y1, x2, y2);
}
n++;
}
else
{
pClip = clip->rects;
if (((n + nClip) * vSize * 4) > w->vertexSize)
{
if (!moreWindowVertices (w, (n + nClip) * vSize * 4))
return;
d = w->vertices + (n * vSize * 4);
}
while (nClip--)
{
cbox = *pClip;
pClip++;
if (cbox.x1 < x1)
cbox.x1 = x1;
if (cbox.y1 < y1)
cbox.y1 = y1;
if (cbox.x2 > x2)
cbox.x2 = x2;
if (cbox.y2 > y2)
cbox.y2 = y2;
if (cbox.x1 < cbox.x2 && cbox.y1 < cbox.y2)
{
if (rect)
{
ADD_RECT (d, matrix, nMatrix,
cbox.x1, cbox.y1, cbox.x2, cbox.y2);
}
else
{
ADD_QUAD (d, matrix, nMatrix,
cbox.x1, cbox.y1, cbox.x2, cbox.y2);
}
n++;
}
}
}
}
}
w->vCount = n * 4;
w->vertexStride = vSize;
w->texCoordSize = 2;
w->drawWindowGeometry = drawWindowGeometry;
}
}
static Bool
enableFragmentProgramAndDrawGeometry (CompWindow *w,
CompTexture *texture,
const FragmentAttrib *attrib,
int filter,
unsigned int mask)
{
FragmentAttrib fa = *attrib;
CompScreen *s = w->screen;
Bool blending;
if (s->canDoSaturated && attrib->saturation != COLOR)
{
int param, function;
param = allocFragmentParameters (&fa, 1);
function = getSaturateFragmentFunction (s, texture, param);
addFragmentFunction (&fa, function);
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, param,
RED_SATURATION_WEIGHT,
GREEN_SATURATION_WEIGHT,
BLUE_SATURATION_WEIGHT,
attrib->saturation / 65535.0f);
}
if (!enableFragmentAttrib (s, &fa, &blending))
return FALSE;
enableTexture (s, texture, filter);
if (mask & PAINT_WINDOW_BLEND_MASK)
{
if (blending)
glEnable (GL_BLEND);
if (attrib->opacity != OPAQUE || attrib->brightness != BRIGHT)
{
GLushort color;
color = (attrib->opacity * attrib->brightness) >> 16;
screenTexEnvMode (s, GL_MODULATE);
glColor4us (color, color, color, attrib->opacity);
(*w->drawWindowGeometry) (w);
glColor4usv (defaultColor);
screenTexEnvMode (s, GL_REPLACE);
}
else
{
(*w->drawWindowGeometry) (w);
}
if (blending)
glDisable (GL_BLEND);
}
else if (attrib->brightness != BRIGHT)
{
screenTexEnvMode (s, GL_MODULATE);
glColor4us (attrib->brightness, attrib->brightness,
attrib->brightness, BRIGHT);
(*w->drawWindowGeometry) (w);
glColor4usv (defaultColor);
screenTexEnvMode (s, GL_REPLACE);
}
else
{
(*w->drawWindowGeometry) (w);
}
disableTexture (w->screen, texture);
disableFragmentAttrib (s, &fa);
return TRUE;
}
static void
enableFragmentOperationsAndDrawGeometry (CompWindow *w,
CompTexture *texture,
const FragmentAttrib *attrib,
int filter,
unsigned int mask)
{
CompScreen *s = w->screen;
if (s->canDoSaturated && attrib->saturation != COLOR)
{
GLfloat constant[4];
if (mask & PAINT_WINDOW_BLEND_MASK)
glEnable (GL_BLEND);
enableTexture (s, texture, filter);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PRIMARY_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glColor4f (1.0f, 1.0f, 1.0f, 0.5f);
s->activeTexture (GL_TEXTURE1_ARB);
enableTexture (s, texture, filter);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
if (s->canDoSlightlySaturated && attrib->saturation > 0)
{
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
constant[0] = 0.5f + 0.5f * RED_SATURATION_WEIGHT;
constant[1] = 0.5f + 0.5f * GREEN_SATURATION_WEIGHT;
constant[2] = 0.5f + 0.5f * BLUE_SATURATION_WEIGHT;
constant[3] = 1.0;
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
s->activeTexture (GL_TEXTURE2_ARB);
enableTexture (s, texture, filter);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
constant[3] = attrib->saturation / 65535.0f;
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
if (attrib->opacity < OPAQUE || attrib->brightness != BRIGHT)
{
s->activeTexture (GL_TEXTURE3_ARB);
enableTexture (s, texture, filter);
constant[3] = attrib->opacity / 65535.0f;
constant[0] = constant[1] = constant[2] = constant[3] *
attrib->brightness / 65535.0f;
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
(*w->drawWindowGeometry) (w);
disableTexture (s, texture);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
s->activeTexture (GL_TEXTURE2_ARB);
}
else
{
(*w->drawWindowGeometry) (w);
}
disableTexture (s, texture);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
s->activeTexture (GL_TEXTURE1_ARB);
}
else
{
glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
constant[3] = attrib->opacity / 65535.0f;
constant[0] = constant[1] = constant[2] = constant[3] *
attrib->brightness / 65535.0f;
constant[0] = 0.5f + 0.5f * RED_SATURATION_WEIGHT * constant[0];
constant[1] = 0.5f + 0.5f * GREEN_SATURATION_WEIGHT * constant[1];
constant[2] = 0.5f + 0.5f * BLUE_SATURATION_WEIGHT * constant[2];
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
(*w->drawWindowGeometry) (w);
}
disableTexture (s, texture);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
s->activeTexture (GL_TEXTURE0_ARB);
disableTexture (s, texture);
glColor4usv (defaultColor);
screenTexEnvMode (s, GL_REPLACE);
if (mask & PAINT_WINDOW_BLEND_MASK)
glDisable (GL_BLEND);
}
else
{
enableTexture (s, texture, filter);
if (mask & PAINT_WINDOW_BLEND_MASK)
{
glEnable (GL_BLEND);
if (attrib->opacity != OPAQUE || attrib->brightness != BRIGHT)
{
GLushort color;
color = (attrib->opacity * attrib->brightness) >> 16;
screenTexEnvMode (s, GL_MODULATE);
glColor4us (color, color, color, attrib->opacity);
(*w->drawWindowGeometry) (w);
glColor4usv (defaultColor);
screenTexEnvMode (s, GL_REPLACE);
}
else
{
(*w->drawWindowGeometry) (w);
}
glDisable (GL_BLEND);
}
else if (attrib->brightness != BRIGHT)
{
screenTexEnvMode (s, GL_MODULATE);
glColor4us (attrib->brightness, attrib->brightness,
attrib->brightness, BRIGHT);
(*w->drawWindowGeometry) (w);
glColor4usv (defaultColor);
screenTexEnvMode (s, GL_REPLACE);
}
else
{
(*w->drawWindowGeometry) (w);
}
disableTexture (w->screen, texture);
}
}
void
drawWindowTexture (CompWindow *w,
CompTexture *texture,
const FragmentAttrib *attrib,
unsigned int mask)
{
int filter;
if (mask & (PAINT_WINDOW_TRANSFORMED_MASK |
PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK))
filter = w->screen->filter[SCREEN_TRANS_FILTER];
else
filter = w->screen->filter[NOTHING_TRANS_FILTER];
if ((!attrib->nFunction && (!w->screen->lighting ||
attrib->saturation == COLOR || attrib->saturation == 0)) ||
!enableFragmentProgramAndDrawGeometry (w,
texture,
attrib,
filter,
mask))
{
enableFragmentOperationsAndDrawGeometry (w,
texture,
attrib,
filter,
mask);
}
}
Bool
drawWindow (CompWindow *w,
const CompTransform *transform,
const FragmentAttrib *fragment,
Region region,
unsigned int mask)
{
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
region = &infiniteRegion;
if (!region->numRects)
return TRUE;
if (w->attrib.map_state != IsViewable)
return TRUE;
if (!w->texture->pixmap && !bindWindow (w))
return FALSE;
if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
mask |= PAINT_WINDOW_BLEND_MASK;
w->vCount = w->indexCount = 0;
(*w->screen->addWindowGeometry) (w, &w->matrix, 1, w->region, region);
if (w->vCount)
(*w->screen->drawWindowTexture) (w, w->texture, fragment, mask);
return TRUE;
}
Bool
paintWindow (CompWindow *w,
const WindowPaintAttrib *attrib,
const CompTransform *transform,
Region region,
unsigned int mask)
{
FragmentAttrib fragment;
Bool status;
w->lastPaint = *attrib;
if (w->alpha || attrib->opacity != OPAQUE)
mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
w->lastMask = mask;
if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
{
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
return FALSE;
if (mask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
return FALSE;
if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
return FALSE;
if (w->shaded)
return FALSE;
return TRUE;
}
if (mask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
return TRUE;
initFragmentAttrib (&fragment, attrib);
if (mask & PAINT_WINDOW_TRANSFORMED_MASK ||
mask & PAINT_WINDOW_WITH_OFFSET_MASK)
{
glPushMatrix ();
glLoadMatrixf (transform->m);
}
status = (*w->screen->drawWindow) (w, transform, &fragment, region, mask);
if (mask & PAINT_WINDOW_TRANSFORMED_MASK ||
mask & PAINT_WINDOW_WITH_OFFSET_MASK)
glPopMatrix ();
return status;
}