Chapter 12. Graphics State

The graphics state is a class of fields that defines everything about the shape and texture of an object in an OpenGL Performer scene. Fields include such things as transparency, shading, reflectance, and texture. The graphics state is set globally for all objects in the scene graph. Individual objects, however, can override graphics state settings. The cost, however, is efficiency. For performance reasons, therefore, it is important to set the fields in the graphics state to satisfy the greatest number of objects in the scene.

This chapter describes in detail all of the fields in the graphics state.

Immediate Mode

The graphics libraries are immediate-mode state machines; if you set a mode, all subsequent geometry is drawn in that mode. For the best performance, mode changes need to be minimized and managed carefully. libpr manages a subset of graphics library state and identifies bits of state as graphics state elements. Each state element is identified with a PFSTATE token; for example., PFSTATE_TRANSPARENCY corresponds to the transparency state element. State elements are loosely partitioned into three categories: modes, values, and attributes.

Modes are the graphics state variables, such as transparency and texture enable, that have simple values like ON and OFF. An example of a mode command is pfTransparency(mode).

Values are not modal, rather they are real numbers which signify a threshold or quantity. An example of a value is the reference alpha value specified with the  pfAlphaFunc() function.

Attributes are references to encapsulations (structures) of graphics state. They logically group the more complicated elements of state, such as textures and lighting models. Attributes are structures that are modified through a procedural interface and must be applied to have an effect. For example, pfApplyTex(tex) applies the texture map, tex, to subsequently drawn geometry.

In libpr, there are three methods of setting a state:

  • Immediate mode

  • Display list mode

  • pfGeoState mode

Like the graphics libraries, libpr supports the notion of both immediate and display-list modes. In immediate mode, graphics mode changes are sent directly to the Geometry Pipeline; that is, they have an immediate effect. In display-list mode, graphics mode changes are captured by the currently active pfDispList, which can be drawn later. libpr display lists differ from graphics library objects because they capture only libpr commands and are reusable. libpr display lists are useful for multiprocessing applications in which one process builds up the list of visible geometry and another process draws it. “Display Lists” describes libpr display lists.

A pfGeoState is a structure that encapsulates all the graphics modes and attributes that libpr manages. You can individually set the state elements of a pfGeoState to define a graphics context. The act of applying a pfGeoState with pfApplyGState() configures the state of the Geometry Pipeline according to the modes, values, and attributes set in the pfGeoState. For example, the following code fragment shows equivalent ways (except for some inheritance properties of pfGeoStates described later) of setting up some lighting parameters suitable for a glass surface:

/* Immediate mode state specification */
pfMaterial *shinyMtl;
pfTransparency(PFTR_ON);
pfApplyMtl(shinyMtl);
pfEnable(PFEN_LIGHTING);
 
/* is equivalent to: */
 
/* GeoState state specification */
pfGeoState	 *gstate;
pfGStateMode(gstate, PFSTATE_TRANSPARENCY, PFTR_ON);
pfGStateAttr(gstate, PFSTATE_FRONTMTL, shinyMtl);
pfGStateMode(gstate, PFSTATE_ENLIGHTING, PF_ON);
pfApplyGState(gstate);

In addition, pfGeoStates have unique state inheritance capabilities that make them very convenient and efficient; they provide independence from ordered drawing. pfGeoStates are described in the section “pfGeoState” of this chapter.

The libpr routines have been designed to produce an efficient structure for managing graphics state. You can also set a graphics state directly through the GL. However, libpr will have no record of these settings and will not be able to optimize them and may make incorrect assumptions about current graphics state if the resulting state does not match the libpr record when libpr routines are called. Therefore, it is best to use the libpr routines whenever possible to change a graphics state and to restore the libpr state if you go directly through the GL.

The following sections will describe the rendering geometry and state elements in detail. There are three types of state elements: modes, values, and attributes. Modes are simple settings that take a set of integer values that include values for enabling and disabling the mode. Modes may also have associated values that allow a setting from a defined range. Attributes are complex state structures that encapsulate a related collection of modes and values. Attribute structures will not include in their definition an enable or disable as the enabling or disabling of a mode is orthogonal to the particular related attribute in use.

Rendering Modes

The libpr library manages a subset of the rendering modes found in OpenGL. In addition, libpr abstracts certain concepts like transparency, providing a higher-level interface that hides the underlying implementation mechanism.

The libpr library provides tokens that identify the modes that it manages. These tokens are used by pfGeoStates and other state-related functions like pfOverride(). The following table enumerates the PFSTATE_* tokens of supported modes, each with a brief description and default value.

Table 12-1 lists and describes the mode tokens.

Table 12-1. pfGeoState Mode Tokens

Token Name

Description

Default Value

PFSTATE_TRANSPARENCY

Transparency modes

PFTR_OFF

PFSTATE_ALPHAFUNC

Alpha function

PFAF_ALWAYS

PFSTATE_ANTIALIAS

Antialiasing mode

PFAA_OFF

PFSTATE_CULLFACE

Face culling mode

PFCF_OFF

PFSTATE_DECAL

Decaling mode for coplanar geometry

PFDECAL_OFF

PFSTATE_SHADEMODEL

Shading model

PFSM_GOURAUD

PFSTATE_ENLIGHTING

Lighting enable flag

PF_OFF

PFSTATE_ENTEXTURE

Texturing enable flag

PF_OFF

PFSTATE_ENFOG

Fogging enable flag

PF_OFF

PFSTATE_ENWIREFRAME

pfGeoSet wireframe mode enable flag

PF_OFF

PFSTATE_ENCOLORTABLE

pfGeoSet colortable enable flag

PF_OFF

PFSTATE_ENHIGHLIGHTING

pfGeoSet highlighting enable flag

PF_OFF

PFSTATE_ENLPOINTSTATE

pfGeoSet light point state enable flag

PF_OFF

PFSTATE_ENTEXGEN

Texture coordinate generation enable flag

PF_OFF

PFSTATE_ENFRAGPROG

Fragment program enable flag

PF_OFF

PFSTATE_ENVTXPROG

Vertex program enable flag

PF_OFF

PFSTATE_ENSHADPROG

Shader program enable flag

PF_OFF

The mode control functions described in the following sections should be used in place of their graphics library counterparts so that OpenGL Performer can correctly track the graphics state. Use pfGStateMode() with the appropriate PFSTATE token to set the mode of a pfGeoState.

Transparency

You can control transparency using pfTransparency(). Possible transparency modes are listed in the following table.

Table 12-2. pfTransparency Tokens

Transparency mode

Description

PFTR_OFF

Transparency disabled.

PFTR_ON
PFTR_FAST

Use the fastest, but not necessarily the best, transparency provided by the hardware.

PFTR_HIGH_QUALITY

Use the best, but not necessarily the fastest, transparency provided by the hardware.

PFTR_MS_ALPHA

Use screen-door transparency when multisampling. Fast but limited number of transparency levels.

PFTR_BLEND_ALPHA

Use alpha-based blend with background color. Slower but high number of transparency levels.

In addition, the flag PFTR_NO_OCCLUDE may be logically ORed into the transparency mode in which case geometry will not write depth values into the frame buffer. This will prevent it from occluding subsequently rendered geometry. Enabling this flag improves the appearance of unordered, blended transparent surfaces.

There are two basic transparency mechanisms: screen-door transparency, which requires hardware multisampling, and blending. Blending offers very high-quality transparency but for proper results requires that transparent surfaces be rendered in back-to-front order after all opaque geometry has been drawn. When using transparent texture maps to “etch” geometry or if the surface has constant transparency, screen-door transparency is usually good enough. Blended transparency is usually required to avoid “banding” on surfaces with low transparency gradients like clouds and smoke.

Shading Model

You can select either flat shading or Gouraud (smooth) shading. pfShadeModel() takes one of two tokens: PFSM_FLAT or PFSM_GOURAUD. One some graphics hardware flat shading can offer a significant performance advantage.

