OpenGL Distilled
5.5. Debugging
Several things can cause reading, drawing, and copying of pixels to produce incorrect results. 5.5.1. Incorrect Raster Position
Many problems with glDrawPixels() and glCopyPixels() stem from a misunderstanding of how OpenGL transforms the raster position. Keep in mind that OpenGL transforms the raster position just as though it were transforming a vertex. To visualize the current raster position, render a single point primitive at the same xyz location as passed to glRasterPos3f(). OpenGL renders the point at the current raster position. If the point doesn't render, either the raster position is invalid, or the point is obscured in z. Keep this in mind to avoid raster position issues in 3D. For 2D rendering, the best way to avoid problems is to use glWindowPos2i() to specify the raster position. Using glRasterPos*() means you must establish a 2D transformation pipeline. If your application mixes 2D and 3D rendering, it must change the transformation pipeline twice each frame. glWindowPos*() eliminates this issue. If your underlying OpenGL implementation is version 1.4 or later, use the glWindowPos*() commands. 5.5.2. Clipped Raster Position
OpenGL clips entire pixel rectangles rendered with the glDrawPixels() command when only the raster position is invalid and outside the view volume. This appears incorrect to new OpenGL programmers when clipped at the left or bottom of the view volume, because intuitively, some of the pixel rectangle should still be visible in that case. See Figures 5-2 and 5-3 for an illustration of this behavior. Check for an invalid raster position by calling glGetBooleanv(). If you know that the raster position will always be valid (or should be valid, if your code is bug free), use an assert(), as shown in the following code: GLboolean valid; glGetBooleanv( GL_CURRENT_RASTER_POSITION_VALID, &valid ); assert( valid ); If you know the raster position is clipped on the left or bottom, use glBitmap() to shift the raster position as described in the section "Handling Clipped Raster Positions" earlier in this chapter. As long as your code sets a valid raster position using glRasterPos*() or glWindowPos*(), you can shift it with glBitmap() as much as necessary, and it will still be valid. 5.5.3. Texture or Fog Enabled
You should disable texture and fog before using the glDrawPixels() and glCopyPixels() commands. The current raster position picks up the current texture coordinates, and if texture mapping is enabled, OpenGL looks up a texture color value and applies it to your pixel rectangle. This behavior is almost never desired by programmers. In the same way, the raster position has a distance from the eye that OpenGL uses to determine a fog color when GL_FOG is enabled. In this case, OpenGL applies the fog color to your pixel rectangle. Disable texturing and fog with the following general-purpose code: GLint maxTex; glGetIntegerv( GL_MAX_TEXTURE_UNITS, &maxTex ); int idx; for (idx=0; idx<maxTex; idx++) { glActiveTexture( GL_TEXTURE0+idx ); glDisable( GL_TEXTURE_1D ); glDisable( GL_TEXTURE_2D ); glDisable( GL_TEXTURE_3D ); // version 1.2 and higher glDisable( GL_TEXTURE_CUBE_MAP ); // version 1.3 and higher } glDisable( GL_FOG ); You should optimize this code to disable only the states that your application has enabled. Note that the above code assumes that both the development and runtime environments support OpenGL version 1.3 or later; see Chapter 7, "Extensions and Versions," for information on writing version-safe code. 5.5.4. Depth Test
When your application sets the raster position with glRasterPos*() or glWindowPos*(), OpenGL transforms the raster position into a 3D window coordinate with a depth value. When OpenGL rasterizes the subsequent pixel rectangle, it uses this depth value in the depth test and writes this value into the depth buffer for each pixel in the rectangle. Some applications require this behavior; others don't. If your application always requires glDrawPixels() commands to win the depth test, set the depth function to GL_ALWAYS or simply disable the depth test altogether: glDisable( GL_DEPTH_TEST ); 5.5.5. Pixel Data Alignment
By default, OpenGL requires that each row in a pixel rectangle start on a 4-byte boundary. Change this with the glPixelTransfer() command; see "glPixelTransfer" in OpenGL® Reference Manual for details. Applications commonly send pixel rectangles composed of RGBA unsigned byte data, and in this case, row alignment isn't a problem; each pixel fits into 4 bytes, so each row starts at a 4-byte boundary without padding. If your application sends RGB unsigned byte data, however, and pixel rows aren't a 4-byte multiple in length, you'll need to add padding so that all rows start on a 4-byte boundary. 5.5.6. Obscured Windows
When your application reads pixels from a partially or completely obscured window, OpenGL isn't required to return valid pixel data corresponding to the obscured region. This is true for glReadPixels(), as well as for the source regions of glCopyPixels() and glCopyTexImage2D() (described in the next chapter). This same caveat applies if the source region is outside the window. The ability of OpenGL to return valid pixel data for obscured windows varies from one window system to the next. For window systems that use backing store or compositing window system technology, obscured regions pose no problem. This issue is still prevalent, however, for many commonly available window systems today. Fortunately, some extensions to OpenGL make this less of an issue:
For more information on pbuffers, refer to platform-specific documentation, as described in Chapter 8, "Platform-Specific Interfaces." For more information on GL_EXT_framebuffer_object, visit the OpenGL Extension Registry Web site: http://oss.sgi.com/projects/ogl-sample/registry/. Also see Chapter 7, "Extensions and Versions." 5.5.7. Memory Allocation Issues
Behavior is undefined if the amount of memory pointed to by the data parameter to glDrawPixels() or glReadPixels() is insufficient to hold the pixel rectangle described by the width, height, format, and type parameters. This typically causes the application to crash, and the call stack implicates the glDrawPixels() or glReadPixels() function. Although the crash is inside the OpenGL implementation, the application's failure to allocate sufficient memory is the root cause. If you have not changed the default state values with glPixelTransfer(), you can easily compute the size of your pixel rectangle as follows:
These rules for calculating the size of data apply to both glDrawPixels() and glReadPixels(). For information on calculating the size of data for format and type other than shown above, see Chapter 8, "Drawing Pixels, Bitmaps, Fonts, and Images," of OpenGL® Programming Guide and Section 4.3, "Drawing, Reading, and Copying Pixels," of The OpenGL Graphics System. |
Категории