Chapter 12. User Interface Mechanisms

Cosmo 3D applications either appear within a csWindow object or a window object that you create using X window code. The window provides an interface for users to interact with the Cosmo 3D application.

Cosmo 3D also supports user interaction by enabling the selection of screen objects.

This chapter discusses how to implement user interaction using X window code, csWindow, and selection mechanisms.

These are the sections in this chapter:

Creating a csWindow

All of the csWindow fields have default values. You may find that they satisfy the needs of your application. worm.cxx, for example, uses all the default values.

If you want to change the initial position, size, and mode of the csWindow object, you use the following methods:

static void         initDisplayMode(unsigned long mode);
static void         initPosition(int x, int y);
static void         initSize(int width, int height);

To reposition or reshape the window after its initial display, use the following methods:

static void         positionWindow(int x, int y);
static void         reshapeWindow(int width, int height);

To specify the title of the window or its icon, use the following methods:

static void         setWindowTitle(const char *title);
static void         setIconTitle(const char *title);

Note: If the title is NULL, the window has no borders, except on the PC.

To show, hide, or iconify a window, use the following methods:

static void         iconifyWindow(void);
static void         showWindow(void);
static void         hideWindow(void);

To create a full screen window, set the position to (0, 0) and the size to the size of the screen. To get the screen dimensions, use csWindow::get().

Manipulating the Window Stack

You can create more than one csWindow object at a time. You control the display of the csWindow objects by manipulating the window stack: the static csWindow methods manipulate the csWindow that is on the top of the stack.

The following methods in csWindow manipulate the window stack:

  • popWindow() raises the current window to top of the window stack.

  • pushWindow() lowers the current window to bottom of the window stack.

Manipulating the Window Buffers

Cosmo 3D uses two buffers:

  • Front buffer—contains the graphic information currently being displayed.

  • Back buffer—stores the next image to be displayed.

When the rendered image is ready to be displayed, you switch the source of the graphic information from one buffer to the other using either swapBuffers() or swapThisWindowBuffers().

Handling User Input

Events, such as mouse motion, key presses, and window resize, are converted to csEvent objects and queued on their associated csWindow. When the application is ready to process these events the getEvents() method of each csWindow can be called to get the array of queued csEvent's. After processing the events, the event array should be discarded by calling the window's resetEvents() method.

Using Callback Functions

Retrieving and handling user events using getEvents() requires constant polling by the application, which can waste processor time. To avoid this polling, a Cosmo 3D application typically sets event callbacks on csWindow objects and calls the static csWindow::mainLoop() method to handle all event processing. Using callbacks, the application is notified when events are waiting to be processed.

To set up event callbacks, an application can use either csWindow::setFrameFunc() or the newer (recommended) methods, setEventFunc(), setRenderFunc(), and setFreeRun().

The user-defined, callback's return value of setFrameFunc() controls the manner in which events are processed. The return values include:

  • BLOCK—the event processing loop blocks until another event occurs on some window.

    In BLOCK mode, the callback is called for every event, but not at all when no events are generated.

  • CONTINUE—the callback is called every time the main loop goes idle.

    In CONTINUE mode, events are queued and delivered when things go idle. The callback continues to be called even when no events are generated.

Each window has its own “frameFunc” and that function is called when there are events on that window. This model gets confusing when multiple windows use the CONTNUE mode.

setEventFunc() defines a per-window event callback similar to setFrameFunc(), but the mode of event handling is controlled by csWindow::setFreeRun(). When there are no more events to process a global callback, setRenderFunc() is called indicating the windows should be re-rendered.

When csWindow::setFreeRun() is TRUE, callbacks are invoked only when the main loop goes idle, similar to the CONTINUE mode. Otherwise, callbacks occur with every event but nothing happens when the main loop is idle.

With the either of these event callback mechanisms, the event information, returned by getEvents(), is extracted from the csEvent objects. The application, however, does not need to call resetEvents(); it is called automatically.

Querying Devices

In addition to the above csEvent-centered model, you can use the methods getMouseX(), getMouseY(), getMouseButtons(), and getDevice() to query the current value of each user input device. This approach is discouraged.

Selecting Screen Objects

Cosmo 3D enables the selection of screen objects in the following ways:

  • csIsectAction—selects the shape closest to the origin of a ray that is intersected by that ray.

  • csCamera::pick()—selects the shape closest to the camera based on window coordinates.

These methods use a csHit object for storing the selected objects.

Using csIsectAction

csIsectAction, when applied to the root node selects all graphical objects intersected by a ray stored in a csSeg, as shown in Figure 12-1.

Figure 12-1. Ray Pick Action

Figure 12-1 Ray Pick Action

The shape closest to the origin of the csSeg and intersected by the line segment is recorded in a csHit object. For information about csHit, see “Storing Selected Screen Objects”.

Using Pick()

csCamera::pick() uses window and viewport coordinates to select the screen object closest to the ray connecting the camera to the point. You might supply the window coordinates using the user input methods; see “Handling User Input”.

When you supply pick() with window coordinates, the method internally uses csContext::getViewport() to convert the coordinates to viewpoint coordinates. The method then calls csIsectAction to construct a ray from the camera to the coordinates. The screen object closest the camera on the ray is recorded in a csHit object. For information about csHit, see “Storing Selected Screen Objects”.

For information about csContext::getViewport(), see “Setting the Screen Display of the Scene”.

Storing Selected Screen Objects

csHit objects hold pointers to objects selected using a variety of mechanisms. The methods in csHit allow you to access the information held by csHit, including:

  • The index number, geomPartNumber, of the triangle, quadrilateral, or polygon inside a csGeoSet.

  • The csGeometry that was intersected.

  • The csShape that was intersected.

  • The normal in local space at the intersection point. (The space of the geometry that was intersected.)

  • The intersection point in local space. (The space of the geometry that was intersected.)

  • The model view matrix for the csGeometry intersected. The model view is the concatenation of the viewing matrix and all the matrices in all csTransform objects above the csShape node.

  • The normal in world space at the intersection point. (The space of the camera used to calculate the hit.)

  • The list of nodes leading from the root of the scene graph to the intersected csGeometry.

  • The intersection point in world space. (The space of the camera used to calculate the hit.)

  • Distance of the intersection from the csSeg origin, which is the same as the distance from the csCamera object.

  • The line segment, csSeg, expressed in three dimensions, that was used in the intersection test.

Creating Your Own Window

Instead of using the window provided by Cosmo 3D, csWindow, you can create your own window using X11 or WIN32 window code. In this case your application controls the csContext, events, and window, as shown in Figure 12-2.

Figure 12-2. Creating Your Own Window

Figure 12-2 Creating Your Own Window

Sample Window Code

For sample code that shows you how to create your own window, see the demonstration programs, cubex.cxx and cubew32.cxx.