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

Appendix C. opviewer Sample Application

The opviewer application illustrates the basic structure of an OpenGL Optimizer opViewer application. It is a working application that allows you to use OpenGL Optimizer rendering tools to manipulate complex models. Figure C-1 shows a model rendered by opviewer.

Figure C-1. Model Rendered by the opviewer Sample Application

Figure C-1 Model Rendered by the opviewer Sample Application

This appendix presents comments and lines of code essentially the same as that of /usr/share/Optimizer/src/sample/opviewer/main.cxx, briefly highlights OpenGL Optimizer features, and refers to detailed discussions that appear in this guide.


Note: The code presented here may not be exactly the same as the code that ships with OpenGL Optimizer, because of late changes.

The rest of this chapter is a running commentary on the code in main.cxx.

The following features are not implemented in opviewer:


Note: The opoptimize sample applications contains many of these features.


Verifying Installation

Use the versions command to verify that you have installed the following software:

  • optimizer_eoe

  • optimizer_dev

  • cosmo3D_eoe

  • cosmo3D_dev

For example, to verify optimizer_dev is installed, use the following command:

% versions | grep optimizer_dev

Install any of these packages if they are missing.

Compiling and Running opviewer

To compile opviewer, enter the command make while in the directory /usr/share/Optimizer/src/sample/opviewer. To list command-line options, invoke the application without options.

To print a list of interactive program controls into your command shell while you run opviewer, place the mouse cursor in the rendering window and enter the h key.

opviewer Code

Inclusions

 

 

 

In addition to the standard library, opviewer requires two base classes from the Cosmo 3D library, and header files from OpenGL Optimizer.

 

#include <stdio.h>

 

#include <Cosmo 3D/csFields.h>

#include <Cosmo3D/csGroup.h>

You can set all csAppearances of the csShapes to minimize mode switching. See “Avoiding OpenGL Mode Switching”.

 

#include <Optimizer/opAppStats.h>

These two headers include the OpenGL Optimizer command-line argument parser, which is discussed in the section “Command-Line Parser: opArgParser”; and the file loading class, discussed in “Saving and Loading Scene-Graph Files”.

 

 

#include <Optimizer/opArgs.h>

#include <Optimizer/opGenLoader.h>

This header includes the basic graphics acceleration tools, most of which are discussed in Chapter 3, “Sending Efficient Graphics Data to the Hardware.”

 

 

#include <Optimizer/opGFXSpeed.h>

 

The library initialization class is discussed in “Calling opInit()”.

 

#include <Optimizer/opInit.h>

The basic control of interactive rendering, including the control of occlusion culling or the ability to manipulate selected portions of the scene graph is provided by the classes in these files. These tools are discussed in “Rendering With View-Frustum and Occlusion Culling: opOccDrawImpl”, and “Interacting With a Rendered Object: opPickDrawImpl”.

 

 

#include <Optimizer/opOccDrawImpl.h>

#include <Optimizer/opPickDrawImpl.h>

OpenGL Optimizer provides several tools for reflection mapping, discussed in Chapter 8, “Efficient High-Quality Lighting Effects: Reflection Mapping.”

 

 

#include <Optimizer/opReflMap.h>

 

Inclusions (cont.)

 

 

Traversal tools are discussed in Chapter 12, “Traversing a Large Scene Graph.”

 

 

#include <Optimizer/opTraverse.h>

You can collect statistics about the number of vertices, triangles, and connected primitives in your scene graph. See “Gathering Triangle Statistics”.

 

 

#include <Optimizer/opTriStats.h>

The next file holds the basic rendering class opViewer, discussed in “Viewing Class: opViewer”.

 

 

#include <Optimizer/opViewer.h>

 

 

Initializations and main()

 

 

 

The tessellators convert abstract geometry into renderable collections of vertices: see “Tessellating Parametric Surfaces”.

 

#include <Optimizer/opTessParaSurfaceAction.h>

#include <Optimizer/opTessNurbSurfaceAction.h>

To guarantee consistent tessellation between adjacent surfaces, that is, rendered surfaces without cracks, OpenGL Optimizer provides topology maintenance tools. See Chapter 10, “Creating and Maintaining Surface Topology.”

 

 

