Chapter 7. Importing Databases
Prev |  | Next

## Chapter 7. Importing Databases

Once you have learned how to create visual simulation applications with OpenGL Performer, your next task is to import visual databases into those applications. OpenGL Performer provides import and export functions for numerous popular database formats to ease this effort.

This chapter describes the following:

- The steps involved in creating custom loaders for other data formats

- Pre-existing file loading utilities

- Several utility functions in the OpenGL Performer database utility library that can make the process of database conversion easier for you

- Supported database formats

- The Maya database exporter

## Overview of OpenGL Performer Database Creation and Conversion

Source code is provided for most of the tools discussed in this chapter. In most cases the loaders are short, easy to understand, and easy to modify.

Table 7-1 lists the subdirectories of `/usr/share/Performer/src/lib` on IRIX and Linux and `%PFROOT%\Src\lib` on Microsoft Windows where you can find the source code for the database processing tools.

Table 7-1. Database-Importer Source Directories

Directory Name | Directory Contents
--- | ---
`libpfdu` | General database processing tools and utilities.
`libpfdb` | Load, convert, and store specific database formats..
`libpfutil` | Additional utility functions.

Before you can import a database, you must create it. Some simulation applications create data procedurally; for examples of this approach, see the “SGI PHD Format” or the “Sierpinski Sponge Loader”” sections of this chapter.

In most cases, however, you must create visual databases manually. Several software packages are available to help with this task, and most such systems facilitate geometric modeling, texture creation, and interactive specification of colors and material properties. Some advanced systems support level-of-detail specification, animation sequences, motion planning for jointed objects, automated roadway and terrain generation, and other specialized functions.

## `libpfdu` - Utilities for Creating Efficient OpenGL Performer Run-Time Structures

There are several layers of support in OpenGL Performer for loading 3D models and 3D environments into OpenGL Performer run-time scene graphs. OpenGL Performer contains the `libpfdu` library devoted to the import of data into (and export of data from) OpenGL Performer run-time structures. Note that two database exporters have already been written for the Medit and DWB database formats.

At the top level of the API, OpenGL Performer provides a standard set of functions to read in files and convert databases of unknown type. This functionality is centered around the notion of a database converter. A database converter is an abstract entity that knows how to perform some or all of a set of database format conversion functions with a particular database format. Moreover, converters must follow certain API guidelines for standard functionality such that they can be easily integrated into OpenGL Performer in a run-time environment without OpenGL Performer needing any prior knowledge of a particular converter's existence. This run-time integration is done through the use of dynamic shared object (DSO) libraries on IRIX and Linux. On Microsoft Windows this is accomplished using Dynamic-link Libraries (DLL).

### pfdLoadFile - Loading Arbitrary Databases into OpenGL Performer

Table 7-2 describes the general routines for 3D databases provided by `libpfdu`.

Table 7-2. `libpfdu` Database Converter Functions

Function Name | Description
--- | ---
pfdInitConverter() | Initialize the library and its classes for the desired format.
pfdLoadFile() | Load a database file into an OpenGL Performer scene graph.
pfdStoreFile() | Store a run-time scene graph into a database file.
pfdConvertFrom() | Convert an external run-time format into an OpenGL Performer scene graph.
pfdConvertTo() | Convert an OpenGL Performer scene graph into an external run-time format.

The database loader utility library, `libpfdu`, provides a convenient function, named pfdLoadFile(), that imports database files stored in any of the supported formats listed in Table 7-6.

Loading database files with pfdLoadFile() is easy. The function prototype is

    pfNode *pfdLoadFile(char *fileName);

pfdLoadFile() tests the filename-extension portion of fileName (the substring starting at the last period in fileName, if any) for one of the format-name codes listed in Table 7-6, then calls the appropriate importer.

The file-format selection process is implemented using dynamic loading of DSOs, dynamic shared objects, for IRIX and Linux and DLLs, dynamic link libraries, for Microsoft Windows. This process allows new loaders that are developed as database formats change to be used with OpenGL Performer-based applications without requiring recompilation of the OpenGL Performer application.

| Note: Subsequent general references in this manual to DSOs also pertain to DLLs unless otherwise noted.

If at all possible, pfdInitConverter() should be called before pfConfig() for the potential formats that may be loaded. This will preload the DSO and allow it to initialize any of its own data structures and classes. This is required if the loader DSO extends OpenGL Performer classes or uses any node traversal callbacks so that if multiprocessing these data elements will all have been precreated and be valid in all potential processes. pfdInitConverter() automatically calls pfdLoadNeededDSOs_EXT() to preload additional DSOs needed by the loader if the given loader has defined that routine. These routines take a filename so that the loader has the option to search through the file for possible DSO references in the file.

#### Loading Process Internals

The details of the loading process internal to pfdLoadFile() include the following:

1. Searching for the named file using the current OpenGL Performer file path.

2. Extraction of the file-type extension.

3. Translation of the extension using a registered alias facility, formation of the DSO or DLL name.

4. Formation of a loader function name.

5. Finding that function within the DSO using either dlsym() on IRIX and Linux or GetProcAddress() on Microsoft Windows.

6. Searching first the current executable and loaded DSOs for the proper load function and then searching through a list of user-defined and standard directories for that DSO. Dynamic loading of the indicated DSO using dlopen() on IRIX and Linux and using LoadLibrary() on Microsoft Windows.

7. Invocation of the loader function.

#### Loader Name

The loader function name is constructed from two components:

- A prefix always consisting of `pfdLoadFile_`.

- Loader suffix, which is the file extension string.

  | Note: The loader function `pfdLoadFile_` must be exported using `_declspec(dllexport)` on Microsoft Windows only.

Examples of several complete loader function names are shown in Table 7-3.

Table 7-3. Loader Name Composition

File Extension | Loader Function Name
--- | ---
`dwb` | pfdLoadFile_dwb()
`flt` | pfdLoadFile_flt()
`medit` | pfdLoadFile_medit()
`obj` | pfdLoadFile_obj()
`pfb` | pfdLoadFile_pfb()

#### Shell Environment Variables

Several shell environment variables are used in the loader location process. These are PFLD_LIBRARY{N32,64}_PATH, LD_LIBRARY{N32,64}_PATH, and PFHOME. Confusion about loader locations can be resolved by consulting the sources mentioned earlier in this chapter to understand the use of these directory lists and reading the following section, “Database Loading Details”. When the pfNotifyLevel is set to the value for PFNFY_DEBUG (5) or greater, the DSO and loader function names are printed as databases are loaded, as is the name of each directory that is searched for the DSO.

The OpenGL Performer sample programs, including `perfly`, use pfdLoadFile() for database importing. This allows them to simultaneously load and display databases in many disparate formats. As you develop your own database loaders, follow the source code examples in any of the `libpfdb` loaders. Then you will be able to load your data into any OpenGL Performer application. You will not need to rebuild `perfly` or other applications to view your databases.

### Database Loading Details

Details about the database loading process are described further in this section, the `pfdLoadFile` man page, and the source code which is in `/usr/share/Performer/src/lib/libpfdu/pfdLoadFile.c` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdu\pfdLoadFile.c` on Microsoft Windows.

The routines pfdInitConverter(), pfdLoadFile(), pfdStoreFile(), pfdConvertFrom(), and pfdConvertTo() exist only as a level of indirection to allow you to manipulate all databases regardless of format through a central API. They are in fact merely a mechanism for creating an open environment for data sharing among the multitudes of three-dimensional database formats. Each of these routines determines, using file-type extensions, which database converter to load as a run-time DSO. The routine then calls the appropriate functionality from that converter's DSO. All converters must provide API that is exactly the same as the corresponding `libpfdu` API with `_EXT` added to the routine names (for example, for `.medit` files, the suffix is `_medit`). Note that multiple physical extensions can be mapped to one converter extension with calls to pfdAddExtAlias(). Several aliases are predefined upon initialization of `libpfdu`.

It is also important to note that because each of these converters is a unique entity that they each may have state that is important to their proper function. Moreover, their database formats may allow for multiple OpenGL Performer interpretations; so, there exist APIs, shown in Table 7-4, not only to initialize and exit database converters, but also to set and get modes, attributes, and values that might affect the converter's methodology.

Table 7-4. `libpfdu` Database Converter Management Functions

Function Name | Description
--- | ---
pfdInitConverter() | Initialize a database conversion DSO.
pfdExitConverter() | Exit a database conversion DSO.
pfdConverterMode() | Specify a mode for a specific conversion DSO.
pfdGetConverterMode() | Get a mode setting from a specific conversion DSO.
pfdConverterAttr() | Specify an attribute for a conversion DSO.
pfdGetConverterAttr() | Get an attribute setting from a conversion DSO.
pfdConverterVal() | Specify a value for a conversion DSO.
pfdGetConverterVal() | Get a value setting from a conversion DSO.

Once again each converter provides the equivalent routines with `_EXT` added to the function name.

For example, the converter for the Open Inventor format would define the function pfdInitConverter_iv() if it needed to be initialized before it was used. Likewise, it would define the function pfdLoadFile_iv() to read an Open Inventor “`.iv`” file into an OpenGL Performer scene graph.

| Note: Because each converter is an individual entity (DSO) and deals with a particular type of database, it may be the case that a converter will not provide all of the functionality listed above, but rather only a subset. For instance, most converters that come with OpenGL Performer only implement their version of pfdLoadFile but not pfdStoreFile, pfdConvertFrom, or pfdConvertTo. However, users are free to add this functionality to the converters using compliant APIs and OpenGL Performer's `libpfdu` will immediately recognize this functionality. Also, `libpfdu` traps access to nonexistent converter functionality and returns gracefully to the calling code while notifying the user that the functionality could not be found.

#### Finding and initializing a Converter

When one of the general database converter functions is called, it in turn calls the corresponding routine provided by the converter, passing on the arguments it was given.

But the first time a converter is called, a search occurs to identify the converter and the functions it provides. This is accomplished as follows.

- Parse the extension—what appears after the final “.” in the filename. This is referred to as EXT in the following bulleted items.

- Check to see if any alias was created for the EXT extension with pfdAddExtAlias(). If a translation is defined, EXT is replaced with that extension.

- Check the current executable to see if the symbol pfdLoadFile_EXT is already defined, that is. if the loader was statically linked into the executable or a DSO was previously loaded by some other mechanism. If not, the search continues.

  For IRIX and Linux:

  - Generate a DSO library name to search for using the extension prototype “libpfEXT_{-g,}.so”. This means the following strings will be constructed:

    `libpfEXT_.so` for the optimized OpenGL loader

    `libpfEXT_-g.so` for the debug OpenGL loader

  - Look for the DSO in several places, including the following:

            .
            $PFLD_LIBRARY_PATH
            $LD_LIBRARY_PATH
            $PFHOME/usr/lib{,32,64}/libpfdb
            $PFHOME/usr/share/Performer/lib/libpfdb

  - Open the DSO using dlopen().

  For Microsoft Windows:

  - Generate a DLL library name to search for using the extension prototype “libpfEXT_{-g,}.so”. This means the following strings will be constructed:

    `libpfEXT_.so` for the optimized OpenGL loader

    `libpfEXT_-g.so` for the debug OpenGL loader

  - Look for the DLL in several places, including the following:

            .
            $PFLD_LIBRARY_PATH
            $LD_LIBRARY_PATH
            $PFHOME/Lib/libpfdb
            $PFHOME/Lib/Debug/libpfdb

  - Open the DLL using LoadLibrary().

- Once the object has been found, processing continues.

  - Query all `libpfdu` converter functionality from the symbol table of the DSO using dlsym() on IRIX and Linux and of the DLL using GetProcAddress() on Microsoft Windows with function names generated by appending _EXT to the name of the corresponding pfd routine name. This symbol dictionary is retained for future use.

  - Invoke the converter's initialization function, pfdInitConverter_EXT(), if it exists.

  - Invoke pfdLoadNeededDSOs_EXT() if it exists. This routine can then recursively call pfdInitConverter_EXT(), as needed.

## Developing Custom Importers

Having fully described how database converters can be integrated into OpenGL Performer and the types of functionality they provide, the next undertaking is actually implementing a converter from scratch. OpenGL Performer makes a great effort at allowing the quick and easy development of effective and efficient database converters.

While creating a new file loader for OpenGL Performer is not inherently difficult, it does require a solid understanding of the following issues:

- The structure and interpretation of the data file to be read

- The scene graph concepts and nodes of `libpf`

- The geometry and attribute definition objects of `libpr`

### Structure and Interpretation of the Database File Format

In order to effectively convert a database into an OpenGL Performer scene graph, it is important to have a substantial understanding of several concepts related to the original database format:

- The parsing of the file based on the database format

- The data types represented in the format and their OpenGL Performer correspondence

- The scene graph structure of the file (if any)

- The method of graphics state definition and inheritance defined in the format

Before trying to convert sophisticated 3D database formats into OpenGL Performer it is important to have a thorough grasp of how every structure in the format needs to affect how OpenGL Performer performs its run-time management of a scene graph. However, although it requires a great deal of understanding to convert complex behaviors of external formats into OpenGL Performer, it is still very straight forward to migrate basic structure, geometry, and graphics state into efficient OpenGL Performer run-time structures using the functionality provided in the OpenGL Performer database builder, pfdBuilder.

### Scene Graph Creation Using Nodes as Defined in `libpf`

Creating an OpenGL Performer scene graph requires a definite knowledge of the following OpenGL Performer `libpf` node types: pfScene, pfGroup, and pfGeode.

These nodes can be used to define a minimally functional OpenGL Performer scene graph. See “Nodes” in Chapter 3 for more details on `libpf` and OpenGL Performer scene graphs and node types.

### Defining Geometry and Graphics State for `libpr`

In order to input geometry and graphics into OpenGL Performer, it is important to have an understanding of how OpenGL Performer's low-level rendering objects work in `libpr,` OpenGL Performer's performance rendering library. The main `libpr` rendering primitives are a pfGeoSet and a pfGeoState. A pfGeoSet is a collection of like geometric primitives that can all be rendered in exactly the same way in one large continuous chunk. A pfGeoState is a complete definition of graphics mode settings for the rendering hardware and software. It contains many attributes such as texture and material. Given a pfGeoSet and a corresponding pfGeoState, `libpr` can completely and efficiently render all of the geometry in the pfGeoSet. For a more detailed description of pfGeoSets and pfGeoStates, see “pfGeoSets and pfGeoStates” in Chapter 12, which goes into detail on all `libpr` primitives and how OpenGL Performer will use them.

However, realizing that OpenGL Performer's structuring of geometry and graphics state is optimized for rendering speed and not for modeling ease or general conceptual partitioning, OpenGL Performer now contains a new mechanism for translating external graphics state and geometry into efficient `libpr` structures. This new mechanism is the pfdBuilder that exists in `libpfdu`.

The pfdBuilder allows the immediate mode input of graphics state and primitives through very simple and exposed data structures. After having received all of the relevant information, the pfdBuilder builds efficient and somewhat optimized `libpr` data structures and returns a low-level `libpf` node that can be attached to an OpenGL Performer scene graph. The pfdBuilder is the recommended method of importing data from non-OpenGL Performer-based formats into OpenGL Performer.

### Creating an OpenGL Performer Database Converter using `libpfdu`

Creating a new format converter is very simple process. More than thirty database loaders are shipped with OpenGL Performer in source code form to serve as practical examples of this process. The loaders read formats that range from trivial to complex and should serve as an instructive starting point for those developing loaders for other formats. These loaders can be found in the directory `/usr/share/Performer/src/lib/libpfdb/libpf*` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpf*` on Microsoft Windows.

