2 /* Copyright (c) Mark J. Kilgard, 1996, 1997. */
4 /* This program is freely distributable without licensing fees
5 and is provided without guarantee or warrantee expressed or
6 implied. This program is -not- in the public domain. */
15 #include <X11/Xutil.h>
16 #include <X11/Xatom.h> /* for XA_RGB_DEFAULT_MAP atom */
18 #include <Xmu/StdCmap.h> /* for XmuLookupStandardColormap */
20 #include <X11/Xmu/StdCmap.h> /* for XmuLookupStandardColormap */
25 #include "layerutil.h"
27 static Criterion requiredOverlayCriteria
[] =
29 {LEVEL
, EQ
, 1}, /* This entry gets poked in
30 determineOverlayVisual. */
32 {XPSEUDOCOLOR
, EQ
, 1},
36 static int numRequiredOverlayCriteria
= sizeof(requiredOverlayCriteria
) / sizeof(Criterion
);
37 static int requiredOverlayCriteriaMask
=
38 (1 << LEVEL
) | (1 << TRANSPARENT
) | (1 << XSTATICGRAY
) | (1 << RGBA
) | (1 << CI_MODE
);
42 checkOverlayAcceptability(XVisualInfo
* vi
, unsigned int mode
)
46 /* Must support OpenGL. */
47 glXGetConfig(__glutDisplay
, vi
, GLX_USE_GL
, &value
);
51 /* Must be color index. */
52 glXGetConfig(__glutDisplay
, vi
, GLX_RGBA
, &value
);
56 /* Must match single/double buffering request. */
57 glXGetConfig(__glutDisplay
, vi
, GLX_DOUBLEBUFFER
, &value
);
58 if (GLUT_WIND_IS_DOUBLE(mode
) != (value
!= 0))
61 /* Must match mono/stereo request. */
62 glXGetConfig(__glutDisplay
, vi
, GLX_STEREO
, &value
);
63 if (GLUT_WIND_IS_STEREO(mode
) != (value
!= 0))
66 /* Alpha and accumulation buffers incompatible with color
68 if (GLUT_WIND_HAS_ALPHA(mode
) || GLUT_WIND_HAS_ACCUM(mode
))
71 /* Look for depth buffer if requested. */
72 glXGetConfig(__glutDisplay
, vi
, GLX_DEPTH_SIZE
, &value
);
73 if (GLUT_WIND_HAS_DEPTH(mode
) && (value
<= 0))
76 /* Look for stencil buffer if requested. */
77 glXGetConfig(__glutDisplay
, vi
, GLX_STENCIL_SIZE
, &value
);
78 if (GLUT_WIND_HAS_STENCIL(mode
) && (value
<= 0))
81 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
82 /* XXX Multisampled overlay color index?? Pretty unlikely. */
83 /* Look for multisampling if requested. */
84 if (__glutIsSupportedByGLX("GLX_SGIS_multisample"))
85 glXGetConfig(__glutDisplay
, vi
, GLX_SAMPLES_SGIS
, &value
);
88 if (GLUT_WIND_IS_MULTISAMPLE(mode
) && (value
<= 0))
97 getOverlayVisualInfoCI(unsigned int mode
)
100 XLayerVisualInfo
*vi
;
101 XLayerVisualInfo
template;
102 XVisualInfo
*goodVisual
, *returnVisual
;
103 int nitems
, i
, j
, bad
;
105 /* The GLX 1.0 glXChooseVisual is does not permit queries
106 based on pixel transparency (and GLX_BUFFER_SIZE uses
107 "smallest that meets" its requirement instead of "largest
108 that meets" that GLUT wants. So, GLUT implements its own
109 visual selection routine for color index overlays. */
111 /* Try three overlay layers. */
112 for (i
= 1; i
<= 3; i
++) {
113 template.vinfo
.screen
= __glutScreen
;
114 template.vinfo
.class = PseudoColor
;
116 template.type
= TransparentPixel
;
117 vi
= __glutXGetLayerVisualInfo(__glutDisplay
,
118 VisualTransparentType
| VisualScreenMask
| VisualClassMask
| VisualLayerMask
,
121 /* Check list for acceptable visual meeting requirements
122 of requested display mode. */
123 for (j
= 0; j
< nitems
; j
++) {
124 bad
= checkOverlayAcceptability(&vi
[j
].vinfo
, mode
);
126 /* Set vi[j].vinfo.visual to mark it unacceptable. */
127 vi
[j
].vinfo
.visual
= NULL
;
131 /* Look through list to find deepest acceptable visual. */
133 for (j
= 0; j
< nitems
; j
++) {
134 if (vi
[j
].vinfo
.visual
) {
135 if (goodVisual
== NULL
) {
136 goodVisual
= &vi
[j
].vinfo
;
138 if (goodVisual
->depth
< vi
[j
].vinfo
.depth
) {
139 goodVisual
= &vi
[j
].vinfo
;
145 /* If a visual is found, clean up and return the visual. */
147 returnVisual
= (XVisualInfo
*) malloc(sizeof(XVisualInfo
));
149 *returnVisual
= *goodVisual
;
163 getOverlayVisualInfoRGB(unsigned int mode
)
166 /* XXX For now, transparent RGBA overlays are not supported
167 by GLUT. RGBA overlays raise difficult questions about
168 what the transparent pixel (really color) value should be.
170 Color index overlay transparency is "easy" because the
171 transparent pixel value does not affect displayable colors
172 (except for stealing one color cell) since colors are
173 determined by indirection through a colormap, and because
174 it is uncommon for arbitrary pixel values in color index to
175 be "calculated" (as can occur with a host of RGBA operations
176 like lighting, blending, etc) so it is easy to avoid the
177 transparent pixel value.
179 Since it is typically easy to avoid the transparent pixel
180 value in color index mode, if GLUT tells the programmer what
181 pixel is transparent, then most program can easily avoid
182 generating that pixel value except when they intend
183 transparency. GLUT returns whatever transparent pixel value
184 is provided by the system through glutGet(
185 GLUT_TRANSPARENT_INDEX).
187 Theory versus practice for RGBA overlay transparency: In
188 theory, the reasonable thing is enabling overlay transparency
189 when an overlay pixel's destination alpha is 0 because this
190 allows overlay transparency to be controlled via alpha and all
191 visibile colors are permited, but no hardware I am aware of
192 supports this practice (and it requires destination alpha which
193 is typically optional and quite uncommon for overlay windows!).
195 In practice, the choice of transparent pixel value is typically
196 "hardwired" into most graphics hardware to a single pixel value.
197 SGI hardware uses true black (0,0,0) without regard for the
198 destination alpha. This is far from ideal because true black (a
199 common color that is easy to accidently generate) can not be
200 generated in an RGBA overlay. I am not sure what other vendors
203 Pragmatically, most of the typical things you want to do in the
204 overlays can be done in color index (rubber banding, pop-up
205 menus, etc.). One solution for GLUT would be to simply
206 "advertise" what RGB triple (or possibly RGBA quadruple or simply
207 A alone) generates transparency. The problem with this approach
208 is that it forces programmers to avoid whatever arbitrary color
209 various systems decide is transparent. This is a difficult
210 burden to place on programmers that want to portably make use of
213 To actually support transparent RGBA overlays, there are really
214 two reaonsable options. ONE: Simply mandate that true black is
215 the RGBA overlay transparent color (what IRIS GL did). This is
216 nice for programmers since only one option, nice for existing SGI
217 hardware, bad for anyone (including SGI) who wants to improve
218 upon "true black" RGB transparency.
220 Or TWO: Provide a set of queriable "transparency types" (like
221 "true black" or "alpha == 0" or "true white" or even a queriable
222 transparent color). This is harder for programmers, OK for
223 existing SGI hardware, and it leaves open the issue of what other
224 modes are reasonable.
226 Option TWO seems the more general approach, but since hardware
227 designers will likely only implement a single mode (this is a
228 scan out issue where bandwidth is pressing issue), codifying
229 multiple speculative approaches nobody may ever implement seems
230 silly. And option ONE fiats a suboptimal solution.
232 Therefore, I defer any decision of how GLUT should support RGBA
233 overlay transparency and leave support for it unimplemented.
234 Nobody has been pressing me for RGBA overlay transparency (though
235 people have requested color index overlay transparency
236 repeatedly). Geez, if you read this far you are either really
237 bored or maybe actually interested in this topic. Anyway, if
238 you have ideas (particularly if you plan on implementing a
239 hardware scheme for RGBA overlay transparency), I'd be
242 For the record, SGI's expiremental Framebufer Configuration
243 experimental GLX extension uses option TWO. Transparency modes
244 for "none" and "RGB" are defined (others could be defined later).
245 What RGB value is the transparent one must be queried.
247 I was hoping GLUT could have something that required less work
248 from the programmer to use portably. -mjk */
250 __glutWarning("RGBA overlays are not supported by GLUT (for now).");
255 getOverlayVisualInfo(unsigned int mode
)
257 /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
258 if (GLUT_WIND_IS_LUMINANCE(mode
))
261 if (GLUT_WIND_IS_RGB(mode
))
262 return getOverlayVisualInfoRGB(mode
);
264 return getOverlayVisualInfoCI(mode
);
269 /* The GLUT overlay can come and go, and the overlay window has
270 a distinct X window ID. Logically though, GLUT treats the
271 normal and overlay windows as a unified window. In
272 particular, X input events typically go to the overlay window
273 since it is "on top of" the normal window. When an overlay
274 window ID is destroyed (due to glutRemoveOverlay or a call to
275 glutEstablishOverlay when an overlay already exists), we
276 still keep track of the overlay window ID until we get back a
277 DestroyNotify event for the overlay window. Otherwise, we
278 could lose track of X input events sent to a destroyed
279 overlay. To avoid this, we keep the destroyed overlay window
280 ID on a "stale window" list. This lets us properly route X
281 input events generated on destroyed overlay windows to the
282 proper GLUT window. */
284 addStaleWindow(GLUTwindow
* window
, Window win
)
288 entry
= (GLUTstale
*) malloc(sizeof(GLUTstale
));
290 __glutFatalError("out of memory");
291 entry
->window
= window
;
293 entry
->next
= __glutStaleWindowList
;
294 __glutStaleWindowList
= entry
;
300 __glutFreeOverlay(GLUToverlay
* overlay
)
302 if (overlay
->visAlloced
)
304 XDestroyWindow(__glutDisplay
, overlay
->win
);
305 glXDestroyContext(__glutDisplay
, overlay
->ctx
);
306 if (overlay
->colormap
) {
307 /* Only color index overlays have colormap data structure. */
308 __glutFreeColormap(overlay
->colormap
);
314 determineOverlayVisual(int *treatAsSingle
, Bool
* visAlloced
, void **fbc
)
316 if (__glutDisplayString
) {
320 /* __glutDisplayString should be NULL except if
321 glutInitDisplayString has been called to register a
322 different display string. Calling glutInitDisplayString
323 means using a string instead of an integer mask determine
325 the visual to use. Using the function pointer variable
326 __glutDetermineVisualFromString below avoids linking in
327 the code for implementing glutInitDisplayString (ie,
328 glut_dstr.o) unless glutInitDisplayString gets called by
331 assert(__glutDetermineVisualFromString
);
333 /* Try three overlay layers. */
336 for (i
= 1; i
<= 3; i
++) {
337 requiredOverlayCriteria
[0].value
= i
;
338 vi
= __glutDetermineVisualFromString(__glutDisplayString
, treatAsSingle
,
339 requiredOverlayCriteria
, numRequiredOverlayCriteria
,
340 requiredOverlayCriteriaMask
, fbc
);
349 return __glutDetermineVisual(__glutDisplayMode
,
350 treatAsSingle
, getOverlayVisualInfo
);
356 glutEstablishOverlay(void)
358 GLUToverlay
*overlay
;
360 XSetWindowAttributes wa
;
361 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
367 /* Register a routine to free an overlay with glut_win.c;
368 this keeps glut_win.c from pulling in all of
369 glut_overlay.c when no overlay functionality is used by
371 __glutFreeOverlayFunc
= __glutFreeOverlay
;
373 window
= __glutCurrentWindow
;
375 /* Allow for an existant overlay to be re-established perhaps
376 if you wanted a different display mode. */
377 if (window
->overlay
) {
379 addStaleWindow(window
, window
->overlay
->win
);
381 __glutFreeOverlay(window
->overlay
);
383 overlay
= (GLUToverlay
*) malloc(sizeof(GLUToverlay
));
385 __glutFatalError("out of memory.");
387 overlay
->vis
= determineOverlayVisual(&overlay
->treatAsSingle
,
388 &overlay
->visAlloced
, (void **) &fbc
);
390 __glutFatalError("lacks overlay support.");
392 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
394 window
->ctx
= glXCreateContextWithConfigSGIX(__glutDisplay
, fbc
,
395 GLX_RGBA_TYPE_SGIX
, None
, __glutTryDirect
);
399 overlay
->ctx
= glXCreateContext(__glutDisplay
, overlay
->vis
,
400 None
, __glutTryDirect
);
404 "failed to create overlay OpenGL rendering context.");
407 overlay
->isDirect
= glXIsDirect(__glutDisplay
, overlay
->ctx
);
408 if (__glutForceDirect
) {
409 if (!overlay
->isDirect
) {
410 __glutFatalError("direct rendering not possible.");
414 __glutSetupColormap(overlay
->vis
, &overlay
->colormap
, &overlay
->cmap
);
415 overlay
->transparentPixel
= __glutGetTransparentPixel(__glutDisplay
,
417 wa
.colormap
= overlay
->cmap
;
418 wa
.background_pixel
= overlay
->transparentPixel
;
419 wa
.event_mask
= window
->eventMask
& GLUT_OVERLAY_EVENT_FILTER_MASK
;
422 /* XXX Overlays not supported in Win32 yet. */
424 overlay
->win
= XCreateWindow(__glutDisplay
,
426 0, 0, window
->width
, window
->height
, 0,
427 overlay
->vis
->depth
, InputOutput
, overlay
->vis
->visual
,
428 CWBackPixel
| CWBorderPixel
| CWEventMask
| CWColormap
,
431 if (window
->children
) {
432 /* Overlay window must be lowered below any GLUT
434 XLowerWindow(__glutDisplay
, overlay
->win
);
436 XMapWindow(__glutDisplay
, overlay
->win
);
437 overlay
->shownState
= 1;
439 overlay
->display
= NULL
;
441 /* Make sure a reshape gets delivered. */
442 window
->forceReshape
= True
;
445 __glutPutOnWorkList(__glutToplevelOf(window
), GLUT_COLORMAP_WORK
);
448 window
->overlay
= overlay
;
449 glutUseLayer(GLUT_OVERLAY
);
451 if (overlay
->treatAsSingle
) {
452 glDrawBuffer(GL_FRONT
);
453 glReadBuffer(GL_FRONT
);
458 glutRemoveOverlay(void)
460 GLUTwindow
*window
= __glutCurrentWindow
;
461 GLUToverlay
*overlay
= __glutCurrentWindow
->overlay
;
463 if (!window
->overlay
)
466 /* If using overlay, switch to the normal layer. */
467 if (window
->renderWin
== overlay
->win
) {
468 glutUseLayer(GLUT_NORMAL
);
471 addStaleWindow(window
, overlay
->win
);
473 __glutFreeOverlay(overlay
);
474 window
->overlay
= NULL
;
476 __glutPutOnWorkList(__glutToplevelOf(window
), GLUT_COLORMAP_WORK
);
481 glutUseLayer(GLenum layer
)
483 GLUTwindow
*window
= __glutCurrentWindow
;
488 window
->renderDc
= window
->hdc
;
490 window
->renderWin
= window
->win
;
491 window
->renderCtx
= window
->ctx
;
494 /* Did you crash here? Calling glutUseLayer(GLUT_OVERLAY)
495 without an overlay established is erroneous. Fix your
498 window
->renderDc
= window
->overlay
->hdc
;
500 window
->renderWin
= window
->overlay
->win
;
501 window
->renderCtx
= window
->overlay
->ctx
;
504 __glutWarning("glutUseLayer: unknown layer, %d.", layer
);
507 __glutSetWindow(window
);
511 glutPostOverlayRedisplay(void)
513 __glutPostRedisplay(__glutCurrentWindow
, GLUT_OVERLAY_REDISPLAY_WORK
);
516 /* The advantage of this routine is that it saves the cost of a
517 glutSetWindow call (entailing an expensive OpenGL context
518 switch), particularly useful when multiple windows need
519 redisplays posted at the same times. */
521 glutPostWindowOverlayRedisplay(int win
)
523 __glutPostRedisplay(__glutWindowList
[win
- 1], GLUT_OVERLAY_REDISPLAY_WORK
);
527 glutOverlayDisplayFunc(GLUTdisplayCB displayFunc
)
529 if (!__glutCurrentWindow
->overlay
) {
530 __glutWarning("glutOverlayDisplayFunc: window has no overlay established");
533 __glutCurrentWindow
->overlay
->display
= displayFunc
;
537 glutHideOverlay(void)
539 if (!__glutCurrentWindow
->overlay
) {
540 __glutWarning("glutHideOverlay: window has no overlay established");
543 XUnmapWindow(__glutDisplay
, __glutCurrentWindow
->overlay
->win
);
544 __glutCurrentWindow
->overlay
->shownState
= 0;
548 glutShowOverlay(void)
550 if (!__glutCurrentWindow
->overlay
) {
551 __glutWarning("glutShowOverlay: window has no overlay established");
554 XMapWindow(__glutDisplay
, __glutCurrentWindow
->overlay
->win
);
555 __glutCurrentWindow
->overlay
->shownState
= 1;
559 glutLayerGet(GLenum param
)
562 case GLUT_OVERLAY_POSSIBLE
:
565 Bool dummy
, visAlloced
;
568 vi
= determineOverlayVisual(&dummy
, &visAlloced
, &fbc
);
576 case GLUT_LAYER_IN_USE
:
577 return __glutCurrentWindow
->renderWin
!= __glutCurrentWindow
->win
;
578 case GLUT_HAS_OVERLAY
:
579 return __glutCurrentWindow
->overlay
!= NULL
;
580 case GLUT_TRANSPARENT_INDEX
:
581 if (__glutCurrentWindow
->overlay
) {
582 return __glutCurrentWindow
->overlay
->transparentPixel
;
586 case GLUT_NORMAL_DAMAGED
:
587 /* __glutWindowDamaged is used so the damage state within
588 the window (or overlay belwo) can be cleared before
589 calling a display callback so on return, the state does
590 not have to be cleared (since upon return from the
591 callback the window could be destroyed (or layer
593 return (__glutCurrentWindow
->workMask
& GLUT_REPAIR_WORK
)
594 || __glutWindowDamaged
;
595 case GLUT_OVERLAY_DAMAGED
:
596 if (__glutCurrentWindow
->overlay
) {
597 return (__glutCurrentWindow
->workMask
& GLUT_OVERLAY_REPAIR_WORK
)
598 || __glutWindowDamaged
;
603 __glutWarning("invalid glutLayerGet param: %d", param
);