I've written a small example program using OpenGL and GLUT to display a 2-by-2 grid of four colored squares using the glDrawPixels
function. Unfortunately, I've found that:
- The colors in the grid are not being displayed properly; and
- When the glPixelZoom function is passed negative arguments to rotate the pixmap, nothing is displayed in the window.
The following C++ code snippet displays the example image. What am I doing wrong here, and what should I change to be able to view the intended colors and rotate the pixmap?
struct RGB
{
unsigned char r, g, b;
};
class Pixmap
{
public:
RGB color[4];
Pixmap()
{
color[0].r = 255;
color[0].g = 0;
color[0].b = 0;
color[1].r = 0;
color[1].g = 255;
color[1].b = 0;
color[2].r = 0;
color[2].g = 0;
color[2].b = 255;
color[3].r = 255;
color[3].g = 255;
color[3].b = 255;
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels( 2, 2, GL_RGB, GL_UNSIGNED_BYTE, color );
glFlush();
}
};开发者_Python百科
// Create an instance of class Pixmap
Pixmap myPixmap;
void myRender()
{
myPixmap.render();
}
int main( int argc, char *argv[] )
{
int screenWidth, screenHeight;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
screenWidth = glutGet(GLUT_SCREEN_WIDTH);
screenHeight = glutGet(GLUT_SCREEN_HEIGHT);
int windowWidth = screenHeight / 2;
int windowHeight = screenHeight / 2;
glutInitWindowSize(windowWidth, windowHeight);
int posX = (screenWidth - windowWidth) / 2;
int posY = (screenHeight - windowHeight) / 4;
glutInitWindowPosition(posX, posY);
glutCreateWindow("Picture");
GLfloat scaleX = 1.0f * windowWidth / 2;
GLfloat scaleY = 1.0f * windowHeight / 2;
glMatrixMode( GL_PROJECTION );
// If glPixelZoom(-scaleX, scaleY)
// then no image is displayed
glPixelZoom(scaleX, scaleY);
glClearColor(1.0, 1.0, 1.0, 0.0);
glColor3f(0.0f, 0.0f, 0.0f);
glutDisplayFunc( myRender );
glutMainLoop();
}
After some experimentation, I think that I've found a solution that appears to be suitable for my own purposes. First, given the example code in my question above, it appears that the pixmap needs to be passed to the glDrawPixels
function as an array GLubyte color[2][2][4]
with an alpha channel. As mentioned by Vaayu, there is also a possibility that the glMatrixMode
function needs to be set up correctly. Second, according to pg. 356 of the OpenGL Programming Guide (7th Edition), the current raster position needs to be set if the glPixelZoom
function is called with negative arguments. Essentially why I couldn't see an image was due to the raster being drawn at a position not within the viewable area of the window. The following code demonstrates how to set the rotation and the current raster position for four separate cases:
// case 0
glWindowPos2i(0, 0);
glPixelZoom(scaleX, scaleY);
// case 1
glWindowPos2i(windowHeight, 0);
glPixelZoom(-scaleX, scaleY);
// case 2
glWindowPos2i(0, windowHeight);
glPixelZoom(scaleX, -scaleY);
// case 3
glWindowPos2i(windowWidth, windowHeight);
glPixelZoom(-scaleX, -scaleY);
So the example given in my original question can be updated:
class Pixmap { public: GLubyte color[2][2][4]; Pixmap() { // red color[0][0][0] = 255; color[0][0][1] = 0; color[0][0][2] = 0; color[0][0][3] = 0; // green color[0][1][0] = 0; color[0][1][1] = 255; color[0][1][2] = 0; color[0][1][3] = 0; // blue color[1][0][0] = 0; color[1][0][1] = 0; color[1][0][2] = 255; color[1][0][3] = 0; // white color[1][1][0] = 255; color[1][1][1] = 255; color[1][1][2] = 255; color[1][1][3] = 0; } void render() { glClear(GL_COLOR_BUFFER_BIT); glDrawPixels( 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, color ); glFlush(); } }; // Create an instance of class Pixmap Pixmap myPixmap; void myRender() { myPixmap.render(); } int main( int argc, char *argv[] ) { int screenWidth, screenHeight; int rotation; // Choose rotation case {0, 1, 2, 3} rotation = 3; glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); screenWidth = glutGet(GLUT_SCREEN_WIDTH); screenHeight = glutGet(GLUT_SCREEN_HEIGHT); int windowWidth = screenHeight / 2; int windowHeight = screenHeight / 2; glutInitWindowSize(windowWidth, windowHeight); int posX = (screenWidth - windowWidth) / 2; int posY = (screenHeight - windowHeight) / 4; glutInitWindowPosition(posX, posY); glutCreateWindow("Picture"); GLfloat scaleX = 1.0f * windowWidth / 2; GLfloat scaleY = 1.0f * windowHeight / 2; glMatrixMode(GL_MODELVIEW); // Select rotation switch(rotation) { case 0: glWindowPos2i(0, 0); glPixelZoom(scaleX, scaleY); break; case 1: glWindowPos2i(windowHeight, 0); glPixelZoom(-scaleX, scaleY); break; case 2: glWindowPos2i(0, windowHeight); glPixelZoom(scaleX, -scaleY); break; case 3: glWindowPos2i(windowWidth, windowHeight); glPixelZoom(-scaleX, -scaleY); break; default: break; } glClearColor(1.0, 1.0, 1.0, 0.0); glColor3f(0.0f, 0.0f, 0.0f); glutDisplayFunc( myRender ); glutMainLoop(); }
glMatrixMode( GL_PROJECTION );
The above line is the one causing problems. Change it to "glMatrixMode(GL_MODELVIEW);" since you are not really using the projection matrix for anything.
The projection matrix is used to set the projection parameters like perspective/orthographic mode, FOV etc. This needs to be done usually at time of creation of window and whenever the window/viewport size changes. The the modelview matrix is used for translations, rotations and scaling.
Due to the way OpenGL works, its very important to keep track of the "state". The general workflow is to set the projection mode, change the parameters as desired and change back to modelview mode immediately, like:
glMatrixMode(GL_PROJECTION);
//...
//do various projection stuff
//...
glMatrixMode(GL_MODELVIEW);
This applies to many things in OpenGL, not just matrix state but other things like lights, blending etc etc too. Its very common to have a "default" state to return to after doing a set of operations before doing another set of operations and again switching back to default state.
精彩评论