Alpha Function

The pfAlphaFunc() function is an extension of the glAlphaFunc() function; it allows OpenGL Performer to keep track of the hardware mode. The alpha function is a pixel test that compares the incoming alpha to a reference value and uses the result to determine whether or not the pixel is rendered. The reference value must be specified in the range [0, 1]. For example, a pixel whose alpha value is 0 is not rendered if the alpha function is PFAF_GREATER and the alpha reference value is also 0. Note that rejecting pixels-based alpha can be faster than using transparency alone. A common technique for improving the performance of filling polygons is to set an alpha function that will reject pixels of low (possibly nonzero) contribution. The alpha function is typically used for see-through textures like trees.

Decals

On Z-buffer-based graphics hardware, coplanar geometry can cause unwanted artifacts due to the finite numerical precision of the hardware which cannot accurately resolve which surface has visual priority. This can result in flimmering, a visual “tearing” or “twinkling” of the surfaces. pfDecal() is used to accurately draw coplanar geometry on SGI graphics platforms and it supports two basic implementation methods : stencil decaling and displace decaling.

The stencil decaling method uses a hardware resource known as a stencil buffer and requires that a single stencil plane (see the man page for glStencilOp()) be available for OpenGL Performer. This method offers the highest image quality but requires that geometry be coplanar and rendered in a specific order which reduces opportunities for the performance advantage of sorting by graphics mode.

A potentially faster method is the displace decaling method. In this case, each layer is displaced towards the eye so it hovers slightly above the preceding layer. Displaced decals need not be coplanar, and can be drawn in any orde, but the displacement may cause geometry to incorrectly poke through other geometry.

The specificaton of a decal plane can improve the displace decaling method. The object geometry will be projected onto the specified plane and if the same plane is specified for base and layer geometry, the base and layer polygons will be generated with identical depth values. If the objects are drawn in priority order, no further operation is necessary. Otherwise, displace can be applied to the planed geometry for a superior result. Decal planes can be specified on pfGeoSets with pfGSetDecalPlane(), on a pfGeoState with the PFSTATE_DECALPLANE attribute to pfGStateAttr(), or globally with pfApplyDecalPlane().

Decals consist of base geometry and layer geometry. The base defines the depth values of the decal while layer geometry is simply inlaid on top of the base. Multiple layers are supported but limited to eight when using displaced decals. Realize that these layers imply superposition; there is no limit to the number of polygons in a layer, only to the number of distinct layers.

The decal mode indicates whether the subsequent geometry is base or layer and the decal method to use. For example, a mode of PFDECAL_BASE_STENCIL means that subsequent geometry is to be considered as base geometry and drawn using the stencil method. All combinations of base/layer and displace/stencil modes are supported but you should make sure to use the same method for a given base-layer pair.

Example 12-1 illustrates the use of pfDecal().

Example 12-1. Using pfDecal() to a Draw Road with Stripes

pfDecal(PFDECAL_BASE_STENCIL);
 
/* ... draw underlying geometry (roadway) here ...*/
 
pfDecal(PFDECAL_LAYER_STENCIL);
 
/* ... draw coplanar layer geometry (stripes) here ... */

pfDecal(PFDECAL_OFF);


Note: libpf applications can use the pfLayer node to include decals within a scene graph.



Frontface / Backface

The  pfCullFace() function controls which side of a polygon (if any) is discarded in the Geometry Pipeline. Polygons are either front-facing or back-facing. A front-facing polygon is described by a counterclockwise order of vertices in screen coordinates, and a back-facing one has a clockwise order. pfCullFace() has four possible arguments:

PFCF_OFF 

Disable face-orientation culling.

PFCF_BACK 

Cull back-facing polygons.

PFCF_FRONT 

Cull front-facing polygons.

PFCF_BOTH 

Cull both front- and back-facing polygons.

In particular, back-face culling is highly recommended since it offers a significant performance advantage for databases where polygons are never be seen from both sides (databases of “solid” objects or with constrained eyepoints).

Antialiasing

The pfAntialias() function is used to turn the antialiasing mode of the hardware on or off. Currently, antialiasing is implemented differently by each different graphics system. Antialiasing can produce artifacts as a result of the way OpenGL Performer and the active hardware platform implement the feature. See the man page for pfAntialias() for implementation details.

Rendering Values

Some modes may also have associated values. These values are set through pfGStateVal(). Table 12-3 lists and describes the value tokens.

Table 12-3. pfGeoState Value Tokens

Token Name

Description

Range

Default Value

PFSTATE_ALPHAREF

Set the alpha function reference value.

0.0 - 1.0

0.0


Enable / Disable

The  pfEnable() and pfDisable() functions control certain rendering modes. Certain modes do not have effect when enabled but require that other attribute(s) be applied. Table 12-4 lists and describes the tokens and also lists the attributes required for the mode to become truly active.

Table 12-4. Enable and Disable Tokens

Token

Action

Attribute(s) Required

PFEN_LIGHTING

Enable or disable lighting.

pfMaterial
pfLight
pfLightModel

PFEN_TEXTURE

Enable or disable texture.

pfTexEnv
pfTexture

PFEN_FOG

Enable or disable fog.

pfFog

PFEN_WIREFRAME

Enable or disable pfGeoSet wireframe rendering.

none

PFEN_COLORTABLE

Enable or disable pfGeoSet colortable mode.

pfColortable

PFEN_HIGHLIGHTING

Enable or disable pfGeoSet highlighting.

pfHighlight

PFEN_TEXGEN

Enable or disable automatic texture coordinate generation.

pfTexGen

PFEN_LPOINTSTATE

Enable or disable pfGeoSet light points.

pfLPointState

PFEN_FRAGPROG

Enable or disable fragment program.

pfFragmentProgram

PFEN_VTXPROG

Enable or disable vertex program.

pfVertexProgram

PFEN_SHADPROG

Enable or disable shader programs.

pfShaderProgram

By default all modes are disabled.

Rendering Attributes

Rendering attributes are state structures that are manipulated through a procedural interface. Examples include pfTexture, pfMaterial, and pfFog. libpr provides tokens that enumerate the graphics attributes it manages. These tokens are used by pfGeoStates and other state-related functions like pfOverride(). Table 12-5 lists and describes the tokens.

Table 12-5. Rendering Attribute Tokens

Attribute Token

Description

Apply Routine

PFSTATE_LIGHTMODEL

Lighting model

pfApplyLModel()

PFSTATE_LIGHTS

Light source definitions

pfLightOn()

PFSTATE_FRONTMTL

Front-face material

pfApplyMtl()

PFSTATE_BACKMTL

Back-face material

pfApplyMtl()

PFSTATE_TEXTURE

Texture

pfApplyTex()

PFSTATE_TEXENV

Texture environment

pfApplyTEnv()

PFSTATE_FOG

Fog model

pfApplyFog()

PFSTATE_COLORTABLE

Color table for pfGeoSets

pfApplyCtab()

PFSTATE_HIGHLIGHT

pfGeoSet highlighting style

pfApplyHlight()

PFSTATE_LPOINTSTATE

pfGeoSet light point definition

pfApplyLPState()

PFSTATE_TEXGEN

Texture coordinate generation

pfApplyTGen()

PFSTATE_FRAGPROG

Fragment program definition

pfGProgramApply()

PFSTATE_VTXPROG

Vertex program definition

pfGProgramApply()

PFSTATE_GPROGPARMS

GPU program parameters definition

pfGPParamsApply()

PFSTATE_SHADPROG

Shader program definition

pfShaderProgramApply()

Rendering attributes control which attributes are applied to geometric primitives when they are processed by the hardware. All OpenGL Performer attributes consist of a control structure, definition routines, and an apply function, pfApply* (except for lights which are “turned on”).

