Developer Documentation
QtBaseViewerPicking.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 
46 //=============================================================================
47 //
48 // CLASS QtBaseViewer - IMPLEMENTATION
49 //
50 //=============================================================================
51 
52 
53 //== INCLUDES =================================================================
54 #include <ACG/GL/acg_glew.hh>
55 #include "QtBaseViewer.hh"
56 #include "QtGLGraphicsScene.hh"
57 #include "QtGLGraphicsView.hh"
58 
59 #include "../GL/GLState.hh"
60 #include "../Scenegraph/SceneGraph.hh"
61 
62 //== NAMESPACES ===============================================================
63 
64 namespace ACG {
65 namespace QtWidgets {
66 
67 //== IMPLEMENTATION ==========================================================
68 
69 static const unsigned int SELECTION_BUFFER_SIZE = 10000;
70 static const unsigned int NAME_STACK_SIZE = 2;
71 
72 //== IMPLEMENTATION ==========================================================
73 
74 
75 void QtBaseViewer::renderPicking(bool _renderPicking, ACG::SceneGraph::PickTarget _mode) {
76  renderPicking_ = _renderPicking;
77  pickRendererMode_ = _mode;
78 }
79 
80 //-----------------------------------------------------------------------------
81 
82 
84  const QPoint& _mousePos,
85  unsigned int& _nodeIdx,
86  unsigned int& _targetIdx,
87  Vec3d* _hitPointPtr )
88 {
89  if (sceneGraphRoot_)
90  {
91  GLint w = glWidth(),
92  h = glHeight(),
93  x = _mousePos.x(),
94  y = h - _mousePos.y();
95  GLint viewport[4] = {0,0,w,h};
96  GLuint nameBuffer[ NAME_STACK_SIZE ];
97 
98  // reduce stack usage
99  std::vector<GLuint> selectionBuffer(SELECTION_BUFFER_SIZE);
100 
101 
102  // Initialize name buffer
103  nameBuffer[0] = 0;
104  nameBuffer[1] = 0;
105 
106  const GLMatrixd& modelview = glstate_->modelview();
107  const GLMatrixd& projection = glstate_->projection();
108 
109 
110  // prepare GL state
111  makeCurrent();
112 
113  glSelectBuffer( SELECTION_BUFFER_SIZE, &selectionBuffer[0] );
114  glRenderMode(GL_SELECT);
115  glMatrixMode(GL_PROJECTION);
116  glLoadIdentity();
117 // gluPickMatrix((GLdouble) x, (GLdouble) y, 3, 3, viewport);
118  // gluPickMatrix implementation as in mesa3d
119  // Translate and scale the picked region to the entire window
120  const float deltax = 3.0f, deltay = 3.0f;
121  glTranslatef(float(viewport[2] - 2 * (x - viewport[0])) / deltax,
122  float(viewport[3] - 2 * (y - viewport[1])) / deltay, 0.0f);
123  glScalef(viewport[2] / deltax, viewport[3] / deltay, 1.0);
124 
125  glMultMatrixd(projection.get_raw_data());
126  glMatrixMode(GL_MODELVIEW);
127  glLoadMatrixd(modelview.get_raw_data());
128  ACG::GLState::disable(GL_LIGHTING);
129  glClear(GL_DEPTH_BUFFER_BIT);
130  glstate_->pick_init (false);
131 
132  // do the picking
133  SceneGraph::PickAction action(*glstate_, _pickTarget, curDrawMode_);
134  SceneGraph::traverse(sceneGraphRoot_, action);
135  int hits = glRenderMode(GL_RENDER);
136 
137  // restore GL state
138  glMatrixMode( GL_PROJECTION );
139  glLoadMatrixd(projection.get_raw_data());
140  glMatrixMode( GL_MODELVIEW );
141  glLoadMatrixd(modelview.get_raw_data());
142  ACG::GLState::enable(GL_LIGHTING);
143 
144 
145  // process hit record
146  if ( hits > 0 )
147  {
148  GLuint *ptr = &selectionBuffer[0],
149  z,
150  min_z=~(0u),
151  max_z=0;
152 
153  for (int i=0; i<hits; ++i)
154  {
155  const GLuint num_names = *ptr++;
156  if ( num_names != NAME_STACK_SIZE )
157  {
158  std::cerr << "QtBaseViewer::pick() : namestack error\n\n";
159  return false;
160  }
161 
162  if ( (z = *ptr++) < min_z )
163  {
164  min_z = z;
165  max_z = *ptr++;
166  for (unsigned int j=0; j<num_names; ++j)
167  nameBuffer[j] = *ptr++;
168  }
169  else ptr += 1+num_names;
170  }
171 
172  _nodeIdx = nameBuffer[0];
173  _targetIdx = nameBuffer[1];
174 
175  if (_hitPointPtr)
176  {
177  GLuint zscale=~(0u);
178  GLdouble min_zz = ((GLdouble)min_z) / ((GLdouble)zscale);
179  GLdouble max_zz = ((GLdouble)max_z) / ((GLdouble)zscale);
180  GLdouble zz = 0.5F * (min_zz + max_zz);
181  *_hitPointPtr = glstate_->unproject(Vec3d(x,y,zz));
182  }
183 
184  return true;
185  }
186  else if (hits < 0)
187  std::cerr << "QtBaseViewer::pick() : selection buffer overflow\n\n";
188  }
189 
190  return false;
191 }
192 
193 
194 //-----------------------------------------------------------------------------
195 
196 
197 bool
199 fast_pick( const QPoint& _mousePos,
200  Vec3d& _hitPoint )
201 {
202  // get x,y,z values of pixel
203  GLint x(_mousePos.x()), y(glHeight() - _mousePos.y());
204  GLfloat z;
205 
206 
207  makeCurrent();
208  glPixelStorei(GL_PACK_ALIGNMENT, 1);
209  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
210  glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
211 
212 
213  if (z < 0.99999)
214  {
215  _hitPoint = glstate_->unproject( Vec3d(x, y, z) );
216  return true;
217  }
218  else return false;
219 }
220 
221 //-----------------------------------------------------------------------------
222 
223 
224 void QtBaseViewer::pickMode( int _id )
225 {
226  if (_id < (int) pick_modes_.size() )
227  {
228  pick_mode_idx_ = _id;
230 
231  // adjust mouse tracking
232  if ( actionMode_ == PickingMode )
234 
235  // adjust Cursor
236  if ( actionMode_ == PickingMode )
237  glView_->setCursor(pick_modes_[pick_mode_idx_].cursor);
238 
239  // emit signal
241  }
242 }
243 
244 
245 //-----------------------------------------------------------------------------
246 
247 
248 void QtBaseViewer::addPickMode(const std::string& _name,
249  bool _tracking,
250  int _pos,
251  bool _visible,
252  QCursor _cursor)
253 {
254  if ((unsigned int)_pos < pick_modes_.size())
255  {
256  std::vector<PickMode>::iterator it = pick_modes_.begin();
257  it += _pos+1;
258  pick_modes_.insert(it, PickMode(_name, _tracking, _visible, _cursor));
259  }
260  else
261  pick_modes_.push_back(PickMode(_name, _tracking, _visible, _cursor));
262 
263  updatePickMenu();
264 }
265 
266 //-----------------------------------------------------------------------------
267 
268 void QtBaseViewer::setPickModeCursor(const std::string& _name, QCursor _cursor)
269 {
270  for (uint i=0; i < pick_modes_.size(); i++)
271  if ( pick_modes_[i].name == _name ){
272  pick_modes_[i].cursor = _cursor;
273 
274  //switch cursor if pickMode is active
275  if (pick_mode_name_ == _name && actionMode_ == PickingMode)
276  glView_->setCursor(_cursor);
277  break;
278  }
279 }
280 
281 //-----------------------------------------------------------------------------
282 
283 void QtBaseViewer::setPickModeMouseTracking(const std::string& _name, bool _mouseTracking)
284 {
285  for (uint i=0; i < pick_modes_.size(); i++)
286  if ( pick_modes_[i].name == _name ){
287  pick_modes_[i].tracking = _mouseTracking;
288 
289  //switch cursor if pickMode is active
290  if (pick_mode_name_ == _name && actionMode_ == PickingMode)
291  trackMouse(_mouseTracking);
292  break;
293  }
294 }
295 
296 //-----------------------------------------------------------------------------
297 
298 
300 {
301  pick_modes_.clear();
302  pick_mode_idx_ = -1;
303  pick_mode_name_ = "";
304  updatePickMenu();
305 }
306 
307 
308 //-----------------------------------------------------------------------------
309 
310 
311 const std::string& QtBaseViewer::pickMode() const
312 {
313  return pick_mode_name_;
314 }
315 
316 
317 //-----------------------------------------------------------------------------
318 
319 
320 void QtBaseViewer::pickMode(const std::string& _name)
321 {
322  for (unsigned int i=0; i<pick_modes_.size(); ++i)
323  {
324  if (pick_modes_[i].name == _name)
325  {
326  pickMode( i );
327  updatePickMenu();
328  return;
329  }
330  }
331 }
332 
333 //-----------------------------------------------------------------------------
334 
337 }
338 
339 
340 //=============================================================================
341 } // namespace QtWidgets
342 } // namespace ACG
343 //=============================================================================
bool fast_pick(const QPoint &_mousePos, Vec3d &_hitPoint)
void trackMouse(bool _track)
Enable/disable mouse tracking (move events with no button press)
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
const std::string & pickMode() const
void pick_init(bool _color)
initialize name/color picking stack (like glInitNames())
Definition: GLState.cc:1043
Namespace providing different geometric functions concerning angles.
void setPickModeCursor(const std::string &_name, QCursor _cursor)
set a new cursor for the pick mode
void renderPicking(bool _renderPicking, ACG::SceneGraph::PickTarget _mode)
virtual void makeCurrent()
Makes this widget the current widget for OpenGL operations.
ACG::SceneGraph::PickTarget pickRendererMode_
PickTarget
What target to use for picking.
Definition: PickTarget.hh:73
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:651
unsigned int glWidth() const
get width of QGLWidget
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
std::vector< PickMode > pick_modes_
void updatePickMenu()
update pick mode menu
void setPickModeMouseTracking(const std::string &_name, bool _mouseTracking)
set mouseTracking for the pick mode
void addPickMode(const std::string &_name, bool _mouse_tracking=false, int _pos=-1, bool _visible=true, QCursor _cursor=Qt::ArrowCursor)
add pick mode
ActionMode actionMode() const
get action mode
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:816
bool pick(SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, unsigned int &_nodeIdx, unsigned int &_targetIdx, Vec3d *_hitPointPtr=0)
const GLMatrixd & projection() const
get projection matrix
Definition: GLState.hh:811
const Scalar * get_raw_data() const
Definition: Matrix4x4T.hh:256
void traverse(BaseNode *_node, Action &_action)
Definition: SceneGraph.hh:137
unsigned int glHeight() const
get height of QGLWidget
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
void signalPickModeChanged(const std::string &)