//----------------------------------------------------------------------------- // pick() -- Perform for select/pick operation; returns the selected (picked) // graphic or zero(0) if nothing was selected. // // 1) When item == 0, returns nearest (by depth buffer) selected entry. // 2) When item < 0, returns furthest (by depth buffer) selected entry. // 3) When item > 0, returns the item'th selected entry or the first entry if // there are less than 'item' entries // 4) Returns zero(0) when there are no entries in the select buffer or if the // Graphic for the select ID is not found. //----------------------------------------------------------------------------- BasicGL::Graphic* GlutDisplay::pick(const int item) { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport); // make sure we are starting at 0, 0 int xm = 0, ym = 0; getMouse(&xm,&ym); int x = xm; int y = viewport[3] - ym; glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix(x, y, getPickWidth(), getPickHeight(), viewport); // Get our ortho parameters GLdouble oLeft(0), oRight(0), oBottom(0), oTop(0), oNear(0), oFar(0); getOrtho(oLeft, oRight, oBottom, oTop, oNear, oFar); glOrtho(oLeft, oRight, oBottom, oTop, oNear, oFar); glMatrixMode(GL_MODELVIEW); if (getDisplayOrientation() != NORMAL) { glPushMatrix(); if (getDisplayOrientation() == CW90) glRotated(-90.0, 0.0, 0.0, 1.0); else if (getDisplayOrientation() == CCW90) glRotated(90.0, 0.0, 0.0, 1.0); else glRotated(180.0, 0.0, 0.0, 1.0); } static const unsigned int MAX_BUFF_SIZE = 1024; GLuint sbuff[MAX_BUFF_SIZE]; clearSelectBuffer(sbuff,MAX_BUFF_SIZE); glSelectBuffer(MAX_BUFF_SIZE, sbuff); glRenderMode(GL_SELECT); glInitNames(); draw(); GLint hits = glRenderMode(GL_RENDER); if (getDisplayOrientation() != NORMAL) glPopMatrix(); Graphic* selected = findSelected(hits, sbuff, item); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); return selected; }
bool GraphicsManager::unproject(float x, float y, float &x1, float &y1, float &z1, float &x2, float &y2, float &z2) const { try { // Generate the inverse of the model matrix Common::TransformationMatrix model; float cPos[3]; float cOrient[3]; memcpy(cPos , CameraMan.getPosition (), 3 * sizeof(float)); memcpy(cOrient, CameraMan.getOrientation(), 3 * sizeof(float)); // Apply camera position model.translate(cPos[0], cPos[1], -cPos[2]); // Apply camera orientation model.rotate( cOrient[2], 0.0f, 0.0f, 1.0f); model.rotate(-cOrient[1], 0.0f, 1.0f, 0.0f); model.rotate( cOrient[0], 1.0f, 0.0f, 0.0f); // Multiply with the inverse of our projection matrix model *= _projectionInv; // Coordinates at the near and far clipping planes Common::Vector3 coordsNear, coordsFar; if (_projectType == kProjectTypePerspective) { /* With a perspective projection, the viewport runs from -1.0 to 0.0 * on the x and y axes, and the clipping planes are at 0.0 and 1.0. */ const float view[4] = { 0.0f, 0.0f, (float) _width, (float) _height }; const float zNear = 0.0f; const float zFar = 1.0f; coordsNear._x = ((2 * (x - view[0])) / (view[2])) - 1.0f; coordsNear._y = ((2 * (y - view[1])) / (view[3])) - 1.0f; coordsNear._z = (2 * zNear) - 1.0f; coordsNear._w = 1.0f; coordsFar._x = ((2 * (x - view[0])) / (view[2])) - 1.0f; coordsFar._y = ((2 * (y - view[1])) / (view[3])) - 1.0f; coordsFar._z = (2 * zFar) - 1.0f; coordsFar._w = 1.0f; } else if (_projectType == kProjectTypeOrthogonal) { /* With an orthogonal projection, the viewport runs from 0.0 to width * on the x axis and from 0.0 to height on the y axis (which already * matches the coordinates we were given), and the clipping planes are * at -clipNear and -clipFar. */ coordsNear._x = x; coordsNear._y = y; coordsNear._z = -_clipNear; coordsNear._w = 1.0f; coordsFar._x = x; coordsFar._y = y; coordsFar._z = -_clipFar; coordsFar._w = 1.0f; } // Unproject Common::Vector3 oNear(model * coordsNear); Common::Vector3 oFar (model * coordsFar ); if ((oNear._w == 0.0f) || (oFar._w == 0.0f)) return false; // TODO: check for close to 0.0f, not exactly 0.0f. // And return the values oNear._w = 1.0f / oNear._w; x1 = oNear._x * oNear._w; y1 = oNear._y * oNear._w; z1 = oNear._z * oNear._w; oFar._w = 1.0f / oFar._w; x2 = oFar._x * oFar._w; y2 = oFar._y * oFar._w; z2 = oFar._z * oFar._w; } catch (Common::Exception &e) { Common::printException(e, "WARNING: "); return false; } catch (...) { return false; } return true; }
bool GraphicsManager::unproject(float x, float y, float &x1, float &y1, float &z1, float &x2, float &y2, float &z2) const { try { // Generate the inverse of the model matrix Common::TransformationMatrix model; float cPos[3]; float cOrient[3]; CameraMan.lock(); memcpy(cPos , CameraMan.getPosition (), 3 * sizeof(float)); memcpy(cOrient, CameraMan.getOrientation(), 3 * sizeof(float)); CameraMan.unlock(); // Apply camera position model.translate(cPos[0], cPos[1], -cPos[2]); // Apply camera orientation model.rotate( cOrient[2], 0.0, 0.0, 1.0); model.rotate(-cOrient[1], 0.0, 1.0, 0.0); model.rotate( cOrient[0], 1.0, 0.0, 0.0); // Multiply with the inverse of our projection matrix model *= _projectionInv; // Viewport coordinates float view[4]; view[0] = 0.0; view[1] = 0.0; view[2] = _screen->w; view[3] = _screen->h; float zNear = 0.0; float zFar = 1.0; // Generate a matrix for the coordinates at the near plane Common::Matrix coordsNear(4, 1); coordsNear(0, 0) = ((2 * (x - view[0])) / (view[2])) - 1.0; coordsNear(1, 0) = ((2 * (y - view[1])) / (view[3])) - 1.0; coordsNear(2, 0) = (2 * zNear) - 1.0; coordsNear(3, 0) = 1.0; // Generate a matrix for the coordinates at the far plane Common::Matrix coordsFar(4, 1); coordsFar(0, 0) = ((2 * (x - view[0])) / (view[2])) - 1.0; coordsFar(1, 0) = ((2 * (y - view[1])) / (view[3])) - 1.0; coordsFar(2, 0) = (2 * zFar) - 1.0; coordsFar(3, 0) = 1.0; // Unproject Common::Matrix oNear(model * coordsNear); Common::Matrix oFar (model * coordsFar ); if ((oNear(3, 0) == 0.0) || (oNear(3, 0) == 0.0)) return false; // And return the values oNear(3, 0) = 1.0 / oNear(3, 0); x1 = oNear(0, 0) * oNear(3, 0); y1 = oNear(1, 0) * oNear(3, 0); z1 = oNear(2, 0) * oNear(3, 0); oFar(3, 0) = 1.0 / oFar(3, 0); x2 = oFar(0, 0) * oFar(3, 0); y2 = oFar(1, 0) * oFar(3, 0); z2 = oFar(2, 0) * oFar(3, 0); } catch (Common::Exception &e) { Common::printException(e, "WARNING: "); return false; } catch (...) { return false; } return true; }