Each attribute has an associated pfNew*() routine that allocates storage for the control structure. When sharing attributes across processors in a multiprocessor application, you should pass the pfNew*() routine a shared memory arena from which to allocate the structure. If you pass NULL as the arena, the attribute is allocated from the heap and is not sharable in a nonshared address space (fork()) multiprocessing application.

All attributes can be applied directly, referenced by a pfGeoState or captured by a display list. When changing an attribute, that change is not visible until the attribute is reapplied. Detailed coverage of attribute implementation is available in the man pages.

Texture

OpenGL Performer supports texturing through pfTextures and pfTexEnvs, which provide encapsulated suppport for graphics library textures (see glTexImage2D() ) and texture environments (see glTexEnv()). A pfTexture defines a texture image, format, and filtering. A pfTexEnv specifies how the texture should interact with the colors of the geometry where it is applied. You need both to display textured data, but you do not need to specify them both at the same time. For example, you could have pfGeoStates each of which had a different texture specified as an attribute and still use an overall texture environment specified with pfApplyTEnv().

A pfTexture is created by calling pfNewTex(). If the desired texture image exists as a disk file in IRIS RGB image format (the file often has a “.rgb” suffix ) or in the OpenGL Performer fast-loading image format (a “.pfi” suffix), you can call pfLoadTexFile() to load the image into CPU memory and completely configure the pfTexture, as shown in the following:

pfTexture *tex = pfLoadTexFile(“brick.rgba”);

Otherwise, pfTexImage() lets you directly provide a GL-ready image array in the same external format as specified on the pfTexture and as expected by glTexImage2D(), as shown in the following:

void pfTexImage(pfTexture* tex, uint* image, 
int comp, int sx, int sy, int sz);

OpenGL expects packed texture data with each row beginning on a long word boundary. However, OpenGL expects the individual components of a texel to be packed in opposite order. For example, OpenGL expects the texels to be packed as RGBA. If you provide your own image array in a multiprocessing environment, it should be allocated from shared memory (along with your pfTexture) to allow different processes to access it. A basic example demonstrating loading a image file and placing the resulting pfTexture on scene graph geometry is at /usr/share/Performer/src/pguide/libpf/C/texture.c on IRIX and Linux and %PFROOT%\Src\pguide\libpf\C\texture.c on Microsoft Windows.


Note: The size of your texture must be an integral power of two on each side. OpenGL refuses to accept badly sized textures. You can rescale your texture images with the izoom or imgworks programs (shipped with IRIX 5.3 in the eoe2.sw.imagetools and imgtools.sw.tools subsystems; and with IRIX 6.2 in the eoe.sw.imagetools and imgworks.sw.tools subsystems).

Your texture source does not have to be a static image. pfTexLoadMode() can be used to set one of the sources listed in Table 12-6 with  PFTEX_LOAD_SOURCE. Note that sources other than CPU memory may not be supported on all graphics platforms, or may have some special restrictions. There are several sample programs that demonstrate paging sequences of texture from different texture sources. For paging from host memory there are the following:

  • On IRIX and Linux:

    • /usr/share/Performer/src/pguide/libpr/C/texlist.c 

    • /usr/share/Performer/src/pguide/libpr/C/mipmap.c 

    • /usr/share/Performer/src/pguide/libpfutil/movietex.c 

  • On Microsoft Windows:

    • %PFROOT%\Src\pguide\libpr\C\texlist.c

    • %PFROOT%\Src\pguide\libpr\C\mipmap.c

    • %PFROOT%\Src\pguide\libpfutil\movietex.c

These examples demonstrate the use of different texture sources for paging textures, and libpufitl utilties for managing texture resources. One thing these examples do is use pfTexLoadImage() to update the pointer to the image data to avoid the expensive reformating the texture. This requires that the provided image data be the same size as the original image data, as well as same number of components and same formats.

Table 12-6. Texture Image Sources

PFTEX_SOURCE_ Token

Source of the Texture Image

IMAGE

CPU memory location specified by pfTexLoadImage() or pfTexImage()

FRAMEBUFFER

Framebuffer location offset from window origin as specified by pfTexLoadOrigin()

VIDEO

Default video source on the system


Video Texturing

The source of texture image data can be live video input. OpenGL Performer supports the video input mechanisms of Sirius Video on RealityEngine and InfiniteReality, DIVO on InfiniteReality, and Silicon Graphics O2 and Octane video input. OpenGL Performer includes a sample program that features video texturing:

/usr/share/Performer/src/pguide/libpf/movietex.c (IRIX and Linux) %PFROOT%\Src\pguide\libpf\movietex.c (Microsoft Windows)

This example demonstrates that all video initialization, including the creation of video library resources, is done in the draw process, as required by the video library. Part of that initialization includes setting the proper number of components on the pfTexture and choosing a texture filter and potentially internal format. Those basic operations are discussed further in this section.

OpenGL Performer will automatically download the frame of video when the texture object is applied through the referencing pfGeoState. Alternatively, you may want to schedule this download to happen at the beginning or end of the rendering frame; you can force it with pfLoadTex().

Textures must be created with sizes that are powers of 2; the input video frame is usually not in powers of 2. The [0,1] texture coordinate range can be scaled into the valid part of the pfTexture with a texture matrix. This matrix can be applied directly to the global state with pfApplyTMat() to affect all pfGeoSets, or can be set on a pfGeoState with the PFSTATE_TEXMAT attribute to pfGStateAttr().

Texture Management

Texture storage is limited only by virtual memory, but for real-time applications you must consider the amount of texture storage the graphics hardware supports. Textures that do not fit in the graphics subsystem are paged as needed when pfApplyTex() is called. The libpr library provides routines for managing hardware texture memory so that a real-time application does not have to get a surprise texture load. pfIsTexLoaded(), called from the drawing process, tells you if the pfTexture is currently properly loaded in texture memory. The initially required textures of an application, or all of the textures if they fit, can be preloaded into texture memory as part of application initialization. pfuMakeSceneTexList() makes a list of all textures referenced by a scene graph and pfuDownloadTexList() loads a list of textures into hardware texture memory (and must be called in the draw process). The Perfly sample program does this as part of its initialization and displays the textures as it preloads them.

There are additional routines to assist with the progressive loading and unloading of pfTextures. pfIdleTex() can be used to free the hardware texture memory owned by a pfTexture. GL host and hardware texture memory resources can be freed with pfDeleteGLHandle() from the drawing process. OpenGL Performer will automatically re-allocate those resources if the pfTexture is used again. For an example of management of texture resources, see the example program /usr/share/Performer/src/pguide/libpfutil/texmem.c for IRIX and Linux or %PFROOT%\Src\pguide\libpfutil\texmem.c for Microsoft Windows. The program uses the pfuTextureManager from libpfutil for basic texture paging support.

The pfLoadTex() function, called from the drawing process, can be used to explicitly load a texture into graphics hardware texture memory (which includes doing any necessary formatting of the texture image). By default, pfLoadTex() loads the entire texture image, including any required minification or magnification levels, into texture memory. pfSubloadTex() and pfSubloadTexLevel() can also be used in the drawing process to do an immediate load of texture memory managed by the given pfTexture and these routines allow you to specify all loading parameters (source, origin, size, etc.). This is useful for loading different images for the same pfTexture in different graphics pipelines. pfSubloadTex() allows you to load a subsection of the texture tile by tile.

A special pfTexFormat() formatting mode, PFTEX_SUBLOAD_FORMAT, allows part or all of the image in texture memory owned by the pfTexture to be replaced using pfApplyTex(), pfLoadTex(), or pfSubloadTex(), without having to go through the expensive reformatting phase. This allows you to quickly update the image of a pfTexture in texture memory. The PFTEX_SUBLOAD_FORMAT used with an appropriate pfTexLoadSize() and pfTexLoadOrigin() allows you to control what part of the texture will be loaded by subsequent calls to pfLoadTex() or pfApplyTex(). There are also different loading modes that cause pfApplyTex() to automatically reload or subload a texture from a specified source. If you want the image of a pfTexture to be updated upon every call to pfApplyTex(), you can set the loading mode of the pfTexture with pfTexLoadMode() to be  PFTEX_BASE_AUTO_REPLACE. pfTexLoadImage() allows you to continuously update the memory location of an IMAGE source texture without triggering any reformatting of the texture.

