36 files changed, 332 insertions, 176 deletions
diff --git a/src/controller/callbacks/mouse.c b/src/controller/callbacks/mouse.c new file mode 100644 index 0000000..fc48eff --- a/dev/null +++ b/src/controller/callbacks/mouse.c @@ -0,0 +1,127 @@ +#include "../../util/check_error.h" +#include "../../util/pick_convert.h" +#include "../../view/exp004geometry.h" +#include "../../view/exp004state0.h" +#include "../actions/process_hits.h" +#include "../actions/set_ortho.h" +#include "../actions/zoom.h" +#include "mouse.h" +#include "reshape.h" +#include <GL/glut.h> +#include <math.h> +#include <stdlib.h> + +/* + * A simple alias to make the code more readable. + */ +#define S exp004state0 + +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]." + */ + 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]." */ + 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; +} |