Glide 2.2 Programming Guide Programming the 3Dfx Interactive Glide™ Rasterization Library 2.2 Document Release 014 08 March 1997 Copyright ã 1995-1997 3Dfx Interactive, Inc. All Rights Reserved 3Dfx Interactive, Inc. 4435 Fortran Avenue San Jose, CA 94134 Trademarks Glide, TexUS, Pixelfx and Texelfx are trademarks of 3Dfx Interactive, Inc. OpenGL is a trademark of Silicon Graphics, Inc. Autodesk CDK is a trademark of Autodesk, Inc. MS-DOS and Win32 are trademarks of Microsoft, Inc. Other product names are trademarks of the respective holders. Copyright © 1995-1997 by 3Dfx Interactive, Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, without prior written consent. Table of Contents Table of Contents List of Figures List of Tables List of Examples Chapter One An Introduction to Glide Why Glide? Voodoo Graphics The Rendering Engine About This Manual Other Documentation Chapter Two Glide in Style In this Chapter Naming and Notational Conventions The State Machine Model Specifying Vertices Numerical Data Chapter Three Getting Started In This Chapter Starting Up Driving Multiple Systems Shutting Down The Display Buffer Masking Writes to the Frame Buffer Swapping Buffers Clearing Buffers Error Handling Chapter Four Rendering Primitives In This Chapter The GrVertex Structure Clipping Triangles Points Lines Convex Polygons Backface Culling Anti-aliasing Chapter Five Color and Lighting In This Chapter Specifying Colors Dithering The Color Combine Unit Gamma Correction Chapter Six Using the Alpha Component In This Chapter Specifying Alpha The Alpha Combine Unit Alpha Buffering Alpha Blending Chapter Seven Depth Buffering In This Chapter Enabling Depth Buffering The Depth Test Fixed Point z buffering Floating Point w buffering Establishing a Depth Bias An Example: Hidden Surface Removal Chapter Eight Special Effects In This Chapter Fog Chroma-keying Alpha Testing Stenciling Chapter Nine Texture Mapping In This Chapter A Look at Texture Mapping and Glide Glide Textures and Texels Texel Coordinate Systems Texture Filtering Texture Clamping Mipmapping Mipmap Blending Trilinear Filtering LOD Bias Combining Textures Examples of Configuring the Texture Pipeline Chapter Ten Managing Texture Memory In This Chapter Texture Map Formats Narrow Channel Compression The Color Palette (not implemented in TMU Revision 0) Texture Memory Computing the Size of a Mipmap Querying for Available Memory Downloading Mipmaps Identifying a Mipmap as the Texel Source Loading a Mipmap into Fragmented Memory Downloading a Decompression Table or Color Palette Loading Mipmaps From Disk Chapter Eleven Accessing the Linear Frame Buffer In This Chapter Acquiring an LFB Read or Write Pointer Calculating a Pixel Address Reading from the LFB Writing to the LFB Setting LFB Write Parameters Special Effects and Linear Frame Buffer Writes Writing a Rectangle of Pixels into the LFB Chapter Twelve Housekeeping Routines In This Chapter Retrieving Configuration Information Checking System Status Utilizing Two Displays Monitoring System Performance Chapter Thirteen Glide Utilities In This Chapter A Higher Level Color Combine Function A Higher Level Alpha Combine Function A Higher Level Texture Combine Function Allocating Texture Memory Downloading Textures Chapter Fourteen Programming Tips and Techniques In This Chapter Floating Point Vertex Snapping and Area Calculations Avoiding Redundant State Setting Avoiding Screen Clears by Rendering Background Polygons Using LOD Bias To Control Texture Aliasing Linear z Buffering and Coordinate System Ranges State Coherency and Contention Between Processes Appendix A A Sample Program Appendix B Glide State Constants Glossary Index List of Figures Figure 1.2 The pixel pipeline. Figure 3.1 Locating the origin. Figure 3.2 Logical layout of the linear frame buffer. Figure 4.1 Specifying a clipping window. Figure 4.2 Pixel rendering. Figure 4.3 Polygons. Figure 4.4 Polygon orientation and the sign of the area. Figure 4.5 Aliased and anti-aliased lines. Figure 4.6 Pixel coverage and lines. Figure 9.1 TMU connectivity. Figure 9.2 Point sampled and bilinear filtering. Figure 9.3 Texture clamping. Figure 9.4 Mipmaps. Figure 10.1 The color palette. Figure 10.2 The size of a mipmap depends on the setting of the evenOdd flag. Figure 10.3 Downloading a mipmap. Figure 10.4 Replacing a single LOD. Figure 10.5 Replacing a few rows of an LOD. Figure 11.1 Reading from and writing to the LFB. Figure 11.2 Frame buffer writes: encoding the location of the origin as the sign of the strideInBytes. Figure 12.1 The Voodoo Graphics status register. List of Tables Table 3.1 Frame buffer color formats. Table 3.2 Frame buffer resolution and configuration. Table 4.1 The location of the origin affects triangle orientation and the sign of its area. Table 5.1 Configuring the color combine unit. Table 5.2 The color combine function scale factor. Table 5.3 Choosing local and other colors for the color combine unit. Table 5.4 Overriding the local color when the high order bit of atexture is set. Table 6.1 Combining functions for alpha. Table 6.2 Scale factors for the alpha combine function. Table 6.3 Specifying local and other alpha values. Table 6.4 Alpha blending factors. Table 7.1 The depth test. Table 8.1 Alpha test functions. Table 9.1 The stw hints. Table 9.2 Mapping pixels to texture coordinates in texture maps. Table 9.3 Texture sizes and shapes. Table 9.4 Texture combine functions. Table 9.5 Scale factors for texture color generation. Table 9.6 The number of TMUs affects texture mapping functionality. Table 10.1 Texture formats. Table 10.2 Glide constants that specify arguments to grTex functions. Table 11.1 Interpreting data read from the LFB. Table 11.2 16-bit LFB data formats. Table 11.3 32-bit LFB data formats. Table 11.4 Color, alpha, and depth sources. Table 11.5 Source data formats for the grLfbWriteRegion() routine. Table 13.1 Color combine functions. Table 13.2 Alpha combine unit modes. Table 13.3 Texture combine functions. List of Examples Example 3.2 Setting a state variable in all Voodoo Graphics subsystems. Example 3.3 A minimal Glide program. Example 4.1 A thousand points of light. Example 4.2 Drawing an anti-aliased triangle. Example 5.1 Drawing a constant color triangle. Example 5.2 Drawing a flat shaded triangle. Example 5.3 Drawing a smooth shaded triangle. Example 5.4 Drawing a flat-shaded textured triangle. Example 5.5 Drawing a smooth-shaded textured triangle. Example 5.6 Drawing a smooth shaded triangle with specular lighting. Example 5.7 Drawing a smooth shaded textured triangle with specular highlights. Example 5.8 Drawing a smooth shaded triangle with monochrome diffuse and colored specular lighting. Example 6.1 Blending two images. Example 6.2 Blending two images, part II. Example 6.3 A compositing example. Example 7.1 Configuring a z buffer. Example 7.2 Configuring a w buffer. Example 7.3 Using a depth bias. Example 7.4 Hidden surface removal using a z buffer. Example 8.1 Fogging with iterated alpha. Example 8.2 Creating a fog table. Example 8.3 Fogging with 1/w and a fog table. Example 8.4 Simulating a blue-screen with chroma-keying. Example 9.1 Setting up simple (decal) texture mapping. Example 9.2 Applying a modulated (projected) texture. Example 9.3 Using trilinear filtering: mipmap blending with bilinear filtering. Example 9.4 Creating a composite texture. Example 10.1 Will the mipmap fit? Example 10.2 Setting up to load several mipmaps. Example 10.3 Downloading a texture for decal texture mapping. Example 10.4 Downloading two textures for modulated or composite texture mapping. Example 10.5 Splitting a texture across two TMUs for trilinear mipmapping. Example 10.6 Using multiple texture base registers. Example 10.7 Loading an NCC table. Example 10.8 Loading a color palette. Example 10.9 Reading a .3DF file. Example 11.1 Reading a pixel value from the LFB. Example 11.2 Enabling specific special effects. Example 11.3 Writing One 565 RGB Pixel to the back buffer (RGB ordering). Example 11.4 Writing Two 565 RGB Pixels to the back buffer (RGB color ordering). Example 11.5 Writing One 888 RGB Pixel to the back buffer (ARGB color ordering). Example 14.1 Snapping coordinates to .0625 resolution. Example 14.2 Masking off precision control bits on Intel processors. Example 14.3 A portable way to snap coordinates to .0625 resolution. An Introduction to Glide Voodoo Graphics is the first video subsystem that enables personal computers and low cost video game platforms to host true 3D entertainment applications. Optimized for real-time texture-mapped 3D images, the Voodoo Graphics subsystem provides acceleration for advanced 3D features including true-perspective texture mapping with trilinear mipmapping and lighting, detail and projected texture mapping, texture anti-aliasing, and high precision subpixel correction. In addition, it supports general purpose 3D pixel processing functions, including triangle-based Gouraud shading, depth buffering, alpha blending, and dithering. real-time, true-perspective, texture-mapped rendering with lighting support at low cost simplified software porting: only the inner rasterization loop is affected lowest cost solution designed expressly for use in the entertainment markets patent pending techniques to reduce texture memory requirements The Glide Rasterization Library is a set of low level rendering functions that serve as a software “micro-layer” to the Voodoo Graphics family of graphics hardware, including the 3Dfx Interactive Texelfx ™ and the Pixelfx™ special purpose chips. Glide perm its easy and efficient implementation of 3D rendering libraries, games, and drivers. Why Glide? Glide serves three primary purposes: * It relieves programmers from hardware specific issues such as timing, maintaining register shadows, and working with hard-coded register constants and offsets. It defines an abstraction of the Voodoo Graphics hardware to facilitate ease of software porting. It acts as a delivery vehicle for sample source code providing in-depth hardware-specific optimizations for the Voodoo Graphics hardware. By abstracting the low level details of interfacing with the Voodoo Graphics hardware into a set of C-callable functions, Glide allows developers to avoid working with hardware registers and memory directly, enabling faster development and lower probabili ty of bugs. Glide also handles mundane and error prone chores such as initialization and shutdown. Glide is but one part of the 3Dfx Interactive Software Developer’s Kit (SDK), which is designed to assist developers in creating tools and titles that are optimized for the Voodoo Graphics hardware. Other components of the SDK include the Game Controller I nterface (GCI) Library and the Texture Utility Software (TexUS™). Glide is not a full featured graphics API such as OpenGL™, PHIGS, or the Autodesk CDK™: it does not provide high level 3D graphics operations such as transformations, display list management, or light source shading. Glide specifically implements only thos e operations that are natively supported by the Voodoo Graphics hardware. In general, Glide does not implement any functions that do not directly access a Voodoo Graphics subsystem’s memory or registers. The Glide Utility Library contains utility routines create fog tables, extensions that do significant pre-processing before calling Glide routines to access the graphics system, and obsolete routines that are provided for interim compatibility as Glide dev elopment continues. The Glide library can be linked with an application with or without debugging aids. The debug version has error checking and parameter validation, which may cause performance degradation. When an application is initially developed and debugged it should us e the debugging version of Glide. After development is complete the release build of Glide is employed for optimum performance. Voodoo Graphics The Voodoo Graphics subsystem sits on the PCI system bus of the host computer. The entry-level system configuration consists of two 3Dfx Interactive proprietary ASICs, Texelfx and Pixelfx and memory. shows the entry level configuration as well as sever al ways to expand the system and enhance graphics performance. Increasing the number of Texelfx ASICs decreases the number of passes required to perform various texture mapping techniques. Systems with more than one Voodoo Graphics subsystem can utilize s can-line interleaving to achieve the highest possible rendering performance. Glide and the Voodoo Graphics hardware supports a rich set of rendering techniques, including Gouraud shading. The programmer provides initial red, green, blue, and alpha values for each vertex; Glide calculates the associated gradients and the hardware automatically iterates the color across the defined triangle. Texture mapping. The programmer provides initial texture values s/w, t/w, and 1/w for each vertex and Glide computes the gradients. The hardware performs the proper iteration and perspective correction for true-perspective texture mapping. During each ite ration of row/column walking, a division is performed by 1/w to correct for perspective distortion. Texture mapping with lighting. Texture-mapped rendering can be combined with Gouraud shading to introduce lighting effects during the texture mapping process. The programmer supplies initial color and texture values, Glide calculates the appropriate gra dients, and the hardware performs the proper calculations to implement the lighting models and texture lookups. A texel is either modulated (multiplied by), added, or blended to the Gouraud shaded color. The selection of color modulation or addition is p rogrammable. Texture space decompression. Texture map compression uses a patent-pending “narrow channel” Yab compression scheme that maps 24-bit RGB values to a 8-bit Yab format with little loss in precision. Depth buffering. Voodoo Graphics supports hardware accelerated depth buffered rendering with no performance penalty. The depth buffer is implemented in frame buffer memory: 2 Mbyte systems can utilize a 640×480 double buffered display buffer and a 16-bit z buffer. To eliminate many of the z aliasing problems typically encountered with 16-bit z buffer systems, the Voodoo Graphics subsystem allows a floating point representation of the 1/w parameter to be used as the depth component. Figure 1.1 Voodoo Graphics system configurations. The Pixelfx chip interfaces with the host computer, the linear frame buffer, and the display monitor, and implements basic 3D primitives including Gouraud shading, alpha blending, depth buffering, dithering, and fog. The TMU (located on the Texelfx chip) implements texture mapping, including true-perspective, detail, and projected texture mapping, bilinear and trilinear filtering, and level-of-detail mipmapping. (a) The basic configuration has one Pixelfx chip and one TMU. The advanced texture mapping techniques of detail texture mapping, projected texture mapping, and trilinear texture filtering are two-pass operations, but there is no performance penalty fo r point sampled or bilinear filtered texture mapping with mipmapping. (b) A two TMU configuration allows single pass, full-speed, detail texture mapping, projected texture mapping, or trilinear filtering. (c) Three TMUs can be chained together to provide single-pass, full-speed rendering of all supported advanced texture mapping features including projected texture mapping. (d) For the highest possible rendering performance, multiple Voodoo Graphics subsystems can be chained together utilizing scan-line interleaving to effectively double the rendering rate of a single subsystem. Pixel blending. The hardware supports alpha blending functions that blend incoming source pixels with current destination pixels with no performance penalty. Alpha buffering is supported, but is mutually exclusive with depth buffering and triple buffer ing. Note that alpha buffering is required only if destination alpha is used in alpha blending; alpha blending modes that do not use destination alpha can be used with depth buffering and triple buffering. Fog. The Voodoo Graphics subsystem supports a 64-entry lookup table to support atmospheric effects such as fog and haze. When enabled, a 14-bit floating point representation of 1/w is used to index into the 64-entry lookup table and interpolate between e ntries. The output of the lookup table is a value that represents the level of blending to be performed between a reference fog color and the incoming pixel. Chroma-keying. Voodoo Graphics supports a chroma-key operation used for transparent object effects. When enabled, an outgoing pixel is compared with the chroma-key register. If a match is detected, the outgoing pixel is invalidated in the pixel pipeline , and the frame buffer is not updated. Color dithering: Numeric operations are performed on 24-bit colors within the Voodoo Graphics subsystem. However, the final stage of the pixel pipeline dithers the color from 24 bits to 16 bits before storing it in the display buffer. The 16-bit color d ithering allows for the generation of photo-realistic images without the additional cost of a true color frame buffer storage area. The Rendering Engine The Voodoo Graphics hardware has a very flexible lighting and texture mapping pipeline to support all of the features described above. Glide abstracts it into three distinct units: the texture combine unit, the color and alpha combine unit, and the speci al effects unit. The basic architecture is illustrated in . Figure 1.2 The pixel pipeline. The rendering engine is structured as a pipeline through which each pixel drawn to the screen must pass. The individual stages of the pixel pipeline modify or invalidate individual pixels based on mode settings. The pixel source is one of four things: a t exture value, an iterated RGBA value, a constant RGBA value, or data for a frame buffer write. Pixels that pass the chroma-key test go to the color combine unit where a user-specified lighting function is applied. The special effects unit further modifies the pixel with alpha and depth testing, fog, and alpha blending operations. The final 24-bit color value is then dithered to 16 bits and written to the frame buffer. About This Manual The Glide 2.2 Programming Guide attempts to introduce a knowledgeable graphics programmer to the capabilities of the Voodoo Graphics subsystem through the Glide interface. The subroutines are introduced in a logical progression: initialization and terminat ion requirements are first, then simple rendering capabilities, followed by more and more complex function. The audience for this manual is the application programmer who just took delivery on a Voodoo Graphics subsystem and wants to port existing applicat ions or develop new applications in Glide. The experienced Glide programmer will use the Glide Reference Manual to research specific Glide functions, but will reach for this manual when trying out new features. Chapter , , describes data types, data formats, and programming model used in Glide and the Voodoo Graphics subsystem. Chapter , , describes the display buffers and the initialization and termination requirements for Glide and the graphics hardware and includes a very simple but complete program that clears the screen. Chapter , , describes the functions that draw points, lines, triangles, and convex polygons in both aliased and anti-aliased forms. In addition, clipping and backface culling are discussed. Chapter , , describes the functions that control the Voodoo Graphics color and alpha combine unit, which can produce effects that run the gamut from simple Gouraud shading to diffuse ambient lighting with specular highlights and other complex lighting mod els. Chapter , , describes the various ways to utilize the alpha channel: alpha blending, alpha buffering, and alpha testing. Chapter , , presents the two flavors of depth buffers. Chapter , , describes other special rendering effects that can be produced in the pixel pipeline: atmospheric effects like fog, haze, and smoke; transparent objects implemented with chroma-keying; stippling; color dithering; alpha masking. Chapter , , describes the texture pipeline and texture mapping while Chapter 10, Managing Texture Memory, describes the process of downloading textures into texture memory. Chapter , , describes the Glide functions that provide a path for reading and writing the frame buffer directly. Chapter , , and Chapter , Glide Utilities, describes the routines in Glide and the Glide Utilities Library that haven’t been discussed already. Chapter 14, Programming Tips and Techniques, give some hints about how to head off trouble and get the best performance from your Voodoo Graphics hardware. The Glide Programming Guide concludes with two appendices, one containing a non-trivial example, and the other summarizing the Glide constants used to set state variables. There is also a Glossary of frequently used terms and comprehensive Index. Other Documentation Available from 3Dfx Interactive, Inc. : Glide 2.2 Reference Manual SST1 Application Notes TexUS Manual Additional published references: FOLE90 Foley, J., A. van Dam, S. Feiner, and J. Hughes, Computer Graphics, Addison-Wesley, Reading, MA, 1990 OPEN92 OpenGL Architecture Review Board, OpenGL Reference Manual, Addison-Wesley, Reading, MA, 1992 OPEN93 OpenGL Architecture Review Board with J. Neider, T. Davis, and M. Woo, OpenGL Programming Guide, Addison-Wesley, Reading, MA, 1992 PHIG88 PHIGS+ Committee, A. van Dam, Chair, “PHIGS+ Functional Description - Revision 3.0”. Computer Graphics, 22(3), p. 125-218 SUTH74 Sutherland, I. E. and G. W. Hodgman, “Reentrant Polygon Clipping”, CACM 17(1), p. 32-42 WATT92 Watt, A. and M. Watt, Advanced Animation and Rendering Techniques: Theory and Practice, Addison-Wesley, Reading, MA, 1992 WILL83 Williams, L., “Pyramidal Parametrics”, SIGGRAPH 83, p. 1-11 Online references: http://www.3dfx.com http://www.sgi.com/grafica/texmap/index.html http://reality.sgi.com/Fun/Free_graphics.html Glide in Style In this Chapter You will learn about: the naming conventions for functions, types, and constants the notational conventions that designate functions, types, variables, parameters, and constants in this manual the state machine model that Glide uses to minimize bandwidth to the hardware and increase graphics performance the functions that save and restore Glide state the GrVertex structure that holds the coordinates and parameters that define a vertex the constraints and properties of numerical data representing geometric, color, and texture coordinates Naming and Notational Conventions Functions are divided into families consisting of routines related in their duties. All Glide functions are prefixed with gr; all Glide Utility functions use gu as the prefix. The Glide prefix is immediately followed by the family name, for example grDrawT riangle() and grDrawPolygon() are both parts of the grDraw family. Glide uses the mixed caps convention for function names. When function names appear in the text of this manual, they will be shown in bold face type. Actual function names end with ‘()’; function family names do not. The internal name for the Voodoo Graphics subsystem is “SST-1”or “SST”. Some function names, type definitions, and constants within Glide reflect this internal name, which is easier to type than Voodoo Graphics. For example, grSstOpen() initializes the ha rdware. Constants are named values that are defined in glide.h. The names of constants use all uppercase letters, as in MAX_NUM_SST and GR_TEXTUREFILTER_BILINEAR and will be shown in Courier font when they appear in the text of this manual. C specifications for functions and data types will be displayed in shaded rectangles throughout this manual. Glide type definitions are shown in Helvetica type to distinguish them from the C keywords and primitive types. Glide makes use of enumerated types for function arguments in order to restrict them to the defined set of values. Enumerated types end with _t, as in GrColorFormat_t. Glide variable names and function arguments will be italicized in both the C specifications and the text. Code segments use Courier font. The State Machine Model Glide is state based: rendering “modes” can be set once and then remain in effect until reset. Parameter values like a reference value for depth comparisons and a specific depth test are set once and will be used whenever depth testing is enabled (until t hey are given new values). The state machine model allows users to set modes and reference values only when they change, minimizing the host-to-hardware transfers. For example, one of the state variables Glide maintains is the “current mipmap”, used during texture mapping. A mipmap is a collection of hierarchically defined texture maps that are loaded into the texture memory that supports the TMUs. A stateless model would not retain information about the contents of the texture memory, so each rendering operation would have to include a texture memory address. Sending redundant state information can lead to noticeable performance degradation. For example, if a system is attempting to render 200,000 triangles per second and the “current mipmap” is sent as a 4-byte address, bandwidth associated with updating this single state variable can amount to 800KB/sec. Compound this with all of the other state information necessary and the amount of unnecessary data sent across the system bus can become overwhelming. Two library functions are used to save and restore state. void grGlideGetState( GrState *state ) void grGlideSetState( const GrState *state ) grGlideGetState() makes a copy of the current state of the current Voodoo Graphics subsystem in a GrState structure state provided by the user. The saved state can be restored at some later time with grGlideSetState(). These routines save and restore all Glide state, and therefore are expensive to use. If only a small subset of Glide state needs to be saved and restored, these routines should not be used. Specifying Vertices Voodoo Graphics is a rendering engine. The user configures the texture and pixel pipelines (see Figure 1.2) and then sends streams of vertices representing points, lines, triangles, and convex polygons. (In fact, the hardware renders only triangles; Glid e converts points and lines to triangles and triangulates polygons as needed.) Vertices are specified in the GrVertex data structure, shown below and defined in glide.h. Up to ten parameters can be used to specify a point: the geometric coordinates (x, y, z, w) where x and y indicate a screen location, z indicates depth, and w is the homogeneous coordinate the color components (r, g, b, a) the texture coordinates (s, t) Note that the GrVertex structure has a spot for z, but actually uses its reciprocal (ooz, for “one over z”). Similarly, 1/w is stored in the variable oow. And, s/w and t/w are stored in the structure (as sow and tow) rather than s and t, because the scale d values are the ones actually used by the Voodoo Graphics system. These values need to be computed only once for each vertex, regardless of how many triangles include the vertex. The GrVertex structure also includes a small array of GrTmuVertex data structures, one for each TMU present in the system, and each of the array elements contains private oow, sow, and tow variables. Each TMU and the Pixelfx chip each have their own copy of 1/w, s/w, and t/w. Normally, they will all be the same. However, projected textures have a different w value than non-projected textures. Projected textures iterate q/w where w is the homogeneous distance from the eye and q is the homogeneous distanc e from the projected source. typedef struct { float oow; /* 1/w */ float sow; /* s/w texture coordinate */ float tow; /* t/w texture coordinate */ } GrTmuVertex; typedef struct { float x, y, z; /* x, y, z of screen space. z is ignored */ float ooz; /* a linear function of 1/z (used for z buffering) */ float oow; /* 1/w (used for w buffering) */ float r, g, b, a; /* red, green, blue, and alpha ([0..255.0]) */ GrTmuVertex tmuvtx[GLIDE_NUM_TMU]; } GrVertex; Every vertex must specify values for x and y, but the other parameters are optional and need only be set if the rendering configuration requires them. lists some typical rendering operations and the vertex parameters they use. Table 2.1 Vertex parameter requirements depend on the rendering function being performed. The x and y coordinates must be specified for every vertex, regardless of the rendering function being performed. The other parameters stored in the GrVertex structure are optional and need to be supplied only if required for the desired computation. The table below details the values required by the rendering functions implemented by Glide and the Voodoo Graphics hardware. rendering function required expected values see variables Chapter all vertices, all x, y –2048 to +2047 4 rendering functions Gouraud shading r, g, b 0 to 255.0 5 alpha a 0 to 255.0 6 blending/testing non-projected tmuvtx[0].o1/w where w is in the 9 texture mapping tmuvtx[0].srange [1..65535] tmuvtx[0].tow s/w where s is in the range [0..255.0] t/w where t is in the range [0..255.0] projected texture tmuvtx[0].o1/w where 1/w is in the 9 mapping tmuvtx[0].srange [–4096..61439] tmuvtx[0].tow s/w where s/w is in the range [–32768..32767] tmuvtx[1].oow, tmuvtx[1].st/w where t/w is in the tmuvtx[1].trange [–32768..32767] q/w where q/w is in the range [–4096..61439] s/w where s/w is in the range [–32768..32767] t/w where t/w is in the range [–32768..32767] linear z buffering ooz 1/z where 1/z is in the range [0, 65535] w buffering oow 1/w where w is in the range [1..65535] fog with iterated a [0..255.0] 8 alpha fog with iterated z ooz 1/z where 1/z is in the 8 range [0, 65535] fog with table oow 1/w where w is in the 8 range [1..65535] Numerical Data The Voodoo Graphics hardware can accept vertex data in either fixed point or floating point formats. However, Glide provides only a floating point interface, since RISC and Pentium processors are optimized for floating point calculations. If you are portin g a fixed point application to the Voodoo Graphics system, plan to convert all your data to floating point representation as part of the porting process. The GrVertex structure contains single-precision, IEEE 754 32-bit floating point values. Geometric Coordinates The x and y coordinates are specified in pixel units in the range [–2048..2047]. The pixel coordinate (0.5, 0.5) represents the exact center of the first visible pixel on the screen. The ooz coordinate should be assigned a value that is linear in screen space. That is, it should be a linear function of 1/w that can be scaled and translated such that it increases or decreases with distance from the viewer. The valid range for ooz value s is [0..65535]. To minimize z aliasing this range should be mapped to the smallest possible range of eye coordinates. For example, if w eye coordinates are within the range [2..15] and 1/w is in the range [1/2..1/15] then the mapping would be approximate ly 1/z = 151214.6/w – 10080.9 where w is eye w and ooz is the value iterated in the Voodoo Graphics subsystem. The w coordinate is a scaled positive depth value used during perspective projection, perspective texture mapping, and depth buffering. Some graphics systems do not use homogeneous coordinates; in these instances the z depth value can be used in lieu of the w coordinate, assuming that the z value is positively increasing into the screen. The range of w is [1..65535]. Glide and Voodoo Graphics actually use the reciprocal of the homogeneous coordinate, 1/w. The valid range for 1/w is [–4096..61439]. Normally, the homogeneous coordinate is clipped to a positive range of [1, far] and so its reciprocal is in the range [1.. 1/far]. Negative values should be avoided. Each TMU and the Pixelfx chip each have their own 1/w. Normally, the values in all the chips will be the same. However, projected textures have a different w value than non-projected textures. Projected textures iterate q/w where w is the homogeneous di stance from the eye and q is the homogeneous distance from the projected source. In this case, q/w has a valid range of [–-4096..61439]. The 1/w value in Pixelfx is used only for fog calculations and w buffering, and is not used for texture mapping. It can be scaled differently than the 1/w values sent to the TMUs. The fog table spans a range in 1/w from [1/65535..1]. If w buffering i s enabled, the w buffer spans a range in 1/w from [1/65528..1]. Therefore, scale the 1/w value in Pixelfx such that the range [1/65535..1] encompasses all that is interesting in the scene. Colors The color components are in the range [0..255] where 0 is black and 255 is maximum intensity. Colors should be clamped to this range. Glide supports four different color byte orderings: RGBA, ARGB, BGRA, and ABGR. Color byte ordering determines how linear frame buffer writes and color arguments passed to the constant color functions (see Chapter 5) are interpreted. Color ordering is est ablished when Glide and the Voodoo Graphics system are initialized (see Chapter ). When the terms “RGB” and “RGBA” appear in this manual, they typically refer to any color system that represents red, green, blue, and optionally, alpha, as separate components, regardless of the byte order or component width. The exceptions will be clearly recognizable as discussions about specific color resolution and format. Texture Coordinates Glide uses texture coordinates in the range [–32768..32767] and refers to them as (s,t) pairs, similar to the naming convention of OpenGL. A texture contains texels with (s,t) coordinates in the range [0..255.0]; the texture may be replicated many times t o cover a surface by mapping the texture coordinates modulo 256 to a texel in the texture. The Voodoo Graphics subsystem iterates s/w and t/w, so s and t must be divided by w (or multiplied by oow) before storing them in the GrVertex structure. The w term iterated by the SST-1 is actually 1/w or the reciprocal of the homogeneous coordinate. The valid range for 1/w is [–4096..61439]. Normally, the homogeneous coordinate is clipped to a positive range of [1..far] and so its reciprocal is in the ra nge [1..1/far]. Negative values should be avoided. Each TMU has its own s, t, and w values. Normally, they will be the same as the w in the Pixelfx. However, in certain cases they will be different. For example, projected textures have a different w valu e than non-projected textures. Projected textures iterate q/w where w is the homogeneous distance from the eye and q is the homogeneous distance from the projected source. In this case, q/w has a valid range of [–4096..61439]. Mipmapping [WILL83] is a method of organizing several pre-filtered texture maps into a single logical entity used for anti-aliased texture mapping. The term mipmap is sometimes used to describe a pyramidal organization of gradually smaller, filtered sub-t extures or an individual texture map within such an organization. Glide adopts the original convention that defines the term mipmap to mean the entire group of textures that comprise a single pyramidal data structure. Individual textures within a mipmap ar e referred to as mipmap levels. Getting Started In This Chapter You will learn how to: initialize Glide configure and initialize the hardware manage multiple Voodoo Graphics subsystems terminate cleanly manage the display buffers detect and respond to errors Starting Up Glide provides several functions to initialize Glide and to detect and configure a Voodoo Graphics subsystem. Two routines, grSstQueryHardware() and grSstQueryBoards() detect the presence of Voodoo Graphics subsystems. Three functions, grGlideInit(), grS stSelect(), and grSstOpen(), initialize Glide and the hardware and must be called, in the order listed, before calling any other Glide routines (except grSstQueryHardware() and grSstQueryBoards()). Failing to do this will cause the system to operate in an undefined (and, most likely, undesirable) state. typedef struct { int num_sst; GrSstConfig_t SSTs[MAX_NUM_SST]; } GrHwConfiguration; FxBool grSstQueryBoards( GrHwConfiguration *hwConfig ) FxBool grSstQueryHardware( GrHwConfiguration *hwConfig ) grSstQueryBoards() determines the number of installed Voodoo Graphics subsystems and stores this number in hwConfig->num_sst. No other information is stored in the structure at this time; grSstQueryHardware() can be called after grGlideInit() to fill in t he rest of the structure. grSstQueryBoards() is the only Glide routine that can be called before grGlideInit(); it does not change the state of any hardware, nor does it render any graphics. grSstQueryHardware() detects the presence of one or more Voodoo Graphics subsystems and determines how they are configured. It should be called immediately after grGlideInit() but before any other Glide functions. grSstQueryHardware() returns a Boolean value: FXTRUE indicates that at least one Voodoo Graphics subsystem was found. The argument, hwConfig, is a pointer to a structure that will be filled in with information about the number and configuration of the Voo doo Graphics subsystems it found. Note that when two Voodoo Graphics subsystems are configured as a single scan-line interleaved system they are viewed by Glide and an application as a single subsystem. The first initialization function, grGlideInit(), sets up the Glide library and thus must be called before any other Glide functions are executed. It allocates memory, sets up pointers, and initializes library variables and counters. There are no argument s, and no value is returned. void grGlideInit( void ) The next function called to initialize the system is grSstSelect(), which makes a specific Voodoo Graphics subsystem “current”. It must be called after grSstQueryHardware() and grGlideInit() but before grSstOpen(). void grSstSelect( int whichSST ) The argument is the ordinal number of the subsystem that will be made active and must be in the range [0..hwconfig.num_sst] where hwConfig is the structure that holds the system configuration information returned by the preceding call to grSstQueryHardware (). If whichSST is outside the proper range of values and the debugging version of Glide is used, a run-time error will be generated. If the release version of Glide is loaded, use of an inappropriate value for whichSST will result in undefined behavior. The final initialization function, grSstOpen(), initializes the currently active Voodoo Graphics subsystem, specified by the most recent call to grSstSelect(), to the default state. All hardware special effects (depth buffering, fog, chroma-key, alpha blending, alpha testing, etc.) are disabled. All global state constants (the chroma-key reference value, the alpha test reference, the constant depth value, the constant alpha value, the constant color value, etc.) and pixel rendering statistic counters are initialized to 0. grSstOpen() should be called once per installed Voodoo Graphics subsystem (note that scan-line interleaved subsystems are treated as a single Voodoo Graphics subsystem) and must be executed after grGlideInit(), grSstQueryHardware() and grSstSelect(). I t returns FXTRUE if the initialization was successful and FXFALSE otherwise. FxBool grSstOpen( GrScreenResolution_t res, GrScreenRefresh_t refresh, GrColorFormat_t cFormat, GrOriginLocation_t locateOrigin, GrSmoothingMode_t smoothMode, int numBuffers ) The arguments to grSstOpen() configure the frame buffer. The screen resolution and refresh rate are specified in the first two arguments, res and refresh. Both variables are given values chosen from enumerated types defined in the sst1vid.h header file. A typical application might set res to GR_RESOLUTION_640x480 and refresh to GR_REFRESH_60HZ. The third argument, cFormat , specifies the packed color RGBA ordering in the frame buffer. Different software systems assume different byte ordering formats for pixel color data. For the widest possible compatibility across a wide range of software, Gli de provides “byte swizzling”, meaning that incoming pixels can have their color values interpreted in one of four different formats that are defined in the enumerated type GrColorFormat_t and are shown in Table 3.1. The color format affects data written t o the linear frame buffer (the subject of Chapter 11) and parameters for the following Glide functions: grBufferClear() (described later in this chapter), grChromakeyValue() (described in Chapter 8), grConstantColorValue() (see Chapter 5), and grFogColo rValue() (see Chapter 8). Table 3.1 Frame buffer color formats. Glide supports four different color byte orderings: RGBA, ARGB, BGRA, and ABGR. Color byte ordering determines how linear frame buffer writes and color arguments passed to the constant color functions are interpreted. The first column in the table shows t he name of the format, as defined in the enumerated type GrColorFormat_t. The second column in the table shows the byte ordering of the color components within a 32-bit word. color format byte ordering GR_COLORFORMAT_RGBA GR_COLORFORMAT_ARGB GR_COLORFORMAT_BGRA GR_COLORFORMAT_ABGR The fourth parameter to grSstOpen() specifies the location of the screen space origin. If locateOrigin is GR_ORIGIN_UPPER_LEFT, the screen space origin is in the upper left corner with positive y going down (a la IBM VGA). GR_ORIGIN_LOWER_LEFT places the screen space origin at the lower left corner with positive y going up (a la SGI GL). Figure 3.1 shows the two possibilities for locating the origin. Figure 3.1 Locating the origin. The Voodoo Graphics hardware allows the origin to be in the upper left or lower left corner of the screen. The choice of coordinate system must be made when first initializing Glide and a Voodoo Graphics subsystem by passing the appropriate parameter to g rSstOpen(). The Voodoo Graphics hardware operates on 32-bit ARGB color values internally. However, these values are eventually dithered to 16-bit RGB (5:6:5) by the hardware. Hardware dithering provides good display quality while at the same time reducing memory con sumption by a third, allowing for less expensive hardware implementations. The fifth argument to grSstOpen(), smoothMode, enables or disables an optional 24-bit smoothing filter that can be applied during video refresh. Enabling smoothing reduces dither ing artifacts but may result in a slightly blurrier image. The final argument to grSstOpen(), numBuffers, specifies double or triple buffering and is an integer value, either 2 or 3. If there is not enough memory to support the desired resolution (e.g. 800´600 triple buffered on a 2MB system) then an error wil l occur. Example . The Glide initialization sequence. This code fragment demonstrates the four Glide functions that must be called, in order, to properly initialize both the software and the hardware subsystems. The parameters to grSstOpen() establish a double buffered frame buffer with 640´480 screen resolu tion and a 60Hz refresh rate. Colors are stored as RGBA, smoothing techniques will be applied to reduce dithering artifacts, and the origin is in the lower left corner. GrHwConfiguration hwconfig; grGlideInit(void); if (grSstQueryHardware(hwconfig)) { grSstSelect(0); grSstOpen( GR_RESOLUTION_640x480, GR_REFRESH_60HZ, GR_COLORFORMAT_RGBA, GR_ORIGIN_LOWER_LEFT, GR_SMOOTHING_ENABLE, 2); }; else printf(“ERROR: no Voodoo Graphics!\n”); Driving Multiple Systems Glide supports two forms of multiple Voodoo Graphics subsystem support: multiple Voodoo Graphics subsystems driving multiple displays and two Voodoo Graphics subsystems driving a single display. Selecting Voodoo Graphics Units At any given moment, only a single Voodoo Graphics subsystem is active. The grSstSelect(), presented above, activates a specific unit. All Glide functions, with the exception of the grGlide family and grSstSelect(), operate on only the currently active Vo odoo Graphics subsystem. Note that the global Glide state is bound to each Voodoo Graphics independently. So, to set the constant color in each Voodoo Graphics unit to the same value, for example, you must write a loop that selects each one in turn and set s the color, as shown in . Example . Setting a state variable in all Voodoo Graphics subsystems. Each Voodoo Graphics subsystem has its own version of the Glide state variables, including a constant color value that will be used to clear the screen. The constant color is zero by default. The code fragment below cycles through all the Voodoo Graphics u nits found by a previous call to grSstQueryHardware(), setting the constant color to black. GrHwConfiguration hwconfig; for ( i = 0; i < hwconfig.num_sst; i++ ) { grSstSelect( i ); grConstantColorValue( ~0 ); /* only affects SST “i” */ } Opening Multiple Voodoo Graphics Units grSstOpen() must be called once for each Voodoo Graphics subsystem that will be used. Note that two Voodoo Graphics subsystems linked together in a scan-line interleaving configuration are treated in software as a single Voodoo Graphics subsystem. Scan-line Interleaved Voodoo Graphics Units Two Voodoo Graphics subsystems can be wired together in a configuration known as scan-line interleaving, which effectively doubles rasterization performance. From an application’s perspective, two Voodoo Graphics subsystems in a scan-line interleaved confi guration are treated as if a single Voodoo Graphics subsystem is installed in the system, including during Voodoo Graphics selection, initialization, state management, texture download, etc. Shutting Down After an application has completed using Glide and the Voodoo Graphics subsystem, proper shutdown must be performed. This allows Glide to de-allocate system resources like memory, timers, address space, and file handles that were used during program execut ion. The function grGlideShutdown() shuts down Glide and all Voodoo Graphics subsystems previously opened with grSstOpen(). It should be called only when an application is finished using Glide, and should not be executed unless grGlideInit() and grSstOpen() have already been called. void grGlideShutdown( void ) shows a minimal Glide program: it executes the four function calls that initialize the Voodoo Graphics subsystem and then terminates. Example . A minimal Glide program. The complete program below includes the Glide initialization and termination procedure and nothing else. #include GrHwConfiguration hw; void main(void) { grGlideInit(void); if (! grSstQueryHardware(hw)) printf(“ERROR: no Voodoo Graphics!\n”); grSstSelect(0); grSstOpen( GR_RESOLUTION_640x480, GR_REFRESH_60HZ, GR_COLORFORMAT_RGBA GR_ORIGIN_LOWER_LEFT, GR_SMOOTHING_ENABLE, 2); grGlideShutdown(); } The Display Buffer Glide manages several logical hardware graphics buffers, all of which are based out of the same area of memory known as the “frame buffer”. Depending on the amount of memory installed on the hardware, the frame buffer is typically arranged as three logical units: the front buffer, the back buffer, and, optionally, the auxiliary buffer. void grRenderBuffer( GrBuffer_t buffer ) grRenderBuffer() selects the buffer for primitive drawing and buffer clears. Valid values are GR_BUFFER_FRONTBUFFER and GR_BUFFER_BACKBUFFER; the default is GR_BUFFER_BACKBUFFER. The auxiliary buffer in a Voodoo Graphics subsystem can be used either as a depth buffer, an alpha buffer, or as a third rendering buffer for triple buffering. The auxiliary buffer is not available on systems with 2MB of frame buffer DRAM running at 80 0´600. However, it is always available on systems with 4MB of frame buffer DRAM installed or with the screen resolution set to 640´480. Triple buffering allows an application to continue rendering even when a swap buffer command is pending. When triple buffering is enabled an application can act as if the hardware is operating in double buffer mode; intricacies of dealing with the third b uffer are hidden from the application by the hardware. Since the auxiliary buffer can serve only a single use, depth buffering, alpha buffering, and triple buffering are mutually exclusive. An application selects the purpose of the auxiliary buffer implicitly whenever depth buffering, alpha buffering, or triple buffering are enabled. For example, if grDepthBufferMode() is called with a parameter other than GR_DEPTHBUFFER_DISABLE (see Cha pter ), it is assumed that the auxiliary buffer will be used for depth buffering. Similarly, grSstOpen() enables triple buffering; alpha buffering is enabled if grAlphaBlendFunction() selects a destination alpha blending factor (see Chapter 6) or grC olorMask() enables writes to the alpha buffer. The release build of Glide does not check for contention of the auxiliary buffer. Unexpected results may occur if the auxiliary buffer is used for more that one function (e.g. both depth buffering and tripl e buffering are enabled). The debugging version of the library will report the contention. Note that source alpha blending can coexist with depth or triple buffering, but destination alpha blending cannot. Table 3.2 Frame buffer resolution and configuration. The frame buffer can be configured with two or three rendering buffers. In double buffer modes, an alpha or depth buffer can also be used. The available resolution depends on the amount of installed memory. frame double double buffer triple buffer buffer mode mode with buffer mode memory 16-bit alpha/depth buffer 2 Mbytes 800 by 600 640 by 480 by 640 by 480 by 16 16 by 16 4 Mbytes 800 by 600 800 by 600 by 800 by 600 by 16 16 by 16 Logical Layout of the Linear Frame Buffer The frame buffer is logically organized as a 1024´1024 array of 16 or 32-bit values, regardless of the amount of memory installed on the board, and is shown in . Scan-line size is independent of screen resolution and is always 1024 pixels wide. The data fo rmat within the frame buffer is programmable and is described in detail in Chapter . Figure 3.2 Logical layout of the linear frame buffer. The frame buffer is logically organized as a 1024´1024 array of 16 or 32-bit values, regardless of the amount of memory installed on the board and the screen resolution. The drawable area is a rectangular subset of the frame buffer; its location depends on the location of the y origin. The remainder of the board’s memory (shaded area) is used as an auxiliary buffer that can be utilized as an alpha/depth buffer or as a third display buffer (triple buffering). This logical layout is independent of the user-specified origin location. Masking Writes to the Frame Buffer Writes to the frame buffer and depth buffer can be selectively disabled and enabled. The Glide functions grColorMask() and grDepthMask() control buffer masking: FXTRUE values allow writes to the associated buffer, FXFALSE values disable writes to the as sociated buffer. Writes to the color and alpha buffers are controlled by grColorMask() whereas writes to the depth buffer are controlled by grDepthMask() (described in Chapter ). Note that disabling writes to the alpha planes is the same as disabling wri tes to the depth planes since they both share the same memory. void grColorMask( FxBool rgb, FxBool alpha ) void grDepthMask( FxBool enable ) grColorMask() specifies whether the color and/or alpha buffers can or cannot be written to during rendering operations. If rgb is FXFALSE, for example, no change is made to the color buffer regardless of the drawing operation attempted. The alpha paramet er is ignored if depth buffering is enabled since the alpha and depth buffers share memory. grDepthMask() enables writes to the depth buffer. The value of grColorMask() and grDepthMask() are ignored during linear frame buffer writes if grLfbBypassMode() is enabled (see Chapter ). The default values are FXTRUE, indicating that the associated buffers are writable. Swapping Buffers In a double or triple buffered frame buffer, the next scene will be rendered in a back buffer while the front buffer is being displayed. After an image has been rendered, it is displayed with a call to grBufferSwap(), which exchanges the front and back b uffers in the Voodoo Graphics subsystem after swapInterval vertical retraces. If the swapInterval is 0, then the buffer swap does not wait for vertical retrace. If the monitor frequency is 60 Hz, for example, a swapInterval of 3 results in a maximum frame rate of 20 Hz. void grBufferSwap( int swapInterval ) A swapInterval of 0 may result in visual artifacts, such as ‘tearing’, since a buffer swap can occur during the middle of a screen refresh cycle. This setting is very useful in performance monitoring situations, as true rendering performance can be measure d without including the time buffer swaps spend waiting for vertical retrace. grBufferSwap() does not wait for the specified vertical blanking period; instead, it queues the buffer swap command and returns immediately. If the application is double buffering, the Voodoo Graphics subsystem will stop rendering and wait until the swap occurs before executing more commands. If the application is triple buffering and the third rendering buffer is available, then rendering commands will take place immediately in the third buffer. A Glide application can poll the Voodoo Graphics subsystem using the grBufferNumPending() function to determine the number of buffers waiting to be viewed, although this is generally not necessary. int grBufferNumPending( void ) grBufferNumPending() returns the number of queued buffer swap requests. The maximum value returned is 7, even though there may be more buffer swap requests in the queue. To minimize rendering latency in response to interactive input, grBufferNumPending() should be called in a loop once per frame until the returned value is less than some small number such as 1, 2, or 3. Synchronizing with Vertical Retrace Synchronization to vertical retrace is supported with the grSstVRetraceOn() and grSstVideoLine() functions. grSstVRetraceOn() returns FXTRUE if the monitor is in vertical retrace and FXFALSE otherwise. FxBool grSstVRetraceOn( void ) grSstVideoLine() returns the current line number of the display beam. This number is 0 during vertical retrace and increases as the display beam progresses down the screen. There are a small number of video lines that are not displayed at the top of the s creen: the vertical backporch. Thus, grSstVideoLine() returns a small positive number when the display beam is at the top of the screen; as the beam goes off the bottom of the screen, the line number may exceed the number returned by grSstScreenHeight(). FxU32 grSstVideoLine( void ) The Glide 2.1 release was the first release to include grSstVideoLine(). Earlier versions used grSstVRetraceTicks(), now obsolete. Note that an application does not need to explicitly synchronize to vertical retrace if it only wishes to remove tearing artifacts. grBufferSwap() will automatically synchronize to vertical retrace if desired. Clearing Buffers The ability to clear a display buffer is fundamental to animation, since the remnants of a previously rendered scene must be reset before a new scene can be rendered. The Voodoo Graphics hardware allows the back buffer and alpha or depth buffer to be clea red simultaneously. A buffer clear fills pixels at twice the rate of triangle rendering, therefore the performance cost of clearing the buffer is half the cost of rendering a rectangle. Clearing the buffer is not necessary when the scene paints a background that covers the en tire area. Buffers are cleared by calling grBufferClear(). The area within the buffer to be cleared is defined by grClipWindow(), described in the next chapter. The three parameters specify the values that will be used to clear the display buffer (color), the alpha buffer (alpha), and the depth buffer (depth). Although the color, alpha, and depth parameters are always specified, the parameters actually used will depend on the current configuration of the hardware; the irrelevant parameters are ignored. The depth parameter can be one of the constants GR_ZDEPTHVALUE_NEAREST, GR_ZDEPTHVALUE_FARTHEST, GR_WDEPTHVALUE_NEAREST, GR_WDEPTHVALUE_FARTHEST, or a direct representation of a value in the depth buffer. See Chapter for more details. void grBufferClear( GrColor_t color, GrAlpha_t alpha, FxU16 depth ) Any buffers that are enabled are automatically and simultaneously cleared by grBufferClear(). For example, if depth buffering is enabled (with grDepthBufferMode(), described in Chapter ), the depth buffer will be cleared to depth. If alpha buffering i s enabled (with grAlphaBlendFunction(), described in Chapter 6), the alpha buffer will be cleared to alpha. And if writes to the display buffer are enabled (with grColorMask(), described in Chapter 5), then it will be cleared to color. If an application does not want a buffer to be cleared, it should mask off writes to the buffer using grDepthMask() and grColorMask() as appropriate. Error Handling Glide provides a family of error management functions to assist a developer with application debugging. This family of routines consists of Glide related error management (errors generated by Glide) and application level error management (errors generated by an application). The debug build of Glide performs extensive parameter validation and resource checking. When an error condition is detected, a user-supplied callback function may be executed. This callback function is installed by calling grErrorSetCallback(). If no call back function is specified, a default error function that prints an error message to stderr is used. void grErrorSetCallback( void (*function)(const char *string, FxBool fatal) ) The callback function accepts a string describing the error and a flag indicating if the error is fatal or recoverable. grErrorSetCallback() is relevant only when using the debugging version of Glide; the release build of Glide removes all internal paramet er validation and error checking so the callback function will never be called. Rendering Primitives In This Chapter You will learn how to: establish a clipping window draw a point, a line, a triangle, or a convex polygon on the screen cull back-facing polygons from the scene draw an anti-aliased point, line, triangle, or convex polygon The GrVertex Structure The GrVertex structure, first presented in Chapter 2, collects together all the parameters that define a vertex. In this chapter, only the x and y coordinates will be discussed; the other parameters are called into play in later chapters. typedef struct { float x, y, z; /* x, y, z of screen space. z is ignored */ float ooz; /* 65535/z (used for z buffering) */ float oow; /* 1/w (used for w buffering) */ float r, g, b, a; /* red, green, blue, and alpha ([0..255.0]) */ GrTmuVertex tmuvtx[GLIDE_NUM_TMU]; } GrVertex; The x and y coordinates are 32-bit floating point values that represent the position of the vertex in screen space. While the Voodoo Graphics hardware renders only triangles, Glide provides functions to draw points, lines, and polygons as well as triangles . When a point, line, triangle, or polygon is rendered, its appearance will reflect the current state of the rendering pipeline. That is, if texture mapping is enabled, then the point, line, triangle, or polygon will be texture mapped. Similarly, alpha blend ing, fogging, color, and lighting effects, chroma-keying, and other special effects will contribute to the appearance of any and all geometric shapes drawn while they are enabled. Clipping The Voodoo Graphics hardware supports per-pixel clipping to an arbitrary rectangle defined with the Glide function grClipWindow(). Any pixels outside the clipping window are rejected. Values are inclusive for minimum x and y values and exclusive for maxi mum x and y values, as shown in Figure 4.1. The clipping window also specifies the area grBufferClear(), described in the last chapter, will clear. Figure 4.1 Specifying a clipping window. The clipping window is defined by two pairs of integers in the range [0..1024) specifying the left and right edges and the top and bottom edges of the rectangle. The grClipWindow() routine has four parameters that define the clipping rectangle. The values must be less than or equal to the current screen resolution and greater than or equal to 0; otherwise, they will be ignored. Glide does not perform any geometric clipping outside of supporting a hardware clipping window. For optimal performance, an application should perform proper geometric clipping before passing any primitives to Glide. The clipping window should not be used in place of true geometric clipping . void grClipWindow( int minX, int minY, int maxX, int maxY ) The default values for the clip window are the full size of the screen: (0,0,640,480) for 640´480 mode and (0,0,800,600) for 800´600 mode. To disable clipping, simply set the size of the clip window to the screen size. The Voodoo Graphics subsystem’s clipp ing window should not be used for general purpose primitive clipping; since clipped pixels are processed but discarded, proper geometric clipping should be done by the application for best performance. The Voodoo Graphics subsystem’s clip window should be used to prevent stray pixels that appear from imprecise geometric clipping. Note that if grLfbBypassMode() is enabled, clipping is not performed on linear frame buffer writes (see Chapter 11 for more information). Triangles The triangle is the basic Glide rendering primitive. The Glide function grDrawTriangle() renders an arbitrarily oriented triangle with vertices a, b, and c to the screen. void grDrawTriangle( const GrVertex *a, const GrVertex *b, const GrVertex *c ) Triangles are rendered with the following filling rules: zero area triangles render zero pixels pixels are rendered if and only if their center lies within the triangle A pixel center is within a triangle if it is inside all three of the edges. When a pixel center lies exactly on an edge, it is inside the triangle if the edge is considered inside, and outside otherwise. Left edges are in, right edges are out. Horizontal e dges with the smaller y value are in; those with a larger y value are out. Figure 4.2 gives an example. Eight triangles are shown, all sharing a common vertex. Only one of the triangles renders the pixel whose center is the shared vertex. Can you guess which one? The shared vertex is part of the “right edge” of triangles A, H, G, and F, and hence outside. It is part of the “top edge” (since the origin is in the lower left) of triangles G, F, E and D, and thus outside them as well. In triangle B, the vertex is on o ne inside edge and one outside edge and hence is considered outside the triangle. Only in triangle C does the vertex lie on two “inside” edges and thus lies inside the triangle. Clipping a Triangle Recall from the clipping window discussion above that the hardware clipping implemented by Voodoo Graphics is at the end of the rendering pipeline: a pixel will incur all the rendering cost only to be discarded just before being written to the frame buffe r. An alternative solution is to use host bandwidth to clip the triangle and process only the pixels that will be displayed. The Glide Utility Library provides just such a function. guDrawTriangleWithClip() uses Sutherland-Hodgman clipping [SUTH74] to cli p the triangle to the rectangle specified by grClipWindow() and then draws the resulting polygon. void guDrawTriangleWithClip( const GrVertex *a, const GrVertex *b, const GrVertex *c ) Figure 4.2 Pixel rendering. Which of the eight triangles shown in diagram (a) will render the pixel at the common vertex? In diagram (b), solid edges are considered inside the triangle while dotted edges are outside. The top row of diagrams are drawn with the origin in the lower left corner. The bottom row represent the other possibility: the origin is in the upper left corner. The two pairs of diagrams are mirror images of each other. Points The Glide function grDrawPoint() renders a single point to the screen. The point will be treated as a triangle with nearly coincident vertices (that is, a very small triangle) for rendering purposes. If many points will be rendered, noticeable performance improvement can be achieved by writing pixels directly to the frame buffer. (grDrawPoint() send three vertices per point to the hardware and iterates along three edges; only one linear frame buffer write per point is required.) void grDrawPoint( const GrVertex *a ) Example . A thousand points of light. This code fragment clears the screen to black and then draws a thousand random points. By default, the rendering buffer is set to GR_BUFFER_BACKBUFFER and the color buffer is writable. The color white is made by specifying maximal values for red, green, an d blue, and a quick way to do that is ~0. Some of the points will be clipped out: the random number generator selects point with coordinates in the range [0..1024); the screen resolution is less than that. By default, the clipping window is set to the scr een size. int n; GrVertex p; /* clear the back buffer to black */ grBufferClear(0, 0, 0); /* set color to white */ grColorCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_CONSTANT, GR_COMBINE_OTHER_NONE,FXFALSE ); grConstantColorValue(~0) /* generate and draw 1000 random points */ for (n=0; n<1000; n++) { p.x = (float) (rand() % 1024); p.y = (float) (rand() % 1024); grDrawPoint(p); } Lines The Glide function grDrawLine() renders an arbitrarily oriented line segment. Enabled special effects (e.g. fog, blending, chroma-key, dithering, etc.) will affect a line’s appearance. void grDrawLine( const GrVertex *a, const GrVertex *b ) Convex Polygons A polygon is a planar area enclosed by a closed loop of line segments, specified by their endpoints. While the Voodoo Graphics hardware does not render polygons directly, Glide provides a set of polygon rendering functions that are optimized for the hardwa re. The polygons rendered by the Glide functions are subject to some strong restrictions: The edges of the polygon cannot intersect. The polygon must be convex, that is, have no indentations. (The glossary at the end of this manual gives a precise definition of convexity.) shows some examples of both valid and invalid polygons. Figure 4.3 Polygons. The convex polygons rendered by Glide are assumed to be planar in coordinate space. Two polygon rendering routines (grDrawPlanarPolygon() and grDrawPlanarPolygonVertexList()) requires that the rendering parameters (r, g, b, a, ooz, oow, sow, tow) be pla nar as well. None of the polygon rendering functions do any geometric clipping. void grDrawPlanarPolygon( int nVerts, int ilist[], const GrVertex vlist[] ) void grDrawPolygon( int nVerts, int ilist[], const GrVertex vlist[] ) grDrawPlanarPolygon() and grDrawPolygon() both render a convex polygon with nVerts vertices. The second argument, ilist, is an array of indices into the list of vertices provided in the third argument. This level of indirection in specifying vertices is useful if you need to pre-process the list to do geometric clipping or hidden surface removal. The preprocessor can create the ilist for you rather than copying selected vertices to a new list. grDrawPlanarPolygon() assumes that the vertex parameters for the polygon are planar. Parameter gradients will be calculated only once for the entire polygon, thus reduce the number of calculations significantly. Another pair polygon rendering functions defined in Glide, grDrawPlanarPolygonVertexList() and grDrawPolygonVertexList(), are functionally equivalent to grDrawPlanarPolygon () and grDrawPolygon() respectively. The difference between the two pairs of ro utines is the way the vertices are specified. void grDrawPlanarPolygonVertexList( int nVerts, const GrVertex vlist[] ) void grDrawPolygonVertexList( int nVerts, const GrVertex vlist[] ) There is no level of indirection in grDrawPlanarPolygonVertexList() and grDrawPolygonVertexList(). The ith vertex of the polygon passed to these routines is vlist[i], assuming that 0£i