There are texture formatting modes that can improve texture performance and these are the modes that are used by default by OpenGL Performer. Of most importance is the 16-bit texel internal formats. These formats cause the resulting texels to have 16 bits of resolution instead of the standard 32. These formats can have dramatically faster texture-fill performance and cause the texture to take up half the hardware texture memory. Therefore, they are strongly recommended and are used by default. There are different formats for each possible number of components to give a choice of how the compression is to be done. These formats are described in the pfTexFormat(3pf) man page.

There may also be formatting modes for internal or external image formats for which OpenGL Performer does not have a token. However, the GL value can be specified. Specifying GL values will make your application GL-specific and may also cause future porting problems; so, it should only be done if absolutely necessary.

The pfTexture class also allows you to define a set of textures that are mutually exclusive; they should always be applied to the same set of geometry; and, thus, they can share the same location in hardware texture memory. With pfTexList(tex, list) you can specify a list of textures to be in a texture set managed by the base texture, tex. The base texture is what gets applied with pfApplyTex(), or assigned to geometry through pfGeoStates. With pfTexFrame(), you can select a given texture from the list (–1 selects the base texture and is the default). This allows you to define a texture movie where each image is the frame of the movie. You can have an image on the base texture to display when the movie is not playing. There are additional loading modes for pfTexLoadMode() described in Table 12-7 to control how the textures in the texture list share memory with the base texture.

Table 12-7. Texture Load Modes

PFTEX_LOAD_ modeToken

Load Mode Values

Description

SOURCE

SOURCE_IMAGE, SOURCE_FRAMEBUFFER PFTEX_SOURCE_VIDEO PFTEX_SOURCE_DMBUF PFTEX_SOURCE_DMVIDEO

Source of image data is host memory image, framebuffer, default video source, digital media buffer, or a video library digital media buffer.

BASE

BASE_APPLY
BASE_AUTO_SUBLOAD

Loading of image for pfTexture is done as required for pfApply, or automatically subloaded upon every pfApply().

LIST

LIST_APPLY
LIST_AUTO_IDLE
LIST_AUTO_SUBLOAD

Loading of list texture image is done as separate apply, causes freeing of previous list texture in hardware texture memory, or is subloaded into memory managed by the base texture.

VIDEO_
INTERLACED

OFF, INTERLACED_ODD, INTERLACED_EVEN,

Video input is interlaced or not and if so, which field (even or odd) is spatially higher.

Texture list textures can share the exact graphics texture memory as the base texture but this has the restriction that the textures must all be the exact same size and format as the base texture. Texture list textures can also indicate that they are mutually exclusive, which will cause the texture memory of previous textures to be freed before applying the new texture. This method has no restrictions on the texture list, but is less efficient than the previous method. Finally, texture list textures can be treated as completely independent textures that should all be kept resident in memory for rapid access upon their application.

The pfTexFilter() function sets a desired filter to a specified filtering method on a pfTexture. The minification and magnification texture filters are described with bitmask tokens. If filters are partially specified, OpenGL Performer fills the rest with machine-dependent fast defaults. The PFTEX_FAST token can be included in the bitmask to allow OpenGL Performer to make machine dependent substitutions where there are large performance differences.

There are a variety of texture filter functions that can improve the look of textures when they are minified and magnified. By default, textures use MIPmapping when minified (though this costs an extra 1/3 in storage space to store the minification levels). Each level of minification or magnification of a texture is twice the size of the previous level. Minification levels are indicated with positive numbers and magnification levels are indicated with nonpositive numbers. The default magnification filter for textures is bilinear interpolation. The use of detail textures and sharpening filters can improve the look of magnified textures. Detailing actually uses an extra detail texture that you provide that is based on a specified level of magnification from the corresponding base texture. The detail texture can be specified with the pfTexDetail() function. By default, MIPmap levels are generated for the texture automatically. OpenGL operation allows for the specification of custom MIPmap levels. Both MIPmap levels and detail levels can be specified with pfTexLevel(). The level number should be a positive number for a minification level and a nonpositive number for a magnification (detail) level. If you are providing your own minification levels, you must provide all log2(MAX(texSizeX, texSizeY)) minification levels. There is only one detail texture for a pfTexture.

Standard MIPmap filtering can induce blurring on a texture if the texture is applied to a polygon which is angled away from the viewer. To reduce this blurring, an anisotropic filter can be used to improve visual quality. pfTexAnisotropy() sets the degree of anisotropy to be used by the specified pfTexture. The default degree of anisotropy is 1, which is the same as the standard isotropic filter. A value of 2 will apply a 2:1 anisotropic filter. The maximum degree of anisotropy can be queried with pfQuerySys(). Anisotropic filtering is supported on OpenGL implementations that support the GL_EXT_texture_filter_anisotropic extension. pfQueryFeature() can be used to determine if anisotropic filtering is supported on the current platform. If the environment variable PF_MAX_ANISOTROPY is set, then an anisotropic filter of the value specified by PF_MAX_ANISOTROPY will be applied to pfTextures that do not set the degree of anisotropy.

The magnification filters use spline functions to control their rate of application as a function of magnification and specified level of magnification for detail textures. These splines can be specified with pfTexSpline(). The specification of the spline is a set of control points that are pairs of nondecreasing magnification levels (specified with nonpositive numbers) and corresponding scaling factors. Magnification filters can be applied to all components of a texture, only the RGB components of a texture, or to just the alpha components. OpenGL does not allow different magnification filters (between detail and sharpen) for RGB and alpha channels.


Note: The specification of detail textures may have GL dependencies and magnifications filters may not be available on all hardware configurations. The pfTexture man page describes these details.


Texture Formats

The format in which an image is stored in texture memory is defined with pfTexFormat():

void pfTexFormat(pfTexture *tex, int format, int type)

The format variable specifies which format to set. Valid formats and their basic types include the following:

  • PFTEX_INTERNAL_FORMAT— Specifies how many bits per component are to be used in internal hardware texture memory storage. The default is 16 bits per full texel and is based on the number of components and external format. See the pfTexture man page for the list of supported formats. Floating point formats are supported only on selected platforms (for example, Onyx4 and Prism systems).

  • PFTEX_IMAGE_FORMAT—Describes the type of image data and must match the number of components, such as PFTEX_LUMINANCE, PFTEX_LUMINANCE_ALPHA, PFTEX_RGB, and PFTEX_RGBA. The default is the token in this list that matches the number of components. Other OpenGL selections can be specified with the GL token.

  • PFTEX_EXTERNAL_FORMAT—Specifies the format of the data in the pfTexImage array. The default is packed 8 bits per component. There are special, fast-loading hardware-ready formats, such as PFTEX_UNSIGNED_SHORT_5_5_5_1.

  • PFTEX_SUBLOAD_FORMAT—Specifies if the texture will be a subloadable paging texture. The default is FALSE.

  • PFTEX_CUBE_MAP—Specifies that the texture is a cube map texture that contains six images. The default is FALSE. Cube maps are supported only on selected platforms (for example, Onyx4 or Prism systems).

In the case of cube maps, where there are six images, the images are specified using the function pfTexMultiImage(). The parameter imageIndex with value 05 specifies the cube face in the following order:

min_x, max_x, min_y, max_y, min_z, max_z

For the order of faces and how the vector from the cube center to each texel is computed, see the sample program in following file:

/usr/share/Performer/src/pguide/libpf/C++/cubeMap.C
(IRIX and Linux)
%PFROOT%\Src\pguide\libpf\C++\cubeMap.C
(Microsoft Windows)

All six images have to be specified, they must have the same size, and the value ns has to be equal to nt.

