Back to July Calendar 

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.