#include "../../util/check_error.h" #include "../../util/pick_convert.h" #include "../../view/geometry.h" #include "../../view/state0.h" #include "../actions/process_hits.h" #include "../actions/set_ortho.h" #include "../actions/zoom.h" #include "mouse.h" #include "reshape.h" #include #include #include /* * A simple alias to make the code more readable. */ #define S state0 void mouse (int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { if (S.selection.active && S.selection.purpose == ZOOM) { /* * NOOP if the mouse was not moved. */ if (x == S.selection.x || y == S.selection.y) return; GLint viewport[4]; glGetIntegerv (GL_VIEWPORT, viewport); zoom (S.selection.x, viewport[3] - S.selection.y, x, viewport[3] - y); } /* * Complete a selection if one was started and not cancelled. */ if (S.selection.active && S.selection.purpose == SET) { /* * "Specify the array to be used for the returned hit records * with glSelectBuffer () [Redbook]." */ GLuint *select_buf = calloc (S.rows, sizeof (GLuint)); glSelectBuffer (S.rows, select_buf); /* * "Enter selection mode by specifying GL_SELECT with * glRenderMode () [Redbook]." */ glRenderMode (GL_SELECT); /* * "Initialize the name stack using glInitNames () and glPush * Names () [Redbook]." */ glInitNames (); glPushName (0); /* * "Define the viewing volume you want to use for selection. * Usually this is different from the viewing volume you * originally used to draw the scene, so you probably want to * save and then restore the current transformation state with * glPushMatrix () and glPopMatrix () [Redbook]." */ glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity (); GLint viewport[4]; glGetIntegerv (GL_VIEWPORT, viewport); double c_x = 0.0; double c_y = 0.0; double w = 0.0; double h = 0.0; pick_convert (S.selection.x, S.selection.y, x, y, &c_x, &c_y, &w, &h); gluPickMatrix (c_x, (GLdouble) viewport[3] - c_y, w, h, viewport); set_ortho (); /* * "Alternately issue primitive drawing commands and commands to * manipulate the name stack so that each primitive of interest * has appropriate names assigned [Redbook]." */ geometry (GL_SELECT); glMatrixMode (GL_PROJECTION); glPopMatrix (); glutSwapBuffers (); /* * "Exit selection mode and process the returned selection data * (the hit records) [Redbook]." */ GLint hits = glRenderMode (GL_RENDER); check_error (__FILE__, __LINE__); /* "process hits from selection mode rendering [Angel,2008]." */ process_hits (hits, select_buf); /* "normal render [Angel,2008]." */ glutPostRedisplay (); } } if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { S.selection.active = true; S.selection.x = x; S.selection.y = y; } return; }