The following are other variants of functions that are used by the cube maps:

  • pfTexMultiName()

  • pfGetTexMultiName()

  • pfLoadMultiTexFile()

  • pfSaveMultiTexFile()

  • pfSubloadMultiTex()

  • pfSubloadTexMultiLevel()

Other than having six images, the cube maps are used as any other pfTexture. The exception is that subloads from other sources than user specified memory are not supported.

In general, you will just need to specify the number of components in pfTexImage(). You
may want to specify a fast-loading hardware-ready external format, such as PFTEX_UNSIGNED_SHORT_5_5_5_1, in which case OpenGL Performer automatically
chooses a matching internal format. See the pfTexFormat(3pf) man page for more informaton on texture configuration details.

Controlling Texture LOD with pfTexLOD

You can control the levels of detail (LODs) of a texture that are accessed and used with pfTexLOD to force higher or lower MIPmap levels to be used when minifying. You can use this to give the graphics hardware a hint about what levels can be accessed (Impact hardware takes great advantage of such a hint) and you can use this to have multiple textures sharing a single MIPmap pyramid in texture memory. For example, a distant object and a close one may use different LODs of the same pfTexture texture. The pfGeoStates of those pfGeoSets would have different pfTexLOD objects that referenced the proper texture LODs. pfTexLevel() would be used to specify and update the proper image for each LOD in the pfTexture. You can use LODs to specify to yourself and the GL which LODs of texture should be loaded from disk into main memory. For example, if the viewer is in one LOD, most of the tex ture in that LOD can often be viewed and, consequently, should be paged into texture memory. You can set LOD parameters on a pfTexture directly or use pfTexLOD.

To use a pfTexLOD object, you do the following:

  1. Set the ranges of the LOD using pfTLODRange() and their corresponding minimum and maximum resolution MIPmap. Because the minimum and maximum limits can be floating-point values, new levels can be smoothly blended in when they become available to avoid popping from one LOD to another.

  2. Optionally, set the bias levels using pfTLODBias() to force blurring of a texture to simulate motion blur and depth of field, to force a texture to be sharper, or to compensate for asymmetric minification of a MIPmapped texture.


    Note: Any LOD settings on pfTexture take priority over current pfTexLOD settings.


  3. Enable LOD control over texture by using the following methods:

    pfEnable(PFEN_TEXLOD);
    pfGeoState::pfGStateMode(myTxLOD, PFSTATE_ENTEXLOD, ON);
    

    where myTxLOD is an instance of pfTexLOD, and ON is a nonzero integer.

  4. Apply the LOD settings to the texture using pfApplyTLOD().

See the following sample program for an example of using a pfTexLOD:

/usr/share/Performer/src/pguide/libpr/C/texlod.c (IRIX and Linux) %PFROOT%\Src\pguide\libpr\C\texlod.con (Microsoft Windows)

Setting the Texture Environment with pfTexEnv

The environment specifies how the colors of the geometry, potentially lit, and the texture image interact. This is described with a pfTexEnv object. The mode of interaction is set with pfTEnvMode() and valid modes include the following:

  • PFTE_MODULATE—The gray scale of the geometry is mixed with the color of the texture (the default).

    This option multiplies the shaded color of the geometry by the texture color. If the texture has an alpha component, the alpha value modulates the geometry's transparency; for example, if a black and white texture, such as text, is applied to a green polygon, the polygon remains green and the writing appears as dark green lettering.

  • PFTE_DECAL—The texture alpha component acts as a selector between 1.0 for the texture color and 0.0 for the base color to decal an image onto geometry.

  • PFTE_BLEND—The alpha acts as a selector between 0.0 for the base color and 1.0 for the texture color modulated by a constant texture blend color specified with pfTEnvBlendColor(). The alpha/intensity components are multiplied.

  • PFTE_ADD—The RGB components of the base color are added to the product of the texture color modulated by the current texture environment blend color. The alpha/intensity components are multiplied.

Automatic Texture Coordinate Generation

Automatic texture coordinate generation is provided with the pfTexGen state attribute. pfTexGen closely corresponds to OpenGL's glTexGen() function. When texture coordinate generation is enabled, a pfTexGen applied with pfApplyTGen() automatically generates texture coordinates for all rendered geometry. Texture coordinates are generated from geometry vertices according to the texture generation mode set with pfTGenMode(). Available modes and their function are listed in Table 12-8.

Table 12-8. Texture Generation Modes

Mode Token

Description

PFTG_OFF

Disables texture coordinate generation.

PFTG_OBJECT_LINEAR

Generates the texture coordinate as the distance from plane in object space.

PFTG_EYE_LINEAR

Generates the texture coordinate as the distance from plane in eye space. The plane is transformed by the inverse of the ModelView matrix when tgen, the pfTexGen, is applied.

PFTG_EYE_LINEAR_IDENT

Generates the texture coordinate as the distance from plane in eye space. The plane is not transformed by the inverse of the ModelView matrix.

PFTG_SPHERE_MAP

Generates the texture coordinate based on the view vector reflected about the vertex normal in eye space.

PFTG_OBJECT_DISTANCE_TO_LINE

Sets the texture coordinate as the distance in object space from the vertex to a line specified with a point and direction vector through pfTGenPoint.

PFTG_EYE_DISTANCE_TO_LINE

Sets the texture coordinate as the distance in eye space from the eye to a line specified with pfTGenPoint through the vertex.

PFTG_REFLECTION_MAP

Sets the texture coordinate to the view vector reflected about the vertex normal in eye space.

PFTG_NORMAL_MAP

Sets the texture coordinate to the vertex normal in eye space.

Some modes refer to a plane which is set with pfTGenPlane() and to a line that is specified as a point and direction with pfTGenPoint(). The default texture generation mode for all texture coordinates is PFTG_OFF. The function pfGetTGenMode() returns the mode of the pfTexGen.

See the man page for the OpenGL function glTexGen() for the specific mathematics of the generation modes for texture coordinates.

Lighting

OpenGL Performer lighting is an extension of graphics library lighting (see glLight() and related functions in OpenGL). The light embodies the color, position, and type (for example, infinite or spot) of the light. The light model specifies the environment for infinite (the default) or local viewing, and two-sided illumination.

The lighting model describes the type of lighting operations to be considered, including local lighting, two-sided lighting, and light attenuation. The fastest light model is infinite, single-sided lighting. A pfLightModel state attribute object is created with pfNewLModel(). A light model also allows you to specify ambient light for the scene, such as might come from the sun with pfLModelAmbient().

The pfLights are created by calling pfNewLight(). A light has color and position. The light colors are specified with pfLightColor() as follows:

void pfLightColor(pfLightSource* lsource, int which, float r, 
   float g, float b);

which specifies one of three light colors as follows:

  • PFLT_AMBIENT

  • PFLT_DIFFUSE

  • PFLT_SPECULAR

You to position the light source using pfLightPos():

void pfLightPos(pfLight* light, float x, float y, 
    float z, float w);

The variable w is the distance between the location in the scene defined by (x, y, z) and the light source lsource. If w equals 0, lsource is infinitely far away and (x, y, z) defines a vector pointing from the origin in the direction of lsource; if w equals 1, lsource is located at the position (x, y, z). The default position is (0, 0, 1, 0), directly overhead and infinitely far away.

The pfLights are attached to a pfGeoState through the PFSTATE_LIGHTS attribute.