#include <Optimizer/opTopo.h>

You have three ways to develop surface connectivity information. The argument list is from best to worst. See Chapter 10, “Creating and Maintaining Surface Topology.”

 

 

enum topologyOption {TOPO_TWO_PASS, TOPO_ONE_PASS, TOPO_NO};

 

 

 

int main(int argc, char *argv[])

{

See “Calling opInit()”.

 

 

opInit();

 

Command-Line Control Parameters

 

 

The command-line control parameters are read using the methods in the class opArgParser (see “Command-Line Parser: opArgParser”). The command-line parameters set switches that allow you to control these features:

 

opArgParser args;
char *filename;

 

Command-Line Control Parameters (cont.)

 

 

 

The location on the screen (x, y) of the rendering window, and the dimensions of the window (w,h). The x-coordinate assumes a screen of width 1280, and a rendering window of width 600 with a 10-pixel boundary.

 

bool haveX=-1, haveY=-1, haveW=-1,
haveH=-1, haveSize=-1;
int x=1280-600-10, y=0, w=600, h=600;

 

OpenGL display lists. See “Display Lists”.

 

bool haveDL;

 

 

 

bool haveFrameCount;
int frames = 0;

Print the scene graph. See “Printing a Scene Graph”.

 

bool havePrint;

Flatten the scene graph, that is, place all leaf nodes directly under one group node. See “Methods in opCollapseAppearances”.

 

 

bool haveFlatten;

Use short representations of surface normal data. See “Vertex Arrays”.

 

 

bool haveShortNorms;

Introduce complex lighting effects with reflection (or environment) maps. See Chapter 8, “Efficient High-Quality Lighting Effects: Reflection Mapping.”

 

 

bool haveReflMap;
char *reflMapFilename;
bool haveCeilingMap;
char *ceilingMapFilename;
bool haveCylinderMap;
bool haveGaussianMap;
int numFiles;

Set a bias for level-of-detail calculations when the scene is moving. This feature of opViewer is discussed in “Viewing Class: opViewer”.

 

bool haveLODbias;
int lodBias;

Specify the hint for maximum deviations of a tessellation from the exact surface representation. See “Tessellating Parametric Surfaces”.

 

 

bool haveChordalTol = -1;
opReal chordalTol = 0.01;

Specify the threshold distance between points below which they are considered identical when building topology. See “Summary of Scene Graph Topology: opTopo”.

 

 

bool haveTopoTol;
opReal topoTol;

 

Command-Line Control Parameters (cont.)

 

 

 

Specify the background color for the rendering window and the model orientation. These settings are controlled by opViewer options. See “Viewing Class: opViewer”.

 

bool haveBackgroundColor;
float backgroundRed, backgroundGreen,
backgroundBlue, backgroundAlpha;
bool haveRotation;
float vx, vy, vz, angle;
bool haveTranslation;
float tx, ty, tz;

Specify the number of vertices in the tessellation of surface boundaries. See “opTessParaSurfaceAction”.

 

 

bool haveSamples;
int samples;

Specify the type of tessellator: a generic parametric surface tessellator or a NURBS surface tessellator. See “Tessellating Parametric Surfaces”.

 

 

bool haveTessType = -1;
char *tessType = NULL;

Specify rendering features: occlusion culling (see “Occlusion Culling”) or interactive manipulation (see Chapter 7, “Interactive Highlighting and Manipulating”).

 

 

// --- Draw impl options
bool haveOccCull;
int nProcs = 2;
bool haveNoPick = false;
bool removeColors;

Play back the scene. See “Rendering With View-Frustum and Occlusion Culling: opOccDrawImpl”

 

 

// Option to playback recordings
bool havePath;
char *pathFile;
bool haveAutoPlay;

Control OpenGL mode switching by clamping the first csAppearance encountered in the draw traversal to all subsequent csShapes. See “Avoiding OpenGL Mode Switching”.

 

bool haveOneAppearance;

By default, build the best topology. See Chapter 10, “Creating and Maintaining Surface Topology.”

 

 

bool isOnePass = false;

Get Command-Line Parameters

 

 

 

You must supply a file with the scene graph. All other command-line control parameters are optional and were described with the argument declarations. See “Command-Line Parser: opArgParser”.

 

args.defRequired( “%s”,
“<filename>”,&filename);

 

args.defOption( “-width %d”,
“-width <window width>”,
&haveW, &w );

args.defOption( “-height %d”,
“-height <window height>”,
&haveH, &h );

args.defOption( “-size %d”,
“-size <window width=hieght>”,
&haveSize, &w );

args.defOption( “-xpos %d”,
“-xpos <window x screen position>”,
&haveX, &x );

args.defOption( “-ypos %d”,
“-ypos <window y screen position>”,
&haveY, &y );

args.defOption( “-useDL”,
“-useDL”,
&haveDL );

args.defOption( “-frames %d”,
“-frames <n>”,
&haveFrameCount, &frames );

args.defOption( “-print”,
“-print”,
&havePrint );
args.defOption( “-flatten”,
“-flatten”,
&haveFlatten );

 

Get Command-Line Parameters (cont.)

 

 

 

args.defOption( “-shortNorms”,
“-shortNorms”,
&haveShortNorms );

args.defOption( “-reflmap %s”,
“-reflmap <filename>”,
&haveReflMap, &reflMapFilename );

args.defOption( “-ceilingmap %s”,
“-ceilingmap”,
&haveCeilingMap, &ceilingMapFilename );

args.defOption( “-cylindermap”,
“-cylindermap”,
&haveCylinderMap );

args.defOption( “-gaussianmap”,
“-gaussianmap”,
&haveGaussianMap );

args.defOption( “-occ %d”,
“-occ <nProcs>”,
&haveOccCull, &nProcs);

args.defOption( “-nopick”,
“-nopick”,
&haveNoPick);

args.defOption( “-lodBias %d”,
“-lodBias <integer>”,
&haveLODbias, &lodBias );

args.defOption( “-noColors”,
“-noColors removes color bindings from csGeoSets”,
&removeColors);

args.defOption( “-path %s”,
“-path <filename>”,
&havePath, &pathFile );

 

Get Command-Line Parameters (cont.)

 

 

args.defOption( “-autoplay”,
“-autoplay”,
&haveAutoPlay);

#ifdef OP_REAL_IS_DOUBLE
args.defOption( “-ctol %l”,
“-ctol <max chordal deviation>”,
&haveChordalTol, &chordalTol );

args.defOption( “-ttol %l”,
“-ttol <topology tolerance> [setting ttol implies automatic topology building]”,
&haveTopoTol, &topoTol );

#else

args.defOption( “-ctol %f”,
“-ctol <max chordal deviation>”,
&haveChordalTol, &chordalTol );

args.defOption( “-ttol %f”,
“-ttol <topology tolerance> [asetting ttol implies automatic topology building]”,
&haveTopoTol, &topoTol );
#endif
args.defOption( “-onePass”,
“-onePass [build topology while tessellating]”,
&isOnePass );

args.defOption( “-oneAppearance”,
“-oneAppearance”,
&haveOneAppearance );

args.defOption( “-ceilingmap %s”,
“-ceilingmap”,
&haveCeilingMap, &ceilingMapFilename );

args.defOption( “-tess %s”,
“-tess <gen[eral] nurb>”,
&haveTessType, &tessType );

 

Get Command-Line Parameters (cont.)

 

 

// User defined background color
args.defOption( “-background %f %f %f %f”,
“-background <red> <green> <blue><alpha>”,
&haveBackgroundColor,
&backgroundRed,
&backgroundGreen,
&backgroundBlue,
&backgroundAlpha );
// User defined model orientation
args.defOption( “-rotation %f %f %f %f”,
“-rotation <vx> <vy> <vz> <angle>”,
&haveRotation, &vx, &vy, &vz, &angle );
args.defOption( “-translation %f %f %f”,
“-translation <tx> <ty> <tz>”,
&haveTranslation, &tx, &ty, &tz );
args.defOption( “-samples %d”,
“-samples <tessellator sample count>”,
&haveSamples, &samples);

 

Establish Status Information

 

 

// Print out version of Optimizer
fprintf(stderr,”%s\n”,opVersion());

//set topoOption
topologyOption topoOption;

if (!haveTopoTol)
{
topoOption = TOPO_NO;
//don't build topology
}
else if (isOnePass)
{
topoOption = TOPO_ONE_PASS;
//build topology while tessellating.
}
else
{
topoOption = TOPO_TWO_PASS;
//build topology in a seperate pass before //tessellation
}

numFiles = args.scanArgs(argc,argv);

if (haveSize)h = w;

 

Create the Appropriate Tessellator See Chapter 11, “Rendering Higher-Order Primitives: Tessellators.”

 

 

// Create a tessellator
opTessParaSurfaceAction *tess;

if ( tessType == NULL )
tess = new opTessParaSurfaceAction;
else if ( strcmp( tessType, “gen” ) == 0 )
tess = new opTessParaSurfaceAction;
else if ( strcmp( tessType, “nurb” ) == 0 )
tess = new opTessNurbSurfaceAction;
else
tess = new opTessParaSurfaceAction;

// Set the chordal tolerance
tess->setChordalDevTol( chordalTol );

// Set the sample count if the user set them
if ( haveSamples )
tess->setSampling( samples );

 

Create the Topology Data StructuresSee Chapter 10, “Creating and Maintaining Surface Topology.”

 

 

//topology
opTopo *topo = new opTopo;

// Set the topology parameters
if ( haveTopoTol )
{

topo->setDistanceTol( topoTol, meter );
}

 

Load the Scene Graph Data

 

 



 




The loader manages topology in one of the following ways:

It anticipates the development of connectivity information for all surfaces in the scene graph followed by tessellating the surface. Code for these steps appears later in the application.

It develops connectivity information as surfaces load, and tessellates them.

It ignores connectivity: it simply tessellates surfaces as they load without regard for adjacencies.

See

“Saving and Loading Scene-Graph Files”; Chapter 10, “Creating and Maintaining Surface Topology”; and “Base Class opTessellateAction”.

 

 

// Create a loader
opGenLoader *loader;
if(topoOption == TOPO_TWO_PASS)
//build topology before tessellating any //surface.
{
loader = new opGenLoader( true, NULL, false );
//the tessellator is not bound to the loader so //that there is no tessellation at loading. The //reason is because tessellation has to wait //until topology construction is completely done //for all the surfaces
}
else if( topoOption == TOPO_ONE_PASS )
//build topology while tessellate
{
tess->setBuildTopoWhileTess(true);
//tell the tessellator to invoke topology //construction at tessellation
tess->setTopo(topo);
//Sets the topology which will be used in the //topology building tessellation.
loader = new opGenLoader( true, tess, false );
//bind tessellator to loader so that //tessellation is invoked at loading
}
else //don't build topology{//bind tessellator to loader so that //tessellation is invoked at loading
loader = new opGenLoader( true, tess, false );

}