This section describes the `libpfdu` framework for creating a 3D database format converter. Consider writing a converter for a simple ASCII format that is called the Imaginary Immediate Mode format with the file type extension .`iim`. This format is much like the more elaborate .`im` format loader used at SGI for the purposes of testing basic OpenGL Performer functionality.

The first thing to do is set up the routine that pfdLoadFile() will call when it attempts to load a file with the extension .`iim`.

    #ifdef WIN32
    #define PFDB_DLLEXPORT __declspec(dllexport)
    #else
    #define PFDB_DLLEXPORT /* no-op */
    #endif
    extern PFDB_DLLEXPORT pfNode *pfdLoadFile_iim(char *fileName)
    {
    }

This function needs to perform several basic actions:

1. Find and open the given file.

2. Reset the `libpfdu` pfdBuilder for input of new geometry and state.

3. Set up any pfdBuilder modes that the converter needs enabled.

4. Set up local data structures that can be used to communicate geometry and graphics state with the pfdBuilder.

5. Set up a `libpf` pfGroup which can hold all of the logical partitions of geometry in the file (or hold a subordinate collection of nodes as a general scene graph if the format supports it).

6. Optionally set up a default state to use for geometry with unspecified graphics state.

7. Parse the file, which entails the following:

   - Filling in the local geometry and graphics state data structures

   - Passing them to the pfdBuilder as inputted from the file

   - Asking the pfdBuilder to build the data structures into OpenGL Performer data structures when a logical partition of the file has ended

   - Attaching the OpenGL Performer node returned by the build to the higher-level group which will hold the entire OpenGL Performer representation of this file. Note that this step becomes more complex if the format supports the notion of hierarchy only in that the appropriate `libpf` nodes must be created and attached to each other using pfAddChild() to build the hierarchy. In this case requests are made for the builder to build after inputting all of the geometry and state found in a particular leaf node in the database.

8. Delete local data structures used to input geometry and graphics state.

9. Close the file.

10. Perform any optional optimization of the OpenGL Performer scene graph. Optimizations might include calls to pfdFreezeTransforms(), pfFlatten() or pfdCleanTree().

11. Return the pfGroup containing the entire OpenGL Performer representation of the database file.

Steps 1-8 expand the function outline to the following:

    extern PFDB_DLLEXPORT pfNode *pfdLoadFile_iim(char *fileName)
    {
      FILE* iimFile;
      pfdGeom* polygon;
      pfGroup* root;

      /* Performer has utility for finding and opening file */
      if ((iimFile = pfdOpenFile(fileName)) == NULL)
      return NULL;

      /* Clear builder from previous converter invocations */
      pfdResetBldrGeometry();
      pfdResetBldrState();

      /* Call pfdBldrMode for any needed modes here */

      /* Create polygon structure */
      /* holds one N-sided polygon where N is < 300 */
      polygon = pfdNewGeom(300);

      /* Create pfGroup to hold entire database */
      /* loaded from this file */
      root = pfNewGroup();

      /* Specify state for geometry with no graphics state */
      /* As well as default enables, etc. This routine */
      /* should invoke pfdCaptureDefaultBldrState()*/
      SetupDefaultGraphicsStateIfThereIsOne();

      /* Do all the real work in parsing the file and */
      /* converting into Performer */
      ParseIIMFile(iimFile, root, polygon);

      /* Delete local polygon struct */
      pfdDelGeom(polygon);

      /* Close File */
      fclose(iimFile);

      /* Optimize OpenGL Performer scene graph */
      /* via use of pfFlatten, pfdCleanTree, etc. */
      OptimizeGraph(root);

      return (pfNode*)root;
    }

At the heart of the file loader lies the ParseIIMFile() function. The specifics of parsing a file are completely dependent on the format; so, the parsing will be left as an exercise to you. However, the following code fragments should show a framework for what goes into integrating the parser with the pfdBuilder framework for geometry and graphics state data conversion. Note that several possible graphics state inheritance models might be used in external formats and that the pfdBuilder is designed to support all of them:

- The default pfdBuilder state inheritance is that of immediate mode graphics state. Immediate mode state is specified through calls to pfdBldrStateMode(), pfdBldrStateAttr(), and pfdBldrStateVal().

- There also exists a pfdBuilder state stack for hierarchical state application to geometry. This is accomplished through the use of pfdPushBldrState() and pfdPopBldrState() in conjunction with the normal use of the immediate mode pfdBuilder state API.

- Lastly, there is a pfdBuilder named state list that can be used to define a number of "named materials" or "named state definitions" that can then be recalled in one API called (for instance, you might define a "brick" state with a red material and a brick texture. Later you might just want to say "brick" is the current state and then input the walls of several buildings). This type of state naming is accomplished by fully specifying the state to be named using the immediate mode API and then calling pfdSaveBldrState(). This state can then be recalled using pfdLoadBldrState().

      ParseIIMFile(FILE *iimFile, pfGroup *root, pfdGeom *poly)
      {
        while((op = GetNextOp(iimFile)) != NULL)
        {
          switch(op)
          {
            case GEOMETRY_POLYGON:
              polygon->numVerts = GetNumVerts(iimFile);

              /* Determine if polygon has Texture Coords */
              if (pfdGetBldrStateMode(PFSTATE_ENTEXTURE)==PF_ON)
                polygon->tbind = PFGS_PER_VERTEX;
              else
                polygon->tbind = PFGS_OFF;

              /* Determine if Polygon has normals */
              if (AreThereNormalsPerVertex() == TRUE)
                polygon->nbind = PFGS_PER_VERTEX;
              else if           (pfdGetBldrStateMode(PFSTATE_ENLIGHTING)==PF_ON)
                polygon->nbind = PFGS_PER_PRIM;
              else
                polygon->nbind = PFGS_OFF;

              /* Determine if Polygon has colors */
              if (AreThereColorsPerVertex() == TRUE)
                polygon->cbind = PFGS_PER_VERTEX;
              else if (AreThereColorsPerPrim() == TRUE)
                polygon->cbind = PFGS_PER_PRIM;
              else
                polygon->cbind = PFGS_OFF;
              for(i=0;i<polygon->numVerts;i++)
              {
                /* Read ith Vertex into local data structure */
                polygon->coords[i][0] = GetNextVertexFloat();
                polygon->coords[i][1] = GetNextVertexFloat();
                polygon->coords[i][2] = GetNextVertexFloat();

                /* Read texture coord for ith vertex if any */
                if (polygon->tbind == PFGS_PER_VERTEX)
                {
                  polygon->texCoords[i][0] = GetNextTexFloat();
                  polygon->texCoords[i][1] = GetNextTexFloat();
                }

                /* Read normal for ith Vertex if normals bound*/
                if (polygon->nbind == PFGS_PER_VERTEX)
                {
                  polygon->norms[i][0] = GetNextNormFloat();
                  polygon->norms[i][1] = GetNextNormFloat();
                  polygon->norms[i][2] = GetNextNormFloat();
                }
                /* Read only one normal per prim if necessary */
                else if ((polygon->nbind == PFGS_PER_PRIM) &&
                         (i == 0))
                {
                  polygon->norms[0][0] = GetNextNormFloat();
                  polygon->norms[0][1] = GetNextNormFloat();
                  polygon->norms[0][2] = GetNextNormFloat();
                }

                /* Get Color for the ith Vertex if color bound*/
                   if (polygon->cbind == PFGS_PER_VERTEX)
                   {
                     polygon->colors[i][0] =
                       GetNextColorFloat();
                     polygon->colors[i][1] =                  GetNextColorFloat();
                     polygon->colors[i][2] =                  GetNextColorFloat();
                   }
                   /* Get one color per prim if necessary */
                   else if ((polygon->cbind == PFGS_PER_PRIM) &&
                            (i == 0))
                   {
                     polygon->colors[0][0] =                  GetNextColorFloat();
                     polygon->colors[0][1] =                  GetNextColorFloat();
                     polygon->colors[0][2] =                  GetNextColorFloat();
                   }
                 }
                 /* Add this polygon to pfdBuilder */
                 /* Because it is a single poly, 1 */
                 /* is specified here */
                 pfdAddBldrGeom(1);
                 break;
               case GRAPHICS_STATE_TEXTURE:
                 {
                   char *texName;
                   pfTexture *tex;
                   texName = ReadTextureName(iimFile);
                   if (texName != NULL)
                   {
                     /* Get prototype tex from pfdBuilder*/
                     tex =
                       pfdGetTemplateObject(pfGetTexClassType());

                     /* This clears that object to default */
                     pfdResetObject(tex);

                     /* If just the name of a pfTexture is */
                     /* set, pfdBuilder will auto find & Load */
                     /* the texture*/
                     pfTexName(tex,texName);

                     /* This is the current pfdBuilder */
                     /* texture and texturing is on */
                     pfdBldrStateAttr(PFSTATE_TEXTURE,tex);
                     pfdBldrStateMode(PFSTATE_ENTEXTURE, PF_ON);
                   }
                   else
                   {
                     /* No texture means disable texturing */
                     /* And set current texture to NULL */
                     pfdBldrStateMode(PFSTATE_ENTEXTURE,PF_OFF);
                     pfdBldrStateAttr(PFSTATE_TEXTURE, NULL);
                   }
                 }
                 break;
            case GRAPHICS_STATE_MATERIAL:
              {
                pfMaterial *mtl;
                mtl = pfdGetTemplateObject(pfGetMtlClassType());
                pfdResetObject(mtl);
                pfMtlColor(mtl, PFMTL_AMBIENT,
                  GetAmRed(), GetAmGreen(), GetAmBlue());
                pfMtlColor(mtl, PFMTL_DIFFUSE,
                  GetDfRed(), GetDfGreen(), GetDfBlue());
                pfMtlColor(mtl, PFMTL_SPECULAR,
                  GetSpRed(), GetSpGreen(), GetSpBlue());
                pfMtlShininess(mtl, GetMtlShininess());
                pfMtlAlpha(mtl, GetMtlAlpha());
                pfdBldrStateAttr(PFSTATE_FRONTMTL, mtl);
                pfdBldrStateAttr(PFSTATE_BACKMTL, mtl);
              }
              break;
            case GRAPHICS_STATE_STORE:
              pfdSaveBldrState(GetStateName());
              break;
            case GRAPHICS_STATE_LOAD:
              pfdLoadBldrState(GetStateName());
              break;
            case GRAPHICS_STATE_PUSH:
              pfdPushBldrState();
              break;
            case GRAPHICS_STATE_POP:
              pfdPopBldrState();
              break;
            case GRAPHICS_STATE_RESET:
              pfdResetBldrState();
              break;
            case GRAPHICS_STATE_CAPTURE_DEFAULT:
              pfdCaptureDefaultBldrState();
              break;
            case BEGIN_LEAF_NODE:
              /* Not really necessary because it is */
              /* destroyed on build*/
              pfdResetBldrGeometry();
              break;
            case END_LEAF_NODE:
                 {
                   pfNode *nd = pfdBuild();
                   if (nd != NULL)
                     pfAddChild(root,nd);
                 }
                 break;
             }
           }
         }

One of the fundamental structures involved in the above routine outline is the pfdGeom structure which you fill in with information about a single primitive, or a single strip of primitives. The pfdGeom structure is essential in communicating with the pfdBuilder and is defined as follows:

    typedef struct _pfdGeom
    {
        int         flags;
        int         nbind, cbind, tbind[PF_MAX_TEXTURES];

        int         numVerts;
        short       primtype;
        float       pixelsize;

        /* Non-indexed attributes - do not set if poly is indexed */
        pfVec3      *coords;
        pfVec3      *norms;
        pfVec4      *colors;
        pfVec2      *texCoords[PF_MAX_TEXTURES];

        /* Indexed attributes - do not set if poly is non-indexed */
        pfVec3      *coordList;
        pfVec3      *normList;
        pfVec4      *colorList;
        pfVec2      *texCoordList[PF_MAX_TEXTURES];

        /* Index lists - do not set if poly is non-indexed */
        ushort      *icoords;
        ushort      *inorms;
        ushort      *icolors;
        ushort      *itexCoords[PF_MAX_TEXTURES];

        int         numTextures;

        struct _pfdGeom         *next;

    } pfdGeom;

See the `pfdGeoBuilder`(3pf) man pages for more information on using this structure along with its sister structure, the pfdPrim.

The above should provide a well-defined framework for creating a database converter that can be used with any OpenGL Performer applications using the pfdLoadFile() functionality.

However, it is also important to note that there are a multitude of pfdBuilder modes and attributes that can be used to affect some of the basic methods that the builder actually uses:

Table 7-5. pfdBuilder Modes and Attributes

