This chapter explores some basic I/O components found in almost every OpenGL Optimizer application. It discusses:
| Note: Appendix C, “opviewer Sample Application,” lists and discusses the opviewer sample code in some detail. opviewer contains all elements discussed in this chapter. |
Every OpenGL Optimizer application must call opInit() once before calling any other OpenGL Optimizer routine. You can terminate an OpenGL Optimizer application with a call to opExit() or call opNotify() with the notification level set to opFatal. (See “Error Handling and Notification”).
If you want to know the OpenGL Optimizer version, call opVersion(), which returns the OpenGL Optimizer version string to use in correspondence concerning the specific OpenGL Optimizer library you have installed.
The string returned by opVersion() is defined as follows:
OP_RELEASE_TYPE | Type of release (alpha, beta, MR, or unreleased) |
OP_MAJOR_VERSION | Major release number |
OP_MINOR_VERSION | Minor release number |
OP_BUILD_NUMBER | Unique build number |
OpenGL Optimizer provides a function that saves scene graphs and a class with methods for loading a scene graph file.
To write a scene graph to a .csb file, use the global function csdStoreFile_csb(). The .csb format is the natural format for OpenGL Optimizer applications.
To load a scene graph, use opGenLoader::load(). opGenLoader is a class with various methods related to loading a file of any supported format. opGenLoader::load(), the method that actually performs the load, determines the file's format based on the file's extension. This method then finds the appropriate loader for the given file name and then calls that loader's entry point. The loader reads and loads the scene graph.
By default, the extension name and prefix are identical. opGenLoader::addType() enables additional bindings.
| opGenLoader(_ flatten, _tesselator, _incremental) |
The arguments to opGenLoader() can be set independently using setFlatten(), setTessellator(), and setIncremental(). If you set these values with these methods, use the opGenLoader() version of the constructor. | |
| addType(ext, tag) |
| |
| load() | Reads a data file if opGenLoader can find a loader that supports the DSO load routine. | |
| setDataFilePath() and getDataFilePath() |
|
The class also includes accessor functions to set and get the flags for flattening and incremental reads and to set and get the tessellator.
opGenloader provides loaders for the following file formats:
.iv— the format used by Open Inventor
.csb—the format used by Cosmo 3D to efficiently store and load scene graphs
.pfb—the format used by IRIS Performer
The .pfb, and .csb files are two efficient binary file formats used by OpenGL Optimizer and Cosmo 3D. You can use opGenLoader to read a file, such as a .iv file, and convert it to the .csb format. The sample application opoptimize gives an example of this conversion.
As you load the contents of a file, you can create the opGenLoader() instance to:
Tessellate higher-order primitives (see Chapter 11, “Rendering Higher-Order Primitives: Tessellators”).
To develop your own scene graph loader, you need to create a DSO with an external entry point, for example:
csGroup *extLoad( char *filename, bool flatten,
opTessellateAction *tessellator, bool incremental );
|
The “ext” in extLoad() is the file extension of your database file. For example, if you were creating a loader for files with the extension .foo, such as. engine.foo, your DSO would be named fooLoader_dp.so for double-precision, or fooLoader_sp.so for single-precision. The precision is defined by setting OP_SINGLE to TRUE or FALSE. The code for the loader would include the following declaration:
extern “C”
{
csGroup *fooLoad( char *filename, bool flatten,
opTessellateAction *tessellator, \
bool incremental );
}
|
The arguments are as follows:
filename | Name of the file to load, for example, opviewer engine.foo. |
tessellator | Pointer to a tessellator action that you can use for b-reps. |
flatten | Optimize the scene graph by state and transform flattening. |
incremental | Perform incremental loading. |
For an example of a loader, see ivLoad() in /usr/share/Optimizer/src/loaders/iv, which contains the source code for the Inventor loader. The ivLoader creates nearly every type of node available in Cosmo 3D.
The DSO must be named extLoader_dp.so (or _sp for single precision) and be placed in a location defined in your LD_LIBRARY_PATH, /usr/lib[32], or both.
The opViewer class provides an interactive Cosmo scene graph viewer for the X Window System. Key features include:
Scene graph viewing (see Figure 2-1)
Mouse control of scene translation and rotation
Keyboard control of various rendering modes
A strip-chart performance meter.
opViewer can be extended by subclassing. OpenGL Optimizer contains some classes derived from opViewer, for example opVizViewer. The node opGLSpyNode, which appears in Figure 2-1, is discussed in “Observing OpenGL Modes”.
In Optimizer 1.1 and later, opViewer supports multi-threaded (nonforked) and multi-pipe rendering. Source to opViewer is included to provide a sufficiently complex example of writing a viewer.
An application that uses opviewer goes through the following steps:
Initializes the library with a call to opInit().
Instantiates an opViewer.
Loads a scene graph.
Calls the opViewer event loop method.
#include <Cosmo3D/csGroup.h>
#include <Optimizer/Optimizer.h>
#include <Optimizer/opInit.h>
#include <Optimizer/opViewer.h>
#include <Optimizer/opGenLoader.h>
#include <Optimizer/opTessParaSurfaceAction.h>
void main(int argc, char **argv)
{
// Initialize OpenGL Optimizer.
opInit();
// Create a loader that will be used to load a scene graph
// from a file.
opGenLoader *loader;
loader = new opGenLoader( true, NULL, false );
// Get name of file containing the scene graph.
char *fileName = argv[1];
// Load the scene graph.
csNode *scene = loader->load( fileName );
csGroup *root = new csGroup;
if (scene)
{
// Add the just loaded scene graph to a csGroup node.
root->addChild(scene);
}
// Throw the loader away, we're done with it delete loader;
// Tessellate the shapes in the scene graph. This is only
// necessary if the scene graph contains untessellated shapes.
opTessParaSurfaceAction *tessAction = new opTessParaSurfaceAction;
tessAction->setChordalDevTol( 0.01 );
tessAction->apply( root );
// Create a viewer with title "Optimizer".
opViewer *viewer = new opViewer("Optimizer");
// Add the scene graph to the viewer.
viewer->addChild( root );
// Set the view point so that the entire scene graph is visible.
viewer->setViewPoint( root );
// Enter the viewer's event loop. Now you can rotate and translate
// the scene graph displayed in the viewer using the mouse.
viewer->eventLoop( );
|
The application can determine interactions with the scene graph by setting drawing implementations (see “Controlling Rendering: opKeyCallback and opDrawImpl”). The sample application opviewer, discussed in Appendix C, “opviewer Sample Application,”, is a full example of how to use an opViewer.
The names of the methods of opViewer are descriptive and often refer the OpenGL Optimizer functionality they control. Here are a few of the main methods:
| addChild(g) | Adds group g as child of the pose transform, shown in Figure 2-1. | |
| eventLoop() | Is the entry point for the X event loop for the window. eventLoop() starts opViewer's interactive mode. Perform all initializations of scene graph data structures before calling eventLoop(). | |
| setDrawImpl() and getDrawImpl() |
| |
| setLODbias() and getLODbias() |
A bias of i has the effect that, given a sequence of level-of-detail nodes indexed by a range of integers, 1 to n, arranged from highest to lowest level of detail, after a level-of-detail calculation that would render node m, the node m+i is rendered instead. This lightens the load on the graphics hardware when you are not likely to need the most accurate object representations. | |
| setViewPoint() |
|
The opViewer class contains additional methods; consult the man page and source code for more details. Note that in OpenGL Optimizer 1.1, opViewer supports multithreaded (nonforked) and multipipe rendering.
opViewer uses objects derived from opDrawImpl to control rendering details and the effects of keyboard controls.
opViewer uses a C++ array of functions to associate a key or combination of keys to a function, which can come from several opDrawImpls (however, you cannot have more than one opDrawImpl active at any given time). The array is an opKeyCallback, which is the following pointer-to-function type:
typedef bool (*opKeyCallback)(opDrawImpl *drawImpl,int key); |
The methods of the opDrawImpl base class do nothing. You create meaningful definitions in the derived subclasses. These are the intended uses of the member functions:
| opDrawImpl(viewer) |
| |
| registerKey(key, keyCB, helpmessage) |
Each subclass defines at least one such member of opKeyCallback. The subclasses of opDrawImpl in the OpenGL Optimizer library call this defining function keyHandler() (see “opDrawImpl Subclasses Used In Sample Applications”, “Rendering With View-Frustum and Occlusion Culling: opOccDrawImpl”, and “Interacting With a Rendered Object: opPickDrawImpl”). Notice that different opDrawImpls cannot associate different definitions for one keyboard key. This allows you to include without ambiguity several opDrawImpls in one opViewer and switch among them. For example you could select among the following opDrawImpls:
| |
| pick() | Allows you to define mouse interactions with a rendered object. See, for example, the class opPickDrawImpl, which is discussed in “Interacting With a Rendered Object: opPickDrawImpl”. | |
| activated() and deactivated() |
| |
| reset() | Returns a scene to the default settings defined by this function. |
Different sample applications create different subclasses of opDrawImpl.
The opDefDrawImpl class defines the default drawing options and their keybinding for opViewer().
The class declaration for opDefDrawImpl is nearly identical to that of opDrawImpl. The main difference is the inclusion of a member of the opKeyCallback function array called keyHandler(), which defines the effects of keyboard commands. This is the prototype for the member function keyHandler():
static bool keyHandler(opDrawImpl *,int); |
| keyHandler() | Defines the effects of the keyboard commands registered by calls to registerKey(). opDefDrawImpl has the keyboard controls described in “opDefDrawImpl Keybindings”. | |
| registerKey() | Registers a keyboard command and specifies the function that interprets the command. The function registerKey() is inherited from opDrawImpl, which is discussed in “Controlling Rendering: opKeyCallback and opDrawImpl”. See the file opDefDrawImpl.cxx for details. |
The class constructor for opDefDrawImpl uses the methods registerKey() and keyHandler() to register the following keyboard commands (see the file opDefDrawImpl.cxx):
| b | Toggles back-face culling (see “Detail Culling”). | |
| B | Toggles bounding-box display. Shows the csBoxBound of each csGeoSet in the scene. | |
| h | Prints help message listing these key actions. | |
| q | Quits. | |
| ESC | Quits. | |
| r | Resets scene to what it was at the start of the application. | |
| l | Toggles the light-direction mode, which allows you to control the location of the light source with your mouse. | |
| L | Toggles a second light source opposite the first if you have a model with normals flipped in opposite directions. | |
| p | Prints the scene graph. | |
| s | Toggles status display. | |
| t | Toggles reflection mapping illumination with the Gaussian map (see Chapter 8, “Efficient High-Quality Lighting Effects: Reflection Mapping”). | |
| w | Toggles wire-frame mode, which shows the edges of the triangles that define the objects in the scene. | |
| W | Toggles hidden-line removal when in wire-frame mode. | |
| SPACE | Stops scene motion. | |
| ? | Prints OpenGL status during the subsequent frame. |
If you want to use the Motif library, opXmViewer uses opXmDrawImpl, which has methods analogous to a combination of opDrawImpl and opPickDrawImpl. The latter is an opDrawImpl that allows manipulation of selected objects in a scene. See “Interacting With a Rendered Object: opPickDrawImpl”