#include "viewer.h" #include "MotionCapturer.h" void get_world_coordinates( double winx, double winy, double winz, double &worldx, double &worldy, double &worldz ) { double mvmatrix[16], projmatrix[16]; int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); gluUnProject( winx, winy, winz, mvmatrix, projmatrix, viewport, &worldx, &worldy, &worldz ); } // returns 0 if the point is a valid intersection // returns 1 if the line lies in the plane // returns -1 if the line is parallel to the plane int intersect_plane( double plane[4], // ax+by+cz+d=0 int winx, int winy, double pt[3] ) { // taken from the comp.graphics.algorithms FAQ double x1, y1, z1; GLint viewport[4]; double x2, y2, z2; // end-points of the line double a = plane[0], b = plane[1], c = plane[2], d = plane[3]; double wx = (double)winx; glGetIntegerv(GL_VIEWPORT, viewport); double wy = (double)( viewport[3]-winy ); // get the two points on this line get_world_coordinates( wx, wy, 0, x1, y1, z1 ); get_world_coordinates( wx, wy, 1, x2, y2, z2 ); double i = (x2-x1); double j = (y2-y1); double k = (z2-z1); double t; if ( a*i+b*j+c*k == 0 ) { if ( a*x1+b*y1+c*z1+d == 0 ) { // line lies in plane pt[X] = (x1+x2)/2; pt[Y] = (y1+y2)/2; pt[Z] = (z1+z2)/2; return 1; } else { // line is parallel to plane return -1; } } t = - (a*x1 + b*y1 + c*z1 + d)/(a*i + b*j + c*k); pt[X] = x1 + i * t; pt[Y] = y1 + j * t; pt[Z] = z1 + k * t; return 0; } // notice that this doesn't reset the projection! // it must be that way so that picking can use it void Gl_Win::drawSetupTransform() { glEnable( GL_DEPTH_TEST ); // compute the aspect ratio so we don't distort things double aspect = ((double) w) / ((double) h); gluPerspective(fieldOfView, aspect, 1, 1000); // set up the drawing transforms glViewport(0,0,w,h); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(eye[X], eye[Y], eye[Z], look[X], look[Y], look[Z], 0,1,0); } /* returns the top Node that was clicked, if hit train and another Node, the one beneath train is returned. returns NULL if no hit. */ Node* Gl_Win::clickInNode( int mouseDownX, int mouseDownY) { GLuint selectedName = 0; // name of the selected Node Node *hitNode = NULL; if (cap == NULL) return NULL; glMatrixMode(GL_PROJECTION); // set up special coordinate system glPushMatrix(); make_current(); // so we're drawing in our window // set up a special coordinate system centered at the mouse // remember, FlTk and Gl have opposite Y directions glLoadIdentity(); // we need the size of the OpenGL window, in its own terms int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); gluPickMatrix((double)mouseDownX, (double)(viewport[3]-mouseDownY), 5, 5, viewport); // set up for picking - make a place to put the results drawSetupTransform(); // so object appear in right place GLuint buf[100]; glSelectBuffer(100,buf); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); // now draw (but nothing is really drawn); drawObjs(false, false, cur_time ); // go back to drawing mode, and see how picking did int hits = glRenderMode(GL_RENDER); selectedName = 0; glPopMatrix(); // all we care about is the last hit if (hits) { selectedName = buf[(hits-1)*4+3]; if ( hits > 1 && (selectedName == cap->pickname_cur - 1) ) { // hack fix for the last drawn joint getting unintentionally selected at times. selectedName = buf[(hits-2)*4+3]; printf("\ncaught ya! avoid sel %s\n", cap->pickarr[selectedName]->name); } hitNode = cap->pickarr[ selectedName ]; printf("hit Node %s \n", hitNode->name); } return hitNode; }