Function Name | Token Description
--- | ---
pfd{Get}BldrMode() | PFDBLDR_MESH_ENABLE
| PFDBLDR_MESH_SHOW_TSTRIPS
| PFDBLDR_MESH_INDEXED
| PFDBLDR_MESH_MAX_TRIS
| PFDBLDR_MESH_RETESSELLATE
| PFDBLDR_MESH_LOCAL_LIGHTING
| PFDBLDR_AUTO_COLORS
| PFDBLDR_AUTO_NORMALS
| PFDBLDR_AUTO_ORIENT
| PFDBLDR_AUTO_ENABLES
| PFDBLDR_AUTO_CMODE
| PFDBLDR_AUTO_DISABLE_TCOORDS_BY_STATE
| PFDBLDR_AUTO_DISABLE_NCOORDS_BY_STATE
| PFDBLDR_AUTO_LIGHTING_STATE_BY_NCOORDS
| PFDBLDR_AUTO_LIGHTING_STATE_BY_MATERIALS
| PFDBLDR_AUTO_TEXTURE_STATE_BY_TEXTURES
| PFDBLDR_AUTO_TEXTURE_STATE_BY_TCOORDS
| PFDBLDR_BREAKUP
| PFDBLDR_BREAKUP_SIZE
| PFDBLDR_BREAKUP_BRANCH
| PFDBLDR_BREAKUP_STRIP_LENGTH
| PFDBLDR_SHARE_MASK
| PFDBLDR_ATTACH_NODE_NAMES
| PFDBLDR_DESTROY_DATA_UPON_BUILD
| PFDBLDR_PF12_STATE_COMPATIBLE
| PFDBLDR_BUILD_LIMIT
| PFDBLDR_GEN_OPENGL_CLAMPED_TEXTURE_COORDS
| PFDBLDR_OPTIMIZE_COUNTS_NULL_ATTRS
pfd{Get}BldrAttr() | PFDBLDR_NODE_NAME_COMPARE
| PFDBLDR_STATE_NAME_COMPARE

Because the pfdBuilder is released as source code, it is easy to add further functionality and more modes and attributes to even further customize this central functionality.

In fact, because the pfdBuilder acts as a “data funnel” in converting data into OpenGL Performer run-time structures, it is easy to control the behavior of many standard conversion tasks through merely globally setting builder modes which will subsequently affect all converters that use the pfdBuilder to process their data.

## Maximizing Database Loading and Paging Performance with PFB and PFI Formats

“Description of Supported Formats” describes all of the file formats supported by OpenGL Performer. Although you can use files in these formats directly, you can dramatically reduce database loading time by preconverting databases into the PFB format and images into the PFI format.

To convert to the PFB file format or the PFI image format, use the `pfconv` and `pficonv` utilities.

### `pfconv`

The `pfconv` utility converts from any format for which a pfdLoadFile...() function exists into any format for which a pfdStoreFile...() exists. The most common format to convert to is the PFB format. For example, to convert `cow.obj` into the PFB format, use the following command:

    % pfconv cow.obj cow.pfb

By default, `pfconv` optimizes the scene graph when doing the conversion. The optimizations are controlled with the `-o` and `-O` command line options. Builder options are controlled with the `-b` and `-B` command line options. Converter modes are controlled with the `-m` and `-M` command line options. Refer to the help page for more specific information about the command line options by entering:

    % pfconv -h

#### Example Conversion

When converting to the PFB format, texture files can be converted to the PFI format using the following command line options:

    % pfconv -M pfb, 5, 1

5 means PFPFB_SAVE_TEXTURE_PFI.

1 means convert .`rgb` texture images to .`pfi`.

### `pficonv`

The `pficonv` utility converts from IRIS libimage format to PFI format image files. For example, to convert `cafe.rgb` into the PFI format, use the following command:

    % pficonv cafe.rgb cafe.pfi

MIPmaps can be automatically generated and stored in the resulting PFI files by adding `-m` to the command line.

## Supported Database Formats

Vendors of several leading database construction and processing tools have provided database-loading software for you to use with OpenGL Performer. This section describes these loaders, the loaders developed by the OpenGL Performer engineering team and several loaders developed in the OpenGL Performer user community for other database formats.

Importing your databases is simple if they are in formats for which OpenGL Performer database loaders have already been written. Each of the loaders listed in Table 7-6 is included with OpenGL Performer. If you want to import or export databases in any of these formats, refer to the appropriate section of this chapter for specific details about the individual loaders.

Table 7-6. Supported Database Formats

Name | Description
--- | ---
3ds | AutoDesk 3DStudio binary data
bin | SGI format used by `powerflip`
bpoly | Side Effects Software PRISMS binary data
byu | Brigham Young University CAD/FEA data
csb | OpenGL Optimizer Format
ct | Cliptexture config file loader - auto-generates viewing geometry
dwb | Coryphaeus Software Designer's Workbench data
dxf | AutoDesk AutoCAD ASCII format
flt11 | MultiGen public domain Flight v11 format
flt | MultiGen OpenFlight format provided by MultiGen
gds | McDonnell-Douglas GDS things data
gfo | Old SGI radiosity data format
im | Simple OpenGL Performer data format
irtp | AAI/Graphicon Interactive Real-Time PHIGS
iv | SGI Open Inventor format (VRML 1.0 superset)
lsa | Lightscape Technologies ASCII radiosity data
lsb | Lightscape Technologies binary radiosity data
medit | Medit Productions medit modeling data
nff | Eric Haines' ray tracing test data
pfb | OpenGL Performer fast binary format
obj | Wavefront Technologies data format
pegg | Radiosity research data format
phd | SGI polyhedron data format
poly | Side Effects Software PRISMS ASCII data
ptu | Simple OpenGL Performer terrain data format
rpc | ArchVision rich photorealistic content
sgf | US Naval Academy standard graphics format
sgo | Paul Haeberli's graphics data format
spf | US Naval Academy simple polygon format
sponge | Sierpinski sponge 3D fractal generator
star | Astronomical data from Yale University star chart
stla | 3D Structures ASCII stereolithography data
stlb | 3D Structures binary stereolithography data
stm | Michael Garland's terrain data format
sv | John Kichury's i3dm modeler format
tri | University of Minnesota Geometry Center data
unc | University of North Carolina walkthrough data
wrl | OpenWorlds VMRL 2.0 provided by DRaW Computing

## Description of Supported Formats

This section describes the different database file formats that OpenGL Performer supports.

### AutoDesk 3DS Format

The AutoDesk 3DS format is used by the 3DStudio program and by a number of 3D file-interchange tools. The OpenGL Performer loader for 3DS files is located in the directory `/usr/share/Performer/src/lib/libpfdb/libpf3ds` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpf3ds` on Microsoft Windows. This loader uses an auxiliary library, `3dsftk.a`, to parse and interpret the 3ds file.

pfdLoadFile() uses the function pfdLoadFile_3ds() to import data from 3DStudio files into OpenGL Performer run-time data structures.

### SGI BIN Format

The SGI BIN format is supported by both Showcase and the `powerflip` demonstration program. BIN files are in a simple format that specifies only independent quadrilaterals.

The image in Figure 7-1 shows several of the BIN-format objects provided in the OpenGL Performer sample data directory.

Figure 7-1. BIN-Format Data Objects

The source code for the BIN-format importer pfdLoadFile_bin() is provided in the file `pfbin.c`. This code shows how easy it can be to implement an importer. Since pfdLoadFile_bin() is based on the pfdBuilder() utility function, it will build efficient triangle-strip pfGeoSets from the quadrilaterals of a given BIN file. The BIN format has the following structure:

1. A 4-byte magic number, 0x5432, which identifies the file as a BIN file.

2. A 4-byte number that contains the number of vertices, which is four times the number of quadrilaterals.

3. Four bytes of zero.

4. A list of polygon data for each vertex in the object. The data consists of three floating-point words of information about normals followed by three floating-point words of vertex information.

The BIN format uses these data structures:

    typedef struct
    {
        float normal[3];
        float coordinate[3];
    } Vertex;

    typedef struct
    {
        long magic;
        long vertices;
        long zero;
        Vertex vertex[1];
    } BinFile;

pfdLoadFile() uses the function pfdLoadFile_bin() to import data from BIN format files into OpenGL Performer run-time data structures:

The pfdLoadFile_bin() function composes a random color for each file it reads. The chosen color has red, green, and blue components uniformly distributed within the range 0.2 to 0.7 and is fully opaque.

### Side Effects POLY Format

The Side Effects software PRISMS database modeler format supports both ASCII and binary forms of the POLY format. The OpenGL Performer loader for ASCII “.poly” files is located in the directory `/usr/share/Performer/src/lib/libpfdb/libpfpoly` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfpoly` for Microsoft Windows. The binary format “.bpoly” loader is located in the directory `/usr/share/Performer/src/lib/libpfdb/libpfbpoly` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfbpoly` for Microsoft Windows. These formats are equivalent in content and differ only in representation.

The POLY format is an easy to understand ASCII data representation with the following structure:

1. A text line containing the keyword “POINTS”

2. One text line for each vertex in the file. Each line begins with a vertex number, followed by a colon, followed by the X, Y, and Z axis coordinates of the vertex, optional additional information, and a new-line character. The optional information includes color specification in the form “c(R,G,B,A)”, a normal vector of the form “n(NX,NY,NZ)”, or a texture coordinate in the form “uv(S,T)” where each of the values shown are floating point numbers.

3. A text line containing the keyword “POLYS”

4. One text line for each polygon in the file. Each line begins with a polygon number, followed by a colon, followed by a series of vertex indices, optional additional information, an optional “<“character, and a new-line. The optional information includes color specification in the form “c(R,G,B,A)”, a normal vector of the form “n(NX,NY,NZ)”, or a texture coordinate in the form “uv(S,T)” where the values in parentheses are floating point numbers.

Here is a sample POLY format file for a cube with colors, texture coordinates, and normals specified at each vertex:

    POINTS
    1: -0.5 -0.5 -0.5 c(0, 0, 0, 1) uv(0, 0) n(0, -1, 0)
    2: -0.5 -0.5 0.5 c(0, 0, 1, 1) uv(0, 0) n(0, -1, 0)
    3: 0.5 -0.5 0.5 c(1, 0, 1, 1) uv(1, 0) n(0, -1, 0)
    4: 0.5 -0.5 -0.5 c(1, 0, 0, 1) uv(1, 0) n(0, -1, 0)
    5: -0.5 -0.5 0.5 c(0, 0, 1, 1) uv(0, 0) n(0, 0, 1)
    6: -0.5 0.5 0.5 c(0, 1, 1, 1) uv(0, 1) n(0, 0, 1)
    7: 0.5 0.5 0.5 c(1, 1, 1, 1) uv(1, 1) n(0, 0, 1)
    8: 0.5 -0.5 0.5 c(1, 0, 1, 1) uv(1, 0) n(0, 0, 1)
    9: -0.5 0.5 0.5 c(0, 1, 1, 1) uv(0, 1) n(0, 1, 0)
    10: -0.5 0.5 -0.5 c(0, 1, 0, 1) uv(0, 1) n(0, 1, 0)
    11: 0.5 0.5 -0.5 c(1, 1, 0, 1) uv(1, 1) n(0, 1, 0)
    12: 0.5 0.5 0.5 c(1, 1, 1, 1) uv(1, 1) n(0, 1, 0)
    13: -0.5 -0.5 -0.5 c(0, 0, 0, 1) uv(0, 0) n(0, 0, -1)
    14: 0.5 -0.5 -0.5 c(1, 0, 0, 1) uv(1, 0) n(0, 0, -1)
    15: 0.5 0.5 -0.5 c(1, 1, 0, 1) uv(1, 1) n(0, 0, -1)
    16: -0.5 0.5 -0.5 c(0, 1, 0, 1) uv(0, 1) n(0, 0, -1)
    17: -0.5 -0.5 -0.5 c(0, 0, 0, 1) uv(0, 0) n(-1, 0, 0)
    18: -0.5 0.5 -0.5 c(0, 1, 0, 1) uv(0, 1) n(-1, 0, 0)
    19: -0.5 0.5 0.5 c(0, 1, 1, 1) uv(0, 1) n(-1, 0, 0)
    20: -0.5 -0.5 0.5 c(0, 0, 1, 1) uv(0, 0) n(-1, 0, 0)
    21: 0.5 0.5 0.5 c(1, 1, 1, 1) uv(1, 1) n(1, 0, 0)
    22: 0.5 0.5 -0.5 c(1, 1, 0, 1) uv(1, 1) n(1, 0, 0)
    23: 0.5 -0.5 -0.5 c(1, 0, 0, 1) uv(1, 0) n(1, 0, 0)
    24: 0.5 -0.5 0.5 c(1, 0, 1, 1) uv(1, 0) n(1, 0, 0)
    POLYS
    1: 1 2 3 4 <
    2: 5 6 7 8 <
    3: 9 10 11 12 <
    4: 13 14 15 16 <
    5: 17 18 19 20 <
    6: 21 22 23 24 <

pfdLoadFile() uses the functions pfdLoadFile_poly() and pfdLoadFile_bpoly() to import data from “.poly” and “.bpoly” format files into OpenGL Performer run-time data structures.

### Brigham Young University BYU Format

The Brigham Young University “.byu” format is used as an interchange format by some finite element analysis packages. The OpenGL Performer loader for “.byu” files is located in the directory `/usr/share/Performer/src/lib/libpfdb/libpfbyu` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfbyu` for Microsoft Windows.

The format of a BYU file consists of four parts as defined below:

1. A text line containing four counts: the number of`parts`, the number of `vertices`, the number of `polygons`, and the number of `elements` in the connectivity array.

2. The part definition list, containing the starting polygon number and ending polygon number (one pair per line) for `parts` lines.

3. The vertex list, which has the X, Y, Z coordinates of each vertex in the database packed two per line. This means that vertices 1 and 2 are on the first line, 3 and 4 are on the second, and so on for (`vertices` + 1)/2 lines of text in the file.

4. The connectivity array, with an entry for each polygon. These entries may span multiple lines in the input file and each consists of three or more vertex indices with the last negated as an end of list flag. For example, if the first polygon were a quad, the connectivity array might start with “1 2 3 -4” to define a polygon that connects the first four vertices in order.

