A pfState holds the global graphic's state description. A pfGeoState encapsulates the graphics state elements, such as lighting, transparency, and texture that define the appearance of a pfGeoSet or pfGeoArray. (Hereafter, this section will refer only to pfGeosets.) Every pfGeoSet must reference a pfGeoState. State definitions for the pfGeoSet come either from its pfGeoState, or from the global, default settings in the global pfState.
This chapter describes how to define the appearance of geometries in the following sections:
Graphics state elements can be directly set in immediate mode through pfApply*() routines. For example, use pfApplyMtl() to set a current material; use pfEnable() to enable a specific mode, such as lighting, or use pfApplyGState() to set a complete collection of graphics state elements. When these calls are made, the current graphics state is recorded by OpenGL Performer in a pfState. This provides functionality, as well as optimizations, to prevent redundant graphics state changes.
pfState contains all global graphics state information and all of the information necessary to define the appearance of a geometry. You must have a current pfState to create any other OpenGL Performer state objects or to do any graphics operations; however, pfWindows by default automatically creates and selects its own pfState when it is opened. You can create and select a pfState object with pfInitState(). There is also a state stack that can be pushed and popped in pfState with pfPushState() and pfPopState(). You can lock state settings can be locked by using the pfState function pfOverride() to prevent future changes. pfState graphic state values become the default appearance values for all pfGeoSets.
pfGeoStates state values found in pfState and are primarily used for specifying the appearance of geometry. pfGeoStates can specify the following, among other things:
Material properties with the pfMaterial state attribute object
Textures with the pfTexture state attribute object
Transparency with the transparency mode
When a pfGeoState is created, it is configured to inherit all appearance values from the current pfState when it is applied. Those values can be changed using methods in pfGeoState: pfGStateAttr(), pfGStateMode(), and pfGStateVal(). pfGeoStates settings can be applied directly to the current global state with pfLoadGState(). pfGeoStates referenced by pfGeoSets only affect the pfGeoSets referencing them. pfApplyGState() will set state values for subsequent pfGeoSets, but those state values will revert back to the previous pfState values for the next call to pfApplyGState(). A pfGeoState can be directly loaded into the current pfState to set inherited values by future pfGeoStates with pfLoadGState().
Create a pfGeoState object using pfNewGState().
Associate the pfGeoState appearance values with a geometry using pfGSetGState().
Specify the modal graphic states, such as enables, you want to change using pfGStateMode().
Specify the attribute graphic states you want to change, such as textures and materials, using pfGStateAttr().
For example, to enable lighting and antialiasing and to set the material of the geometry to metal, use code similar to the following:
pfMaterial *mtl = pfNewMtl(arena); pfGeoState *gstate = pfNewGState(arena); pfGStateMode(gstate, PFSTATE_ENLIGHTING, PF_ON); pfGStateMode(gstate, PFSTATE_ANTIALIAS, PFAA_ON); pfGStateAttr(gstate, PFSTATE_FRONTMTL, mtl);
Generally, pfGeoState values alter global, pfState appearance values for specific pfGeoSets. You can also use a pfGeoState to set global state values by attaching a pfGeoState object to a scene node using pfSceneGState(), as follows:
void pfSceneGState(pfScene *scene, pfGeoState *gstate);
OpenGL Performer does a pfPushState() and a pfLoadGState() of the pfScene pfGeoState before rendering the scene graph.
pfState contains the default, global state values, many of which define the appearance of the geometric objects in the scene. When pfGeoSets are drawn with pfDrawGSet(), they automatically call pfApplyGState() on their pfGeoState. If a pfGeoState is not defined for a geometry, the appearance values are 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. A state value defined for a specific pfGeoSet takes precedence over the corresponding global state value.
Changing the graphics context from the global value to a value defined for a specific geometry impacts the performance of an application. For that reason, it is important to set the global appearance values to satisfy most geometries, thus changing the local appearance values as little as possible.
Many pfGeoState graphic states, such as transparency, are specified with a token. These graphic states are set using pfGStateMode().
Table 8-1 shows the modal graphic states you can specify along with their possible values and defaults.
Float between 0.0 and 1.0
PFCF_OFF, PFCF_BACK, PFCF_FRONT, PFCF_BOTH
PF_OFF, PFTG_OBJECT_LINEAR, PFTG_EYE_LINEAR, PFTG_EYE_LINEAR_IDENT
pfTransparency sets the type of transparency computation used for rendering transparency effects. The different types of transparency computations define how the geometry's color and the framebuffer color are blended. Transparency can have different performance and image-quality characteristics on different graphics subsystems. For this reason, it is better to provide OpenGL Performer with a hint, such as PFTR_HIGH_QUALITY, rather than specifying a method that does not work on all platforms; OpenGL Performer interprets the hint, PFTR_HIGH_QUALITY, for all platforms.
Transparency modes include:
PFTR_HIGH_QUALITY—uses methods for highest image quality.
Dec aled geometry can be thought of as a stack, where each layer has visual priority over the geometry beneath it in the stack. As with transparencies, different hardware platforms offer different methods with different performance and image quality characteristics. For this reason, OpenGL Performer allows and recommends that unless you have specific motivation, use a hint rather than a specific method, which might not work on all platforms.
See the pfDecal man page for the definition of the decal mode values. PFDECAL_OFF is the default.
pfAlphaFunc sets the alpha function mode. The alpha function mode specifies whether or not a given pixel is rendered according to its alpha value. For example, if you set pfAlphaFunc to PFAF_GREATER, only pixels with alpha values greater than a reference value are rendered.
You specify the reference value using PFSTATE_ALPHAREF. For example, to render only those pixels with alpha values greater than 0.5, use the following code:
pfGStateMode(gstate, PFSTATE_ALPHAFUNC, PFAF_GREATER); pfGStateValue(gstate, PFSTATE_ALPHAREF, 0.5);
See the pfAlphaFunc man page for the definition of the PFSTATE_ALPHAFUNC mode values.
Many pfGeoState graphic states are specified using an object, such as pfMaterial. These graphic states are set using pfGStateAttr(). To use an object as the definition for an attribute, you must create the object and define it before calling pfGStateAttr().
Table 8-2 shows the attribute pfGeoState values and the objects that define them.
All attributes default to NULL, which means that OpenGL default values are used.
For more information about any of the attributes, see the man pages of the objects associated with them.
T extures are images that are applied to the surface of a geometry, as shown in Figure 8-1.
Textures can add tremendous realism to the rendered scene because they can be real photographs. An image of the pitted rind of an orange applied to a sphere, for example, creates a realistic-looking orange.
To use a texture, follow these steps:
Enable texture mapping.
Create a pfTexture.
Load or create the texture image and assign it to the pfTexture.
Optionally set the texture environment using pfTexEnv.
Set the texture coordinates on the pfGeoSet using pfGSetAttr, or else use a pfTexGen in the pfGeoState to automatically generate texture coordinates.
pfGStateMode(gstate, PFSTATE_ENTEXTURE, PF_ON); pfGSetGState(gset, gstate);
The first line enables texture mapping, and the second line selects the pfGeoSet that is to be texture mapped.
pfTexture *pfNewTex(void *arena)
The arena is that part of memory shared by all OpenGL Performer processes.
int pfLoadTexFile(pfTexture *tex, char *fname)
The texture must be in either the SGI format or the fast-loading OpenGL Performer PFI format. The texture is created with reasonable defaults for the specified image for the various control modes discussed further in this section.
pfFilePathv(“/usr/demos/data/textures", "/usr/demos/data/images", "/usr/share/Performer/data”, NULL);
OpenGL Performer searches through the directories in the order of their specification.
Two tools help you preload textures:
pfList *pfuMakeSceneTexList(pfScene *scene) void pfuDownloadTexList(pfList *list, int mode)
pfuMakeSceneTexList() traverses the scene graph and builds a list of all the textures used. pfuDownloadTexList() downloads the textures specified in the list to the GL and hardware texture memory and must be called from the DRAW process.
void pfTexImage(pfTexture* tex, uint* image, int comp, int sx, int sy, int sz);
One component—consisting of intensity (I) or luminance (L) only, useful geometries that repeat but vary in contrast, such as grass and sand.
Two components—consisting of intensity and transparency (IA), useful for geometries that repeat but vary in contrast and transparency, such as clouds.
Three components—consisting of red, green, and blue (RGB).
Four components—consisting of red, green, blue, and alpha (RGBA), useful for full-color textures.
A texture object also contains information about the handling of the image data, including
Texture wrap options, which specifies what happens when the texture is too small to completely cover a geometry, set with pfTexRepeat(). Options include repeating the texture until the geometry is covered or expanding the texture so that it covers the geometry.
The prototypes for these basic configuration routines are:
void pfTexFormat(pfTexture *tex, int format, int type); void pfTexFilter(pfTexture *tex, int filt, int type); void pfTexRepeat(pfTexture *tex, int wrap, int type);
void pfTexFormat(pfTexture *tex, int format, int type)
format specifies which format to set. Valid formats and their basic types include:
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.
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 with 8-bits per component. There are special fast-loading hardware ready formats, such as PFTEX_UNSIGNED_SHORT_5_5_5_1.
In general, you 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 will automatically choose a matching internal format. See the pfTexFormat(3pf) man page for more information on texture configuration details.
The environment specifies how the potentially lit colors of the geometry and the texture image interact. This is described with a pfTexEnv object. The mode of interaction is set with pfTEnvMode(), and valid modes include:
PFTE_MODULATE—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_BLEND—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.
The texture coordinates specify how the coordinates of the texture map to the coordinates of the geometry, as shown in Figure 8-2.
void pfGSetAttr(pfGeoSet *gset, PFGS_TEXCOORD2, PFGS_PER_VERTEX, void *alist, ushort *llist)
alist is a pointer to the array of pfVec2 texture coordinates.
ilist is an optional pointer to the indices in the texture coordinate array.
Texture coordinates can also be automatically generated by various functions specified by a pfTexGen object. See Chapter 9, “Graphics State ,” in the OpenGL Performer Programmer's Guide, and the pfTGenMode(3pf) man page for more information on this object.
Figure 8-3 shows three of these lighting conditions on a sphere illuminated from above.
pfMaterial * pfNewMtl(void *arena); void pfMtlColor(pfMaterial *mtl, int color, float r, float g, float b); void pfMtlShininess(pfMaterial *mtl, float shininess);
arena is memory allocated from the shared memory arena.
color specifies one of the lighting conditions:
To define more than one of these lighting conditions, use the method repeatedly with a different token for color each time.
shininess is a float between 0.0 and 128.0 where 0.0 is very dull and 128.0 is very shiny.
Loading material information is computationally intensive. In some situations, you can take a shortcut. For example, consider the case where you have three differently colored but otherwise identical balls. Rather than reload a new material for each ball, you can change the color of the material of each ball through the object colors. pfMtlColorMode() specifies the particular material attribute that can be set through object or vertex colors. Changing a material color this way is much faster than switching to a different material; it allows for sharing of materials and shading control.
The default is PFMTL_CMODE_AD, which sets the material's ambient and diffuse colors with the pfGeoSet colors. To turn this default functionality off, set the color mode to PFMTL_CMODE_COLOR, so that geometry colors will only set the current GL color and will not affect the material state.
With the method pfMtlSide(), you can specify whether to apply 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 only takes effect if a two-sided lighting model is active. Two-sided lighting typically has a significant performance cost.
Object materials only have effects when lighting is active.
Lighting requires a specified lighting model, an active light, and the enabling of graphics lighting operations. As lighting is typically applied to an entire scene, you probably want to enable lighting in your global state with pfEnable(PFEN_LIGHTING), or in the scene pfGeoState:
pfGeoState *gstate = pfNewGState(arena); pfScene *sceneNode = pfNewScene(void); pfGStateMode(gstate, PFSTATE_ENLIGHTING, PF_ON); pfSceneGState(sceneNode, gstate);
The lighting model, specified with the pfLightModel state attribute object, 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 light model also allows you to specify ambient light for the scene, such as might come from the sun, with pfLModelAmbient().
void pfLightColor(pfLightSource* lsource, int which, float r, float g, float b);
which specifies one of three light regions:
r, g, and b specify the color components of the specified light color.
To position the light source using pfLightPos():
void pfLightPos(pfLight* light, float x, float y, float z, float w);
w is the distance between the location in the scene defined by (x, y, z) and the light source, lsource. If w equals zero, lsource is infinitely far away and (x, y, z) defines a vector pointing from the origin in the direction of lsource. If w equals one, lsource is located at the position, (x, y, z). The default position is (0, 0, 1, 0): directly overhead, infinitely far away.
pfLightSource nodes are nodes that can be placed in the scene graph and have their position transformed by pfSCS and other transform nodes. pfLightSource nodes are active for the rendering of the entire scene. pfLightSource nodes are not pfLights and cannot be attached to pfGeoStates, and visa vera.