// Load the file on the command line and get a // scene graph back
csGroup *obj = loader->load( filename );

 

Load the Scene Graph Data (cont.)If there are several files making up the scene graph, place them under a csGroup node.

 

 

if (numFiles)
{
int i;
csGroup *grp = new csGroup;
if (obj)
{
grp->addChild(obj);
}
char **xtraFiles =
args.getRemainingArgs();

for (i=0;i<numFiles;i++)
{
fprintf(stderr,”loading file %d %s\n”,i,xtraFiles[i]);

obj = loader->load(xtraFiles[i]);
if (obj)
{
grp->addChild(obj);
}
}
obj = grp;
}
// Throw the loader away, we're done with it
delete loader;

 

Build Topology and Tessellate

 

 



 




The most accurate topology, which yields crack-free tessellations, is created by two traversals of the scene graph: one to establish adjacencies of surfaces, and the second to tessellate the surfaces (this is the default behavior). See “Building Topology: Computing and Using Connectivity Information”.

 

 

// Build topology if we haven't done it and the // user asks for it
if ( obj && topoOption == TOPO_TWO_PASS)
{

fprintf(stderr, “Building topology starts ... \n”);
topo->buildTopologyTraverse( );
fprintf(stderr, “Building topology done\n”);

fprintf(stderr, “Tessellation starts ... \n”);
tess->apply( obj );
fprintf(stderr, “Tessellation done ... \n”);
}