The following BYU format file defines two adjoining quads:

    2 6 2 0
    1 1
    2 2
    0 0 0 10 0 0
    10 10 0 0 10 0
    10 10 10 0 10 10
    1 2 3 -4
    4 3 5 -6

pfdLoadFile() uses the function pfdLoadFile_byu() to import data from “.byu” format files into OpenGL Performer run-time data structures.

### Optimizer CSB Format

OpenGL Performer can load native OpenGL Optimizer format files using this loader. OpenGL Optimizer can also load OpenGL Performer's PFB native format files, providing full database interoperability. This allows you to use OpenGL Optimizer database simplification and optimization tools on OpenGL Performer databases.

### Virtual Cliptexture CT Loader

The OpenGL Performer CT loader allows you to create and configure cliptextures and virtual cliptextures, complete with a scene graph containing simple geometry and callbacks. See the Cliptexture chapter for more details.

### Designer's Workbench DWB Format

The binary DWB format is used for input and output by the Designer's Workbench, EasyT, and EasyScene database modeling tools produced by Coryphaeus Software. DWB is an advanced database format that directly represents many of OpenGL Performer's attribute and hierarchical scene graph concepts.

An importer for this format, named pfdLoadFile_dwb(), has been provided by Coryphaeus Software for your use. The loader code and its associated documentation are in the directory `/usr/share/Performer/src/lib/libpfdb/libpfdwb` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfdwb` for Microsoft Windows.The image in Figure 7-2 shows a model of the Soma Cube puzzle invented by Piet Hein. The model was created using Designer's Workbench. Each of the pieces is stored as an individual DWB-format file. Do you see how to form the 3 x 3 cube at the lower left from the seven individual pieces?

Figure 7-2. Soma Cube Puzzle in DWB Form

pfdLoadFile() uses the function pfdLoadFile_dwb() to load Designer's Workbench files into OpenGL Performer run-time data structures.

### AutoCAD DXF Format

The DXF format originated with Autodesk's AutoCAD database modeling system. The version recognized by the pfdLoadFile_dxf() database importer is a subset of ASCII Drawing Interchange Format (DXF) Release 12. The binary version of the DXF format, also known as DXF, is not supported. Source code for the importer is in the file `/usr/share/Performer/src/lib/libpfdb/libpfdxf/pfdxf.c` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfdxf\pfdxf.c` for Microsoft Windows. pfdLoadFile_dxf() was derived from the DXF-to-DKB data file converter developed and placed in the public domain by Aaron A. Collins.

The image in Figure 7-3 shows a DXF model of the famous Utah teapot. This model was loaded from DXF format using the pfdLoadFile_dxf() database importer.

Figure 7-3. The Famous Teapot in DXF Form

The DXF format has an unusual though well-documented structure. The general organization of a DXF file is the following:

1. HEADER section with general information about the file

2. TABLES section to provide definitions for named items, including:

   - LTYPE, the line-type table

   - LAYER, the layer table

   - STYLE, the text-style table

   - VIEW, the view table

   - UCS, the user coordinate-system table

   - VPORT, the viewport configuration table

   - DIMSTYLE, the dimension style table

   - APPID, the application identification table

3. BLOCKS section containing block definition entities

4. ENTITIES section containing entities and block references

5. END-OF-FILE

Within each section are groups of values, where each value is defined by a two-line pair of tokens. The first token is a numeric code indicating how to interpret the information on the next line. For example, the sequence

    10
    1.000
    20
    5.000
    30
    3.000

defines a “start point” at the XYZ location (1, 5, 3). The codes 10, 20, and 30 indicate, respectively, that the primary X, Y, and Z values follow. All data values are retained in a set of numbered registers (10, 20, and 30 in this example), which allows values to be reused. This simple state-machine type of run-length coding makes DXF files space-efficient at the cost of making them harder to interpret.

pfdLoadFile() uses the function pfdLoadFile_dxf() to load DXF format files into OpenGL Performer run-time data structures.

Several widely available technical books provide full details of this format if you need more information. Chief among these are AutoCAD Programming, 2nd Edition, by Dennis N. Jump, Windcrest Books, 1991, and AutoCAD: The Complete Reference, Second Edition, by Nelson Johnson, Osborne McGraw-Hill, 1991.

### MultiGen OpenFlight Format

The OpenFlight format is a binary format used for input and output by the MultiGen and ModelGen database modeling tools produced by MultiGen. It is a comprehensive format that can represent nearly all of OpenGL Performer's advanced concepts, including object hierarchy, instancing, level-of-detail selection, light-point specification, texture mapping, and material property specification.

MultiGen has provided an OpenFlight-format importer, pfdLoadFile_flt(), for your use. The loaders and associated documentation are in the directories `/usr/share/Performer/src/lib/libpfdb/libpfflt11` and `libpfflt` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfflt11` and `libpfllt` for Microsoft Windows. Refer to the `Readme` files in these directories for important information about the loaders and for help in contacting MultiGen for information about pfdLoadFile_flt() or the OpenFlight format.

The image in Figure 7-4 shows a model of a spacecraft created by Viewpoint Animation Engineering using MultiGen. This OpenFlight format model was loaded into OpenGL Performer using pfdLoadFile_flt().

Figure 7-4. Spacecraft Model in OpenFlight Format

pfdLoadFile() uses the function pfdLoadFile_flt() to load OpenFlight format files into OpenGL Performer run-time data structures.

Files in the OpenFlight format are structured as a linear sequence of records. The first few bytes of each record are a header containing an op-code, the length of the record, and possibly an ASCII name for the record. The first record in the file is a special “database header” record whose op-code, stored as a 2-byte short integer, has the value 1. This op-code header can be used to identify OpenFlight-format files. By convention, these files have a `“.flt`” filename extension.

pfdLoadFile_flt() makes use of several environment variables when locating data and texture files. These variables and several additional functions, including pfdConverterMode_flt(), pfdGetConverterMode_flt(), and pfdConverterAttr_flt() assist in OpenFlight file processing.

### McDonnell-Douglas GDS Format

The “.gds” format (also known as the “Things” format) is used in at least one CAD system, and a minimal loader for this format has been developed for OpenGL Performer users. The OpenGL Performer loader for “.gds” files is located in the directory `/usr/share/Performer/src/lib/libpfdb/libpfgds` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfgds` for Microsoft Windows.

The GDS format subset accepted by the pfdLoadFile_gds() function is easy to describe. It consists of the following five sequential sections in an ASCII file:

1. The number of `vertices`, which is given following a “YIN” tag

2. The vertices, with one X, Y, Z triple per line for `vertices` lines

3. The number zero on a line by itself

4. The number of `polygons` on a line by itself

5. A series of polygon definitions, each of which is represented on two or more lines. The first line contains the number one and the name of a material to use for the polygon. The next line or lines contain the indices for the polygons vertices. The first number on the first line is the number of `vertices`. This is followed by that number of vertex indices on that and possibly subsequent lines.

pfdLoadFile() uses the function pfdLoadFile_gds() to load “.gds” format files into IRIS Performer.

### SGI GFO Format

The GFO format is the simple ASCII format of the `barcelona` database that is provided in the OpenGL Performer sample database directory. This database represents the famous German Pavilion at the Barcelona Exhibition of 1929, which was designed by Ludwig Mies van der Rohe and is shown in Figure 7-5.

Figure 7-5. GFO Database of Mies van der Rohe's German Pavilion

The source code for the GFO-format loader is provided in the file`/usr/share/Performer/src/lib/libpfdb/libpfgfo/pfgfo.c` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfgfo\pfgfo.c` for Microsoft Windows.

pfdLoadFile() uses the function pfdLoadFile_gfo() to load GFO format files into OpenGL Performer run-time data-structures.

When working with GFO files, remember that hardware lighting is not used since all illumination effects have already been accounted for with the ambient color at each vertex.

The GFO format defines polygons with a color at every vertex. It is the output format of an early radiosity system. Files in this format have a simple ASCII structure, as indicated by the following abbreviated GFO file:

    scope {
    v3f {42.9632 8.7500 0.9374}
    cpack {0x8785a9}
    v3f {42.9632 8.0000 0.9374}
    cpack {0x8785a9}
    ...
    v3f {-1.0000 -6.5858 10.0000}
    cpack {0xffffff}
    polygon {cpack[0] v3f[0] cpack[1] v3f[1] cpack[2] v3f[2] cpack[3] v3f[3] }
    polygon {cpack[4] v3f[4] cpack[5] v3f[5] cpack[6] v3f[6] cpack[7] v3f[7] }
    ...
    polygon {cpack[7330] v3f[7330] cpack[7331] v3f[7331] cpack[7332] v3f[7332] cpack[7333] v3f[7333] }
    instance {
    polygon[0]
    polygon[1]
    ...
    polygon[2675]
    }
    }

This example is taken from the file `barcelona-l.gfo`, one of only two known databases in the GFO format. The importer uses functions from the `libpfdu` library ( such as those from the pfdBuilder) to generate efficient shared triangle strips. This increases the speed with which GFO databases can be drawn and reduces the size and complexity of the loader, since the builder's functions hide the details of the pfGeoSet construction process.

### SGI IM Format

The “.im” format is a simple format developed for test purposes by the OpenGL Performer engineering team. As new features are added to OpenGL Performer, the “.im” loader is extended to allow experimentation and testing. A recent example of this is support for pfText, pfString, and pfFont objects which can be seen by running Perfly on the sample data file `fontsample.im`. The OpenGL Performer “.im” loader is in the directory `/usr/share/Performer/src/lib/libpfdb/libpfim` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfim` for Microsoft Windows.

Here is an example IM format file that creates an extruded 3D text string. Copy this to a file ending in the extension “.im” and load it into Perfly. For a complete example of how text is handled in OpenGL Performer, use Perfly to examine the file`/usr/share/Performer/data/fontsample2.im` on IRIX and Linux and in `%PFROOT%\Data\fontsample2.im` on Microsoft Windows.

    breakup 0 0.0 0 0
    new root top
    end_root

    new font mistr-extruded Mistr 3
    end_font

    new str_text textnode mistr-extruded 1
    Hello World||
    end_text

    attach top textnode

pfdLoadFile() uses the function pfdLoadFile_im() to load “`.im`” format files into OpenGL Performer run-time data structures:

pfdLoadFile_im() searches the current OpenGL Performer file path for the named file and returns a pointer to the pfNode parenting the imported scene graph, or NULL if the file is not readable or does not contain a valid database.

### AAI/Graphicon IRTP Format

The AAI/Graphicon “.irtp” format is used by the TopGen database modeling system and by the Graphicon-2000 image generator. The name IRTP is an acronym for Interactive Real-Time PHIGS. The OpenGL Performer “.irtp” loader is in the directory `/usr/share/Performer/src/lib/libpfdb/libpfirtp` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfirtp` for Microsoft Windows. Though loader does not support the more arcane IRTP features, such as binary separating planes or a global matrix table, it has served as a basis for porting applications to OpenGL Performer and the RealityEngine.

pfdLoadFile() uses the function pfdLoadFile_irtp() to load IRTP format files into OpenGL Performer run-time data structures.

### SGI Open Inventor Format

The Open Inventor object-oriented 3D-graphics toolkit defines a persistent data format that is also a superset of the VRML networked graphics data format. The image in Figure 7-6 shows a sample Open Inventor data file.

Figure 7-6. Aircar Database in IRIS Inventor Format

The model in Figure 7-6 represents one design for the perennial “personal aircar of the future” concept. It was created, using Imagine, by Mike Halvorson of Impulse, and was modeled after the Moller 400 as described in Popular Mechanics.

The Open Inventor data-file loader provided with OpenGL Performer reads both binary and ASCII format Open Inventor data files. Open Inventor scene graph description files in both formats have the suffix `“.iv`” appended to their file names.

Here is a simple Open Inventor file that defines a cone:

    #Inventor V2.1 ascii

    Separator {
     Cone {
     }
    }

The source code for the Open Inventor format importer is provided in the `libpfdb/libpfiv` source directory.

pfdLoadFile() uses the function pfdLoadFile_iv() to load Open Inventor format files into OpenGL Performer run-time data-structures. OpenGL Performer also comes with an Inventor loader that works with Open Inventor 2.0, if Open Inventor 2.1 is not installed.

### Lightscape Technologies LSA and LSB Formats

The Lightscape Visualization system is a product of Lightscape Technologies, Inc., and is designed to compute accurate simulations of global illumination within complex 3D environments. The output files created with Lightscape Visualization can be read into OpenGL Performer for real-time visual exploration.

Lightscape Technologies provides importers for two of their database formats, the simple ASCII LSA format and the comprehensive binary LSB format. These loaders are in the files `pflsa.c` and `pflsb.c` in the directories `/usr/share/Performer/src/lib/libpfdb/libpflsa` and `libpflsb` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpflsa` and `libpflsb` for Microsoft Windows. Files in the LSA format are in ASCII and have the following components:

1. A 4x4 view matrix representing a default transformation

2. Counts of the number of independent triangles, independent quadrilaterals, triangle meshes, and quadrilateral meshes in the file

3. Geometric data definitions

There are four types of geometric definitions in LSA files. The formats of these definitions are as shown in Table 7-7.

Table 7-7. Geometric Definitions in LSA Files

Geometric Type | Format
--- | ---
Triangle | t X1 Y1 Z1 C1 X2 Y2 Z2 C2 X3 Y3 Z3 C3
Triangle mesh | tm n X1 Y1 Z1 C1 X2 Y2 Z2 C2 ...
Quadrilateral | q X1 Y1 Z1 C1 X2 Y2 Z2 C2 X3 Y3 Z3 C3 X4 Y4 Z4 C4
Quadrilateral mesh | qm n X1 Y1 Z1 C1 X2 Y2 Z2 C2 ...

