source: trunk/src/opengl/glut/glut_overlay.c

Last change on this file was 2996, checked in by jeroen, 25 years ago

* empty log message *

File size: 19.5 KB
Line 
1/* $Id: glut_overlay.c,v 1.3 2000-03-04 19:10:15 jeroen Exp $ */
2/* Copyright (c) Mark J. Kilgard, 1996, 1997. */
3
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. */
7
8#include <stdlib.h>
9#include <stdio.h>
10#include <string.h>
11#include <assert.h>
12
13
14#if !defined(_WIN32) && !defined(__WIN32OS2__)
15#include <X11/Xlib.h>
16#include <X11/Xutil.h>
17#include <X11/Xatom.h> /* for XA_RGB_DEFAULT_MAP atom */
18#if defined (__vms)
19#include <Xmu/StdCmap.h> /* for XmuLookupStandardColormap */
20#else
21#include <X11/Xmu/StdCmap.h> /* for XmuLookupStandardColormap */
22#endif
23#endif /* !_WIN32 */
24
25#include "glutint.h"
26#include "layerutil.h"
27
28//#if defined(__WIN32OS2__)
29//#include "wgl.h"
30//#endif
31
32static Criterion requiredOverlayCriteria[] =
33{
34 {LEVEL, EQ, 1}, /* This entry gets poked in
35 determineOverlayVisual. */
36 {TRANSPARENT, EQ, 1},
37 {XPSEUDOCOLOR, EQ, 1},
38 {RGBA, EQ, 0},
39 {BUFFER_SIZE, GTE, 1}
40};
41static int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion);
42static int requiredOverlayCriteriaMask =
43(1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE);
44
45#if !defined(_WIN32) && !defined(__WIN32OS2__)
46static int
47checkOverlayAcceptability(XVisualInfo * vi, unsigned int mode)
48{
49 int value;
50
51 /* Must support OpenGL. */
52 glXGetConfig(__glutDisplay, vi, GLX_USE_GL, &value);
53 if (!value)
54 return 1;
55
56 /* Must be color index. */
57 glXGetConfig(__glutDisplay, vi, GLX_RGBA, &value);
58 if (value)
59 return 1;
60
61 /* Must match single/double buffering request. */
62 glXGetConfig(__glutDisplay, vi, GLX_DOUBLEBUFFER, &value);
63 if (GLUT_WIND_IS_DOUBLE(mode) != (value != 0))
64 return 1;
65
66 /* Must match mono/stereo request. */
67 glXGetConfig(__glutDisplay, vi, GLX_STEREO, &value);
68 if (GLUT_WIND_IS_STEREO(mode) != (value != 0))
69 return 1;
70
71 /* Alpha and accumulation buffers incompatible with color
72 index. */
73 if (GLUT_WIND_HAS_ALPHA(mode) || GLUT_WIND_HAS_ACCUM(mode))
74 return 1;
75
76 /* Look for depth buffer if requested. */
77 glXGetConfig(__glutDisplay, vi, GLX_DEPTH_SIZE, &value);
78 if (GLUT_WIND_HAS_DEPTH(mode) && (value <= 0))
79 return 1;
80
81 /* Look for stencil buffer if requested. */
82 glXGetConfig(__glutDisplay, vi, GLX_STENCIL_SIZE, &value);
83 if (GLUT_WIND_HAS_STENCIL(mode) && (value <= 0))
84 return 1;
85
86#if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
87 /* XXX Multisampled overlay color index?? Pretty unlikely. */
88 /* Look for multisampling if requested. */
89 if (__glutIsSupportedByGLX("GLX_SGIS_multisample"))
90 glXGetConfig(__glutDisplay, vi, GLX_SAMPLES_SGIS, &value);
91 else
92 value = 0;
93 if (GLUT_WIND_IS_MULTISAMPLE(mode) && (value <= 0))
94 return 1;
95#endif
96
97 return 0;
98}
99#endif
100
101static XVisualInfo *
102getOverlayVisualInfoCI(unsigned int mode)
103{
104#if !defined(_WIN32) && !defined(__WIN32OS2__)
105 XLayerVisualInfo *vi;
106 XLayerVisualInfo template;
107 XVisualInfo *goodVisual, *returnVisual;
108 int nitems, i, j, bad;
109
110 /* The GLX 1.0 glXChooseVisual is does not permit queries
111 based on pixel transparency (and GLX_BUFFER_SIZE uses
112 "smallest that meets" its requirement instead of "largest
113 that meets" that GLUT wants. So, GLUT implements its own
114 visual selection routine for color index overlays. */
115
116 /* Try three overlay layers. */
117 for (i = 1; i <= 3; i++) {
118 template.vinfo.screen = __glutScreen;
119 template.vinfo.class = PseudoColor;
120 template.layer = i;
121 template.type = TransparentPixel;
122 vi = __glutXGetLayerVisualInfo(__glutDisplay,
123 VisualTransparentType | VisualScreenMask | VisualClassMask | VisualLayerMask,
124 &template, &nitems);
125 if (vi) {
126 /* Check list for acceptable visual meeting requirements
127 of requested display mode. */
128 for (j = 0; j < nitems; j++) {
129 bad = checkOverlayAcceptability(&vi[j].vinfo, mode);
130 if (bad) {
131 /* Set vi[j].vinfo.visual to mark it unacceptable. */
132 vi[j].vinfo.visual = NULL;
133 }
134 }
135
136 /* Look through list to find deepest acceptable visual. */
137 goodVisual = NULL;
138 for (j = 0; j < nitems; j++) {
139 if (vi[j].vinfo.visual) {
140 if (goodVisual == NULL) {
141 goodVisual = &vi[j].vinfo;
142 } else {
143 if (goodVisual->depth < vi[j].vinfo.depth) {
144 goodVisual = &vi[j].vinfo;
145 }
146 }
147 }
148 }
149
150 /* If a visual is found, clean up and return the visual. */
151 if (goodVisual) {
152 returnVisual = (XVisualInfo *) malloc(sizeof(XVisualInfo));
153 if (returnVisual) {
154 *returnVisual = *goodVisual;
155 }
156 XFree(vi);
157 return returnVisual;
158 }
159 XFree(vi);
160 }
161 }
162#endif /* !_WIN32 */
163 return NULL;
164}
165
166/* ARGSUSED */
167static XVisualInfo *
168getOverlayVisualInfoRGB(unsigned int mode)
169{
170
171 /* XXX For now, transparent RGBA overlays are not supported
172 by GLUT. RGBA overlays raise difficult questions about
173 what the transparent pixel (really color) value should be.
174
175 Color index overlay transparency is "easy" because the
176 transparent pixel value does not affect displayable colors
177 (except for stealing one color cell) since colors are
178 determined by indirection through a colormap, and because
179 it is uncommon for arbitrary pixel values in color index to
180 be "calculated" (as can occur with a host of RGBA operations
181 like lighting, blending, etc) so it is easy to avoid the
182 transparent pixel value.
183
184 Since it is typically easy to avoid the transparent pixel
185 value in color index mode, if GLUT tells the programmer what
186 pixel is transparent, then most program can easily avoid
187 generating that pixel value except when they intend
188 transparency. GLUT returns whatever transparent pixel value
189 is provided by the system through glutGet(
190 GLUT_TRANSPARENT_INDEX).
191
192 Theory versus practice for RGBA overlay transparency: In
193 theory, the reasonable thing is enabling overlay transparency
194 when an overlay pixel's destination alpha is 0 because this
195 allows overlay transparency to be controlled via alpha and all
196 visibile colors are permited, but no hardware I am aware of
197 supports this practice (and it requires destination alpha which
198 is typically optional and quite uncommon for overlay windows!).
199
200 In practice, the choice of transparent pixel value is typically
201 "hardwired" into most graphics hardware to a single pixel value.
202 SGI hardware uses true black (0,0,0) without regard for the
203 destination alpha. This is far from ideal because true black (a
204 common color that is easy to accidently generate) can not be
205 generated in an RGBA overlay. I am not sure what other vendors
206 do.
207
208 Pragmatically, most of the typical things you want to do in the
209 overlays can be done in color index (rubber banding, pop-up
210 menus, etc.). One solution for GLUT would be to simply
211 "advertise" what RGB triple (or possibly RGBA quadruple or simply
212 A alone) generates transparency. The problem with this approach
213 is that it forces programmers to avoid whatever arbitrary color
214 various systems decide is transparent. This is a difficult
215 burden to place on programmers that want to portably make use of
216 overlays.
217
218 To actually support transparent RGBA overlays, there are really
219 two reaonsable options. ONE: Simply mandate that true black is
220 the RGBA overlay transparent color (what IRIS GL did). This is
221 nice for programmers since only one option, nice for existing SGI
222 hardware, bad for anyone (including SGI) who wants to improve
223 upon "true black" RGB transparency.
224
225 Or TWO: Provide a set of queriable "transparency types" (like
226 "true black" or "alpha == 0" or "true white" or even a queriable
227 transparent color). This is harder for programmers, OK for
228 existing SGI hardware, and it leaves open the issue of what other
229 modes are reasonable.
230
231 Option TWO seems the more general approach, but since hardware
232 designers will likely only implement a single mode (this is a
233 scan out issue where bandwidth is pressing issue), codifying
234 multiple speculative approaches nobody may ever implement seems
235 silly. And option ONE fiats a suboptimal solution.
236
237 Therefore, I defer any decision of how GLUT should support RGBA
238 overlay transparency and leave support for it unimplemented.
239 Nobody has been pressing me for RGBA overlay transparency (though
240 people have requested color index overlay transparency
241 repeatedly). Geez, if you read this far you are either really
242 bored or maybe actually interested in this topic. Anyway, if
243 you have ideas (particularly if you plan on implementing a
244 hardware scheme for RGBA overlay transparency), I'd be
245 interested.
246
247 For the record, SGI's expiremental Framebufer Configuration
248 experimental GLX extension uses option TWO. Transparency modes
249 for "none" and "RGB" are defined (others could be defined later).
250 What RGB value is the transparent one must be queried.
251
252 I was hoping GLUT could have something that required less work
253 from the programmer to use portably. -mjk */
254
255 __glutWarning("RGBA overlays are not supported by GLUT (for now).");
256 return NULL;
257}
258
259static XVisualInfo *
260getOverlayVisualInfo(unsigned int mode)
261{
262 /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
263 if (GLUT_WIND_IS_LUMINANCE(mode))
264 return NULL;
265
266 if (GLUT_WIND_IS_RGB(mode))
267 return getOverlayVisualInfoRGB(mode);
268 else
269 return getOverlayVisualInfoCI(mode);
270}
271
272#if !defined(_WIN32) && !defined(__WIN32OS2__)
273
274/* The GLUT overlay can come and go, and the overlay window has
275 a distinct X window ID. Logically though, GLUT treats the
276 normal and overlay windows as a unified window. In
277 particular, X input events typically go to the overlay window
278 since it is "on top of" the normal window. When an overlay
279 window ID is destroyed (due to glutRemoveOverlay or a call to
280 glutEstablishOverlay when an overlay already exists), we
281 still keep track of the overlay window ID until we get back a
282 DestroyNotify event for the overlay window. Otherwise, we
283 could lose track of X input events sent to a destroyed
284 overlay. To avoid this, we keep the destroyed overlay window
285 ID on a "stale window" list. This lets us properly route X
286 input events generated on destroyed overlay windows to the
287 proper GLUT window. */
288static void
289addStaleWindow(GLUTwindow * window, Window win)
290{
291 GLUTstale *entry;
292
293 entry = (GLUTstale *) malloc(sizeof(GLUTstale));
294 if (!entry)
295 __glutFatalError("out of memory");
296 entry->window = window;
297 entry->win = win;
298 entry->next = __glutStaleWindowList;
299 __glutStaleWindowList = entry;
300}
301
302#endif
303
304void
305__glutFreeOverlay(GLUToverlay * overlay)
306{
307 if (overlay->visAlloced)
308 XFree(overlay->vis);
309 XDestroyWindow(__glutDisplay, overlay->win);
310 glXDestroyContext(__glutDisplay, overlay->ctx);
311 if (overlay->colormap) {
312 /* Only color index overlays have colormap data structure. */
313 __glutFreeColormap(overlay->colormap);
314 }
315 free(overlay);
316}
317
318static XVisualInfo *
319determineOverlayVisual(Bool *treatAsSingle, Bool * visAlloced, void **fbc)
320{
321 if (__glutDisplayString) {
322 XVisualInfo *vi;
323 int i;
324
325 /* __glutDisplayString should be NULL except if
326 glutInitDisplayString has been called to register a
327 different display string. Calling glutInitDisplayString
328 means using a string instead of an integer mask determine
329
330 the visual to use. Using the function pointer variable
331 __glutDetermineVisualFromString below avoids linking in
332 the code for implementing glutInitDisplayString (ie,
333 glut_dstr.o) unless glutInitDisplayString gets called by
334 the application. */
335
336 assert(__glutDetermineVisualFromString);
337
338 /* Try three overlay layers. */
339 *visAlloced = False;
340 *fbc = NULL;
341 for (i = 1; i <= 3; i++) {
342 requiredOverlayCriteria[0].value = i;
343 vi = __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
344 requiredOverlayCriteria, numRequiredOverlayCriteria,
345 requiredOverlayCriteriaMask, fbc);
346 if (vi) {
347 return vi;
348 }
349 }
350 return NULL;
351 } else {
352 *visAlloced = True;
353 *fbc = NULL;
354 return __glutDetermineVisual(__glutDisplayMode,
355 treatAsSingle, getOverlayVisualInfo);
356 }
357}
358
359/* CENTRY */
360void APIENTRY
361glutEstablishOverlay(void)
362{
363 GLUToverlay *overlay;
364 GLUTwindow *window;
365 XSetWindowAttributes wa;
366#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
367 GLXFBConfigSGIX fbc;
368#else
369 void *fbc;
370#endif
371
372 /* Register a routine to free an overlay with glut_win.c;
373 this keeps glut_win.c from pulling in all of
374 glut_overlay.c when no overlay functionality is used by
375 the application. */
376 __glutFreeOverlayFunc = __glutFreeOverlay;
377
378 window = __glutCurrentWindow;
379
380 /* Allow for an existant overlay to be re-established perhaps
381 if you wanted a different display mode. */
382 if (window->overlay) {
383#if !defined(_WIN32) && !defined(__WIN32OS2__)
384 addStaleWindow(window, window->overlay->win);
385#endif
386 __glutFreeOverlay(window->overlay);
387 }
388 overlay = (GLUToverlay *) malloc(sizeof(GLUToverlay));
389 if (!overlay)
390 __glutFatalError("out of memory.");
391
392 overlay->vis = determineOverlayVisual(&overlay->treatAsSingle,
393 &overlay->visAlloced, (void **) &fbc);
394 if (!overlay->vis) {
395 __glutFatalError("lacks overlay support.");
396 }
397#if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
398 if (fbc) {
399 window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
400 GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
401 } else
402#endif
403 {
404 overlay->ctx = glXCreateContext(__glutDisplay, overlay->vis,
405 None, __glutTryDirect);
406 }
407 if (!overlay->ctx) {
408 __glutFatalError(
409 "failed to create overlay OpenGL rendering context.");
410 }
411#if !defined(_WIN32) && !defined(__WIN32OS2__)
412 overlay->isDirect = glXIsDirect(__glutDisplay, overlay->ctx);
413 if (__glutForceDirect) {
414 if (!overlay->isDirect) {
415 __glutFatalError("direct rendering not possible.");
416 }
417 }
418#endif
419 __glutSetupColormap(overlay->vis, &overlay->colormap, &overlay->cmap);
420 overlay->transparentPixel = __glutGetTransparentPixel(__glutDisplay,
421 overlay->vis);
422 wa.colormap = overlay->cmap;
423 wa.background_pixel = overlay->transparentPixel;
424 wa.event_mask = window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK;
425 wa.border_pixel = 0;
426#if defined(_WIN32)
427 /* XXX Overlays not supported in Win32 yet. */
428#else
429#if defined(__WIN32OS2__)
430 /* Overlay support is also not available in Odin! */
431#else
432 overlay->win = XCreateWindow(__glutDisplay,
433 window->win,
434 0, 0, window->width, window->height, 0,
435 overlay->vis->depth, InputOutput, overlay->vis->visual,
436 CWBackPixel | CWBorderPixel | CWEventMask | CWColormap,
437 &wa);
438#endif
439#endif
440 if (window->children) {
441 /* Overlay window must be lowered below any GLUT
442 subwindows. */
443 XLowerWindow(__glutDisplay, overlay->win);
444 }
445 XMapWindow(__glutDisplay, overlay->win);
446 overlay->shownState = 1;
447
448 overlay->display = NULL;
449
450 /* Make sure a reshape gets delivered. */
451 window->forceReshape = True;
452
453#if !defined(_WIN32) && !defined(__WIN32OS2__)
454 __glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
455#endif
456
457 window->overlay = overlay;
458 glutUseLayer((GLenum)GLUT_OVERLAY);
459
460 if (overlay->treatAsSingle) {
461 glDrawBuffer(GL_FRONT);
462 glReadBuffer(GL_FRONT);
463 }
464}
465
466void APIENTRY
467glutRemoveOverlay(void)
468{
469 GLUTwindow *window = __glutCurrentWindow;
470 GLUToverlay *overlay = __glutCurrentWindow->overlay;
471
472 if (!window->overlay)
473 return;
474
475 /* If using overlay, switch to the normal layer. */
476 if (window->renderWin == overlay->win) {
477 glutUseLayer((GLenum)GLUT_NORMAL);
478 }
479#if !defined(_WIN32) && !defined(__WIN32OS2__)
480 addStaleWindow(window, overlay->win);
481#endif
482 __glutFreeOverlay(overlay);
483 window->overlay = NULL;
484#if !defined(_WIN32) && !defined(__WIN32OS2__)
485 __glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
486#endif
487}
488
489void APIENTRY
490glutUseLayer(GLenum layer)
491{
492 GLUTwindow *window = __glutCurrentWindow;
493
494 switch (layer) {
495 case GLUT_NORMAL:
496#if defined(_WIN32) || defined(__WIN32OS2__)
497 window->renderDc = window->hdc;
498#endif
499 window->renderWin = window->win;
500 window->renderCtx = window->ctx;
501 break;
502 case GLUT_OVERLAY:
503 /* Did you crash here? Calling glutUseLayer(GLUT_OVERLAY)
504 without an overlay established is erroneous. Fix your
505 code. */
506#if defined(_WIN32) || defined(__WIN32OS2__)
507 window->renderDc = window->overlay->hdc;
508#endif
509 window->renderWin = window->overlay->win;
510 window->renderCtx = window->overlay->ctx;
511 break;
512 default:
513 __glutWarning("glutUseLayer: unknown layer, %d.", layer);
514 break;
515 }
516 __glutSetWindow(window);
517}
518
519void APIENTRY
520glutPostOverlayRedisplay(void)
521{
522 __glutPostRedisplay(__glutCurrentWindow, GLUT_OVERLAY_REDISPLAY_WORK);
523}
524
525/* The advantage of this routine is that it saves the cost of a
526 glutSetWindow call (entailing an expensive OpenGL context
527 switch), particularly useful when multiple windows need
528 redisplays posted at the same times. */
529void APIENTRY
530glutPostWindowOverlayRedisplay(int win)
531{
532 __glutPostRedisplay(__glutWindowList[win - 1], GLUT_OVERLAY_REDISPLAY_WORK);
533}
534
535void APIENTRY
536glutOverlayDisplayFunc(GLUTdisplayCB displayFunc)
537{
538 if (!__glutCurrentWindow->overlay) {
539 __glutWarning("glutOverlayDisplayFunc: window has no overlay established");
540 return;
541 }
542 __glutCurrentWindow->overlay->display = displayFunc;
543}
544
545void APIENTRY
546glutHideOverlay(void)
547{
548 if (!__glutCurrentWindow->overlay) {
549 __glutWarning("glutHideOverlay: window has no overlay established");
550 return;
551 }
552 XUnmapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
553 __glutCurrentWindow->overlay->shownState = 0;
554}
555
556void APIENTRY
557glutShowOverlay(void)
558{
559 if (!__glutCurrentWindow->overlay) {
560 __glutWarning("glutShowOverlay: window has no overlay established");
561 return;
562 }
563 XMapWindow(__glutDisplay, __glutCurrentWindow->overlay->win);
564 __glutCurrentWindow->overlay->shownState = 1;
565}
566
567int APIENTRY
568glutLayerGet(GLenum param)
569{
570 switch (param) {
571 case GLUT_OVERLAY_POSSIBLE:
572 {
573 XVisualInfo *vi;
574 Bool dummy, visAlloced;
575 void *fbc;
576
577 vi = determineOverlayVisual(&dummy, &visAlloced, &fbc);
578 if (vi) {
579 if (visAlloced)
580 XFree(vi);
581 return 1;
582 }
583 return 0;
584 }
585 case GLUT_LAYER_IN_USE:
586 return __glutCurrentWindow->renderWin != __glutCurrentWindow->win;
587 case GLUT_HAS_OVERLAY:
588 return __glutCurrentWindow->overlay != NULL;
589 case GLUT_TRANSPARENT_INDEX:
590 if (__glutCurrentWindow->overlay) {
591 return __glutCurrentWindow->overlay->transparentPixel;
592 } else {
593 return -1;
594 }
595 case GLUT_NORMAL_DAMAGED:
596 /* __glutWindowDamaged is used so the damage state within
597 the window (or overlay belwo) can be cleared before
598 calling a display callback so on return, the state does
599 not have to be cleared (since upon return from the
600 callback the window could be destroyed (or layer
601 removed). */
602 return (__glutCurrentWindow->workMask & GLUT_REPAIR_WORK)
603 || __glutWindowDamaged;
604 case GLUT_OVERLAY_DAMAGED:
605 if (__glutCurrentWindow->overlay) {
606 return (__glutCurrentWindow->workMask & GLUT_OVERLAY_REPAIR_WORK)
607 || __glutWindowDamaged;
608 } else {
609 return -1;
610 }
611 default:
612 __glutWarning("invalid glutLayerGet param: %d", param);
613 return -1;
614 }
615}
616/* ENDCENTRY */
Note: See TracBrowser for help on using the repository browser.