delete tess;

 

Set Parameters to Draw the Scene

 

 

 

 

// If the scene graph was loaded successfully, draw it else end the program
if ( obj )
{

See “Gathering Triangle Statistics”.

 

// Get stats on the scene graph
opTriStats stats;
stats.apply(obj);
printf(“Scene statistics:\n”);
stats.print();

See “Avoiding OpenGL Mode Switching”.

 

 

if (haveOneAppearance)
{
opCollapseAppearances c;
c.apply(obj);
}

if (removeColors)
opRemoveColorBindings(obj);

See “Methods in opCollapseAppearances”.

 

 

// Optionally flatten the scene graph
if (haveFlatten)
obj = opFlattenScene(obj);

See “Vertex Arrays”.

 

 

if (haveShortNorms)
opShortNormsScene(obj);

See “Viewing Class: opViewer”.

 

 

// Note: viewer must be created before // opDListScene.
opViewer *viewer =
new opViewer(“Optimizer”, x, y, w, h);

Set the background color. See “Viewing Class: opViewer”.

 

 

if ( haveBackgroundColor )
{
viewer->setBackgroundColor( backgroundRed, backgroundGreen, backgroundBlue, backgroundAlpha );
}

Set the bias for LOD calculations color. See “Viewing Class: opViewer”.

 

 

// Set the LOD bias
if (haveLODbias)
{
viewer->setLODbias( lodBias );
}

 

Set Parameters to Draw the Scene (cont.)

 

 

 

See “Controlling Rendering: opKeyCallback and opDrawImpl”; “Rendering With View-Frustum and Occlusion Culling: opOccDrawImpl”; and “Interacting With a Rendered Object: opPickDrawImpl”.

 

// Make Occ draw object the default.
opOccDrawImpl *occDrawImpl = NULL;
if (haveOccCull || havePath)
{
occDrawImpl = new opOccDrawImpl(viewer,nProcs);
viewer->setDrawImpl(occDrawImpl);

if (havePath) occDrawImpl->loadRecording(pathFile);
}

opPickDrawImpl *pi = NULL;
if (! haveNoPick) // bad grammar, i know
{
pi = new opPickDrawImpl(viewer);
// Use default DrawImpl until pick invoked
}

See “Printing a Scene Graph”

 

 

if (havePrint) opPrintScene(obj);

See “Viewing Class: opViewer” on page 9.

 

 

 



 

viewer->addChild(obj);
viewer->setViewPoint(obj);

 

Set Parameters to Draw the Scene (cont.)

 

 

 

See Chapter 8, “Efficient High-Quality Lighting Effects: Reflection Mapping.”

 

// A new reflection map
opReflMap *rm = NULL;
if ( haveReflMap )
{
rm = new opReflMap( obj, reflMapFilename, opReflMap::SPHERE );
}
else if ( haveGaussianMap )
{
rm = new opReflMap( obj, (char *)NULL, opReflMap::GAUSSIAN | opReflMap::SPHERE );
}
else if ( haveCylinderMap )
{
rm = new opReflMap( obj, (char *)NULL, opReflMap::CYLINDER );
}
else if ( haveCeilingMap )
{
rm = new opReflMap( obj, ceilingMapFilename, opReflMap::CEILING );
}
viewer->setReflMap( rm );

 

// --- picker needs refl map for highlighting // (could be passed into constructor also)

if (pi != NULL)

pi->setReflMap( rm );

See “Display Lists”.

 

 

// Build display lists
// Note: this must be done after
// instantiating opReflMap and any
// other csGeometry changes.
if (haveDL)
{
printf(“Display listing scene.\n”);
opDListScene(obj);
}

 

Set Parameters to Draw the Scene (cont.)

 

 

 

Set orientation of model, if specified. See “Viewing Class: opViewer”.

 

if ( haveRotation )
{
viewer->setModelRotation( vx, vy, vz, angle );
}

if ( haveTranslation )
{
viewer->setModelTranslation( tx, ty, tz );
}

Draw the Scene

 

 

if (haveFrameCount)
for (int i=0;i<frames;++i)
viewer->update();
else if (haveAutoPlay && havePath)
occDrawImpl->playback(true);
else
viewer->eventLoop();
}

}


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