The Cn values in Table 7-7 refer to colors in the format accepted by the OpenGL function glColor(); these colors should be provided in decimal form. The X, Y, and Z values are vertex coordinates. Polygon vertex ordering in LSA files is consistently counterclockwise, and polygon normals are not specified. The first few lines of the LSA sample file `chamber.0.lsa` provide an example of the format:

     0.486911  0.03228900  0.979046  0.9596590
    -1.665110  0.00944197  0.286293  0.2806240
     0.000000  1.92730000 -0.017805 -0.0174524
     0.240398 -5.54670000 13.021200 13.4945000

    1782 4751 0 0

    t 4.35 -7.3677 2.57 6188666 6.5 -9.3 2.57 5663353 4.35 -9.3 2.57 5728890
    t 6.5 -9.3 2.57 5663353 4.35 -7.3677 2.57 6188666 6.5 -8.2463 2.57 6057596

The count line indicates that the file contains 1782 independent triangles and 4751 independent quadrilaterals, which together represent 11,284 triangles. The image in Figure 7-7 shows this database, the New Jerusalem City Hall. This was produced by A.J. Diamond of Donald Schmitt and Company, Toronto, Canada, using the Lightscape Visualization system.

Figure 7-7. LSA-Format City Hall Database

pfdLoadFile() uses the function pfdLoadFile_lsa() to load LSA format files into OpenGL Performer run-time data structures.

Files in the LSB binary format have a very different structure from LSA files. Representing not just polygon data, they contain much of the structural information present in the `“.ls`” files used by the Lightscape Visualization system, including material, layer, and texture definitions as well as a hierarchical mesh definition for geometry. This information is structured as a series of data sections, which include the following:

- The signature, a text string that identifies the file

- The header, which contains global file information

- The material table, defining material properties

- The layer table, defining grouping and association

- The texture table, referencing texture images

- Geometry in the form of clusters

The format of the geometric clusters is somewhat complicated. A cluster is a group of coplanar surfaces called patches that share a common material, layer, and normal. Each patch shares at least one edge with another patch in the cluster. Each patch defines either a convex quadrilateral or a triangle, and patches represent quad-trees called nodes. Each node points to its corner vertices and its children. The leaf nodes point to their corner vertices and the child pointers can optionally point to the vertices that split an edge of the node. Only the locations of vertices that are corners of the patches are stored in the file; other vertices are created by subdividing nodes of the quad-tree as the LSB file is loaded. The color information for each vertex is unique and is specified in the file.

The image in Figure 7-8 shows an LSB-format database developed during the design of a hospital operating room. This database was produced by the DeWolff Partnership of Rochester, New York, using the Lightscape Visualization system.

Figure 7-8. LSB-Format Operating Room Database

pfdLoadFile() uses the function pfdLoadFile_lsb() to load LSB format files into OpenGL Performer run-time data structures.

When working with Lightscape Technologies files, remember that hardware lighting is not needed because all illumination effects have already been accounted for with the ambient color at each vertex.

### Medit Productions MEDIT Format

The “.medit” format is used by the Medit database modeling system produced by Medit Productions. The OpenGL Performer “.medit” loader is in the directory `/usr/share/Performer/src/lib/libpfdb/libpfmedit` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfmedit` for Microsoft Windows.

pfdLoadFile() uses the function pfdLoadFile_medit() to load MEDIT format files into OpenGL Performer run-time data structures.

### NFF Neutral File Format

The “.nff” format was developed by Eric Haines as a way to provide standard procedural databases for evaluating ray tracing software. OpenGL Performer includes an extended NFF loader with superquadric torus support, a named `build` keyword, and numerous small bug fixes. The “.nff” loader is located in the directory `/usr/share/Performer/src/lib/libpfdb/libpfnff` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfnff` for Microsoft Windows.

The file `/usr/share/Performer/data/sampler.nff` on IRIX and Linux and `%PFROOT%\Data\sampler.nff` on Microsoft Windows uses each of the NFF data types. It is an excellent way to explore the “Show Tree”, “Draw Style”, and “Highlight Mode” features of Perfly. It is included here:

    #-- torus
    f .75 .00 .25 .6 .8 20 0
    t 5 5 0 0 0 1 2 1
    build torus

    #-- cylinder
    f .00 .75 .25 .6 .8 20 0
    c
    15 5 -3 2
    15 5 3 2
    #-- put a disc on the top and bottom of the cylinder
    d 15 5 -3 0 0 -1 0 2
    d 15 5 3 0 0 1 0 2
    build cylinder

    #-- cone
    f .00 .25 .75 .6 .8 20 0
    c
    25 5 -3 3
    25 5 3 0
    #-- put a disc on the bottom of the cone
    d 25 5 -3 0 0 -1 0 3
    build cone

    #-- sphere
    f .75 .00 .75 .6 .8 20 0
    s 5 15 0 3
    build sphere

    #-- hexahedron
    f .25 .25 .50 .6 .8 20 0
    h 13 13 -2 17 17 2
    build hexahedron

    #-- superquadric sphere
    f .80 .10 .30 .6 .8 20 0
    ss 25 15 0 2 2 2 .1 .4
    build superquadric_sphere

    #-- disc (washer shape)
    f .20 .20 .90 .6 .8 20 0
    d 5 25 0 0 0 1 1 2.5
    build disc

    #-- grid (height field)
    f .80 .80 .10 .6 .8 20 0
    g 4 4 12 18 22 28 0 4
    0 0 0 0
    0 1 0 0
    0 0 -1 0
    0 0 0 0
    build grid

    #-- superquadric torid
    f .40 .20 .60 .6 .8 20 0
    st 25 25 0 0.5 0.5 0.5 .33 .33 3
    build superquadric_torid

    #-- polygon with no normals
    f .20 .20 .20 .6 .8 20 0
    p 4
    -5 -5 -10
    35 -5 -10
    35 35 -10
    -5 35 -10
    build polygon

pfdLoadFile() uses the function pfdLoadFile_nff() to load NFF format files into OpenGL Performer run-time data structures.

### Wavefront Technology OBJ Format

The OBJ format is an ASCII data representation read and written by the Wavefront Technology `Model` program. A number of database models in this format have been placed in the public domain, making this a useful format to have available. OpenGL Performer provides the function pfdLoadFile_obj() to import OBJ files. The source code for pfdLoadFile_obj() is in the file `pfobj.c` in the loader source directory `/usr/share/Performer/src/lib/libpfdb/libpfobj` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfobj` for Microsoft Windows.

The OBJ-format database shown in Figure 7-9 models an office building that is part of the SGI corporate campus in Mountain View, California.

Figure 7-9. SGI Office Building as OBJ Database

Files in the OBJ format have a flexible all-ASCII structure, with simple keywords to direct the parsing of the data. This format is best illustrated with a short example that defines a texture-mapped square:

    #-- `v' defines a vertex; here are four vertices
    v -5.000000  5.000000 0.000000
    v -5.000000 -5.000000 0.000000
    v  5.000000 -5.000000 0.000000
    v  5.000000  5.000000 0.000000

    #-- `vt' defines a vertex texture coordinate; four are given
    vt 0.000000 1.000000 0.000000
    vt 0.000000 0.000000 0.000000
    vt 1.000000 0.000000 0.000000
    vt 1.000000 1.000000 0.000000

    #-- `usemtl' means select the material definition defined
    #-- by the name MaterialName
    usemtl MaterialName

    #-- `usemap' means select the texturing definition defined
    #-- by the name TextureName
    usemap TextureName

    #-- `f' defines a face. This face has four vertices ordered
    #-- counterclockwise from the upper left in both geometric
    #-- and texture coordinates. Each pair of numbers separated
    #-- by a slash indicates vertex and texture indices,
    #-- respectively, for a polygon vertex.
    f 1/1 2/2 3/3 4/4

pfdLoadFile() uses the function pfdLoadFile_obj() to load Wavefront OBJ files into OpenGL Performer run-time data structures.

### SGI PFB Format

| Note: The PFB format is undocumented and is subject to change.

Although OpenGL Performer has no true native database format, the PFB format is designed to exactly replicate the OpenGL Performer scene graph; this design increases loading speed. A file in the PFB format has the following advantages:

- PFB files often load in one tenth (or less) of the time it takes an equivalent file in another format to load.

- PFB files are often half the size of equivalent files in another format.

You can think of the PFB format as being a cache. You can convert your files into PFB for fast and efficient loading or paging, but you should always keep your original files in case you wish to modify them.

#### Converting to the PFB Format

You can convert files into the PFB format in one of the following ways:

- Use the function pfdStoreFile_pfb() in `libpfpfb`.

- Use `pfconv`.

### SGI PFI Format

The PFI image file format is designed for fast loading of images into pfTextures. pfLoadTexFile() can load PFI files as the image of a pfTexture. Since the format of the image in a PFI file matches that of a pfTexture, data is not reformatted at load time. Eliminating the reformatting often cuts the load time of textures to half of the load time of the same image in the IRIS RGB image format.

PFI files can contain the mipmaps of the image. This feature saves significant time in the OpenGL Performer DRAW process since it does not have to generate the mipmaps.

#### Creating PFI Files

PFI files are created in the following ways:

- pfSaveTexFile() creates a PFI file from a pfTexture.

- The pfdImage methods in`libpfdu` create PFI files.

- `pficonv` converts IRIS RGB image files into PFI files.

- `pfconv` converts all referenced image files into PFI files when the setting PFPFB_SAVE_TEXTURE_PFI mode is PF_ON. The command line options to do this with `pfconv` is `-Mpfb,5`.

### SGI PHD Format

The PHD format was created to describe the geometric polyhedron definitions derived mathematically by Andrew Hume and by the `Kaleido` program of Zvi Har'El. This format describes only the geometric shape of polyhedra; it provides no specification for color, texture, or appearance attributes such as specularity.

The OpenGL Performer sample data directories contain numerous polyhedra in the PHD format. The image in Figure 7-10 shows many of the polyhedron definitions laboriously computed by Andrew Hume.

Figure 7-10. Plethora of Polyhedra in PHD Format

The source code for the PHD-format importer is in the file `/usr/share/Performer/src/lib/libpfdb/libpfpoly/pfphd.c` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfpoly\pfdhd.c` on Microsoft Windows.

PHD format files have a line-structured ASCII form; an initial keyword defines the contents of each line of data. The file format consists of a filename definition (introduced by the keyword `file`) followed by one or more object definitions.

Object definitions are bracketed by the keywords `object.begin` and `object.end` and contain one or more polygon definitions. Objects can have a name in quotes following the `object.begin` keyword; such a name is used by the loader for the name of the corresponding OpenGL Performer node.

Polygon definitions are bracketed by the keywords `polygon.begin` and `polygon.end` and contain three or more vertex definitions.

Vertex definitions are introduced by the `vertex` keyword and define the X, Y, and Z coordinates of a single vertex.

The following is a PHD-format definition of a unit-radius tetrahedron centered at the origin of the coordinate axes. It is derived from the database developed by Andrew Hume but has since been translated, scaled, and reformatted.

    file 000.phd
    object.begin "tetrahedron"
    polygon.begin
    vertex -0.090722 -0.366647  0.925925
    vertex  0.544331 -0.628540 -0.555555
    vertex  0.453608  0.890430  0.037037
    polygon.end
    polygon.begin
    vertex -0.907218  0.104757 -0.407407
    vertex -0.090722 -0.366647  0.925925
    vertex  0.453608  0.890430  0.037037
    polygon.end
    polygon.begin
    vertex -0.090722 -0.366647  0.925925
    vertex -0.907218  0.104757 -0.407407
    vertex  0.544331 -0.628540 -0.555555
    polygon.end
    polygon.begin
    vertex  0.453608  0.890430  0.037037
    vertex  0.544331 -0.628540 -0.555555
    vertex -0.907218  0.104757 -0.407407
    polygon.end
    object.end

pfdLoadFile() uses the function pfdLoadFile_phd() to load PHD format files into OpenGL Performer run-time data structures.

The pfdLoadFile_phd() function composes a color with red, green, and blue components uniformly distributed within the range 0.2 to 0.7 that is consistent for each polygon with the same number of vertices within a single polyhedron.

### SGI PTU Format

The PTU format is named for the OpenGL Performer Terrain Utilities, of which the pfdLoadFile_ptu() function is the sole example at the present time. This function accepts as input the name of a control file (the file with the `“.ptu`” filename extension) that defines the desired terrain parameters and references additional data files.

The database shown in Figure 7-11 represents a portion of the Yellowstone National Park. This terrain database was generated completely by the OpenGL Performer Terrain Utility data generator from digital terrain elevation data and satellite photographic images. Image manipulation is performed using the SGI ImageVision Library functions.

Figure 7-11. Terrain Database Generated by PTU Tools

The PTU control file has a fixed format that does not use keywords. The contents of this file are simply ASCII values representing the following data items:

1. The name to be assigned to the top-level pfNode built by pfdLoadFile_ptu().

2. The number of desired levels-of-detail (LOD) for the resulting terrain surface. The pfdLoadFile_ptu() function will construct this many versions of the terrain, each representing the whole surface but with exponentially fewer numbers of polygons in each version.

3. The number of highest-LOD tiles that will tessellate the entire terrain surface in the X and Y axis directions.

4. Two numeric values that define the mapping of texture image pixels to world-coordinate terrain geometry. These values are the number of meters per texel (texture pixel) of filtered grid post data in the X and Y axis dimensions.

5. The name of an image file that represents terrain height at regularly spaced sample points in the form of a monochrome image whose brightness at each pixel indicates the height at that sample point. Additional arguments are the number of samples in the input image in the X and Y directions, as well as the desired number of samples in these directions. The pfdLoadFile_ptu() function resamples the grid posts from the original to the desired resolution by filtering the height image using SGI ImageVision Library functions.

6. The name of an image file that represents the terrain texture image at regularly spaced sample points. Subsequent arguments are the number of samples in the image in the X and Y directions as well as the desired number of samples in these directions. This image will be applied to the terrain geometry. The scale values provided in the PTU file allow the terrain grid and texture image to be adjusted to create an orthographic alignment.

7. An optional second texture-image filename that serves as a detail texture when the terrain is viewed on RealityEngine systems. This texture is used in addition to the base texture image.

8. An optional detail-texture spline-table definition. The blending of the primary texture image and the secondary detail texture is controlled by a blend table defined by this spline function. The spline table is optional even when a detail texture is specified. Detail texture and its associated blend functions are applicable only on RealityEngine systems.

The source code for the PTU-format importer is provided in the file `/usr/share/Performer/src/lib/libpfdb/libpfptu/pfptu.c` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfptu\pfptu.c` on Microsoft Windows.

