#include "exp004mouse.h" #include "exp004processhits.h" #include "exp004reshape.h" #include "set_ortho.h" #include "../view/exp004geometry.h" #include "../view/exp004state0.h" #include "../util/check_error.h" #include "../util/pick_convert.h" #include #include #include /* * A simple alias to make the code more readable. */ #define S exp004state0 void exp004mouse (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; /* * Convert the selection boundary from window coordinates to * world coordinates. */ glMatrixMode (GL_MODELVIEW); glLoadIdentity (); GLdouble model[16]; glGetDoublev (GL_MODELVIEW_MATRIX, model); GLdouble projection[16]; glGetDoublev (GL_PROJECTION_MATRIX, projection); GLint viewport[4]; glGetIntegerv (GL_VIEWPORT, viewport); check_error (__FILE__, __LINE__); GLdouble start_position[3]; gluUnProject (S.selection.x, viewport[3] - S.selection.y, 0, model, projection, viewport, &start_position[0], &start_position[1], &start_position[2]); check_error (__FILE__, __LINE__); GLdouble end_position[3]; gluUnProject (x, viewport[3] - y, 0, model, projection, viewport, &end_position[0], &end_position[1], &end_position[2]); check_error (__FILE__, __LINE__); S.zoom.active = true; S.zoom.coords[0] = fmin (start_position[0], end_position[0]); S.zoom.coords[1] = fmax (start_position[0], end_position[0]); S.zoom.coords[2] = fmin (start_position[1], end_position[1]); S.zoom.coords[3] = fmax (start_position[1], end_position[1]); exp004reshape (S.viewport.w, S.viewport.h); glutPostRedisplay (); } /* * 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]." */ exp004geometry (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]." */ exp004processhits (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; }