The transformation matrix that is on the matrix stack at the time the light is applied controls the interpretation of the light source direction:

  • To attach a light to the viewer (like a miner's head-mounted light), call pfLightOn() only once with an identity matrix on the stack.

  • To attach a light to the world (like the sun or moon), call pfLightOn() every frame with only the viewing transformation on the stack.

  • To attach a light to an object (like the headlights of a car), call pfLightOn() every frame with the combined viewing and modeling transformation on the stack.

The number of lights you can have turned on at any one time is limited by PF_MAX_LIGHTS, just as is true with the graphics libraries.


Note: In previous versions, attenuation was also part of the light model definition. In OpenGL, attenuation is defined per light . The libpr API for setting it is pfLightAtten().



Note: libpf applications can include light sources in a scene graph with the pfLightSource node.


Materials

OpenGL Performer materials are an extension of graphics library material (see glMaterial()). pfMaterials encapsulate the ambient, diffuse, specular, and emissive colors of an object as well as its shininess and transparency. A pfMaterial is created by calling pfNewMtl(). As with any of the other attributes, a pfMaterial can be referenced in a pfGeoState, captured by a display list, or invoked as an immediate mode command.

The pfMaterials, by default, allow object colors to set the ambient and diffuse colors. This allows the same pfMaterial to be used for objects of different colors, removing the need for material changes and thus improving performance. This mode can be changed with pfMtlColorMode(mtl, side, PFMTL_CMODE_*). OpenGL allows front or back materials to track the current color. If the same material is used for both front and back materials, there is no difference in functionality.

With the function pfMtlSide() you can specify whether to apply the the material on the side facing the viewer (PFMTL_FRONT), the side not facing the viewer (PFMTL_BACK), or both (PFMTL_BOTH). Back-sided lighting will only take affect if there is a two-sided lighting model active. Two-sided lighting typically has some significant performance cost.

Object materials only have an effect when lighting is active.

Color Tables

A pfColortable substitutes its own color array for the normal color attribute array ( PFGS_COLOR4) of a pfGeoSet. This allows the same geometry to appear differently in different views simply by applying a different pfColortable for each view. By leaving the selection of color tables to the global state, you can use a single call to switch color tables for an entire scene. In this way, color tables can simulate time-of-day changes, infrared imaging, psychedelia, and other effects.

The  pfNewCtab() function creates and returns a handle to a pfColortable. As with other attributes, you can specify which color table to use in a pfGeoState or you can use pfApplyCtab() to set the global color table, either in immediate mode or in a display list. For an applied color table to have effect, color table mode must also be enabled.

Fog

A pfFog is created by calling pfNewFog(). As with any of the other attributes, a pfFog can be referenced in a pfGeoState, captured by a display list, or invoked as an immediate mode command. Fog is the atmospheric effect of aerosol water particles that occlude vision over distance. SGI graphics hardware can simulate this phenomenon in several different fashions. A fog color is blended with the resultant pixel color based on the range from the viewpoint and the fog function. pfFog supports several different fogging methods. Table 12-9 lists the pfFog tokens and their corresponding actions.

Table 12-9. pfFog Tokens

pfFog Token

Action

PFFOG_VTX_LIN

Compute fog linearly at vertices.

PFFOG_VTX_EXP

Compute fog exponentially at vertices (ex).

PFFOG_VTX_EXP2

Compute fog exponentially at vertices (ex squared).

PFFOG_PIX_LIN

Compute fog linearly at pixels.

PFFOG_PIX_EXP

Compute fog exponentially at pixels (ex).

PFFOG_PIX_EXP2

Compute fog exponentially at pixels (ex squared).

PFFOG_PIX_SPLINE

Compute fog using a spline function at pixels.

The pfFogType() function uses these tokens to set the type of fog. A detailed explanation of fog types is given in the man pages pfFog(3pf) and glFog(3g).

You can set the near and far edges of the fog with pfFogRange(). For exponential fog functions, the near edge of fog is always zero in eye coordinates. The near edge is where the onset of fog blending occurs, and the far edge is where all pixels are 100% fog color.

The token PFFOG_PIX_SPLINE selects a spline function to be applied when generating the hardware fog tables. This is further described in the pfFog(3pf) man page. Spline fog allows you to define an arbitrary fog ramp that can more closely simulate real-world phenomena like horizon haze.

For best fogging effects, the ratio of the far to the near clipping planes should be minimized. In general, it is more effective to add a small amount to the near plane than to reduce the far plane.

Highlights

OpenGL Performer provides a mechanism for highlighting geometry with alternative rendering styles, useful for debugging and interactivity. A pfHighlight, created with pfNewHlight(), encapsulates the state elements and modes for these rendering styles. A pfHighlight can be applied to an individual pfGeoSet with pfGSetHlight() or can be applied to multiple pfGeoStates through a pfGeoState or pfApplyHlight(). The highlighting effects are added to the normal rendering phase of the geometry. pfHighlights make use of special outlining and fill modes and have a concept of a foreground color and a background color that can both be set with pfHlightColor(). The available rendering styles can be combined by ORing together tokens for pfHlightMode() and are described in Table 12-10.

Table 12-10. pfHlightMode() Tokens

PFHL_ Mode Bitmask Token

Description

LINES

Outlines the triangles in the highlight foreground color according to pfHlightLineWidth().

LINESPAT
LINESPAT2

Outlines triangles with patterned lines in the highlight foreground color or in two colors using the background color.

FILL

Draws geometry with the highlight foreground color. Combined with SKIP_BASE, this is a fast highlighting mode.

FILLPAT
FILLPAT2

Draws the highlighted geometry as patterned with one or two colors.

FILLTEX

Draws a highlighting fill pass with a special highlight texture.

LINES_R
FILL_R

Reverses the highlighting foreground and background colors for lines and fill, respectively.

POINTS

Renders the vertices of the geometry as points according to pfHlightPntSize().

NORMALS

Displays the normals of the geometry with lines according to pfHlightNormalLength().

BBOX_LINES
BBOX_FILL

Displays the bounding box of the pfGeoSet as outlines and/or a filled box. Combined with PFHL_SKIP_BASE, this is a fast highlighting mode.

SKIP_BASE

Causes the normal drawing phase of the pfGeoSet to be skipped. This is recommended when using PFHL_FILL or PFHL_BBOX_FILL.

For a demonstration of the highlighting styles, see the sample program /usr/share/Performer/pguide/src/libpr/C/hlcube.c on IRIX and Linux and %PFROOT%\Src\pguide\libpr\C\hlcube.c on Microsoft Windows.

Graphics Library Matrix Routines

OpenGL Performer provides extensions to the standard graphics library matrix-manipulation functions. These functions are similar to their graphics library counterparts, with the exception that they can be placed in OpenGL Performer display lists. Table 12-11 lists and describes the matrix manipulation routines.

Table 12-11. Matrix Manipulation Routines

Routines

Action

pfScale()

Concatenate a scaling matrix.

pfTranslate()

Concatenate a translation matrix.

pfRotate()

Concatenate a rotation matrix.

pfPushMatrix()

Push down the matrix stack.

pfPushIdentMatrix()

Push the matrix stack and load an identity matrix on top.

pfPopMatrix()

Pop the matrix stack.

pfLoadMatrix()

Add a matrix to the top of the stack.

pfMultMatrix()

Concatenate a matrix.


Sprite Transformations

A sprite is a special transformation used to efficiently render complex geometry with axial or point symmetry. A classic sprite example is a tree which is rendered as a single, texture-mapped quadrilateral. The texture image is of a tree and has an alpha component whose values “etch” the tree shape into the quad. In this case, the sprite transformation rotates the quad around the tree trunk axis so that it always faces the viewer. Another example is a puff of smoke which again is a texture-mapped quad but is rotated about a point to face the viewer so it appears the same from any viewing angle. The pfSprite transformation mechanism supports both these simple examples as well as more complicated ones involving arbitrary 3D geometry.

A pfSprite is a structure that is manipulated through a procedural interface. It is different from attributes like pfTexture and pfMaterial since it affects transformation, rather than state related to appearance. A pfSprite is activated with  pfBeginSprite(). This enables sprite mode and any pfGeoSet that is drawn before sprite mode is ended with pfEndSprite() will be transformed by the pfSprite. First, the pfGeoSet is translated to the location specified with pfPositionSprite(). Then, it is rotated, either about the sprite position or axis depending on the pfSprite's configuration. Note that pfBeginSprite(), pfPositionSprite(), and pfEndSprite() are display listable and this will be captured by any active pfDispList.

A pfSprite's rotation mode is set by specifying the PFSPRITE_ROT token to pfSpriteMode(). In all modes, the Y axis of the geometry is rotated to point to the eye position. Rotation modes are listed below.

Table 12-12. pfSprite Rotation Modes

PFSPRITE_ Rotation Token

Rotation Characteristics

AXIAL_ROT

Geometry's Z axis is rotated about the axis specified with pfSpriteAxis().

POINT_ROT_EYE

Geometry is rotated about the sprite position with the object coordinate Z axis constrained to the window coordinate Y axis; that is, the geometry's Z axis stays “upright.”

POINT_ROT_WORLD

Geometry is rotated about the sprite position with the object coordinate Z axis constrained to the sprite axis.

Rather than using the graphics hardware's matrix stack, pfSprites transform small pfGeoSets on the CPU for improved performance. However, when a pfGeoSet contains a certain number of primitives, it becomes more efficient to use the hardware matrix stack. While this threshold is dependent on the CPU and graphics hardware used, you may specify it with the PFSPRITE_MATRIX_THRESHOLD token to pfSpriteMode(). The corresponding value is the minimum vertex requirement for hardware matrix transformation. Any pfGeoSet with fewer vertices will be transformed on the CPU. If you want a pfSprite to affect non-pfGeoSet geometry, you should set the matrix threshold to zero so that the pfSprite will always use the matrix stack. When using the matrix stack, pfBeginSprite() pushes the stack and  pfEndSprite() pops the matrix stack so the sprite transformation is limited in scope.

The pfSprites are dependent on the viewing location and orientation and the current modeling transformation. You can specify these with calls to pfViewMat() and pfModelMat(), respectively. Note that libpf-based applications need not call these routines since libpf does it automatically.

Display Lists

The libpr library supports display lists , which can capture and later execute libpr graphics commands. pfNewDList() creates and returns a handle to a new pfDispList. A pfDispList can be selected as the current display list with pfOpenDList(), which puts the system in display list mode. Any subsequent libpr graphics commands, such as pfTransparency(), pfApplyTex(), or pfDrawGSet() are added to the current display list. Commands are added until pfCloseDList() returns the system to immediate mode. It is not valid to have multiple pfDispLists open at a given time but a pfDispList may be reopened, in which case, commands are appended to the end of the list.

Once a display list is constructed, it can be executed by calling pfDrawDList(), which traverses the list and sends commands down the Geometry Pipeline.

The pfDispLists are designed for multiprocessing, where one process builds a display list of the visible scene and another process draws it. The function pfResetDList() facilitates this by making pfDispLists reusable. Commands added to a reset display list overwrite any previously entered commands. A display list is typically reset at the beginning of a frame and then filled with the visible scene.

The pfDispLists support concurrent multiprocessing, where the producer and consumer processes simultaneously write and read the display list. The PFDL_RING argument to pfNewDList() creates a ring buffer or FIFO-type display list. pfDispLists automatically ensure ring buffer consistency by providing synchronization and mutual exclusion to processes on ring buffer full or empty conditions.

For more information and the application of display lists, see Chapter 15, “ClipTextures”.

Combining Display Lists

The contents of one pfDispList may be appended to a second pfDispList by using the function, pfAppendDList(). All pfDispList elements in src are appended to the pfDispList dlist.

Alternately, you can append the contents of one pfDispList to a second pfDispList by using the function pfDispList::append(). All pfDispList elements in src are appended to the pfDispList on which the append method is invoked.

State Management

A pfState is a structure that represents the entire libpr graphics state. A pfState maintains a stack of graphics states that can be pushed and popped to save and restore the state. The top of the stack describes the current graphics state of a window as it is known to OpenGL Performer.

The pfInitState() function initializes internal libpr state structures and should be called at the beginning of an application before any pfStates are created. Multiprocessing applications should pass a usinit() semaphore arena pointer to pfInitState(), such as pfGetSemaArena(), so OpenGL Performer can safely manage state between processes. pfNewState() creates and returns a handle to a new pfState, which is typically used to define the state of a single window. If using pfWindows, discussed in Chapter 16, “Windows”, a pfState is automatically created for the pfWindow when the window is opened and the current pfState is switched when the current pfWindow changes. pfSelectState() can be used to efficiently switch a different, complete pfState. pfLoadState() forces the full application of a pfState.

Pushing and Popping State

The pfPushState() function pushes the state stack of the currently active pfState, duplicating the top state. Subsequent modifications of the state through libpr routines are recorded in the top of the stack. Consequently, a call to pfPopState() restores the state elements that were modified after pfPushState().

The code fragment in Example 12-2 illustrates how to push and pop state.

Example 12-2. Pushing and Popping Graphics State

/* set state to transparency=off and texture=brickTex */
pfTransparency(PFTR_OFF);
pfApplyTex(brickTex);
 
/* ... draw geometry here using original state ... */
 
/* save old state. establish new state */
pfPushState();
pfTransparency(PFTR_ON);
pfApplyTex(woodTex);
 
/* ... draw geometry here using new state ...*/
 
/* restore state to transparency=off and texture=brickTex */
pfPopState();


State Override

The pfOverride() function implements a global override feature for libpr graphics state and attributes. pfOverride() takes a mask that indicates which state elements to affect and a value specifying whether the elements should be overridden. The mask is a bitwise OR of the state tokens listed previously.

The values of the state elements at the time of overriding become fixed and cannot be changed until pfOverride() is called again with a value of zero to release the state elements.

The code fragment in Example 12-3 illustrates the use of pfOverride().

Example 12-3. Using pfOverride()

pfTransparency(PFTR_OFF);
pfApplyTex(brickTex);
 
/*
 * Transparency will be disabled and only the brick texture
 * will be applied to subsequent geometry.
 */
pfOverride(PFSTATE_TRANSPARENCY | PFSTATE_TEXTURE, 1);
/* Draw geometry */
 
/* Transparency and texture can now be changed */
pfOverride(PFSTATE_TRANSPARENCY | PFSTATE_TEXTURE, 0);


pfGeoState

A pfGeoState encapsulates all the rendering modes, values, and attributes managed by libpr. See “Rendering Modes”, “Rendering Values”, and “Rendering Attributes” for more information. pfGeoStates provide a mechanism for combining state into logical units and define the appearance of geometry. For example, you can set a brick-like texture and a reddish-orange material on a pfGeoSet and use it when drawing brick buildings.

You can specify texture matricies on pfGeoSets.

Local and Global State

There are two levels of rendering state: local and global. A record of both is kept in the current pfState. The local state is that defined by the settings of the current pfGeoState. The rendering state and attributes of a pfGeoState can be either locally set or globally inherited. If all state elements are set locally, a pfGeoState becomes a full graphics context—that is, all state is then defined at the pfGeoState level. Global state elements are set with libpr immediate-mode routines like pfEnable(), pfApplyTex(), pfDecal(), or pfTransparency() or by drawing a pfDispList containing these commands with pfDrawDList(). Local state elements for subsequent pfGeoSets are set by applying a pfGeoState with pfApplyGState() (note that pfDrawGSet() automatically calls pfApplyGState() if the pfGeoSet has an attached pfGeoState). The state elements applied by a pfGeoState are those modes, enables, and attributes that are explicitly set on the pfGeoState. Those settings revert back to the pfState settings for the next call to pfApplyGState(). A pfGeoState can be explicitly loaded into a pfState to affect future pfGeoStates with pfLoadGState().


Note: By default, all state elements are inherited from the global state. Inherited state elements are evaluated faster than values that have been explicitly set.

While it can be useful to have all state defined at the pfGeoState level, it usually makes sense to inherit most state from global default values and then explicitly set only those state elements that are expected to change often.

Examples of useful global defaults are lighting model, lights, texture environment, and fog. Highly variable state is likely to be limited to a small set such as textures, materials, and transparency. For example, if the majority of your database is lighted, simply configure and enable lighting at the beginning of your application. All pfGeoStates will be lighted, except the ones for which you explicitly disable lighting. Then, attach different pfMaterials and pfTextures to pfGeoStates to define specific state combinations.


Note: Use caution when enabling modes in the global state. These modes may have cost even when they have no visible effect. Therefore, geometry that cannot use these modes should have a pfGeoState that explicitly disables the mode. Modes that require special care include the texturing enable and transparency.

You specify that a pfGeoState should inherit state elements from the global default with pfGStateInherit(gstate, mask). mask is a bitmask of tokens that indicates which state elements to inherit. These tokens are listed in the “Rendering Modes”, “Rendering Values”, and “Rendering Attributes” sections of this chapter. For example, PFSTATE_ENLIGHTING | PFSTATE_ENTEXTURE makes gstate inherit the enable modes for lighting and texturing.

A state element ceases to be inherited when it is set in a pfGeoState. Rendering modes, values, and attributes are set with pfGStateMode(), pfGStateVal(), and pfGStateAttr(), respectively. For example, to specify that gstate is transparent and textured with treeTex, use the following:

pfGStateMode(gstate, PFSTATE_TRANSPARENCY, PFTR_ON);
pfGStateAttr(gstate, PFSTATE_TEXTURE, treeTex);

Applying pfGeoStates

Use pfApplyGState() to apply the state encapsulated by a pfGeoState to the Geometry Pipeline. The effect of applying a pfGeoState is similar to applying each state element individually. For example, if you set a pfTexture and enable a decal mode on a pfGeoState, applying it essentially calls pfApplyTex() and pfDecal(). If in display-list mode, pfApplyGState() is captured by the current display list.

State is (logically) pushed before and popped after pfGeoStates are applied so that pfGeoStates do not inherit state from each other. This is a very powerful and convenient characteristic since, as a result, pfGeoStates are order-independent, and you do not have to worry about one pfGeoState corrupting another. The code fragment in Example 12-4 illustrates how pfGeoStates inherit state.

Example 12-4. Inheriting State

/* gstateA should be textured */
pfGStateMode(gstateA, PFSTATE_ENTEXTURE, PF_ON);
 
/* gstateB inherits the global texture enable mode */
pfGStateInherit(gstateB, PFSTATE_ENTEXTURE);
 
/* Texturing is disabled as the global default */
pfDisable(PFEN_TEXTURE);
 
/* Texturing is enabled when gstateA is applied */
pfApplyGState(gstateA);
/* Draw geometry that will be textured */
 
/* The global texture enable mode of OFF is restored 
so that gstateB is NOT textured. */
pfApplyGState(gstateB);
/* Draw geometry that will not be textured */

The actual pfGeoState pop is a "lazy" pop that does not happen unless a subsequent pfGeoState requires the global state to be restored. This means that the actual state between pfGeoStates is not necessarily the global state. If a return to global state is required, call pfFlushState() to restore the global state. Any modification to the global state made using libpr functions—pfTransparency(), pfDecal(), and so on—becomes the default global state.

For best performance, set as little local pfGeoState state as possible. You can accomplish this by setting global defaults that satisfy the majority of the requirements of the pfGeoStates being drawn. By default, all pfGeoState state is inherited from the global default.

pfGeoSets and pfGeoStates

There is a special relationship between pfGeoSets and pfGeoStates. Together they completely define both geometry and graphics state. You can attach a pfGeoState to a pfGeoSet with pfGSetGState() to specify the appearance of geometry. Whenever the pfGeoSet is drawn with pfDrawGSet(), the attached pfGeoState is first applied using pfApplyGState(). If a pfGeoSet does not have a pfGeoState, its state description is considered undefined. To inherit all values from the global pfState, a pfGeoSet should have a pfGeoState with all values set to inherit, which is the default.

This combination of routines allows the application to combine geometry and state in high-performance units that are unaffected by rendering order. To further increase performance, sharing pfGeoStates among pfGeoSets is encouraged.

Table 12-13 lists and describes the pfGeoState routines.

Table 12-13. pfGeoState Routines

Routiine

Description

pfNewGState()

Create a new pfGeoState.

pfCopy()

Make a copy of the pfGeoState.

pfDelete()

Delete the pfGeoState.

pfGStateMode()

Set a specific state mode.

pfGStateVal()

Set a specific state value.

pfGStateAttr()

Set a specific state attribute.

pfGStateInherit()

Specify which state elements are inherited from the global state.

pfApplyGState()

Apply pfGeoState's non-inherited state elements to graphics.

pfLoadGState()

Load pfGeoState's settings into the pfState, inherited by future pfGeoStates.

pfGetCurGState()

Return the current pfGeoState in effect.

pfGStateFuncs()

Assign pre/post callbacks to pfGeoState.

pfApplyGStateTable()

Specify a able of pfGeoStates used for indexing.

Figure 12-1 diagrams the conceptual structure of a pfGeoState.

Figure 12-1. pfGeoState Structure

pfGeoState Structure

Multitexture Support in pfGeoState

Some graphic hardware supports the use of multiple texture maps on a single polygon. These multiple texture maps are blended together according to a collection of texture environments. Figure 12-2 demonstrates the OpenGL definition for generating the color of a multitextured pixel. The figure assumes that the hardware has four texture units and so each pixel can receive contribution from four texture maps.

Figure 12-2. Generating the Color of a Multitextured Pixel

Generating the Color of a Multitextured Pixel

In the figure, the shaded and un-textured color of a pixel enters the first texture blending unit together with the texture color computed by the first texture unit. The texture environment marked TexEnv 0 determines the math operation between the two. The output color of this operation feeds the second texture blending unit together with the texture color computed by the second texture unit. This process continues four times until the final color of the pixel is generated.

The pfGeoState class allows specifying multiple texture maps on a single pfGeoSet. All these texture maps will be applied when the pfGeoSet is applied (providing that the graphic hardware has enough texture mapping units). pfGeoState also allows specifying multiple pfTexEnv, pfTexGen, pfTexMat, and pfTexLOD objects—one for each pfTexture.

The following code fragment shows how to add multiple textures to a pfGeoState:

{
    pfGeoState *gstate;
    pfTexture  *tex;
    pfTexEnv   *tev;
    gstate = pfNewGState (pfGetSharedArena());
    for (i = 0 ; i < PF_MAX_TEXTURES ; i ++)
    {
            /* Load texture # i from a file */
            tex = pfNewTex (pfGetSharedArena());
            pfLoadTexFile (tex, texture_file_name[i]);

            tev = pfNewTEnv (pfGetSharedArena());

            /* Enable texture unit # i on the pfGeoState. */
            pfGStateMultiMode (gstate, PFSTATE_ENTEXTURE, i, 1);

            /* Attach texture for texture unit # i */
            pfGStateMultiAttr (gstate, PFSTATE_TEXTURE, i, tex);

            /* Attach texture environment for texture unit # i */
            pfGStateMultiAttr (gstate, PFSTATE_TEXENV, i, tev);
    }
}

Notes:

  • pfGeoState recognizes texture units starting at the first array (index of 0) and ending immediately before the first disabled texture unit. For example, enabling texture units 0, 1, and 3 is equivalent to enabling only texture units 0 and 1.

  • pfGeoState can inherit all or none of the texture units. It is enough to specify one texture unit in order to avoid inheriting any other texture unit. In order to inherit all texture units, one must specify no texture units on the pfGeoState.

  • For every texture unit enabled, the application must provide texture coordinates. Neither OpenGL Performer nor OpenGL will share texture coordinates between texture units. There are two ways to set texture coordinates:

    • Specifying a pfTexGen for a texture unit

    • Specifying a texture-coordinate attribute array for a texture unit on a pfGeoSet See section “Attributes” in Chapter 8.