pfdLoadFile() uses the function pfdLoadFile_ptu() to load PTU format files into OpenGL Performer run-time data structures.

### ArchVision RPC Format

ArchVision provides the rich photorealistic content (RPC) loader. The RPC loader loads in images from an ArchVision RPC file. The images represent views of an object from a set of directions around the object. If you provide an existing pfIBRnode, the images are loaded into a pfIBRtexture of the node. Otherwise, the function creates a new pfIBRnode with a single pfGeoSet and a pfIBRtexture containing the images. In the case of new content with meshes, the pfGeoSet contains the mesh, which becomes the proxy in the pfIBRnode.

The following functions allow you to access and alter the modes, values, and attributes of the RPC loader:

- pfdConverterMode_rpc(), pfdGetConverterMode_rpc()

- pfdConverterVal_rpc(), pfdGetConverterVal_rpc()

- pfdConverterAttr_rpc(), pfdGetConverterAttr_rpc()

You control the RPC converter modes with the token PFRPC_USE_USER_IBRNODE. By default, the loader creates a pfIBRnode with a single pfGeoSet and a pfIBRtexture that contains the loaded images. If this mode is set to PF_ON and you supply a pfIBRnode using pfdConverterAttr_rpc(), the images are loaded into the pfIBRtexture of that node.

Table 7-8 describes the RPC converter values.

Table 7-8. RPC Converter Values

Converter Value | Description
--- | ---
PFRPC_SKIP_TEXTURES | Skips every n images. ArchVision RPC files often contain hundreds of images. A pfIBRtexture containing so many images would be too large. The default is set to `2`. If you want to use all images in the file, set it to `0`.
PFRPC_CROP_LEFT | Crops the loaded images by the specified number of pixels on the left.
PFRPC_CROP_RIGHT | Crops the loaded images by the specified number of pixels on the right. Note that the resulting image width should be a power of 2.
PFRPC_CROP_TOP | Crops the loaded images by the specified number of pixels on the top.
PFRPC_CROP_BOTTOM | Crops the loaded images by the specified number of pixels on the bottom. Note that the resulting image height should be a power of 2.
PFRPC_SCALE_WIDTH | Scales the billboard width in the case of a pfIBRnode without a proxy.
PFRPC_SCALE_HEIGHT | Scales the billboard height in the case of a pfIBRnode without a proxy.
PFRPC_NEAREST | Sets flag PFIBR_NEAREST on the pfIBRnode created by the loader.
PFRPC_USE_NEAREST_RING | In the case of content with a proxy and having more than one ring of views, forces the mode in which views are selected from the nearest ring rather than having the views blended between the two nearest rings.
PFRPC_COMBINED_TEXTURE_SIZE | Combines textures into a square texture of the specified size (should be a power of 2). By default, if the texture size is not a power of 2, textures are combined into a texture of size 2048x2048. If the texture size is power of 2, textures are not combined into a bigger texture unless the value PFRPC_COMBINED_TEXTURE_SIZE is explicitly specified. You can also set it to `0` to disable combining.

Table 7-9 describes the converter attributes.

Table 7-9. RPC Converter Attributes

Converter Attribute | Description
--- | ---
PFRPC_USER_IBRNODE | Specifies a pfIBRnode. The images from the RPC file are loaded into the pfIBRtexture of the node.
PFRPC_RING_FILE | Specifies the path to ring files that define the rings of views where proxies are used. There is one file for each component of the input RPC file, indexed by extension .0, .1, .2, and so on. Each line of the ring file contains the angle of the ring from the horizon and the number of views in that ring. If no ring file is specified, each component has only one ring of 16 views at horizontal angle 0. You can use an environment variable of the same name to set this attribute.
PFRPC_SKIP_TEXTURES PFRPC_SCALE_WIDTH PFRPC_FLIP_TEXTURES PFRPC_NEAREST PFRPC_USE_NEAREST_RING PFRPC_COMBINED_TEXTURE_SIZE | See Table 7-8 for the descriptions of these attributes. You can use an environment variable of the same name to set this attribute. Setting attribute values through the use of environment variables allows you to affect the loading of the files without the necessity of changing your application.

| Note: The loader is using a relatively slow, third-party routine for decompressing images. For a faster load time, you may want to convert your RPC files into PFB files using `pfconv`.

Two sample RPC files can be found in directory `/usr/share/Performer/data/ibr/rpc` for IRIX and Linux and in `%PFROOT%\Data\ibr\rpc` for MicroSoft Windows. You can download other files from the ArchVision webpage at `www.archvision.com`.

### USNA Standard Graphics Format

The SGF format is used at the United States Naval Academy as a standard graphics format for geometric data. The loader was developed based on the description of the standard graphics format as described by David F. Rogers and J. Alan Adams in the book Mathematical Elements for Computer Graphics. The OpenGL Performer “.sgf” format loader is located in the directory `/usr/share/Performer/src/lib/libpfdb/libpfsgf` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfsgf` for Microsoft Windows

Here is the vector definition for four stacked squares in SGF form:

    0, 0, 0
    1, 0, 0
    1, 1, 0
    0, 1, 0
    0, 0, 0
    1.0e37, 1.0e37, 1.0e37
    0, 0, 1
    1, 0, 1
    1, 1, 1
    0, 1, 1
    0, 0, 1
    1.0e37, 1.0e37, 1.0e37
    0, 0, 2
    1, 0, 2
    1, 1, 2
    0, 1, 2
    0, 0, 2
    1.0e37, 1.0e37, 1.0e37
    0, 0, 3
    1, 0, 3
    1, 1, 3
    0, 1, 3
    0, 0, 3
    1.0e37, 1.0e37, 1.0e37

pfdLoadFile() uses the function pfdLoadFile_sgf() to load SGF format files into OpenGL Performer run-time data-structures.

### SGI SGO Format

The SGI Object format is used by several utility programs and was one of the first database formats supported by OpenGL Performer. The image in Figure 7-12 shows a model generated by Paul Haeberli and loaded into Perfly by the pfdLoadFile_sgo() database importer.

Figure 7-12. Model in SGO Format

Objects in the SGO format have per-vertex color specification and multiple data formats. Objects contained in SGO files are constructed from three data types:

- Lists of quadrilaterals

- Lists of triangles

- Triangle meshes

Objects of different types can be included as data within one SGO file.

The SGO format has the following structure:

1. A magic number, 0x5424, which identifies the file as an SGO file.

2. A set of data for each object. Each object definition begins with an identifying token, followed by geometric data. There can be multiple object definitions in a single file. An end-of-data token terminates the file.

The layout of an SGO file is the following:

    <SGO-file magic number>
    <data-type token for object #1>
    <data for object #1>
    <data-type token for object #2>
    <data for object #2>
    ...
    <data-type token for object #n>
    <data for object #n>
    <end-of-data token>

Each of the identifying tokens is 4 bytes long. Table 7-10 lists the symbol, value, and meaning for each token.

Table 7-10. Object Tokens in the SGO Format

Symbol | Value | Meaning
--- | --- | ---
OBJ_QUADLIST | 1 | Independent quadrilaterals
OBJ_TRILIST | 2 | Independent triangles
OBJ_TRIMESH | 3 | Triangle mesh
OBJ_END | 4 | End-of-data token

The next word following any of the three object types is the number of 4-byte words of data for that object. The format of this data varies depending on the object type.

For quadrilateral list (OBJ_QUADLIST) and triangle list (OBJ_TRILIST) objects, there are nine words of floating-point data for each vertex, as follows:

1. Three words that specify the components of the normal vector at the vertex

2. Three words that specify the red, green, and blue color components, scaled to the range 0.0 to 1.0

3. Three words that specify the X, Y, and Z coordinates of the vertex itself

In quadrilateral lists, vertices are in groups of four; so, there are 4 × 9 = 36 words of data for each quadrilateral. In triangle lists, vertices are in groups of three, for 3 x 9 = 27 words per triangle.

The triangle mesh, OBJ_TRIMESH, is the most complicated of the three object data types. Triangle mesh data consists of a set of vertices followed by a set of mesh-control commands. Triangle mesh data has the following format:

1. A long word that contains the number of words in the complete triangle mesh data packet

2. A long word that contains the number of floating-point words required by the vertex data, at nine words per vertex

3. The data for each vertex, consisting of nine floating-point words representing normal, color, and coordinate data

4. A list of triangle mesh controls

The triangle mesh controls, each of which is one word in length, are listed in Table 7-11.

Table 7-11. Mesh Control Tokens in the SGO Format

Symbol | Value | Meaning
--- | --- | ---
OP_BGNTMESH | 1 | Begin a triangle strip.
OP_SWAPTMESH | 2 | Exchange old vertices.
OP_ENDBGNTMESH | 3 | End then begin a strip.
OP_ENDTMESH | 4 | Terminate triangle mesh.

The triangle-mesh controls are interpreted sequentially. The first control must always be OP_BGNTMESH, which initiates the mesh-decoding logic. After each mesh control is a word (of type long integer) that indicates how many vertex indices follow. The vertex indices are in byte offsets, so to access vertex n, you must use the byte offset n x 9 x 4.

pfdLoadFile() uses the function pfdLoadFile_sgo() to load SGO format files into OpenGL Performer run-time data structures.

You can find the source code for the SGO-format importer in the file `pfsgo.c`. This importer does not attempt to decode any triangle meshes present in input files; instead, it terminates the file conversion process as soon as an OBJ_TRIMESH data-type token is encountered. If you use SGO-format files containing triangle meshes you will need to extend the conversion support to include the triangle mesh data type.

### USNA Simple Polygon File Format

The “.spf” format is used at the United States Naval Academy as a simple polygon file format for geometric data. The loader was developed based on the description in the book Mathematical Elements for Computer Graphics. The OpenGL Performer “.spf” loader is in the directory `/usr/share/Performer/src/lib/libpfdb/libpfspf` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfspf` on Microsoft Windows.

The following “.spf” format file is defined in that book.

    polygon with a hole
    14,2
    4,4
    4,26
    20,26
    28,18
    28,4
    21,4
    21,8
    10,8
    10,4
    10,12
    10,20
    17,20
    21,16
    21,12
    9,1,2,3,4,5,6,7,8,9
    5,10,11,12,13,14

If you look at this file in Perfly, you will see that the hole is not cut out of the letter “A” as might be desired. Such computational geometry computations are not considered the province of simple database loaders.

pfdLoadFile() uses the function pfdLoadFile_spf() to load SPF format files into OpenGL Performer run-time data structures.

### Sierpinski Sponge Loader

The Sierpinski Sponge (also known as Menger Sponge) loader is not based on a data format but rather is a procedural data generator. The loader interprets the portion of the user-provided filename before the period and extension as an integer which specifies the number of recursive subdivisions desired in data generation. For example, providing the pseudo filename “3.sponge” to Perfly will result in the Sponge loader being invoked and generating a sponge object using three levels of recursion, resulting in a 35712 polygon database object. The OpenGL Performer “.sponge” loader can be found in the directory `/usr/share/Performer/src/lib/libpfdb/libpfsponge` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfsponge` on Microsoft Windows.

pfdLoadFile() uses the function pfdLoadFile_sponge() to load Sponge format files into OpenGL Performer run-time data structures.

### Star Chart Format

The “.star” format is a distillation of astronomical data from the Yale Compact Star Chart (YCSC). The sample data file `/usr/share/Performer/data/3010.star` for IRIX and Linux and `%PFROOT%\Data\3010.star` for Microsoft Windows contains data from the YCSC that has been reduced to a list of the 3010 brightest stars as seen from Earth and positioned as 3010 points of light on a unit-radius sphere. The OpenGL Performer “.star” loader can read this data and is provided as a convenience for making dusk, dawn, and night-time scenes. The loader is in the directory `/usr/share/Performer/src/lib/libpfdb/libpfstar` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfstar` on Microsoft Windows.

Data in a “.star” file is simply a series of ASCII lines with the “s” (for star) keyword followed by X, Y, and Z coordinates, brightness, and an optional name. Here are the 10 brightest stars (excluding Sol) in the “.star” format:

    s -0.18746032  0.93921369 -0.28763914 1.00 Sirius
    s -0.06323564  0.60291260 -0.79529721 1.00 Canopus
    s -0.78377002 -0.52700269  0.32859191 1.00 Arcturus
    s  0.18718566  0.73014212  0.65715599 1.00 Capella
    s  0.12507832 -0.76942003  0.62637711 0.99 Vega
    s  0.13051330  0.68228769  0.71933979 0.99 Capella
    s  0.19507207  0.97036278 -0.14262892 0.98 Rigel
    s -0.37387931 -0.31261155 -0.87320572 0.94 Rigil Kentaurus
    s -0.41809806  0.90381104  0.09121194 0.94 Procyon
    s  0.49255905  0.22369388 -0.84103900 0.92 Achernar

pfdLoadFile() uses the function pfdLoadFile_star() to load Star format files into OpenGL Performer run-time data structures.

### 3D Lithography STL Format

The STL format is used to define 3D solids to be imaged by 3D lithography systems. STL defines objects as collections of triangular facets, each with an associated face normal. The ASCII version of this format is known as STLA and has a very simple structure.

The image in Figure 7-13 shows a typical STLA mechanical CAD database. This model is defined in the `bendix.stla` sample data file.

Figure 7-13. Sample STLA Database

