summaryrefslogtreecommitdiffstats
path: root/src/glut/glx/glut_overlay.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glut/glx/glut_overlay.c')
-rw-r--r--src/glut/glx/glut_overlay.c607
1 files changed, 607 insertions, 0 deletions
diff --git a/src/glut/glx/glut_overlay.c b/src/glut/glx/glut_overlay.c
new file mode 100644
index 00000000000..13ece12a159
--- /dev/null
+++ b/src/glut/glx/glut_overlay.c
@@ -0,0 +1,607 @@
+
+/* Copyright (c) Mark J. Kilgard, 1996, 1997. */
+
+/* This program is freely distributable without licensing fees
+ and is provided without guarantee or warrantee expressed or
+ implied. This program is -not- in the public domain. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#if !defined(_WIN32)
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h> /* for XA_RGB_DEFAULT_MAP atom */
+#if defined (__vms)
+#include <Xmu/StdCmap.h> /* for XmuLookupStandardColormap */
+#else
+#include <X11/Xmu/StdCmap.h> /* for XmuLookupStandardColormap */
+#endif
+#endif /* !_WIN32 */
+
+#include "glutint.h"
+#include "layerutil.h"
+
+static Criterion requiredOverlayCriteria[] =
+{
+ {LEVEL, EQ, 1}, /* This entry gets poked in
+ determineOverlayVisual. */
+ {TRANSPARENT, EQ, 1},
+ {XPSEUDOCOLOR, EQ, 1},
+ {RGBA, EQ, 0},
+ {BUFFER_SIZE, GTE, 1}
+};
+static int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion);
+static int requiredOverlayCriteriaMask =
+(1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE);
+
+#if !defined(_WIN32)
+static int
+checkOverlayAcceptability(XVisualInfo * vi, unsigned int mode)
+{
+ int value;
+
+ /* Must support OpenGL. */
+ glXGetConfig(__glutDisplay, vi, GLX_USE_GL, &value);
+ if (!value)
+ return 1;
+
+ /* Must be color index. */
+ glXGetConfig(__glutDisplay, vi, GLX_RGBA, &value);
+ if (value)
+ return 1;
+
+ /* Must match single/double buffering request. */
+ glXGetConfig(__glutDisplay, vi, GLX_DOUBLEBUFFER, &value);
+ if (GLUT_WIND_IS_DOUBLE(mode) != (value != 0))
+ return 1;
+
+ /* Must match mono/stereo request. */
+ glXGetConfig(__glutDisplay, vi, GLX_STEREO, &value);
+ if (GLUT_WIND_IS_STEREO(mode) != (value != 0))
+ return 1;
+
+ /* Alpha and accumulation buffers incompatible with color
+ index. */
+ if (GLUT_WIND_HAS_ALPHA(mode) || GLUT_WIND_HAS_ACCUM(mode))
+ return 1;
+
+ /* Look for depth buffer if requested. */
+ glXGetConfig(__glutDisplay, vi, GLX_DEPTH_SIZE, &value);
+ if (GLUT_WIND_HAS_DEPTH(mode) && (value <= 0))
+ return 1;
+
+ /* Look for stencil buffer if requested. */
+ glXGetConfig(__glutDisplay, vi, GLX_STENCIL_SIZE, &value);
+ if (GLUT_WIND_HAS_STENCIL(mode) && (value <= 0))
+ return 1;
+
+#if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
+ /* XXX Multisampled overlay color index?? Pretty unlikely. */
+ /* Look for multisampling if requested. */
+ if (__glutIsSupportedByGLX("GLX_SGIS_multisample"))
+ glXGetConfig(__glutDisplay, vi, GLX_SAMPLES_SGIS, &value);
+ else
+ value = 0;
+ if (GLUT_WIND_IS_MULTISAMPLE(mode) && (value <= 0))
+ return 1;
+#endif
+
+ return 0;
+}
+#endif
+
+static XVisualInfo *
+getOverlayVisualInfoCI(unsigned int mode)
+{
+#if !defined(_WIN32)
+ XLayerVisualInfo *vi;
+ XLayerVisualInfo template;
+ XVisualInfo *goodVisual, *returnVisual;
+ int nitems, i, j, bad;
+
+ /* The GLX 1.0 glXChooseVisual is does not permit queries
+ based on pixel transparency (and GLX_BUFFER_SIZE uses
+ "smallest that meets" its requirement instead of "largest
+ that meets" that GLUT wants. So, GLUT implements its own
+ visual selection routine for color index overlays. */
+
+ /* Try three overlay layers. */
+ for (i = 1; i <= 3; i++) {
+ template.vinfo.screen = __glutScreen;
+ template.vinfo.class = PseudoColor;
+ template.layer = i;
+ template.type = TransparentPixel;
+ vi = __glutXGetLayerVisualInfo(__glutDisplay,
+ VisualTransparentType | VisualScreenMask | VisualClassMask | VisualLayerMask,
+ &template, &nitems);
+ if (vi) {
+ /* Check list for acceptable visual meeting requirements
+ of requested display mode. */
+ for (j = 0; j < nitems; j++) {
+ bad = checkOverlayAcceptability(&vi[j].vinfo, mode);
+ if (bad) {
+ /* Set vi[j].vinfo.visual to mark it unacceptable. */
+ vi[j].vinfo.visual = NULL;
+ }
+ }
+
+ /* Look through list to find deepest acceptable visual. */
+ goodVisual = NULL;
+ for (j = 0; j < nitems; j++) {
+ if (vi[j].vinfo.visual) {
+ if (goodVisual == NULL) {
+ goodVisual = &vi[j].vinfo;
+ } else {
+ if (goodVisual->depth < vi[j].vinfo.depth) {
+ goodVisual = &vi[j].vinfo;
+ }
+ }
+ }
+ }
+
+ /* If a visual is found, clean up and return the visual. */
+ if (goodVisual) {
+ returnVisual = (XVisualInfo *) malloc(sizeof(XVisualInfo));
+ if (returnVisual) {
+ *returnVisual = *goodVisual;
+ }
+ XFree(vi);
+ return returnVisual;
+ }
+ XFree(vi);
+ }
+ }
+#endif /* !_WIN32 */
+ return NULL;
+}
+
+/* ARGSUSED */
+static XVisualInfo *
+getOverlayVisualInfoRGB(unsigned int mode)
+{
+
+ /* XXX For now, transparent RGBA overlays are not supported
+ by GLUT. RGBA overlays raise difficult questions about
+ what the transparent pixel (really color) value should be.
+
+ Color index overlay transparency is "easy" because the
+ transparent pixel value does not affect displayable colors
+ (except for stealing one color cell) since colors are
+ determined by indirection through a colormap, and because
+ it is uncommon for arbitrary pixel values in color index to
+ be "calculated" (as can occur with a host of RGBA operations
+ like lighting, blending, etc) so it is easy to avoid the
+ transparent pixel value.
+
+ Since it is typically easy to avoid the transparent pixel
+ value in color index mode, if GLUT tells the programmer what
+ pixel is transparent, then most program can easily avoid
+ generating that pixel value except when they intend
+ transparency. GLUT returns whatever transparent pixel value
+ is provided by the system through glutGet(
+ GLUT_TRANSPARENT_INDEX).
+
+ Theory versus practice for RGBA overlay transparency: In
+ theory, the reasonable thing is enabling overlay transparency
+ when an overlay pixel's destination alpha is 0 because this
+ allows overlay transparency to be controlled via alpha and all
+ visibile colors are permited, but no hardware I am aware of
+ supports this practice (and it requires destination alpha which
+ is typically optional and quite uncommon for overlay windows!).
+
+ In practice, the choice of transparent pixel value is typically
+ "hardwired" into most graphics hardware to a single pixel value.
+ SGI hardware uses true black (0,0,0) without regard for the
+ destination alpha. This is far from ideal because true black (a
+ common color that is easy to accidently generate) can not be
+ generated in an RGBA overlay. I am not sure what other vendors
+ do.
+
+ Pragmatically, most of the typical things you want to do in the
+ overlays can be done in color index (rubber banding, pop-up
+ menus, etc.). One solution for GLUT would be to simply
+ "advertise" what RGB triple (or possibly RGBA quadruple or simply
+ A alone) generates transparency. The problem with this approach
+ is that it forces programmers to avoid whatever arbitrary color
+ various systems decide is transparent. This is a difficult
+ burden to place on programmers that want to portably make use of
+ overlays.
+
+ To actually support transparent RGBA overlays, there are really
+ two reaonsable options. ONE: Simply mandate that true black is
+ the RGBA overlay transparent color (what IRIS GL did). This is
+ nice for programmers since only one option, nice for existing SGI
+ hardware, bad for anyone (including SGI) who wants to improve
+ upon "true black" RGB transparency.
+
+ Or TWO: Provide a set of queriable "transparency types" (like
+ "true black" or "alpha == 0" or "true white" or even a queriable
+ transparent color). This is harder for programmers, OK for
+ existing SGI hardware, and it leaves open the issue of what other
+ modes are reasonable.
+
+ Option TWO seems the more general approach, but since hardware
+ designers will likely only implement a single mode (this is a
+ scan out issue where bandwidth is pressing issue), codifying
+ multiple speculative approaches nobody may ever implement seems
+ silly. And option ONE fiats a suboptimal solution.
+
+ Therefore, I defer any decision of how GLUT should support RGBA
+ overlay transparency and leave support for it unimplemented.
+ Nobody has been pressing me for RGBA overlay transparency (though
+ people have requested color index overlay transparency
+ repeatedly). Geez, if you read this far you are either really
+ bored or maybe actually interested in this topic. Anyway, if
+ you have ideas (particularly if you plan on implementing a
+ hardware scheme for RGBA overlay transparency), I'd be
+ interested.
+
+ For the record, SGI's expiremental Framebufer Configuration
+ experimental GLX extension uses option TWO. Transparency modes
+ for "none" and "RGB" are defined (others could be defined later).
+ What RGB value is the transparent one must be queried.
+
+ I was hoping GLUT could have something that required less work
+ from the programmer to use portably. -mjk */
+
+ __glutWarning("RGBA overlays are not supported by GLUT (for now).");
+ return NULL;
+}
+
+static XVisualInfo *
+getOverlayVisualInfo(unsigned int mode)
+{
+ /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
+ if (GLUT_WIND_IS_LUMINANCE(mode))
+ return NULL;
+
+ if (GLUT_WIND_IS_RGB(mode))
+ return getOverlayVisualInfoRGB(mode);
+ else
+ return getOverlayVisualInfoCI(mode);
+}
+
+#if !defined(_WIN32)
+
+/* The GLUT overlay can come and go, and the overlay window has
+ a distinct X window ID. Logically though, GLUT treats the
+ normal and overlay windows as a unified window. In
+ particular, X input events typically go to the overlay window
+ since it is "on top of" the normal window. When an overlay
+ window ID is destroyed (due to glutRemoveOverlay or a call to
+ glutEstablishOverlay when an overlay already exists), we
+ still keep track of the overlay window ID until we get back a
+ DestroyNotify event for the overlay window. Otherwise, we
+ could lose track of X input events sent to a destroyed
+ overlay. To avoid this, we keep the destroyed overlay window
+ ID on a "stale window" list. This lets us properly route X
+ input events generated on destroyed overlay windows to the
+ proper GLUT window. */
+static void
+addStaleWindow(GLUTwindow * window, Window win)
+{
+ GLUTstale *entry;
+
+ entry = (GLUTstale *) malloc(sizeof(GLUTstale));
+ if (!entry)
+ __glutFatalError("out of memory");
+ entry->window = window;
+ entry->win = win;
+ entry->next = __glutStaleWindowList;
+ __glutStaleWindowList = entry;
+}
+
+#endif
+
+void
+__glutFreeOverlay(GLUToverlay * overlay)
+{
+ if (overlay->visAlloced)
+ XFree(overlay->vis);
+ XDestroyWindow(__glutDisplay, overlay->win);
+ glXDestroyContext(__glutDisplay, overlay->ctx);
+ if (overlay->colormap) {
+ /* Only color index overlays have colormap data structure. */
+ __glutFreeColormap(overlay->colormap);
+ }
+ free(overlay);
+}
+
+static XVisualInfo *
+determineOverlayVisual(int *treatAsSingle, Bool * visAlloced, void **fbc)
+{
+ if (__glutDisplayString) {
+ XVisualInfo *vi;
+ int i;
+
+ /* __glutDisplayString should be NULL except if
+ glutInitDisplayString has been called to register a
+ different display string. Calling glutInitDisplayString
+ means using a string instead of an integer mask determine
+
+ the visual to use. Using the function pointer variable
+ __glutDetermineVisualFromString below avoids linking in
+ the code for implementing glutInitDisplayString (ie,
+ glut_dstr.o) unless glutInitDisplayString gets called by
+ the application. */
+
+ assert(__glutDetermineVisualFromString);
+
+ /* Try three overlay layers. */
+ *visAlloced = False;
+ *fbc = NULL;
+ for (i = 1; i <= 3; i++) {
+ requiredOverlayCriteria[0].value = i;
+ vi = __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
+ requiredOverlayCriteria, numRequiredOverlayCriteria,
+ requiredOverlayCriteriaMask, fbc);
+ if (vi) {
+ return vi;
+ }
+ }
+ return NULL;
+ } else {
+ *visAlloced = True;
+ *fbc = NULL;
+ return __glutDetermineVisual(__glutDisplayMode,
+ treatAsSingle, getOverlayVisualInfo);
+ }
+}
+
+/* CENTRY */
+void APIENTRY
+glutEstablishOverlay(void)
+{
+ GLUToverlay *overlay;
+ GLUTwindow *window;
+ XSetWindowAttributes wa;
+#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
+ GLXFBConfigSGIX fbc;
+#else
+ void *fbc;
+#endif
+
+ /* Register a routine to free an overlay with glut_win.c;
+ this keeps glut_win.c from pulling in all of
+ glut_overlay.c when no overlay functionality is used by
+ the application. */
+ __glutFreeOverlayFunc = __glutFreeOverlay;
+
+ window = __glutCurrentWindow;
+
+ /* Allow for an existant overlay to be re-established perhaps
+ if you wanted a different display mode. */
+ if (window->overlay) {
+#if !defined(_WIN32)
+ addStaleWindow(window, window->overlay->win);
+#endif
+ __glutFreeOverlay(window->overlay);
+ }
+ overlay = (GLUToverlay *) malloc(sizeof(GLUToverlay));
+ if (!overlay)
+ __glutFatalError("out of memory.");
+
+ overlay->vis = determineOverlayVisual(&overlay->treatAsSingle,
+ &overlay->visAlloced, (void **) &fbc);
+ if (!overlay->vis) {
+ __glutFatalError("lacks overlay support.");
+ }
+#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
+ if (fbc) {
+ window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
+ GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
+ } else
+#endif
+ {
+ overlay->ctx = glXCreateContext(__glutDisplay, overlay->vis,
+ None, __glutTryDirect);
+ }
+ if (!overlay->ctx) {
+ __glutFatalError(
+ "failed to create overlay OpenGL rendering context.");
+ }
+#if !defined(_WIN32)
+ overlay->isDirect = glXIsDirect(__glutDisplay, overlay->ctx);
+ if (__glutForceDirect) {
+ if (!overlay->isDirect) {
+ __glutFatalError("direct rendering not possible.");
+ }
+ }
+#endif
+ __glutSetupColormap(overlay->vis, &overlay->colormap, &overlay->cmap);
+ overlay->transparentPixel = __glutGetTransparentPixel(__glutDisplay,
+ overlay->vis);
+ wa.colormap = overlay->cmap;
+ wa.background_pixel = overlay->transparentPixel;
+ wa.event_mask = window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK;
+ wa.border_pixel = 0;
+#if defined(_WIN32)
+ /* XXX Overlays not supported in Win32 yet. */
+#else
+ overlay->win = XCreateWindow(__glutDisplay,
+ window->win,
+ 0, 0, window->width, window->height, 0,
+ overlay->vis->depth, InputOutput, overlay->vis->visual,
+ CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
+ &wa);
+#endif
+ if (window->children) {
+ /* Overlay window must be lowered below any GLUT
+ subwindows. */
+ XLowerWindow(__glutDisplay, overlay->win);
+ }
+ XMapWindow(__glutDisplay, overlay->win);
+ overlay->shownState = 1;
+
+ overlay->display = NULL;
+
+ /* Make sure a reshape gets delivered. */
+ window->forceReshape = True;
+
+#if !defined(_WIN32)
+ __glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
+#endif
+
+ window->overlay = overlay;
+ glutUseLayer(GLUT_OVERLAY);
+
+ if (overlay->treatAsSingle) {
+ glDrawBuffer(GL_FRONT);
+ glReadBuffer(GL_FRONT);
+ }
+}
+
+void APIENTRY
+glutRemoveOverlay(void)
+{
+ GLUTwindow *window = __glutCurrentWindow;
+ GLUToverlay *overlay = __glutCurrentWindow->overlay;
+
+ if (!window->overlay)
+ return;
+
+ /* If using overlay, switch to the normal layer. */
+ if (window->renderWin == overlay->win) {
+ glutUseLayer(GLUT_NORMAL);
+ }
+#if !defined(_WIN32)
+ addStaleWindow(window, overlay->win);
+#endif
+ __glutFreeOverlay(overlay);
+ window->overlay = NULL;
+#if !defined(_WIN32)
+ __glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
+#endif
+}
+
+void APIENTRY
+glutUseLayer(GLenum layer)
+{
+ GLUTwindow *window = __glutCurrentWindow;
+
+ switch (layer) {
+ case GLUT_NORMAL:
+#ifdef _WIN32
+ window->renderDc = window->hdc;
+#endif
+ window->renderWin = window->win;
+ window->renderCtx = window->ctx;
+ break;
+ case GLUT_OVERLAY:
+ /* Did you crash here? Calling glutUseLayer(GLUT_OVERLAY)
+ without an overlay established is erroneous. Fix your
+ code. */
+#ifdef _WIN32
+ window->renderDc = window->overlay->hdc;
+#endif
+ window->renderWin = window->overlay->win;
+ window->renderCtx = window->overlay->ctx;
+ break;
+ default:
+ __glutWarning("glutUseLayer: unknown layer, %d.", layer);
+ break;
+ }
+ __glutSetWindow(window);
+}
+
+void APIENTRY
+glutPostOverlayRedisplay(void)
+{
+ __glutPostRedisplay(__glutCurrentWindow, GLUT_OVERLAY_REDISPLAY_WORK);
+}
+
+/* The advantage of this routine is that it saves the cost of a
+ glutSetWindow call (entailing an expensive OpenGL context
+ switch), particularly useful when multiple windows need
+ redisplays posted at the same times. */
+void APIENTRY
+glutPostWindowOverlayRedisplay(int win)
+{
+ __glutPostRedisplay(__glutWindowList[win - 1], GLUT_OVERLAY_REDISPLAY_WORK);
+}
+
+void APIENTRY
+glutOverlayDisplayFunc(GLUTdisplayCB displayFunc)
+{
+ if (!__glutCurrentWindow->overlay) {
+ __glutWarning("glutOverlayDisplayFunc: window has no overlay established");
+ return;
+ }
+ __glutCurrentWindow->overlay->display = displayFunc;
+}
+
+void APIENTRY
+glutHideOverlay(void)
+{
+ if (!__glutCurrentWindow->overlay) {
+ __glutWarning("glutHideOverlay: window has no overlay established");
+ return;
+ }
+ XUnmapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
+ __glutCurrentWindow->overlay->shownState = 0;
+}
+
+void APIENTRY
+glutShowOverlay(void)
+{
+ if (!__glutCurrentWindow->overlay) {
+ __glutWarning("glutShowOverlay: window has no overlay established");
+ return;
+ }
+ XMapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
+ __glutCurrentWindow->overlay->shownState = 1;
+}
+
+int APIENTRY
+glutLayerGet(GLenum param)
+{
+ switch (param) {
+ case GLUT_OVERLAY_POSSIBLE:
+ {
+ XVisualInfo *vi;
+ Bool dummy, visAlloced;
+ void *fbc;
+
+ vi = determineOverlayVisual(&dummy, &visAlloced, &fbc);
+ if (vi) {
+ if (visAlloced)
+ XFree(vi);
+ return 1;
+ }
+ return 0;
+ }
+ case GLUT_LAYER_IN_USE:
+ return __glutCurrentWindow->renderWin != __glutCurrentWindow->win;
+ case GLUT_HAS_OVERLAY:
+ return __glutCurrentWindow->overlay != NULL;
+ case GLUT_TRANSPARENT_INDEX:
+ if (__glutCurrentWindow->overlay) {
+ return __glutCurrentWindow->overlay->transparentPixel;
+ } else {
+ return -1;
+ }
+ case GLUT_NORMAL_DAMAGED:
+ /* __glutWindowDamaged is used so the damage state within
+ the window (or overlay belwo) can be cleared before
+ calling a display callback so on return, the state does
+ not have to be cleared (since upon return from the
+ callback the window could be destroyed (or layer
+ removed). */
+ return (__glutCurrentWindow->workMask & GLUT_REPAIR_WORK)
+ || __glutWindowDamaged;
+ case GLUT_OVERLAY_DAMAGED:
+ if (__glutCurrentWindow->overlay) {
+ return (__glutCurrentWindow->workMask & GLUT_OVERLAY_REPAIR_WORK)
+ || __glutWindowDamaged;
+ } else {
+ return -1;
+ }
+ default:
+ __glutWarning("invalid glutLayerGet param: %d", param);
+ return -1;
+ }
+}
+/* ENDCENTRY */