Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

glut_overlay.c

Go to the documentation of this file.
00001 
00002 /* Copyright (c) Mark J. Kilgard, 1996, 1997.  */
00003 
00004 /* This program is freely distributable without licensing fees
00005    and is provided without guarantee or warrantee expressed or
00006    implied. This program is -not- in the public domain. */
00007 
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <assert.h>
00012 
00013 #if !defined(_WIN32)
00014 #include <X11/Xlib.h>
00015 #include <X11/Xutil.h>
00016 #include <X11/Xatom.h>  /* for XA_RGB_DEFAULT_MAP atom */
00017 #if defined (__vms)
00018 #include <Xmu/StdCmap.h>  /* for XmuLookupStandardColormap */
00019 #else
00020 #include <X11/Xmu/StdCmap.h>  /* for XmuLookupStandardColormap */
00021 #endif
00022 #endif /* !_WIN32 */
00023 
00024 #include "glutint.h"
00025 #include "layerutil.h"
00026 
00027 static Criterion requiredOverlayCriteria[] =
00028 {
00029   {LEVEL, EQ, 1},       /* This entry gets poked in
00030                            determineOverlayVisual. */
00031   {TRANSPARENT, EQ, 1},
00032   {XPSEUDOCOLOR, EQ, 1},
00033   {RGBA, EQ, 0},
00034   {BUFFER_SIZE, GTE, 1}
00035 };
00036 static int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion);
00037 static int requiredOverlayCriteriaMask =
00038 (1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE);
00039 
00040 #if !defined(_WIN32)
00041 static int
00042 checkOverlayAcceptability(XVisualInfo * vi, unsigned int mode)
00043 {
00044   int value;
00045 
00046   /* Must support OpenGL. */
00047   glXGetConfig(__glutDisplay, vi, GLX_USE_GL, &value);
00048   if (!value)
00049     return 1;
00050 
00051   /* Must be color index. */
00052   glXGetConfig(__glutDisplay, vi, GLX_RGBA, &value);
00053   if (value)
00054     return 1;
00055 
00056   /* Must match single/double buffering request. */
00057   glXGetConfig(__glutDisplay, vi, GLX_DOUBLEBUFFER, &value);
00058   if (GLUT_WIND_IS_DOUBLE(mode) != (value != 0))
00059     return 1;
00060 
00061   /* Must match mono/stereo request. */
00062   glXGetConfig(__glutDisplay, vi, GLX_STEREO, &value);
00063   if (GLUT_WIND_IS_STEREO(mode) != (value != 0))
00064     return 1;
00065 
00066   /* Alpha and accumulation buffers incompatible with color
00067      index. */
00068   if (GLUT_WIND_HAS_ALPHA(mode) || GLUT_WIND_HAS_ACCUM(mode))
00069     return 1;
00070 
00071   /* Look for depth buffer if requested. */
00072   glXGetConfig(__glutDisplay, vi, GLX_DEPTH_SIZE, &value);
00073   if (GLUT_WIND_HAS_DEPTH(mode) && (value <= 0))
00074     return 1;
00075 
00076   /* Look for stencil buffer if requested. */
00077   glXGetConfig(__glutDisplay, vi, GLX_STENCIL_SIZE, &value);
00078   if (GLUT_WIND_HAS_STENCIL(mode) && (value <= 0))
00079     return 1;
00080 
00081 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
00082   /* XXX Multisampled overlay color index??  Pretty unlikely. */
00083   /* Look for multisampling if requested. */
00084   if (__glutIsSupportedByGLX("GLX_SGIS_multisample"))
00085     glXGetConfig(__glutDisplay, vi, GLX_SAMPLES_SGIS, &value);
00086   else
00087     value = 0;
00088   if (GLUT_WIND_IS_MULTISAMPLE(mode) && (value <= 0))
00089     return 1;
00090 #endif
00091 
00092   return 0;
00093 }
00094 #endif
00095 
00096 static XVisualInfo *
00097 getOverlayVisualInfoCI(unsigned int mode)
00098 {
00099 #if !defined(_WIN32)
00100   XLayerVisualInfo *vi;
00101   XLayerVisualInfo template;
00102   XVisualInfo *goodVisual, *returnVisual;
00103   int nitems, i, j, bad;
00104 
00105   /* The GLX 1.0 glXChooseVisual is does not permit queries
00106      based on pixel transparency (and GLX_BUFFER_SIZE uses
00107      "smallest that meets" its requirement instead of "largest
00108      that meets" that GLUT wants. So, GLUT implements its own
00109      visual selection routine for color index overlays. */
00110 
00111   /* Try three overlay layers. */
00112   for (i = 1; i <= 3; i++) {
00113     template.vinfo.screen = __glutScreen;
00114     template.vinfo.class = PseudoColor;
00115     template.layer = i;
00116     template.type = TransparentPixel;
00117     vi = __glutXGetLayerVisualInfo(__glutDisplay,
00118       VisualTransparentType | VisualScreenMask | VisualClassMask | VisualLayerMask,
00119       &template, &nitems);
00120     if (vi) {
00121       /* Check list for acceptable visual meeting requirements
00122          of requested display mode. */
00123       for (j = 0; j < nitems; j++) {
00124         bad = checkOverlayAcceptability(&vi[j].vinfo, mode);
00125         if (bad) {
00126           /* Set vi[j].vinfo.visual to mark it unacceptable. */
00127           vi[j].vinfo.visual = NULL;
00128         }
00129       }
00130 
00131       /* Look through list to find deepest acceptable visual. */
00132       goodVisual = NULL;
00133       for (j = 0; j < nitems; j++) {
00134         if (vi[j].vinfo.visual) {
00135           if (goodVisual == NULL) {
00136             goodVisual = &vi[j].vinfo;
00137           } else {
00138             if (goodVisual->depth < vi[j].vinfo.depth) {
00139               goodVisual = &vi[j].vinfo;
00140             }
00141           }
00142         }
00143       }
00144 
00145       /* If a visual is found, clean up and return the visual. */
00146       if (goodVisual) {
00147         returnVisual = (XVisualInfo *) malloc(sizeof(XVisualInfo));
00148         if (returnVisual) {
00149           *returnVisual = *goodVisual;
00150         }
00151         XFree(vi);
00152         return returnVisual;
00153       }
00154       XFree(vi);
00155     }
00156   }
00157 #endif /* !_WIN32 */
00158   return NULL;
00159 }
00160 
00161 /* ARGSUSED */
00162 static XVisualInfo *
00163 getOverlayVisualInfoRGB(unsigned int mode)
00164 {
00165 
00166   /* XXX For now, transparent RGBA overlays are not supported
00167      by GLUT.  RGBA overlays raise difficult questions about
00168      what the transparent pixel (really color) value should be.
00169 
00170      Color index overlay transparency is "easy" because the
00171      transparent pixel value does not affect displayable colors
00172      (except for stealing one color cell) since colors are
00173      determined by indirection through a colormap, and because
00174      it is uncommon for arbitrary pixel values in color index to
00175      be "calculated" (as can occur with a host of RGBA operations
00176      like lighting, blending, etc) so it is easy to avoid the
00177      transparent pixel value.
00178 
00179      Since it is typically easy to avoid the transparent pixel
00180      value in color index mode, if GLUT tells the programmer what
00181      pixel is transparent, then most program can easily avoid
00182      generating that pixel value except when they intend
00183      transparency.  GLUT returns whatever transparent pixel value
00184      is provided by the system through glutGet(
00185      GLUT_TRANSPARENT_INDEX).
00186 
00187      Theory versus practice for RGBA overlay transparency: In
00188      theory, the reasonable thing is enabling overlay transparency
00189      when an overlay pixel's destination alpha is 0 because this
00190      allows overlay transparency to be controlled via alpha and all
00191      visibile colors are permited, but no hardware I am aware of
00192      supports this practice (and it requires destination alpha which
00193      is typically optional and quite uncommon for overlay windows!). 
00194 
00195      In practice, the choice of  transparent pixel value is typically
00196      "hardwired" into most graphics hardware to a single pixel value.
00197      SGI hardware uses true black (0,0,0) without regard for the
00198      destination alpha.  This is far from ideal because true black (a
00199      common color that is easy to accidently generate) can not be
00200      generated in an RGBA overlay. I am not sure what other vendors
00201      do.
00202 
00203      Pragmatically, most of the typical things you want to do in the
00204      overlays can be done in color index (rubber banding, pop-up
00205      menus, etc.).  One solution for GLUT would be to simply
00206      "advertise" what RGB triple (or possibly RGBA quadruple or simply 
00207      A alone) generates transparency.  The problem with this approach
00208      is that it forces programmers to avoid whatever arbitrary color
00209      various systems decide is transparent.  This is a difficult
00210      burden to place on programmers that want to portably make use of
00211      overlays.
00212 
00213      To actually support transparent RGBA overlays, there are really
00214      two reaonsable options.  ONE: Simply mandate that true black is
00215      the RGBA overlay transparent color (what IRIS GL did).  This is
00216      nice for programmers since only one option, nice for existing SGI 
00217      hardware, bad for anyone (including SGI) who wants to improve
00218      upon "true black" RGB transparency. 
00219 
00220      Or TWO: Provide a set of queriable "transparency types" (like
00221      "true black" or "alpha == 0" or "true white" or even a queriable
00222      transparent color).  This is harder for programmers, OK for
00223      existing SGI hardware, and it leaves open the issue of what other 
00224      modes are reasonable.
00225 
00226      Option TWO seems the more general approach, but since hardware
00227      designers will likely only implement a single mode (this is a
00228      scan out issue where bandwidth is pressing issue), codifying
00229      multiple speculative approaches nobody may ever implement seems
00230      silly.  And option ONE fiats a suboptimal solution.
00231 
00232      Therefore, I defer any decision of how GLUT should support RGBA
00233      overlay transparency and leave support for it unimplemented.
00234      Nobody has been pressing me for RGBA overlay transparency (though 
00235      people have requested color index overlay transparency
00236      repeatedly).  Geez, if you read this far you are either really
00237      bored or maybe actually  interested in this topic.  Anyway, if
00238      you have ideas (particularly if you plan on implementing a
00239      hardware scheme for RGBA overlay transparency), I'd be
00240      interested.
00241 
00242      For the record, SGI's expiremental Framebufer Configuration
00243      experimental GLX extension uses option TWO.  Transparency modes
00244      for "none" and "RGB" are defined (others could be defined later). 
00245      What RGB value is the transparent one must be queried. 
00246 
00247      I was hoping GLUT could have something that required less work
00248      from the programmer to use portably. -mjk */
00249 
00250   __glutWarning("RGBA overlays are not supported by GLUT (for now).");
00251   return NULL;
00252 }
00253 
00254 static XVisualInfo *
00255 getOverlayVisualInfo(unsigned int mode)
00256 {
00257   /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
00258   if (GLUT_WIND_IS_LUMINANCE(mode))
00259     return NULL;
00260 
00261   if (GLUT_WIND_IS_RGB(mode))
00262     return getOverlayVisualInfoRGB(mode);
00263   else
00264     return getOverlayVisualInfoCI(mode);
00265 }
00266 
00267 #if !defined(_WIN32)
00268 
00269 /* The GLUT overlay can come and go, and the overlay window has
00270    a distinct X window ID.  Logically though, GLUT treats the
00271    normal and overlay windows as a unified window.  In
00272    particular, X input events typically go to the overlay window 
00273    since it is "on top of" the normal window.  When an overlay
00274    window ID is destroyed (due to glutRemoveOverlay or a call to 
00275    glutEstablishOverlay when an overlay already exists), we
00276    still keep track of the overlay window ID until we get back a 
00277    DestroyNotify event for the overlay window. Otherwise, we
00278    could lose track of X input events sent to a destroyed
00279    overlay.  To avoid this, we keep the destroyed overlay window 
00280    ID on a "stale window" list.  This lets us properly route X
00281    input events generated on destroyed overlay windows to the
00282    proper GLUT window. */
00283 static void
00284 addStaleWindow(GLUTwindow * window, Window win)
00285 {
00286   GLUTstale *entry;
00287 
00288   entry = (GLUTstale *) malloc(sizeof(GLUTstale));
00289   if (!entry)
00290     __glutFatalError("out of memory");
00291   entry->window = window;
00292   entry->win = win;
00293   entry->next = __glutStaleWindowList;
00294   __glutStaleWindowList = entry;
00295 }
00296 
00297 #endif
00298 
00299 void
00300 __glutFreeOverlay(GLUToverlay * overlay)
00301 {
00302   if (overlay->visAlloced)
00303     XFree(overlay->vis);
00304   XDestroyWindow(__glutDisplay, overlay->win);
00305   glXDestroyContext(__glutDisplay, overlay->ctx);
00306   if (overlay->colormap) {
00307     /* Only color index overlays have colormap data structure. */
00308     __glutFreeColormap(overlay->colormap);
00309   }
00310   free(overlay);
00311 }
00312 
00313 static XVisualInfo *
00314 determineOverlayVisual(int *treatAsSingle, Bool * visAlloced, void **fbc)
00315 {
00316   if (__glutDisplayString) {
00317     XVisualInfo *vi;
00318     int i;
00319 
00320     /* __glutDisplayString should be NULL except if
00321        glutInitDisplayString has been called to register a
00322        different display string.  Calling glutInitDisplayString
00323        means using a string instead of an integer mask determine 
00324 
00325        the visual to use. Using the function pointer variable
00326        __glutDetermineVisualFromString below avoids linking in
00327        the code for implementing glutInitDisplayString (ie,
00328        glut_dstr.o) unless glutInitDisplayString gets called by
00329        the application. */
00330 
00331     assert(__glutDetermineVisualFromString);
00332 
00333     /* Try three overlay layers. */
00334     *visAlloced = False;
00335     *fbc = NULL;
00336     for (i = 1; i <= 3; i++) {
00337       requiredOverlayCriteria[0].value = i;
00338       vi = __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
00339         requiredOverlayCriteria, numRequiredOverlayCriteria,
00340         requiredOverlayCriteriaMask, fbc);
00341       if (vi) {
00342         return vi;
00343       }
00344     }
00345     return NULL;
00346   } else {
00347     *visAlloced = True;
00348     *fbc = NULL;
00349     return __glutDetermineVisual(__glutDisplayMode,
00350       treatAsSingle, getOverlayVisualInfo);
00351   }
00352 }
00353 
00354 /* CENTRY */
00355 void APIENTRY
00356 glutEstablishOverlay(void)
00357 {
00358   GLUToverlay *overlay;
00359   GLUTwindow *window;
00360   XSetWindowAttributes wa;
00361 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
00362   GLXFBConfigSGIX fbc;
00363 #else
00364   void *fbc;
00365 #endif
00366 
00367   /* Register a routine to free an overlay with glut_win.c;
00368      this keeps glut_win.c from pulling in all of
00369      glut_overlay.c when no overlay functionality is used by
00370      the application. */
00371   __glutFreeOverlayFunc = __glutFreeOverlay;
00372 
00373   window = __glutCurrentWindow;
00374 
00375   /* Allow for an existant overlay to be re-established perhaps
00376      if you wanted a different display mode. */
00377   if (window->overlay) {
00378 #if !defined(_WIN32)
00379     addStaleWindow(window, window->overlay->win);
00380 #endif
00381     __glutFreeOverlay(window->overlay);
00382   }
00383   overlay = (GLUToverlay *) malloc(sizeof(GLUToverlay));
00384   if (!overlay)
00385     __glutFatalError("out of memory.");
00386 
00387   overlay->vis = determineOverlayVisual(&overlay->treatAsSingle,
00388     &overlay->visAlloced, (void **) &fbc);
00389   if (!overlay->vis) {
00390     __glutFatalError("lacks overlay support.");
00391   }
00392 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig) && defined(__sgi)
00393   if (fbc) {
00394     window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
00395       GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
00396   } else
00397 #endif
00398   {
00399     overlay->ctx = glXCreateContext(__glutDisplay, overlay->vis,
00400       None, __glutTryDirect);
00401   }
00402   if (!overlay->ctx) {
00403     __glutFatalError(
00404       "failed to create overlay OpenGL rendering context.");
00405   }
00406 #if !defined(_WIN32)
00407   overlay->isDirect = glXIsDirect(__glutDisplay, overlay->ctx);
00408   if (__glutForceDirect) {
00409     if (!overlay->isDirect) {
00410       __glutFatalError("direct rendering not possible.");
00411     }
00412   }
00413 #endif
00414   __glutSetupColormap(overlay->vis, &overlay->colormap, &overlay->cmap);
00415   overlay->transparentPixel = __glutGetTransparentPixel(__glutDisplay,
00416     overlay->vis);
00417   wa.colormap = overlay->cmap;
00418   wa.background_pixel = overlay->transparentPixel;
00419   wa.event_mask = window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK;
00420   wa.border_pixel = 0;
00421 #if defined(_WIN32)
00422   /* XXX Overlays not supported in Win32 yet. */
00423 #else
00424   overlay->win = XCreateWindow(__glutDisplay,
00425     window->win,
00426     window->x, window->y, window->width, window->height, 0,
00427     overlay->vis->depth, InputOutput, overlay->vis->visual,
00428     CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
00429     &wa);
00430 #endif
00431   if (window->children) {
00432     /* Overlay window must be lowered below any GLUT
00433        subwindows. */
00434     XLowerWindow(__glutDisplay, overlay->win);
00435   }
00436   XMapWindow(__glutDisplay, overlay->win);
00437   overlay->shownState = 1;
00438 
00439   overlay->display = NULL;
00440 
00441   /* Make sure a reshape gets delivered. */
00442   window->forceReshape = True;
00443 
00444 #if !defined(_WIN32)
00445   __glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
00446 #endif
00447 
00448   window->overlay = overlay;
00449   glutUseLayer(GLUT_OVERLAY);
00450 
00451   if (overlay->treatAsSingle) {
00452     glDrawBuffer(GL_FRONT);
00453     glReadBuffer(GL_FRONT);
00454   }
00455 }
00456 
00457 void APIENTRY
00458 glutRemoveOverlay(void)
00459 {
00460   GLUTwindow *window = __glutCurrentWindow;
00461   GLUToverlay *overlay = __glutCurrentWindow->overlay;
00462 
00463   if (!window->overlay)
00464     return;
00465 
00466   /* If using overlay, switch to the normal layer. */
00467   if (window->renderWin == overlay->win) {
00468     glutUseLayer(GLUT_NORMAL);
00469   }
00470 #if !defined(_WIN32)
00471   addStaleWindow(window, overlay->win);
00472 #endif
00473   __glutFreeOverlay(overlay);
00474   window->overlay = NULL;
00475 #if !defined(_WIN32)
00476   __glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
00477 #endif
00478 }
00479 
00480 void APIENTRY
00481 glutUseLayer(GLenum layer)
00482 {
00483   GLUTwindow *window = __glutCurrentWindow;
00484 
00485   switch (layer) {
00486   case GLUT_NORMAL:
00487 #ifdef _WIN32
00488     window->renderDc = window->hdc;
00489 #endif
00490     window->renderWin = window->win;
00491     window->renderCtx = window->ctx;
00492     break;
00493   case GLUT_OVERLAY:
00494     /* Did you crash here?  Calling glutUseLayer(GLUT_OVERLAY)
00495        without an overlay established is erroneous.  Fix your
00496        code. */
00497 #ifdef _WIN32
00498     window->renderDc = window->overlay->hdc;
00499 #endif
00500     window->renderWin = window->overlay->win;
00501     window->renderCtx = window->overlay->ctx;
00502     break;
00503   default:
00504     __glutWarning("glutUseLayer: unknown layer, %d.", layer);
00505     break;
00506   }
00507   __glutSetWindow(window);
00508 }
00509 
00510 void APIENTRY
00511 glutPostOverlayRedisplay(void)
00512 {
00513   __glutPostRedisplay(__glutCurrentWindow, GLUT_OVERLAY_REDISPLAY_WORK);
00514 }
00515 
00516 /* The advantage of this routine is that it saves the cost of a
00517    glutSetWindow call (entailing an expensive OpenGL context
00518    switch), particularly useful when multiple windows need
00519    redisplays posted at the same times. */
00520 void APIENTRY
00521 glutPostWindowOverlayRedisplay(int win)
00522 {
00523   __glutPostRedisplay(__glutWindowList[win - 1], GLUT_OVERLAY_REDISPLAY_WORK);
00524 }
00525 
00526 void APIENTRY
00527 glutOverlayDisplayFunc(GLUTdisplayCB displayFunc)
00528 {
00529   if (!__glutCurrentWindow->overlay) {
00530     __glutWarning("glutOverlayDisplayFunc: window has no overlay established");
00531     return;
00532   }
00533   __glutCurrentWindow->overlay->display = displayFunc;
00534 }
00535 
00536 void APIENTRY
00537 glutHideOverlay(void)
00538 {
00539   if (!__glutCurrentWindow->overlay) {
00540     __glutWarning("glutHideOverlay: window has no overlay established");
00541     return;
00542   }
00543   XUnmapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
00544   __glutCurrentWindow->overlay->shownState = 0;
00545 }
00546 
00547 void APIENTRY
00548 glutShowOverlay(void)
00549 {
00550   if (!__glutCurrentWindow->overlay) {
00551     __glutWarning("glutShowOverlay: window has no overlay established");
00552     return;
00553   }
00554   XMapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
00555   __glutCurrentWindow->overlay->shownState = 1;
00556 }
00557 
00558 int APIENTRY
00559 glutLayerGet(GLenum param)
00560 {
00561   switch (param) {
00562   case GLUT_OVERLAY_POSSIBLE:
00563     {
00564       XVisualInfo *vi;
00565       Bool dummy, visAlloced;
00566       void *fbc;
00567 
00568       vi = determineOverlayVisual(&dummy, &visAlloced, &fbc);
00569       if (vi) {
00570         if (visAlloced)
00571           XFree(vi);
00572         return 1;
00573       }
00574       return 0;
00575     }
00576   case GLUT_LAYER_IN_USE:
00577     return __glutCurrentWindow->renderWin != __glutCurrentWindow->win;
00578   case GLUT_HAS_OVERLAY:
00579     return __glutCurrentWindow->overlay != NULL;
00580   case GLUT_TRANSPARENT_INDEX:
00581     if (__glutCurrentWindow->overlay) {
00582       return __glutCurrentWindow->overlay->transparentPixel;
00583     } else {
00584       return -1;
00585     }
00586   case GLUT_NORMAL_DAMAGED:
00587     /* __glutWindowDamaged is used so the damage state within
00588        the window (or overlay belwo) can be cleared before
00589        calling a display callback so on return, the state does
00590        not have to be cleared (since upon return from the
00591        callback the window could be destroyed (or layer
00592        removed). */
00593     return (__glutCurrentWindow->workMask & GLUT_REPAIR_WORK)
00594       || __glutWindowDamaged;
00595   case GLUT_OVERLAY_DAMAGED:
00596     if (__glutCurrentWindow->overlay) {
00597       return (__glutCurrentWindow->workMask & GLUT_OVERLAY_REPAIR_WORK)
00598         || __glutWindowDamaged;
00599     } else {
00600       return -1;
00601     }
00602   default:
00603     __glutWarning("invalid glutLayerGet param: %d", param);
00604     return -1;
00605   }
00606 }
00607 /* ENDCENTRY */

Generated on Mon Sep 18 11:39:31 2006 for jot by  doxygen 1.4.4