The source code for the STLA-format loader is in the files `/usr/share/Performer/src/lib/libpfdb/libpfstla/pfstla.c` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfstla\pfstla.c` on Microsoft Windows.

STLA-format files have a line-structured ASCII form; an initial keyword defines the contents of each line of data. An STLA file consists of one or more facet definitions, each of which contains the following:

1. The facet normal, indicated with the `facet normal` keyword

2. The facet vertices, bracketed by `outer loop` and `endloop` keywords

3. The `endloop` keyword

Here is an excerpt from `nut.stl`a, one of the STLA files provided in the OpenGL Performer sample data directories. These are the first two polygons of a 524-triangle hex-nut object:

    facet normal 0 -1 0
     outer loop
      vertex 0.180666 -7.62 2.70757
      vertex -4.78652 -7.62 1.76185
      vertex -4.436 -7.62 0
     endloop
    endfacet
    facet normal -0.381579 -0.921214 -0.075915
     outer loop
      vertex -4.48833 -7.59833 0
      vertex -4.436 -7.62 0
      vertex -4.78652 -7.62 1.76185
     endloop
    endfacet

Use this function to import data from STLA-format files into OpenGL Performer run-time data structures:

    pfNode *pfdLoadFile_stla(char *fileName);

pfdLoadFile_stla() searches the current OpenGL Performer file path for the file named by the fileName argument and returns a pointer to the pfNode that parents the imported scene graph, or NULL if the file is not readable or does not contain recognizable STLA format data.

### SuperViewer SV Format

The SuperViewer (SV) format is one of the several database formats that the I3DM database modeling tool can read and write. The I3DM modeler was developed by John Kichury of SGI and is provided with OpenGL Performer. The source code for the SV format importer is in the file `pfsv.c`.

The passenger vehicle database shown in Figure 7-14 was modeled using I3DM and is stored in the SV database format.

Figure 7-14. Early Automobile in SuperViewer SV Format

Within SV files, object geometry and attributes are described between text lines that contain the keywords `model` and `endmodel`. For example:

    model wing
    geometry and attributes
    endmodel

Any number of models can appear within a SuperViewer file. The geometry and attribute data mentioned above each consist of one of the following types:

- 3D Polygon with vertex normals and optional texture coordinates:

      poly3dn <num_vertices> [textured]
      x1 y1 z1 nx1 ny1 nz1  [s1 t1]
      x2 y2 z2 nx2 ny2 nz2  [s2 t2]
      ...

  where the coordinates and normals are defined as follows:

  - Xn Yn Zn are the nth vertex coordinates

  - Nxn Nyn Nzn are the nth vertex normals

  - Sn Tn are the nth texture coordinates

- 3D Triangle mesh with vertex normals and optional texture coordinates

      tmeshn <num_vertices> [textured]
      x1 y1 z1 nx1 ny1 nz1  [s1 t1]
      x2 y2 z2 nx2 ny2 nz2  [s2 t2]
      ...

  where the coordinates and normals are defined as follows:

  - Xn Yn Zn are the nth vertex coordinates

  - Nxn Nyn Nzn are the nth vertex normals

  - Sn Tn are the nth texture coordinates

- Material definition. If the material directive exists before a model definition, it is taken as a new material specification. Its format is the following:

      material n Ar Ag Ab Dr Dg Db Sr Sg Sb Shine Er Eg Eb

  where the variables represent the following:

  - n is an integer specifying a material number

  - Ar Ag Ab is the ambient color.

  - Dr Dg Db is the diffuse color.

  - Sr Sg Sb is the specular color.

  - Shine is the material shininess.

  - Er Eg Eb is the emissive color.

  If the material directive exists within a model description, the format is the following:

      material n

  where n is an integer specifying which material (as defined by the material description above) is to be assigned to subsequent data.

- Texture definition. If the texture directive exists before a model definition it is taken as a new texture specification. Its format is the following:

      texture n TextureFileName

  If the texture directive exists within a model description, the format is the following:

      texture n

  where n is an integer specifying which texture (as defined by the texture description above) is to be assigned to subsequent data.

- Backface polygon display mode. The backface directive is specified within model definitions to control backface polygon culling:

      backface mode

  where a mode of “on” allows the display of backfacing polygons and a mode of “off” suppresses their display.

In actual use the SV format is somewhat self-documenting. Here is part of the SV file `apple.sv` from the directory `/usr/share/Performer/data` on IRIX and Linux and in `%PFROOT%\Data` on Microsoft Windows:

    material 20 0.0 0.0 0 0.400000 0.000000 0 0.333333 0.000000 0.0 10.0000 0 0 0
    material 42 0.2 0.2 0 0.666667 0.666667 0 0.800000 0.800000 0.8 94.1606 0 0 0
    material 44 0.0 0.2 0 0.000000 0.200000 0 0.000000 0.266667 0.0  5.0000 0 0 0

    texture 4 prchmnt.rgb
    texture 6 wood.rgb

    model LEAF
    material 44
    texture 4
    backface on
    poly3dn 4 textured
     1.35265 1.35761 13.8338 0.0686595 -0.234553 -0.969676 0 1
     0.88243 0.96366 14.0329 0.0502096 -0.376701 -0.924973 0 0.75
    -4.44467 1.24026 13.5669 0.0363863 -0.337291 -0.940697 0.0909091 0.75
    -2.37938 2.17479 13.3626 0.0363863 -0.337291 -0.940697 0.0909091 1
    poly3dn 4 textured
    -2.37938 2.17479 13.3626 0.0363863 -0.337291 -0.940697 0.0909091 1
    -4.44467 1.24026 13.5669 0.0363863 -0.337291 -0.940697 0.0909091 0.75
    -9.23775 2.34664 13.1475 0.0344832 -0.284369 -0.958095 0.181818 0.75
    -6.69592 3.94535 12.6716 0.0344832 -0.284369 -0.958095 0.181818 1

This excerpt specifies material properties and references texture images stored in the files `prchmnt.rgb` and `wood.rgb`, and then defines two polygons.

pfdLoadFile() uses the function pfdLoadFile_sv() to load SuperViewer files into OpenGL Performer run-time data structures.

### Geometry Center Triangle Format

The “.tri” format is used at the University of Minnesota's Geometry Center as a simple geometric data representation. The loader was developed by inspection of a few sample files. The OpenGL Performer “.tri” loader is in the directory `/usr/share/Performer/src/lib/libpfdb/libpftri` on IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpftri` on Microsoft Windows.

These files have a very simple format: a line per vertex with position and normal given on each line as 6 ASCII numeric values. The file is simply a series of these triangle definitions. Here are the first two triangles from the data file `/usr/share/Performer/data/mobrect.tri` on IRIX and Linux and in `%PFROOT%\Data\mobrect.tri` on Microsoft Windows:

    1.788180  1.000870 0.135214 0.076169 -0.085488 0.993423
    1.574000  0.925908 0.146652 0.089015 -0.086072 0.992304
    1.793360  0.634711 0.099409 0.076402 -0.111845 0.990784
    0.836848 -0.595230 0.197960 0.156677  0.044503 0.986647
    0.709638 -0.345676 0.210010 0.157642  0.021968 0.987252
    0.581200 -0.535321 0.234807 0.145068  0.030985 0.988936

pfdLoadFile() uses the function pfdLoadFile_tri() to load “.tri” format files into OpenGL Performer run-time data structures.

### UNC Walkthrough Format

The “.unc” format was once used at the University of North Carolina as a format for geometric data in an architectural walkthrough application. The loader was developed based on inspection of a few sample files. The OpenGL Performer “.unc” loader is in the directory `/usr/share/Performer/src/lib/libpfdb/libpfunc` for IRIX and Linux and in `%PFROOT%\Src\lib\libpfdb\libpfunc` for Microsoft Windows.

pfdLoadFile() uses the function pfdLoadFile_unc() to load UNC format files into OpenGL Performer run-time data structures.

### WRL Format

The VRML 2.0 format for OpenGL Performer, wrl, is made by DRaW Computing Associates. It accepts geometry and texture only. Basic geometry nodes like Sphere, Cone, Cylinder, Box and related nodes like Shape, Material, Appearance, TextureTransform, ImageTexture, and ElevationGrid are supported. Also, complex geometries can be obtained using the IndexedFaceSet node. You can do geometric manipulations to nodes using Group nodes and Transform nodes. You can also make very complex structures using PROTOs, where you group many geometry nodes.

## Database Operators with Pseudo Loaders

The OpenGL Performer dynamic database loading mechanism provides additional DSOs that operate on the resulting scene graph from a file or set of files after the file(s) are loaded. This mechanism, called “ pseudo loaders,” enables the desired operator DSO to be specified as additional suffixes to the filename. The DSO matching the last suffix is loaded first and provided the entire filename. That pseudo loader then can parse the arbitrary filename and invoke the next operator or loader and then operate on the results. This process allows additional arguments to be buried in the specified filename for the pseudo loader to detect and parse.

One set of pseudo loaders included with OpenGL Performer are the `rot`, `trans`, and `scale` loaders. These loaders take hpr and xyz arguments in addition to their Filename and can be invoked from any program using pfdLoadFile(), as shown in this example:

    % perfly cow.obj.-90,90,0.rot

-90, 90, and 0 are the h, p, and r values, respectively.

If you are using a shell with argument expansion, such as `csh`, you can create interesting cow art. Try out the following example:

    % perfly cow.obj.{0,1},0,0.trans cow.obj.{0,1,2,3,4},0,-5.trans

Specifying a base filename is only needed if the specified pseudo loader expects a file to process. Loaders can generate their scene graphics procedurally based on simple parameters specified in the command string.

The pseudo loaders in the OpenGL Performer distribution are described in Table 7-12.

Table 7-12. OpenGL Performer Pseudo Loaders

Pseudo Loaders | Description
--- | ---
`libpfrot` | Add pfSCS at root to rotate scene graph by specified h,p,r.
`libpftrans` | Add pfSCS at root to translate scene graph by specified x,y,z.
`libpfscale` | Add pfSCS at root to sale scene graph by specified x,y,z.
`libpfclosest` | Adds run-time application callback to highlight closest point each frame.
`libpfcliptile` | Adds callback to compute for the specified tilename, minS ,minT, maxS, and maxT, the proper virtual cliptexture viewing parameters.
`libpfsphere` | Generates a sphere database with morphing LOD starting from an n-gon for specified n, power of 2.
`libpfvct` | Convert normal cliptexture `.ct` file to virtual cliptexture.
`libpfsubdiv` | Subdivide an arbitrary file using Loop or Catmull-Clark subdivision.
`libpfgeoa` | Convert geometry from pfGeoSets to pfGeoArrays.
`libpfbreakup` | Create an artificial hierarchy from unstructured input.

Pseudo loaders should define pfdLoadNeededDSOs_EXT() for the following:

- Preinitializing DSOs

- Loading other special files

- Performing additional initialization, such as class initialization, that should happen before pfConfig()

The `libpfbreakup` pseudo loader, which creates an artificial hierarchy from unstructured input, uses the pfdBreakup() function, whose syntax follows:

    pfNode * pfdBreakup(pfGeode *geode, float geodeSize, int stripLength, int geodeChild);

The function accepts a pfGeode that contains pfGeoSets of type `PFGS_TRISTRIPS` and builds a new scene graph with the same geometric content but with a spatial subdivision structure designed for efficient processing. The function returns the root of the new scene graph (a pfGroup) or, if the subdivision was not done, a copy of the original pfGeode.

The first triangle strips of all pfGeoSets in `geode` are split into strips no longer than `stripLength`. If the pfGeoSets do not contain triangle strips, they are left untouched and `geode` is subdivided based on the geometrical centers of the split pfGeoSets using an octree. The degree of recursive partitioning desired is specified in the function arguments. The resulting scene graph is a pfGroup that contains more pfGroups, recursively. The recursion stops if the resulting pfGeode is smaller than `geodeSize` (`geodeSize` is the maximum size of the leaf octants in world coordinates) or the number of its pfGeoSets is smaller than `geodeChild`.

| Note: The input pfGeode is not deleted.

See also “The libpfsubdiv Pseudo Loader” in Chapter 9.

## The Maya Database Exporter

OpenGL Performer provides the PFBexport plug-in for Maya. This Maya exporter converts a Maya scene into OpenGL Performer data structures and saves them in an OpenGL Performer binary (`.pfb`) or ASCII (`.pfa`) file. These output files can be displayed with the OpenGL Performer viewer or imported into an OpenGL Performer application. The exporter produces a log file that describes the Maya objects converted and flags any errors or unsupported features.

This section describes the following topics:

- “Installation Requirements”

- “Exporting a Scene Using the Graphical Interface”

- “ Exporting a Scene Using the Maya Embedded Language (MEL)”

- “ Translation Details”

### Installation Requirements

The Maya exporter should be installed for you automatically as part of the OpenGL Performer installation process. You must have a licensed copy of Maya 4.5 or later installed on every machine that runs the exporter because it is a Maya plug-in and can only run within the Maya environment. This differs from previous OpenGL Performer file loaders that run within the OpenGL Performer environment. The Maya exporter is available for both IRIX and Windows, but not for Linux.

The `.pfa` and `.pfb` files produced by the Maya exporter can be viewed on any machine with OpenGL Performer 3.1 or later installed. These files are not compatible with previous versions of OpenGL Performer. Maya has capabilities like subdivision surfaces and non-uniform rational B-splines (NURBS) that require the OpenGL Performer 3.1 or later run-time environment. The exporter can optimize geometry to take advantage of the new OpenGL extensions available on Onyx 4 systems. These extensions also need OpenGL Performer 3.1 or later support.

If you launch Maya and it cannot find the plug-in, you can troubleshoot by checking the MAYA_PLUG_IN_PATH and MAYA_SCRIPT_PATH environment variables. Both variables should be defined at installation to reference the OpenGL Performer directory containing the Maya extensions.

Table 7-13 shows the default path for IRIX and Microsoft Windows.

Table 7-13. Default Path for the Maya Export Plug-in

Platform | Default Path
--- | ---
IRIX | `/usr/share/OpenGL Performer/bin`
Microsoft Windows | `c:/SGI/OpenGL Performer/Bin`

### Exporting a Scene Using the Graphical Interface

Any Maya scene can be exported to OpenGL Performer format. Unsupported features will be flagged in the export log file and may result in objects missing from the scene when viewed with OpenGL Performer. To run the plug-in from the Maya graphical user interface, use the Export All or Export Selection items from the File menu. As shown in Figure 7-15, you should be able to select `PFBexport` as one of the file types. The only supported extensions are `.pfb` and `.pfa`.

Figure 7-15. Maya Export Screen

There are a number of parameters that control how Maya content is translated to OpenGL Performer format. You can produce exported files that take advantage of OpenGL extensions for multitexturing and vertex buffer objects but you must be running Maya on a platform which has these features. In general, OpenGL Performer .pfa and .pfb files are cross-platform and can be successfully imported on machines that are less-capable than where they originated with some loss of fidelity. For example, displaying a multitextured object on an Octane will drop all textures but the first.

