Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 
51 
52 
53 //=============================================================================
54 //
55 // CLASS glViewer - IMPLEMENTATION
56 //
57 //=============================================================================
58 
59 
60 //== INCLUDES =================================================================
61 
62 #include "QtBaseViewer.hh"
63 #include "QtGLGraphicsScene.hh"
64 #include "QtGLGraphicsView.hh"
65 
66 #if QT_VERSION < 0x050000
67 #include <QGLFramebufferObject>
68 #else
69 #include <QOpenGLFramebufferObject>
70 #endif
71 
72 //== NAMESPACES ===============================================================
73 
74 //== IMPLEMENTATION ==========================================================
75 
76 
78  const QPoint& _mousePos,
79  size_t& _nodeIdx,
80  size_t& _targetIdx,
81  ACG::Vec3d* _hitPointPtr )
82 {
83  if (sceneGraphRoot_)
84  {
85  // unsigned int node, target;
86  // QTime time;
87  // time.start ();
88  int rv = pickFromCache (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
89 
90  // cache will return -1 if a update is needed or caching is not supported
91  if (rv < 0)
92  rv = pickColor (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
93 
94  // printf ("ColorPicking took %d msec\n",time.restart ());
95 
96  // if (rv > 0 && (node != _nodeIdx || target != _targetIdx))
97  // printf ("***** Picking difference Color %d/%d GL %d/%d\n",node, target, _nodeIdx, _targetIdx);
98  if (rv > 0)
99  return rv;
100  }
101  return false;
102 }
103 
104 
105 //-----------------------------------------------------------------------------
106 
108  const QPoint& _mousePos,
109  size_t& _nodeIdx,
110  size_t& _targetIdx,
111  ACG::Vec3d* _hitPointPtr )
112 {
113  GLint w = glWidth(),
114  h = glHeight(),
115  l = scenePos().x(),
116  b = scene()->height () - scenePos().y() - h,
117  x = _mousePos.x(),
118  y = scene()->height () - _mousePos.y(),
119  pW = 1,
120  pH = 1;
121  GLubyte pixels[9][4];
122  GLfloat depths[9];
123  int hit = -1;
124 
125  // traversing order (center, top, bottom, ...)
126  unsigned char order[9] = { 4, 7, 1, 3, 5, 0, 2, 6, 8 };
127 
129  {
130  // delete pick cache if the size changed
131  if (pickCache_ && pickCache_->size () != QSize (glWidth (), glHeight ()))
132  {
133  delete pickCache_;
134  pickCache_ = NULL;
135  }
136  // create a new pick cache frambuffer object
137  if (!pickCache_)
138  {
139  pickCache_ = new QFramebufferObject (glWidth (), glHeight (), QFramebufferObject::Depth);
140  if (!pickCache_->isValid ())
141  {
142  pickCacheSupported_ = false;
143  delete pickCache_;
144  pickCache_ = NULL;
145  }
146  }
147  if (pickCache_)
148  {
149  // the viewport for the framebuffer object
150  l = 0;
151  b = 0;
152  x = _mousePos.x() - scenePos().x();
153  y = glHeight() - (_mousePos.y() - scenePos().y());
154 
155  // we can only pick inside of our window
156  if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
157  return 0;
158 
159  pickCache_->bind ();
160  }
161  }
162 
163  const ACG::GLMatrixd& modelview = properties_.glState().modelview();
164  const ACG::GLMatrixd& projection = properties_.glState().projection();
165 
166  ACG::Vec4f clear_color = properties_.glState().clear_color();
167  properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0));
168 
169  // prepare GL state
170  makeCurrent();
171 
172  glViewport (l, b, w, h);
173  glMatrixMode(GL_PROJECTION);
174  glLoadIdentity();
175 
176  glMultMatrixd(projection.get_raw_data());
177  glMatrixMode(GL_MODELVIEW);
178  glLoadMatrixd(modelview.get_raw_data());
179  ACG::GLState::disable(GL_LIGHTING);
180  ACG::GLState::disable(GL_BLEND);
181  ACG::GLState::enable(GL_DEPTH_TEST);
182  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
183  properties_.glState().pick_init (true);
184 
185  // do the picking
187  ACG::SceneGraph::traverse_multipass(sceneGraphRoot_, action,properties_.glState() );
188 
189  // restore GL state
190  glMatrixMode( GL_PROJECTION );
191  glLoadMatrixd(projection.get_raw_data());
192  glMatrixMode( GL_MODELVIEW );
193  glLoadMatrixd(modelview.get_raw_data());
194  ACG::GLState::enable(GL_LIGHTING);
195 
196  properties_.glState().set_clear_color (clear_color);
197 
198  if (properties_.glState().pick_error ())
199  {
200  if (pickCache_ && pickCache_->isBound ())
201  pickCache_->release ();
202 
203  std::cerr << "error - picking color stack invalid" << std::endl;
204  return -1;
205  }
206 
207  glPixelStorei(GL_PACK_ALIGNMENT, 1);
208  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
209 
210  // we can only read inside our viewport
211  if (x + 1 < w)
212  pW++;
213 
214  if (y + 1 < h)
215  pH++;
216 
217  if (x > 0)
218  {
219  x--;
220  pW++;
221  }
222  if (y > 0)
223  {
224  y--;
225  pH++;
226  }
227 
228  if (pH != 3 || pW != 3)
229  {
230  // initialize unused values with 0
231  for (int i = 0; i < 9; i++)
232  {
233  pixels[i][0] = 0;
234  pixels[i][1] = 0;
235  pixels[i][2] = 0;
236  pixels[i][3] = 0;
237  depths[i] = 0.0;
238  }
239  }
240 
241  // read from framebuffer
242  glReadPixels (x, y, pW, pH, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
243  glReadPixels (x, y, pW, pH, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
244 
245  // unbind pick cache
246  if (pickCache_ && pickCache_->isBound ())
247  {
248  pickCache_->release ();
249  updatePickCache_ = false;
250  pickCacheTarget_ = _pickTarget;
251  }
252 
253  // get first found pixel
254  for (int i = 0; i < 9; i++)
255  {
256  if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0 || pixels[order[i]][3] != 0))
257  {
258  hit = order[i];
259  break;
260  }
261  }
262 
263  if (hit < 0)
264  return 0;
265 
266 
267  ACG::Vec4uc rgba;
268  rgba[0] = pixels[hit][0];
269  rgba[1] = pixels[hit][1];
270  rgba[2] = pixels[hit][2];
271  rgba[3] = pixels[hit][3];
272 
273  std::vector<size_t> rv = properties_.glState().pick_color_to_stack (rgba);
274 
275  // something wrong with the color stack ?
276  if (rv.size () < 2)
277  {
278  std::cerr << "error - picking color not found in stack" << std::endl;
279  return -1;
280  }
281 
282  _nodeIdx = rv[1];
283  _targetIdx = rv[0];
284 
285 // // Debug Code to visualize picking cache ( DO NOT REMOVE!!!! Jan )
286 // QImage murks(glWidth (),glHeight (),QImage::Format_ARGB32);
287 // murks = pickCache_->toImage();
288 // for ( int i = 0 ; i < glWidth() ; ++i )
289 // for ( int j = 0 ; j < glHeight() ; ++j ) {
290 // QColor bla (murks.pixel(i,j));
291 // bla.setAlpha(255);
292 // murks.setPixel(i,j,bla.rgba());
293 // }
294 // murks.save("murks.png");
295 
296  if (_hitPointPtr)
297  {
298  *_hitPointPtr = properties_.glState().unproject (
299  ACG::Vec3d(_mousePos.x(), scene()->height () - _mousePos.y(),depths[hit]));
300  }
301 
302  return 1;
303 }
304 
305 //-----------------------------------------------------------------------------
306 
308  const QPoint& _mousePos,
309  size_t& _nodeIdx,
310  size_t& _targetIdx,
311  ACG::Vec3d* _hitPointPtr )
312 {
313  // do we need an update?
315  pickCacheTarget_ != _pickTarget)
316  return -1;
317 
318  GLint x = _mousePos.x() - scenePos().x(),
319  y = glHeight() - (_mousePos.y() - scenePos().y()),
320  pW = 1,
321  pH = 1;
322  GLubyte pixels[9][4];
323  GLfloat depths[9];
324  int hit = -1;
325 
326  // traversing order (center, top, bottom, ...)
327  unsigned char order[9] = { 4, 7, 1, 3, 5, 0, 2, 6, 8 };
328 
329  // can't pick outside
330  if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
331  return 0;
332 
333  // bind cache framebuffer object
334  pickCache_->bind ();
335 
336  glPixelStorei(GL_PACK_ALIGNMENT, 1);
337  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
338 
339  // we can only read inside our viewport
340  if (x + 1 < (int)glWidth ())
341  pW++;
342 
343  if (y + 1 < (int)glHeight ())
344  pH++;
345 
346  if (x > 0)
347  {
348  x--;
349  pW++;
350  }
351  if (y > 0)
352  {
353  y--;
354  pH++;
355  }
356 
357  if (pH != 3 || pW != 3)
358  {
359  // initialize unused values with 0
360  for (int i = 0; i < 9; i++)
361  {
362  pixels[i][0] = 0;
363  pixels[i][1] = 0;
364  pixels[i][2] = 0;
365  pixels[i][3] = 0;
366  depths[i] = 0.0;
367  }
368  }
369 
370  // read from framebuffer
371  glReadPixels (x, y, pW, pH, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
372  glReadPixels (x, y, pW, pH, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
373 
374  // unbind
375  pickCache_->release ();
376 
377  // get first found pixel
378  for (int i = 0; i < 9; i++)
379  {
380  if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0 || pixels[order[i]][3] != 0))
381  {
382  hit = order[i];
383  break;
384  }
385  }
386 
387  if (hit < 0)
388  return 0;
389 
390 
391  ACG::Vec4uc rgba;
392  rgba[0] = pixels[hit][0];
393  rgba[1] = pixels[hit][1];
394  rgba[2] = pixels[hit][2];
395  rgba[3] = pixels[hit][3];
396 
397  std::vector<size_t> rv = properties_.glState().pick_color_to_stack (rgba);
398 
399  // something wrong with the color stack ?
400  if (rv.size () < 2)
401  return -1;
402 
403  _nodeIdx = rv[1];
404  _targetIdx = rv[0];
405 
406  if (_hitPointPtr)
407  {
408  *_hitPointPtr = properties_.glState().unproject(
409  ACG::Vec3d(_mousePos.x(), scene()->height () - _mousePos.y(),depths[hit]));
410  }
411 
412  return 1;
413 }
414 
415 //-----------------------------------------------------------------------------
416 
418  const QRegion& _region,
419  QList<QPair<size_t, size_t> >& _list,
420  QVector<float>* _depths,
421  QVector<ACG::Vec3d>* _points)
422 {
423  QRect rect = _region.boundingRect();
424  GLint w = glWidth(),
425  h = glHeight(),
426  l = scenePos().x(),
427  b = scene()->height () - scenePos().y() - h,
428  x = rect.x(),
429  y = scene()->height () - rect.bottom();
430 
431  GLubyte* buffer = 0;
432  GLfloat* depths = 0;
433 
435  {
436  // delete pick cache if the size changed
437  if (pickCache_ && pickCache_->size () != QSize (glWidth (), glHeight ()))
438  {
439  delete pickCache_;
440  pickCache_ = NULL;
441  }
442  // create a new pick cache frambuffer object
443  if (!pickCache_)
444  {
445  pickCache_ = new QFramebufferObject (glWidth (), glHeight (), QFramebufferObject::Depth);
446  if (!pickCache_->isValid ())
447  {
448  pickCacheSupported_ = false;
449  delete pickCache_;
450  pickCache_ = NULL;
451  }
452  }
453  if (pickCache_)
454  {
455  // the viewport for the framebuffer object
456  l = 0;
457  b = 0;
458  x = rect.x() - scenePos().x();
459  y = glHeight() - (rect.bottom() - scenePos().y());
460 
461  // we can only pick inside of our window
462  if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
463  return 0;
464 
465  pickCache_->bind ();
466  }
467  }
468 
469  const ACG::GLMatrixd& modelview = properties_.glState().modelview();
470  const ACG::GLMatrixd& projection = properties_.glState().projection();
471 
472  ACG::Vec4f clear_color = properties_.glState().clear_color();
473  properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0));
474 
475  // prepare GL state
476  makeCurrent();
477 
478  glViewport (l, b, w, h);
479  glMatrixMode(GL_PROJECTION);
480  glLoadIdentity();
481 
482  glMultMatrixd(projection.get_raw_data());
483  glMatrixMode(GL_MODELVIEW);
484  glLoadMatrixd(modelview.get_raw_data());
485  ACG::GLState::disable(GL_LIGHTING);
486  ACG::GLState::disable(GL_BLEND);
487  ACG::GLState::enable(GL_DEPTH_TEST);
488  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
489  properties_.glState().pick_init (true);
490 
491  // do the picking
493  ACG::SceneGraph::traverse_multipass(sceneGraphRoot_, action,properties_.glState());
494 
495  // restore GL state
496  glMatrixMode( GL_PROJECTION );
497  glLoadMatrixd(projection.get_raw_data());
498  glMatrixMode( GL_MODELVIEW );
499  glLoadMatrixd(modelview.get_raw_data());
500  ACG::GLState::enable(GL_LIGHTING);
501  ACG::GLState::enable(GL_BLEND);
502 
503  properties_.glState().set_clear_color(clear_color);
504 
505  if (properties_.glState().pick_error ())
506  {
507  if (pickCache_ && pickCache_->isBound ())
508  pickCache_->release ();
509  return false;
510  }
511 
512  buffer = new GLubyte[4 * rect.width() * rect.height()];
513 
514 
515 
516  glPixelStorei(GL_PACK_ALIGNMENT, 1);
517  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
518 
519  glReadPixels (x, y, rect.width(),
520  rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer);
521 
522  if (_depths || _points ) {
523  depths = new GLfloat[ rect.width() * rect.height() ];
524  glReadPixels (x, y, rect.width(), rect.height(), GL_DEPTH_COMPONENT, GL_FLOAT, depths);
525 
526  /* Debug code, writing out the depth image
527  QImage depthmapimage(rect.width(), rect.height(), QImage::Format_Indexed8);
528 
529  // color map
530  for ( int i = 0 ; i <= 255 ; i++ )
531  depthmapimage.setColor( i, qRgb( i, i, i ) );
532 
533  for ( int i = 0 ; i < rect.width() ; i++ )
534  for ( int j = 0 ; j < rect.height() ; j++ )
535  {
536  depthmapimage.setPixel(i,rect.height()-j-1, (unsigned int)(depths[j*rect.width()+i]*255));
537  }
538 
539  depthmapimage.save("test.png");
540  */
541  }
542 
543  // Iterate over the bounding rectangle of the region
544  for (int y = 0; y < rect.height (); y++)
545  for (int x = 0; x < rect.width (); x++)
546  {
547 
548  // Check if the current point is in the polygon of the region
549  if (_region.contains (QPoint (rect.x() + x, rect.y() + y)))
550  {
551 
552  // Calculate position inside the buffer
553  const int bPos = (((rect.height () - (y + 1)) * rect.width ()) + x) * 4;
554 
555  // Get the picking color from the buffer at the current position
556  if (buffer[bPos + 2] != 0 || buffer[bPos + 1] != 0 || buffer[bPos] != 0 || buffer[bPos + 3] != 0)
557  {
558  ACG::Vec4uc rgba;
559  rgba[0] = buffer[bPos];
560  rgba[1] = buffer[bPos + 1];
561  rgba[2] = buffer[bPos + 2];
562  rgba[3] = buffer[bPos + 3];
563 
564  std::vector<size_t> rv = properties_.glState().pick_color_to_stack (rgba);
565  if (rv.size () < 2)
566  continue;
567 
568  QPair<size_t, size_t> curr(rv[1], rv[0]);
569 
570  // added a new (targetidx/nodeidx) pair
571  if( !_list.contains(curr))
572  {
573  _list << curr;
574 
575  if ( _depths || _points ) {
576 
577  const double curr_depth(depths[(rect.height()-(y+1))*rect.width() + x]);
578 
579  // If depths should be returned, we extract it here
580  if (_depths)
581  (*_depths) << curr_depth;
582 
583  // unproject depth to real (3D) depth value
584  if ( _points )
585  (*_points) << properties_.glState().unproject(ACG::Vec3d(x+rect.x(),h-(y+rect.y()),curr_depth));
586  }
587  }
588  }
589  }
590  }
591 
592  delete[] buffer;
593 
594  if ( _depths || _points )
595  delete[] depths;
596 
597  // unbind pick cache
598  if (pickCache_ && pickCache_->isBound ())
599  {
600  pickCache_->release ();
601  updatePickCache_ = false;
602  pickCacheTarget_ = _pickTarget;
603  }
604 
605  return true;
606 }
607 
608 
609 //-----------------------------------------------------------------------------
610 
611 bool
613 fast_pick( const QPoint& _mousePos,
614  ACG::Vec3d& _hitPoint )
615 {
616  // get x,y,z values of pixel
617  GLint x(_mousePos.x()), y(glHeight() - _mousePos.y());
618  GLfloat z;
619 
620 
621  makeCurrent();
622  glPixelStorei(GL_PACK_ALIGNMENT, 1);
623  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
624  glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
625 
626 
627  if (z < 0.99999)
628  {
629  _hitPoint = properties_.glState().unproject( ACG::Vec3d(x, y, z) );
630  return true;
631  }
632  else return false;
633 }
634 
635 
636 //=============================================================================
637 
638 //=============================================================================
bool pickCacheSupported_
Is pick caching supported.
const GLMatrixd & projection() const
get projection matrix
Definition: GLState.hh:789
ACG::SceneGraph::PickTarget pickCacheTarget_
Pick target stored in pick cache.
bool pick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
static void disable(GLenum _cap)
replaces glDisable, but supports locking
Definition: GLState.cc:1518
int pickColor(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
pick using colors
static void enable(GLenum _cap)
replaces glEnable, but supports locking
Definition: GLState.cc:1504
ACG::GLState & glState()
Get the glState of the Viewer.
virtual void makeCurrent()
Makes this widget the current widget for OpenGL operations.
unsigned int glWidth() const
get width of QGLWidget
unsigned int glHeight() const
get height of QGLWidget
const Vec4f & clear_color() const
get background color
Definition: GLState.hh:924
QFramebufferObject * pickCache_
Framebuffer object that holds the pick cache.
void pick_init(bool _color)
initialize name/color picking stack (like glInitNames())
Definition: GLState.cc:1040
std::vector< size_t > pick_color_to_stack(Vec4uc _rgba) const
Definition: GLState.cc:1101
int pickFromCache(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
pick from cache
bool pick_region(ACG::SceneGraph::PickTarget _pickTarget, const QRegion &_region, QList< QPair< size_t, size_t > > &_list, QVector< float > *_depths=0, QVector< ACG::Vec3d > *_points=0)
Perform picking action n a whole region.
const Scalar * get_raw_data() const
Definition: Matrix4x4T.hh:262
void traverse_multipass(BaseNode *_node, Action &_action, const unsigned int &_pass)
Definition: SceneGraph.hh:260
bool pick_error() const
Definition: GLState.cc:1119
bool fast_pick(const QPoint &_mousePos, ACG::Vec3d &_hitPoint)
QGLFramebufferObject QFramebufferObject
Framebuffer object that holds the pick cache.
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:794
void set_clear_color(const Vec4f &_col)
set background color
Definition: GLState.cc:661
PickTarget
What target to use for picking.
Definition: BaseNode.hh:99
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
bool updatePickCache_
Should the pick cache be updated.
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:650
Viewer::ViewerProperties & properties_
All properties for this viewer.