SGI Techpubs Library

IRIX 6.5  »  Books  »  Developer  »  
OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)    table of contents  |  additional info  |  download
find in page

Chapter 2. Basic I/O: Getting Started with OpenGL Optimizer

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.


Calling opInit()

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


Saving and Loading Scene-Graph Files

OpenGL Optimizer provides a function that saves scene graphs and a class with methods for loading a scene graph file.

Saving a Scene Graph to a 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.

Loading a Scene Graph

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 Methods

opGenLoader(_ flatten, _tesselator, _incremental)  


Sets logical flags indicating whether, upon loading the file, the loader should flatten the scene graph, tessellate geometric primitives on the fly, and/or incrementally read the graph. By default, opGenLoader looks in /usr/lib, /usr/libl, or wherever the LD_LIBRARY_PATH is set on the IRIX machine.

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)  


Adds a loader that reads files with the extension ext. The name of the dso containing the loader is tagLoader_sp.so or tagLoader_dp.so, depending on whether you compile in single or double precision. The variable tag can include a pathname.

load()  

Reads a data file if opGenLoader can find a loader that supports the DSO load routine.

setDataFilePath() and getDataFilePath()  


Set the search paths for the DSO.

The class also includes accessor functions to set and get the flags for flattening and incremental reads and to set and get the tessellator.

Supported File Formats

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:

Creating a Scene Graph Loader

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.

Viewing Class: opViewer

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.

Figure 2-1. opViewer Scene Graph

Figure 2-1 opViewer Scene Graph

An application that uses opviewer goes through the following steps:

  1. Initializes the library with a call to opInit().

  2. Instantiates an opViewer.

  3. Loads a scene graph.

  4. Calls the opViewer event loop method.

    Example 2-1.


    #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.

opViewer Methods

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() 


Sets and gets the opDrawImpl that currently controls scene graph interactions. The constructor sets a default opDrawImpl, but you can use others to allow, for example, highlighting and independent manipulation of subgraphs (see Chapter 7, “Interactive Highlighting and Manipulating”).

setLODbias() and getLODbias()  


Set and get a bias for levels of detail when a scene is rotating.

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() 


Sets the view frustum to contain the bounding box of the graph rooted at the node passed as an argument. If the argument is NULL, the bounding box of the entire scene graph is used.

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.

Controlling Rendering: opKeyCallback and opDrawImpl

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);

opDrawImpl Methods

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)  


Registers keys and their effects using the member function registerKey().

registerKey(key, keyCB, helpmessage)  


Registers a keyboard key and a callback function keyCB. keyCB becomes a member of the opKeyCallback pointer-to-function array maintained by the opViewer. keyCB interprets key in terms of the opDrawImpl's methods.

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()  


Defines callbacks that are implemented when you switch to and from an opDrawImpl using opViewer::setDrawImpl().

reset()  

Returns a scene to the default settings defined by this function.

opDrawImpl Subclasses Used In Sample Applications

Different sample applications create different subclasses of opDrawImpl.

opDefDrawImpl: Controlling Rendering for opViewer

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);

opDefDrawImpl Methods

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.

opDefDrawImpl Keybindings

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.

opXmDrawImpl: Controlling Rendering for opXmViewer

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”

OpenGL Optimizer Programmer's Guide: An Open API for Large-Model Visualization
(document number: 007-2852-002 / published: 1998-06-09)    table of contents  |  additional info  |  download

    Front Matter
    About This Guide
    Part I. Getting Started
    Part II. High-Level Strategic Tools for Fast Rendering
    Part III. Specific Tools for Fast Rendering
    Part IV. Managing and Rendering Higher-Order Geometric Primitives
    Part V. Traversers, Low-Level Geometry Processing, and Multiprocessing
    Part VI. Utilities and Troubleshooting
    Part VII. Appendices
    Glossary
    Index


home/search | what's new | help