As shown in Figure 7-16, you can optimize for earlier versions of SGI hardware by choosing Optimize for OpenGL 1.0. If you have have an Onyx 4 system, do not check this option or you will not get the best graphics performance. If your graphics hardware does not have multitexturing capabilities, do check this option.

Figure 7-16. Maya Export Options

Table 7-14 describes the export options.

Table 7-14. Maya Export Options

Category | Option | Description
--- | --- | ---
Export Options | Export geometry only | If checked, only geometry will be included in the are also exported. This can result in poor performance from using too many light sources.
| Optimize for OpenGL 1.0 | If checked, the exporter optimizes for earlier versions of SGI hardware without multitexturing capabilities. Do not check this option for an Onyx4 system.
| Visual preview | If checked, you get a visual preview.
Geometry Options | Indexed meshes | If checked, polygon mesh geometry will be exported as indexed, allowing vertices to be shared. Non-indexed meshes are faster on OpenGL 1.0.
| Triangle strips | If checked, the exporter will convert polygon meshes to triangle lists or triangle strips if possible. This option is faster on all platforms but should not be checked if you are producing subdivision surfaces (see the option Force subdivision surfaces). If not checked, the Maya polygonal structure is preserved in the OpenGL Performer geometry. (Triangle stripping is not performed on indexed meshes.)
| Force subdivision surfaces | If checked, the exporter will convert polygon meshes to subdivision surfaces in the OpenGL Performer file. This works best with low-count polygon meshes. Using complex meshes can exhaust memory or produce large models that are slow to display.
| Force polygon meshes | If checked, the exporter will convert subdivision surfaces and NURBS models to polygon meshes. The format of the output meshes is controlled by the mesh export options (see category Export geometry). If not checked, subdivision surfaces and NURBS from Maya are preserved in OpenGL Performer.
Texture Options | Export textures | If checked, texturing and UV mapping is enabled. Objects that are textured in Maya will be output as textured in the OpenGL Performer file. If you uncheck this box, the exporter ignores all Maya texturing and produces OpenGL Performer geometry with materials only.
| Make RGB texture files | If checked, all textures encountered in Maya are converted to RGB format as part of the export process. The Width and Height sliders control the size of the RGB texture images. This option should be checked if you are using procedural textures in your Maya scene or if you plan to use IRIX to display your OpenGL Performer files.

### Exporting a Scene Using the Maya Embedded Language (MEL)

If you are familiar with MEL, the Maya scripting language, you can invoke the OpenGL Performer export plug-in from within a script. This allows you to do batch translation of Maya files to OpenGL Performer. The following sample MEL script converts all of the Maya binary (`.mb`) files in a given directory to OpenGL Performer binary (`.pfb`) format:

    global proc int ExportAsPFB(string $indir, string $opts)
    {
        string $infile;
        string $outfile;
        string $files[];
        string $s;
        int $succeed = 1;

        if ($opts == "")
            $opts = "textures=1;width=256;height=256;indexed=1;tristrip=1;"
                    "gl1=1;preview=0;";
        if ($indir == "")
            $indir = "./";
        setProject $indir;
        $files=`getFileList -folder $indir -filespec "*.mb"`;

        for ($infile in $files)
        {
            $outfile = $indir + substring($infile, 1, size($infile) - 3) +
                       ".pfb";
            $infile = $indir + $infile;
            file -open -force $infile;
            $s = `file -exportAll -type "PFBexport" -options $opts -force
                 $outfile`;
            $succeed = `file -query -exists $s`;
            if (!$succeed)
                $s = "ERROR: failed to export " + $outfile + "\n";
            else
                $s = "exported " + $s + "\n";
            print $s;
        }
        return $succeed;
    }

### Translation Details

This section describes the translation of Maya scenes to OpenGL Performer using the following topics:

- “Supported Maya Features”

- “Hierarchy”

- “Geometry”

- “Shaders”

#### Supported Maya Features

Maya has many capabilities that cannot be represented in OpenGL Performer, particularly in the area of shaders. Some of these features are simply ignored while others may suffer quality loss. OpenGL Performer uses the OpenGL graphics pipeline, which only allows light sources to illuminate objects directly. Light reflected from objects does not illuminate other objects in the scene as it does with Maya. Consequently, high-quality shading effects are often lost in the conversion.

Table 7-15 lists the Maya features that are supported by the exporter (column 1) and those that are not supported (column 2).

Table 7-15. Maya Features Supported by the Exporter

Supported Maya Features | Unsupported Maya Features
--- | ---
Polygonal meshes | Layered shaders
Subdivision surfaces | Ramp shaders
NURBS | Shading maps
Multitexturing | Anisotropic materials
Lambert, Blinn and Phong materials | Volumetric materials
Layered textures | Translucence
Procedural textures | Displacement mapping
Filtering, mipmapping | Quadratic, quartic, and Gaussian filtering
Reflection mapping | 3D or cube map textures
Cameras | Animation and skinning
Ambient, point, directional, and spot light sources | Area and volume light sources
Node instancing | Ray tracing
Shadow mapping | Custom shaders and mental ray
Bump mapping | Glow, fog, and motion blur
Vertex colors | Dynamics and fluids
Per-object light list | Switches, expressions, and scripting

#### Hierarchy

The exporter attempts to preserve the structure of the Maya scene graph as much as possible in the OpenGL Performer output. Nodes that are instanced in Maya are also shared in the OpenGL Performer hierarchy.

Maya and OpenGL Performer use different internal coordinate systems. This is not a issue when importing a Maya scene into an OpenGL Performer application if you use the whole scene because the root transformation corrects for the coordinate system differences. However, if you take part of a scene from a `.pfb` file exported from Maya and use it within another OpenGL Performer scene, the Maya objects may be oriented incorrectly.

The following subsections describe translation details surrounding the scene graph hierarchy:

- Naming

- Cameras

- Light Sources

- Sprites and Billboards

Naming

Node names are preserved so that Maya objects can be found by name in an OpenGL Performer application. The name of an OpenGL Performer scene graph node is composed of the file base name and the Maya object name. This is to permit multiple Maya files to be imported without naming conflicts. For example, the Maya object pCubeShape exported to file `/usr/people/nola/myscene.pfb` would be called `myscene.pCubeShape` in the OpenGL Performer scene graph.

Cameras

Maya cameras are kept in the scene graph and any camera node may be used to view the scene. In OpenGL Performer, the camera functionality is provided by the channel, which is the root of the scene hierarchy. Maya cameras are exported as OpenGL Performer DCS (dynamic coordinate system) nodes and keep their relative position within the hierarchy so that they are accessible in OpenGL Performer applications. The root of the exported scene graph includes the appropriate viewing transformation to display the scene from the viewpoint of the current Maya viewport camera. The Maya background color associated with the camera is not preserved in the OpenGL Performer scene.

Light Sources

OpenGL Performer has equivalents for ambient, directional, point, and spot light sources because they are supported by the OpenGL pipeline. Area and volume lights are ignored by the exporter. The exporter honors Maya per-object lighting. If you specify that only certain lights should affect an object in Maya, this light list is associated with the OpenGL Performer object. Because adding a light source in a real-time system can be computationally costly, it is a good idea to use as few lights as possible when exporting to OpenGL Performer.

Sprites and Billboards

A Maya sprite is an animated particle type that maps an image sequence onto a flat rectangle. Sprites always face the camera and maintain their size when moved in the Z direction. The sprite texture can be a single image or a sequence of images (texture animation). Sprites are supported by the exporter.

Maya does not have an equivalent to the OpenGL Performer billboard that makes arbitrary geometry face the camera at run time. Billboards are exported as DCS nodes.

#### Geometry

Maya has three ways to construct and represent geometry:

- Indexed triangle meshes

- Subdivision surfaces

- NURBS

OpenGL Performer supports all three of these surface description methods directly. So, Maya geometry can be displayed without a loss of fidelity.

The following subsections further describe geometry translation:

- Polygonal Meshes

- Subdivision Surfaces

- UV Mapping

Polygonal Meshes

Polygonal meshes in Maya are indexed and share vertex, normal, and texture coordinate data whenever possible. In Maya, different faces in the mesh can use different shaders. Therefore, a single mesh can be associated with multiple appearances. In this case, one mesh in Maya can produce several OpenGL Performer meshes, one for each appearance. This is true of surfaces as well.

There are several ways to export Maya meshes to OpenGL Performer depending on how you plan to use the geometry and the platform. Static geometry that is not modified at run time can be highly optimized to display quickly. Meshes that will be dynamically modified preserve the original Maya structure to make vertex manipulation at run time easier and more efficient.

All exported meshes have locations and either normals or vertex colors depending on how they were constructed in Maya. Texture coordinate sets are only included if texture output is enabled and the mesh is textured. Per-vertex colors are not supported by the exporter and will be ignored.

Subdivision Surfaces

Both Maya and OpenGL Performer subdivision surfaces use the Catmull-Clark algorithm. Therefore, run-time tesselation should produce results similar to Maya. OpenGL Performer subdivision surfaces allow multiple materials on a single mesh and will preserve connectivity.

Although Maya NURBS shapes can use multiple shaders, the OpenGL Performer NURBS geode only supports one material. The exporter does not support the use of multiple shaders across a NURBS surface.

You can export a surface as a polygonal mesh and the exporter will use Maya to tesselate the surface.

UV Mapping

The UV mapping process transforms or generates texture coordinates for a mesh. Static UV mapping is applied to the Maya texture coordinates at export time. Environment mapping dynamically generates texture coordinates at run time based on the location of the viewer. Texture coordinate animation is not supported by the exporter.

Table 7-16 describes how the exporter supports the various UV mapping methods.

Table 7-16. Maya Exporter Support for UV Mapping Methods

UV Map Method | Exporter Support
--- | ---
place2dTexture | 2D translation, scaling and rotation of the texture coordinates done at export time.
envSphere | Spherical environment mapping. Texture coordinates are generated by OpenGL Performer at run time.
envCube | Cubic environment mapping. Texture coordinates are generated by OpenGL Performer at run time.
Place3dTexture | 3D matrix applied to texture coordinates at run time.
envSky | Ignored.
envChrome | Ignored.
envBall | Ignored.

#### Shaders

The following subsections describe how the exporter supports Maya shaders:

- Materials

- Textures

- Texture Effects

- Procedural Textures

- Layered Textures

Materials

Lambert, Blinn, and Phong materials are supported by the exporter but not all of the material properties are honored, as shown in Table 7-17.

Table 7-17. Maya Exporter Support for Material Properties

Material Property | Exporter Support
--- | ---
Color | Becomes diffuse material color.
Transparency | Becomes material transparency. You cannot specify a map here to be used as an alpha channel. The texture alpha channel must be included in the texture file.
Ambient color | Becomes ambient material color. If a texture map is used here, it is added to the overall color and light sources do not affect it.
Incandescence | Becomes emissive material color. If a texture map is used here, it is added to the overall color.
Diffuse | Is used as a multiplier for diffuse material color.
Translucence | Ignored.
Glow intensity | Ignored.
Hide source | Ignored.
Matte opacity | Ignored.
Ray trace options | Ignored.

Textures

All textures used with OpenGL Performer must come from bitmap files. Because OpenGL Performer does not support all texture formats on every platform, use the `.rgb` format for textures if you plan to use your exported files on multiple platforms.

OpenGL Performer multitexturing support is hardware-based and varies across platforms. On some older IRIX systems, multitexturing is not supported. Newer hardware can have two or four texture units. The Maya exporter supports a maximum of eight textures per object. It is possible to produce `.pfb` files that will not look the same on all platforms. If you use more than eight textures on a single mesh, the exporter will ignore the extra textures and produce an error message in the log file.

Texture Effects

Maya allows you to correctly color your textures by adding and/or multiplying the texture by a color before applying it (using the `color` `gain` and `color` `offset` attributes). You can also invert or filter the texels. These texture effects are only preserved if you convert your textures to RGB. The exporter captures the texture after these computations have been performed.

Table 7-18 describes how the exporter supports the various the Maya texture properties.

Table 7-18. Maya Exporter Support for Texture Properties

Texture Property | Exporter Support
--- | ---
Image name | Name of bitmap file containing texture data.
Color gain | Ignored unless the Make RGB option is enabled.
Color offset | Ignored unless the Make RGB option is enabled.
Invert | Ignored the unless Make RGB option is enabled.
Wrap | Becomes texture wrap mode.
Filter | Only `mipmap` and `box` filters may be used.
Hardware cycling | If animation export is enabled, a texture animation is produced. Otherwise, it is ignored.
Filter offset | Ignored.
Blend | Ignored.
Alpha gain | Ignored.
Alpha offset | Ignored.
Alpha is luminance | Ignored.
Default color | Ignored.
Color remap | Ignored.

Procedural Textures

Maya has a rich library of procedural textures that can dynamically create texel patterns without requiring bitmap files. When the exporter encounters a procedural texture, it produces a reference to a bitmap file containing a snapshot of the procedural texture from Maya. If the Make RGB option is enabled, the exporter creates a separate RGB bitmap file for every texture used in the scene. This step only needs to be done when you add new textures or change the construction options on an existing procedural texture.The name of the RGB file is constructed by using the name of the Maya texture object with a `.rgb` suffix. Consequently, if you export multiple files that use the same object names, the exporter will use the same filename for multiple textures. Consequently, the same filenames could cause problems if the textures are not the same.

Procedural textures are emulated in OpenGL Performer using 2D UV coordinates and the texture matrix. It is not always possible to get the same results as Maya, particularly with 3D textures. The exporter uses the first UV set on the mesh to map the snapshot of the procedural texture. By manipulating these UVs, you can often improve the real-time appearance of procedural textures.

Layered Textures

Layered textures in Maya allow the artist to blend several different textures together to produce an output color. The exporter supports layered textures but OpenGL Performer cannot implement all of the blend modes. Only the `None`, `Over`, `In`, `Ad`d and `Multiply` blend modes are honored. All other modes default to `Multiply`.

Prev | Table of Contents | Next
Chapter 6. Creating Visual Effects |  | Chapter 8. Geometry