Next | Prev | Up | Top | Contents | Index

Looking at the Example Program

As the example program illustrates, integrating OpenGL drawing routines with a simple IRIS IM program involves only a few steps. Except for window creation and event handling, these steps are actually independent of whether the program uses Xt and Motif or Xlib.

The rest of this chapter looks at each step. Each step is discussed in one section:

Note that event handling, which is different depending on whether you use Xlib or Motif, is discussed in "Input Handling With Widgets and Xt" and, for Xlib programming, "Xlib Event Handling".


Opening the X Display

Before making any GLX (or OpenGL) calls, a program must open a display (required) and should find out whether the X server supports GLX (optional).

To open a display, use XOpenDisplay() if you're programming with Xlib, or XtOpenApplication() if you're working with widgets as in Example 2-1 above. XtOpenApplication() actually opens the display and performs some additional setup:

It is recommend (but not required) that you find out whether the X server supports GLX by calling glXQueryExtension().

Bool glXQueryExtension ( Display *dpy, int *errorBase, int *eventBase )
In most cases, NULL is appropriate for both errorBase and eventBase. See the reference page for more information.

Note: This call is not required (and therefore not part of motif/simplest.c), because glXChooseVisual() simply fails if GLX is not supported. It is included here because it's recommended for the sake of portability. If glXQueryExtension() succeeds, use glXQueryVersion() to find out which version of GLX is being used; an older version of the extension may not be able to do everything your version can do.

The following pseudo-code demonstrates checking for the version number:

glXQueryVersion(dpy, &major, &minor);
if (((major == 1) && (minor == 0)){
     /*assume GLX 1.0, avoid GLX 1.1 functionality*/
     }else
     /*can use GLX 1.1 functionality*/
 } 
Currently, GLX 1.0 and GLX 1.1 are supported as follows:

GLX 1.0

IRIX 5.1, 5.2, and 6.0.1

GLX 1.1

IRIX 5.3, 6.1, and 6.2
GLX 1.1 supports a few additional functions and provides a mechanism for using extensions. See the glxintro reference page.


Selecting a Visual

A visual determines how pixel values are mapped to the screen. The display mode of your OpenGL program (RGBA or color index) determines which X visuals are suitable. To find a visual with the attributes you want, call glXChooseVisual() with the desired parameters. Here's the function prototype:

XVisualInfo* glXChooseVisual(Display *dpy, int screen, int *attribList)
The visual returned by glXChooseVisual() is always a visual that supports OpenGL. It is guaranteed to have Boolean attributes matching those specified, and integer attributes with values at least as large as those specified. For detailed information, see the glXChooseVisual() reference page.

The framebuffer capabilities and other attributes of a window are determined statically by the visual used to create it. For example, to change a window from single-buffer to double-buffer, you have to switch to a different window created with a different visual.

Note: In general, ask for 1 bit of red, green, and blue to get maximum color resolution. Zero matches to the smallest available color resolution. Instead of calling glXChooseVisual(), you can also choose a visual as follows:

There is also an experimental extension that allows you to create and choose a glXFBConfig construct, which packages GLX drawable information, for use instead of a visual. See "The Framebuffer Configuration Extension".


Creating a Rendering Context

Creating a rendering context is the application's responsibility. Even if you choose to use IRIS IM, the widget does no context management. Before you can draw anything, you must therefore create a rendering context for OpenGL using glXCreateContext(), which has the following function prototype:

GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis,
                            GLXContext shareList, Bool direct)
Here's how you use the arguments:

dpy

The display you've already opened.

vis

The visual you've chosen with glXChooseVisual().

sharedList

A context to share display lists with, or NULL to not share display lists.

direct

Lets you specify direct or indirect rendering. For best performance, always request direct rendering. The OpenGL implementation automatically switches to indirect rendering when direct rendering isn't possible (for example, when rendering remotely). See "Direct and Indirect Rendering".

Creating the Window

After picking a visual and creating a context, you need to create a drawable (window or pixmap) that uses the chosen visual. How you create the drawable depends on whether you use Xlib or Motif calls and is discussed, with program examples, in "Drawing-Area Widget Setup and Creation" and "Creating a Colormap and a Window".


Binding the Context to the Window

If you're working with Xlib, bind the context to the window by calling glXMakeCurrent(). Example 3-2 is a complete Xlib program and illustrates how the function is used.

If you're working with widgets and have an OpenGL context and a window, bind them together with GLwDrawingAreaMakeCurrent(). This IRIS IM function is a front end to glXMakeCurrent(); it allows you to bind the context to the window without having to know the drawable ID and display.

If GLwDrawingAreaMakeCurrent() is successful, subsequent OpenGL calls use the new context to draw on the given drawable. The call fails if the context and the drawable are mismatched; that is, if they were created with different visuals.

Note: Don't make OpenGL calls until the context and window have been bound (made current). For each thread of execution, at most one context can be bound to at most one window or pixmap.

Note: "The Make Current Read Extension" allows you to attach separate read and write drawables to a GLX context.


Mapping the Window

A window can become visible only if it's mapped and all its parent windows are mapped. Note that mapping the window is not directly related to binding it to an OpenGL rendering context, but both need to happen if you want to display an
OpenGL application.

Mapping the window or realizing the widget is not synchronous with the call that performs the action. When a window is mapped, the window manager makes it visible if no other actions are specified to happen before. For example, some window managers display just an outline of the window instead of the window itself, letting the user position the window. When the user clicks, the window becomes visible.

If a window is mapped but is not yet visible, you may already set OpenGL state; for example, you may load textures or set colors, but rendering to the window is discarded (this includes rendering to a back buffer if you're doing double-buffering). You need to get an Expose event--if using Xlib--or the expose callback before the window is guaranteed to be visible on the screen. The init callback does not guarantee that the window is visible, only that it exists.

How you map the window on the screen depends on whether you've chosen to create an X window from scratch or use a widget:


Next | Prev | Up | Top | Contents | Index