←Previous Entry Next Entry→ August 13, 2005
Saturday the 13th. Nothing better to do than twiddle over the OpenGL code, huh?
Yesterday's code is still mysterious, no? I fixed the flicker by using double buffering, but I still don't see where the "blue rectangle" and "red rectangle" messages are supposed to appear. In fact, they don't appear. Why not? Drop me a note if you figure this out.
Too late, I already done dug the bug. The Angel OpenGL Primer text has quite a few errors here. Maybe the editor's text was replaced by the raw text? It's been known to happen (see last few presidential state addresses.) The oddest error was the use of glLoadName() instead of glPushName(). The color scheme in the following code is different than what I've used before because I saved it in DEVCPP and then exported it to html from there. That's easier than editing the whole thing entirely.
// Based on code from OpenGl Primer by Edward Angel
#include <GL/glut.h>
#include <math.h>
#include <iostream>
#define NULL 0
int doubleb; //window ids //singleb,
//prototypes
void display();
void mouse(int, int, int, int);
void keyIt(unsigned char, int, int);
void reshapeIt(int, int);
void display();
void quit_menu(int);
void drawObjects(GLenum);
void processHits(GLuint, GLuint[]);
////////////////////////////////////////
int main(int argc, char** argv) {
glutInit(&argc, argv);
//create a double buffered window
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
doubleb = glutCreateWindow("double buffered");
glutDisplayFunc(display);
glutReshapeFunc(reshapeIt);
glutIdleFunc(display);
glutMouseFunc(mouse);
//Enter event loop
glutMainLoop();
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
drawObjects(GL_RENDER);
glutSwapBuffers();
}
void drawObjects(GLenum mode) {
if(mode == GL_SELECT) glPushName(1);
glColor3f(1.0,0.0,0.0); //red
glRectf(-0.5,-0.5,1.0,1.0);
if(mode == GL_SELECT) glPushName(2);
glColor3f(0.0,0.0,1.0); //blue
glRectf(-1.0,-1.0,0.5,0.5);
}
/////HERE COME DA MOUSE
#define SIZE 500
#define N 3
void mouse(int btn, int state, int x, int y) {
GLuint nameBuffer[SIZE];
//When a scene is rendered in selection mode
//each primitive in the clipping volume generates
//a message called a hit, which is stored in a
//buffer called the name stack.
GLuint hits;
GLint viewport[4];
if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
//initialize the name stack
glInitNames();
glPushName(0);
//identify array for the selection data
glSelectBuffer(SIZE, nameBuffer);
//set up viewing for selection mode
//The viewport array will contain
//0: X origin of viewport
//1: Y origin of viewport
//2: X size of viewport and
//3: Y size of viewport
glGetIntegerv(GL_VIEWPORT, viewport);
glMatrixMode(GL_PROJECTION);
//save original viewing matrix
glPushMatrix();
glLoadIdentity();
// NXN pick area around cursor
// need to invert mouse y to get world coordinates
// By examining the selection buffer, you can see which objects were clicked
gluPickMatrix((GLdouble) x,
(GLdouble) (viewport[3] - y),
N, N, viewport);
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glRenderMode(GL_SELECT);
drawObjects(GL_SELECT);
glMatrixMode(GL_PROJECTION);
//restore viewing matrix
glPopMatrix();
//return to normal render mode
// and return the number of hits in selection
// mode.
hits = glRenderMode(GL_RENDER);
//printf("hits =%d\n",hits);
//process hits from selection mode rendering
processHits(hits, nameBuffer);
//normal render
}
}
void processHits(GLuint hits, GLuint buffer[]) {
GLuint i, j;//unsigned
GLuint names, *ptr;
printf ("hits = %d\n", hits);
ptr = (GLuint *) buffer;
//printf ("ptr = %d\n", ptr);
//loop over number of hits
for(i=0; i<hits; i++) {
names = *ptr;
printf("names = %d\n", *ptr);
//skip over number of names and depths
ptr += 3;
// check each name in record
for (j=0; j<names; j++) {
if(*ptr == 1) printf("red rectangle\n");
else printf("blue rectangle\n");
// go to next hit record
ptr++;
}
}
}
void reshapeIt(int w, int h) {
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0,2.0,-2.0,2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
The screen capture at right shows what happens when you click outside the red and black rectangles: you get a report that you didn't hit anything (twice.) Left button clicking inside the the red rectangle leads to the report of 1 hit, which put 1 in the names buffer which then leads to the report of the red rectangle being hit (twice.) Clicking on the overlapping region (where the red rectangle is behind the blue rectangle) leads to a report of 2 hits and two ids are pushed on the names stack: uh, "1" and "2," huh? For some reason the report of a blue rectangle is always accompanied by the report of a red rectangle, even if only the blue rectangle is hit. Hmmm.