This section outlines the basic sequence for initializing Inventor for use with the Xt Intrinsics, a library built on top of the X Window System library. An Xt widget contains an X window, along with extra functions for controlling the widget behavior. Because they contain a window, widgets can receive events from the X server.
The SoXt::init() routine returns an Xt widget that serves as the application's main shell window. In the following example, the widget is named myWindow. An SoXtRenderArea is later put into this window.
The basic steps are as follows:
C++ :
Be sure your program calls show() for the child widgets before it calls show() for the shell widget. If you try to show the shell widget first, you receive this error: “Shell widget x has zero width and/or height.”
The SoXtRenderArea is an Xt widget that performs OpenGL rendering. When it receives X events, it translates them into SoEvents, which are then passed to the scene manager for handling.
The scene graph to be rendered is set into the render area with the setSceneGraph() method. (This method increments the root's reference count.) The getSceneGraph() method returns the root node of this scene graph.
Other useful methods on SoXtRenderArea include the following:
setTransparencyType() | specifies how transparent objects are rendered (see the section on the render action in Applying Actions for details). |
setAntialiasing() | specifies the antialiasing methods. |
setBorder() | shows or hides the window border. |
setBackgroundColor() | specifies the window background color. |
The render area attaches a node sensor to the root of the scene graph and automatically redraws the scene whenever the scene graph changes. Use the following method to change the priority of the redraw sensor:
setRedrawPriority() | specifies the priority of the redraw sensor (default priority is 10000) |
Use the following two methods if you wish to disable automatic redrawing:
setAutoRedraw() | enables or disables the redraw sensor on the render area. |
render() | redraws the scene immediately. If AutoRedraw is TRUE, you don't need to make this call. |
See the Open Inventor C++ Reference Manual on SoXtRenderArea for more information on these methods.
If you use the default values when you create an SoXtRenderArea, mouse and keyboard events are handled automatically. The constructor for SoXtRenderArea is
SoXtRenderArea(Widget parent = NULL, const char * name = NULL, SbBool buildInsideParent = TRUE, SbBool getMouseInput = TRUE, SbBool getKeyboardInput = TRUE);
To disable input from either the mouse or the keyboard, specify FALSE for the getMouseInput or getKeyboardInput variable. For example, to disable mouse input:
C++ :
Inventor defines three Xt devices:
The overlay planes are a separate set of bitplanes that can be used for special purposes in Inventor. (Check your release notes for the number of overlay planes, which is implementation-dependent.) The overlay planes are typically used for objects in the scene that appear on top of the main image and are redrawn independently. Although you are limited with respect to color and complexity of the scene graph placed in the overlay planes, using them enables you to quickly redraw a simple scene graph without having to redraw the “complete” scene graph. The overlay planes provide a useful mechanism for providing user feedback—for example, for rapidly drawing geometry that follows the cursor.
Use the following methods to place a scene graph in the overlay planes:
setOverlaySceneGraph() | sets the scene graph to render in the overlay planes |
setOverlayColorMap() | sets the colors to use for the overlay bit planes; the overlay planes usually use color-index mode |
setOverlayBackgroundIndex() | sets the index of the background color for the overlay image (the default is 0, the clear color) |
The overlay scene graph has its own redraw sensor and is similar to the “regular” scene graph, with these restrictions:
setOverlayColorMap(int startIndex, int num, const SbColor * colors);
To render a shape with a particular color, use an SoColorIndex node to set the current color index. Do not use an SoMaterial node or SoBaseColor node to set colors when you are in color-index mode (they are ignored).
Using the Overlay Planes illustrates use of the overlay planes with a viewer component. By default, color 0 is used for the overlay plane's background color (the clear color), so this example uses color 1 for the object.
Example : Using the Overlay Planes
C++ :
Components are widgets that provide some 3D-related editing function. All components in the Inventor Component Library return an Xt widget handle for standard Motif-style layout and control. The render area is an example of a simple component. Viewer components are derived from SoXtRenderArea.
Each component contains a user interface with such things as buttons, menus, and sliders that allow the user to change the scene graph interactively. One example of a component is the material editor, used in Examples 16-2, 16-3, and 16-4. With this editor, the user can customize objects shown in the Inventor window by interactively changing values for ambient, diffuse, specular, transparent, emissive, and shininess elements and immediately see the effects of those changes. Another example is the examiner viewer, which enables the user to move the camera through the scene, providing real-time changes in how the scene is viewed. Component Classes shows the component class tree.
An SoXtComponent is an Inventor C++ wrapper around a Motif-compliant widget. This means that you can layer components in a window with other Motif widgets using standard layout schemes such as bulletin boards, form widgets, and row/column widgets. The material editor itself is an SoXtComponent made up of other components and Motif-style widgets. (Its color sliders are derived from SoXtComponent, and the radio buttons, toggle buttons, and menu are Motif-style widgets.) You can pass in a widget name to each component, which can then be used in resource files as the Motif name of the widget.
Components fall into two general classes, viewers and editors, depending on which part of the scene graph they affect. Viewers affect the camera node in the scene, and editors affect other nodes and fields in the scene, such as SoMaterial nodes and SoDirectionalLight nodes.
Follow these general steps to use any component in your program. (Additional considerations for specific components are outlined in the following sections.)
Create the component using its constructor. The constructor has the form:
SoXtComponent(Widget parent = NULL, const char * name = NULL, SbBool buildInsideParent = TRUE, SbBool getMouseInput = TRUE, SbBool getKeyboardInput = TRUE);
For example:
C++ :
This step initializes local variables and structures and builds the component. You supply the parent widget you want the component to appear in. If you do not supply a parent widget, or if you pass FALSE for the buildInsideParent parameter, the component is created inside its own shell. An important side effect is that if the component is put in its own window, it can resize itself when necessary. If the component is built into the widget tree, it cannot resize itself. If you do not supply a name, the name is the class name—“SoXtMaterialEditor,” in this case.
If you specify FALSE for the buildInsideParent parameter, the component is built inside its own shell, but it uses the passed parent as part of the widget hierarchy for X resource lookup.
The show() and hide() methods are routines that allow you to manage the component widget. In summary, the show() method is used to make the component visible. The hide() method is used to make the component invisible. However, in Motif-compliant applications, the topmost parent of the widget tree must be realized before its children are displayed. Additionally, only the children that are managed are displayed.
If the Inventor component is a top-level shell widget (that is, no parent widget was passed to the constructor), the show() method causes the component to call XtRealizeWidget() on itself, and XtManageChild() on its children.
If the component is not a top-level shell widget, the show() method causes the component to call XtManageChild() on itself and all its children. These widgets won't be visible, though, until XtRealizeWidget() is called on the top-level widget.
The show() and hide() methods on SoXtComponent do some additional work that the component relies on. When you use a component, be sure to call its show() method, not XtManage() or XtRealize(), and hide(), not XtUnmanage() and XtUnrealize(). For instance:
C++ :
Each component also has a series of specialized methods for changing its behavior while the program is running. (See SoXtComponent in the Open Inventor C++ Reference Manual.) These methods include the following:
setTitle() | places a title in the title bar of a component that is a top-level shell widget |
setSize() | sizes the component (uses XtSetValue()) |
getSize() | returns the size of the component (uses XtGetValue()) |
isVisible() | returns TRUE if the component is currently mapped and realized on the display |
There are two ways for a component to pass data back to the application:
Editor components such as the material editor can also use callback functions to pass data back to the application. Using a Callback Function illustrates the use of a callback procedure with the material editor.
A list of callback functions and associated data, SoCallbackList, is automatically created when a component is constructed. You can add functions to and remove functions from this list and pass a pointer to the callback data.
Some widgets, such as viewers, use lists of callback functions:
addStartCallback(functionName, userData) removeStartCallback(functionName, userData)
addFinishCallback(functionName, userData) removeFinishCallback(functionName, userData)
The material editor invokes its callbacks or updates the nodes it is attached to according to a programmable update frequency. Use the setUpdateFrequency() method to specify this frequency. Choices are as follows:
CONTINUOUS | continuously update the field as the value changes (the default) |
AFTER_ACCEPT | update the field only when the user hits the accept button |
Using a Callback Function builds a render area in a window supplied by the application and a material editor in its own window. It uses callbacks for the component to report new values.
Example : Using a Callback Function
C++ :
One way to affect a scene graph directly is to attach an editor component to a node in the scene graph. Attaching a Material Editor shows using the attach() method to attach the material editor to a material node:
C++ :
The syntax for attach() here is attach(SoMaterial* material, int index = 0);
material | the node to edit |
index | for multiple-value materials, the index within the node of the material to edit |
In the same way, viewers are “attached” to the scene graph whose camera they edit. For example:
C++ :
See the section called “Viewers” for a detailed description of what happens when a viewer is attached to a scene graph.
Attaching a Material Editor builds a render area in a window supplied by the application and a material editor in its own window. It attaches the editor to the material of an object. Material Editor and Render Area Created in Separate Windows shows the image created by this example.
Example : Attaching a Material Editor
C++ :
C++ :
Placing Two Components in the Same Window builds a render area and a material editor in a window supplied by the application. It uses a Motif-compliant form widget to lay both components inside the same window. The editor is attached to the material of an object. Using the Material Editor Component to Edit a Scene shows how this example initially looks on the screen.
Example : Placing Two Components in the Same Window
C++ :
C++ :
Viewers, such as the examiner viewer and the fly viewer, change the camera position and thus affect how a scene is viewed. The examiner viewer uses a virtual trackball to rotate the scene graph around a point of interest. With the fly viewer, mouse movements have the effect of tilting the viewer's head up, down, to the left, and to the right, as well as moving in the direction the viewer is facing.
All viewers have the following elements built into them:
When you construct a viewer, you can specify whether the viewer is a browser viewer (BROWSER; the default) or an editor viewer (EDITOR). If the browser creates a camera node (see the following section), this camera node is removed from the scene graph when the viewer is detached. If an editor viewer creates a camera node, the camera node is retained when the viewer is detached.
The constructor for each viewer takes an additional parameter that specifies what to build. By default, the decoration and pop-up menu are created. For example, the constructor for the examiner viewer is as follows:
SoXtExaminerViewer(Widget parent = NULL, const char* name = NULL, SbBool buildInsideParent = TRUE, SoXtFullViewer::BuildFlag buildFlag = BUILD_ALL, SoXtViewer::Type type = BROWSER);
The buildFlag can be one of the following values:
BUILD_NONE | the decoration and pop-up menu are not created |
BUILD_DECORATION | only the decoration is created |
BUILD_POPUP | only the pop-up menu is created |
BUILD_ALL | the decoration and pop-up menu are created |
If the user doesn't need the viewer decoration, you can disable the creation of the decoration at construction time using the buildFlag; this will improve performance.
When you call setSceneGraph() for a viewer, several things happen automatically. First, the viewer searches the scene graph for a camera. If it finds one, it uses that camera. If it doesn't find a camera, it adds one. Second, it adds headlight, draw-style, and lighting-model nodes to the scene graph. (The following paragraphs describe these steps in detail.)
Call setSceneGraph(NULL) to disconnect the scene graph from the viewer component. If the viewer created a camera and the viewer is a browser, it removes the camera. If the viewer is an editor, it leaves the camera, since the view is saved along with the scene graph. For both types of viewers, the headlight group is removed when the scene graph is removed.
All viewers search from the scene graph root downward for the first camera. If the viewer finds a camera, it uses it. If it doesn't find one, it creates a camera (of class SoPerspectiveCamera by default). If the viewer is an editor, it inserts the camera under the scene graph root, as shown in Inserting a Camera for an Editor Viewer . When you save the scene graph, this new camera is saved with it. If the viewer is a browser, it inserts the camera above the scene graph, as shown in Inserting a Camera for a Browser Viewer . This camera is not saved with the scene graph and is removed when the viewer is detached.
Viewer components by default also add a directional light source to the scene. The viewer continuously changes the position of this light so that it tracks the camera and functions as a headlight shining on the camera's field of view. This headlight group is added just after the camera in the scene graph. To write the scene graph to a file without the headlight, you can either detach the viewer or turn off the headlight (see the setHeadlight() method for SoXtViewer in the Open Inventor C++ Reference Manual).
All viewers include a pop-up menu that allows you to change the draw-style of the entire scene. Sometimes, when the viewer changes the draw-style, it also changes the lighting model (for example, wireframe draw-style uses base-color lighting). When a viewer is attached, it inserts draw-style and lighting-model nodes above the scene graph, as shown in Viewer Pop-up Menu . The following list describes the choices for draw-style and the accompanying changes in lighting model:
Use the setBufferingType() method for SoXtViewer to specify whether the viewer should use single buffering, double buffering, or a combination. The default buffering type is double buffering. Double buffering provides smoother redraws, but offers fewer colors. Buffering types are as follows:
SoXtViewer::BUFFER_SINGLE | uses only one buffer; the image flickers between redraws |
SoXtViewer::BUFFER_DOUBLE | redraws in the back buffer and then swaps buffers |
SoXtViewer::BUFFER_INTERACTIVE | uses double buffering only when the user is doing interactive work; otherwise, uses single buffering |
Other useful methods for SoXtViewer include the following:
setHeadlight() | turns the headlight on and off. The headlight is ON by default. |
setViewing() | allows you to turn the viewer on and off. When the viewer is turned off, events over the render area are sent to the scene graph. |
viewAll() | automatically views the entire scene graph. |
setAutoClipping() | turns autoclipping on and off. When ON, the near and far camera clipping planes are continuously adjusted around the scene's bounding box to minimize clipping. Autoclipping is ON by default. |
saveHomePosition() | saves the current camera values so that the camera can quickly be reset to this position later. |
resetToHomePosition() | sets the camera position to the previously saved home position. |
setStereoViewing() | renders the scene twice, offsetting the camera in between. Stereo glasses must be used when this scene is viewed. (This feature is hardware-dependent. See your release notice for information on whether this feature is supported.) |
setSteroOffset() | sets the spacing between the eyes for stereo viewing. |
See SoXtViewer in the Open Inventor C++ Reference Manual for further details.
The SoXtFullViewer class, derived from SoXtViewer, is the abstract base class for all viewers that include decoration around the render area. This decoration is made up of thumbwheels, sliders, and push buttons. The setDecoration() method allows you to show or hide the component trims. The setPopupMenuEnabled() method allows you to enable or disable the viewer pop-up menu.
You can add optional application icons to the upper left corner of the component. Use the following methods to add these icons:
addAppPushButton() | adds a push button for the application to the end of the button list |
insertAppPushButton() | places a push button at the specified index in the button list |
removeAppPushButton() | removes a push button from the button list |
See SoXtFullViewer in the Open Inventor C++ Reference Manual for further details.
Using a Browser Examiner Viewer creates a simple scene graph with a material and a dish. It then creates a browser examiner viewer and attaches it to the scene graph. The camera and light in the scene are automatically created by the viewer.
Example : Using a Browser Examiner Viewer
C++ :
This section describes the convenience routines provided by Inventor for exchanging Inventor data between applications. Inventor's copy and paste methods conform to the X Consortium's Inter-Client Communication Conventions Manual (ICCCM), July 1989, which presents guidelines on how processes communicate with each other when exchanging data.
Inventor currently supports two data types, Inventor and string. If you need to copy and paste additional data types, or if you need more control over copy and paste functions than is provided by Inventor's convenience routines, you can use the Motif or Xt data-exchange routines directly. For more information, see the X Toolkit Intrinsics Programming Manual by Adrian Nye and Tim O'Reilly (Sebastopol, Ca.: O'Reilly & Associates, 1990).
The SoXtClipboard class handles the details of exchanging data according to the ICCCM guidelines. This class includes a constructor, as well as copy() and paste() methods.
The constructor for SoXtClipboard has the following syntax:
SoXtClipboard (Widget w, Atom selectionAtom = XA_CLIPBOARD);
The clipboard is associated with a particular widget, such as a render area widget or a top-level widget. For example, you could pass in
C++ :
as the first parameter of this constructor.
The X Toolkit supports several types of selections (primary, secondary, and clipboard; these are also referred to as selection atoms). By default, Inventor supports the clipboard selection (XA_CLIPBOARD). If you need to perform data transfers from the primary or secondary selections, you can specify the selection type in the constructor for SoXtClipboard. In most cases, however, you use the default selection type.
Use one of Inventor's three copy() methods to copy data onto the SoXtClipboard. You can specify a node, a path, or a path list to copy:
copy(SoNode **node*, Time eventTime);
copy(SoPath **path*, Time *eventTim*e);
copy(SoPathList &pathList, Time eventTime);
The copy() and paste() methods require an event time, which is the time stamp from the user event that triggered the copy or paste request. This event could be a keyboard press event or a menu pick event, for example, and is used by the X server to synchronize copy and paste requests. Behind the scenes, the data is copied into a bytestream and made available to any X client that requests it.
The paste() method also requires a callback function that is invoked with the paste data. The paste data is always a path list, regardless of what was copied originally:
paste(Time eventTime, SoXtClipboardPasteCB pasteDoneFunc, void userData = NULL);
The paste() method requests data from the X server and calls the pasteDoneFunc when the data is ready. A paste is asynchronous. It simply makes a request to the X server for data to paste and then returns. When the data is delivered, the pasteDoneFunc is called and passed the user data along with a list of paths that were pasted. If no data is delivered, the pasteDoneFunc is never called. It is up to the application to delete the path list for the paste data when the application is finished with it.
SoXtClipboard can easily be used along with SoSelection. You can obtain a path list from the selection node and then tell the clipboard to copy that path list.