/* * 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 */ #include #include #include #include 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; }