//============================================================================= // // OpenFlipper // Copyright (C) 2008 by Computer Graphics Group, RWTH Aachen // www.openflipper.org // //----------------------------------------------------------------------------- // // License // // OpenFlipper is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // OpenFlipper is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenFlipper. If not, see . // //----------------------------------------------------------------------------- // // $Revision$ // $Author$ // $Date$ // //============================================================================= //============================================================================= // // CLASS glViewer - IMPLEMENTATION // //============================================================================= //== INCLUDES ================================================================= #include "QtBaseViewer.hh" #include "QtGLGraphicsScene.hh" #include "QtGLGraphicsView.hh" //== NAMESPACES =============================================================== //== IMPLEMENTATION ========================================================== static const unsigned int SELECTION_BUFFER_SIZE = 10000; static const unsigned int NAME_STACK_SIZE = 2; //== IMPLEMENTATION ========================================================== bool glViewer::pick( ACG::SceneGraph::PickTarget _pickTarget, const QPoint& _mousePos, unsigned int& _nodeIdx, unsigned int& _targetIdx, ACG::Vec3d* _hitPointPtr ) { if (sceneGraphRoot_) { // unsigned int node, target; // QTime time; // time.start (); int rv = pickColor (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr); // printf ("ColorPicking took %d msec\n",time.restart ()); // rv = -1; // node = _nodeIdx; // target = _targetIdx; if (rv < 0) rv = pickGL (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr); // printf ("GLPicking took %d msec\n",time.restart ()); // if (rv > 0 && (node != _nodeIdx || target != _targetIdx)) // printf ("***** Picking difference Color %d/%d GL %d/%d\n",node, target, _nodeIdx, _targetIdx); if (rv > 0) return rv; } return false; } //----------------------------------------------------------------------------- int glViewer::pickColor( ACG::SceneGraph::PickTarget _pickTarget, const QPoint& _mousePos, unsigned int& _nodeIdx, unsigned int& _targetIdx, ACG::Vec3d* _hitPointPtr ) { GLint w = glWidth(), h = glHeight(), l = scenePos().x(), b = scene()->height () - scenePos().y() - h, x = _mousePos.x(), y = scene()->height () - _mousePos.y(); GLubyte pixels[9][3]; GLfloat depths[9]; int hit = -1; unsigned char order[9] = { 4, 7, 1, 3, 5, 0, 2, 6, 8 }; const ACG::GLMatrixd& modelview = properties_.glState().modelview(); const ACG::GLMatrixd& projection = properties_.glState().projection(); ACG::Vec4f clear_color = properties_.glState().clear_color(); properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0)); // prepare GL state makeCurrent(); glViewport (l, b, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMultMatrixd(projection.get_raw_data()); glMatrixMode(GL_MODELVIEW); glLoadMatrixd(modelview.get_raw_data()); glDisable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); properties_.glState().pick_init (true); // do the picking ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode()); ACG::SceneGraph::traverse(sceneGraphRoot_, action); // restore GL state glMatrixMode( GL_PROJECTION ); glLoadMatrixd(projection.get_raw_data()); glMatrixMode( GL_MODELVIEW ); glLoadMatrixd(modelview.get_raw_data()); glEnable(GL_LIGHTING); properties_.glState().set_clear_color (clear_color); if (properties_.glState().pick_error ()) return -1; glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glReadPixels (x - 1, y - 1, 3, 3, GL_RGB, GL_UNSIGNED_BYTE, pixels); glReadPixels (x - 1, y - 1, 3, 3, GL_DEPTH_COMPONENT, GL_FLOAT, depths); for (int i = 0; i < 9; i++) { if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0)) { hit = order[i]; break; } } if (hit < 0) return 0; ACG::Vec3uc rgb; rgb[0] = pixels[hit][0]; rgb[1] = pixels[hit][1]; rgb[2] = pixels[hit][2]; std::vector rv = properties_.glState().pick_color_to_stack (rgb); // something wrong with the color stack ? if (rv.size () < 2) return -1; _nodeIdx = rv[1]; _targetIdx = rv[0]; if (_hitPointPtr) { *_hitPointPtr = properties_.glState().unproject(ACG::Vec3d(x,y,depths[hit])); } return 1; } //----------------------------------------------------------------------------- bool glViewer::pickGL( ACG::SceneGraph::PickTarget _pickTarget, const QPoint& _mousePos, unsigned int& _nodeIdx, unsigned int& _targetIdx, ACG::Vec3d* _hitPointPtr ) { GLint w = glWidth(), h = glHeight(), l = scenePos().x(), b = scene()->height () - scenePos().y() - h, x = _mousePos.x(), y = scene()->height () - _mousePos.y(); GLint viewport[4] = {l,b,w,h}; GLuint selectionBuffer[ SELECTION_BUFFER_SIZE ], nameBuffer[ NAME_STACK_SIZE ]; const ACG::GLMatrixd& modelview = properties_.glState().modelview(); const ACG::GLMatrixd& projection = properties_.glState().projection(); // prepare GL state makeCurrent(); glSelectBuffer( SELECTION_BUFFER_SIZE, selectionBuffer ); glRenderMode(GL_SELECT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPickMatrix((GLdouble) x, (GLdouble) y, 3, 3, viewport); glMultMatrixd(projection.get_raw_data()); glMatrixMode(GL_MODELVIEW); glLoadMatrixd(modelview.get_raw_data()); glDisable(GL_LIGHTING); glClear(GL_DEPTH_BUFFER_BIT); properties_.glState().pick_init (false); // do the picking ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode()); ACG::SceneGraph::traverse(sceneGraphRoot_, action); int hits = glRenderMode(GL_RENDER); // restore GL state glMatrixMode( GL_PROJECTION ); glLoadMatrixd(projection.get_raw_data()); glMatrixMode( GL_MODELVIEW ); glLoadMatrixd(modelview.get_raw_data()); glEnable(GL_LIGHTING); // process hit record if ( hits > 0 ) { GLuint *ptr = selectionBuffer, num_names, z, min_z=~(0u), max_z=0; for (int i=0; i >& _list) { GLint w = glWidth(), h = glHeight(), l = scenePos().x(), b = scene()->height () - scenePos().y() - h; GLubyte* buffer; QRect rect = _region.boundingRect(); const ACG::GLMatrixd& modelview = properties_.glState().modelview(); const ACG::GLMatrixd& projection = properties_.glState().projection(); ACG::Vec4f clear_color = properties_.glState().clear_color(); properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0)); // prepare GL state makeCurrent(); glViewport (l, b, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMultMatrixd(projection.get_raw_data()); glMatrixMode(GL_MODELVIEW); glLoadMatrixd(modelview.get_raw_data()); glDisable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); properties_.glState().pick_init (true); // do the picking ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode()); ACG::SceneGraph::traverse(sceneGraphRoot_, action); // restore GL state glMatrixMode( GL_PROJECTION ); glLoadMatrixd(projection.get_raw_data()); glMatrixMode( GL_MODELVIEW ); glLoadMatrixd(modelview.get_raw_data()); glEnable(GL_LIGHTING); properties_.glState().set_clear_color (clear_color); if (properties_.glState().pick_error ()) return false; buffer = new GLubyte[3 * rect.width() * rect.height()]; glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glReadPixels (rect.x(), scene()->height () - rect.bottom() , rect.width(), rect.height(), GL_RGB, GL_UNSIGNED_BYTE, buffer); QSet > found; for (int y = 0; y < rect.height (); y++) for (int x = 0; x < rect.width (); x++) { if (_region.contains (QPoint (rect.x() + x, rect.y() + y))) { int bPos = (((rect.height () - (y + 1)) * rect.width ()) + x) * 3; if (buffer[bPos + 2] != 0 || buffer[bPos + 1] != 0 || buffer[bPos] != 0) { ACG::Vec3uc rgb; rgb[0] = buffer[bPos]; rgb[1] = buffer[bPos + 1]; rgb[2] = buffer[bPos + 2]; std::vector rv = properties_.glState().pick_color_to_stack (rgb); if (rv.size () < 2) continue; found << QPair(rv[1], rv[0]); } } } delete buffer; _list = found.toList(); return true; } //----------------------------------------------------------------------------- bool glViewer:: fast_pick( const QPoint& _mousePos, ACG::Vec3d& _hitPoint ) { // get x,y,z values of pixel GLint x(_mousePos.x()), y(glHeight() - _mousePos.y()); GLfloat z; makeCurrent(); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z); if (z < 0.99999) { _hitPoint = properties_.glState().unproject( ACG::Vec3d(x, y, z) ); return true; } else return false; } //============================================================================= //=============================================================================