QtBaseViewerPicking.cc 12 KB
Newer Older
Jan Möbius's avatar
 
Jan Möbius committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//=============================================================================
//
//                               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 <http://www.gnu.org/licenses/>.
//
//-----------------------------------------------------------------------------
//
Jan Möbius's avatar
Jan Möbius committed
26
27
28
//   $Revision$
//   $Author$
//   $Date$
Jan Möbius's avatar
 
Jan Möbius committed
29
30
31
32
33
34
35
36
//
//=============================================================================




//=============================================================================
//
Jan Möbius's avatar
   
Jan Möbius committed
37
//  CLASS glViewer - IMPLEMENTATION
Jan Möbius's avatar
 
Jan Möbius committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//
//=============================================================================


//== 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 ==========================================================


Jan Möbius's avatar
   
Jan Möbius committed
58
bool glViewer::pick( ACG::SceneGraph::PickTarget _pickTarget,
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
59
60
61
62
63
64
65
                     const QPoint&               _mousePos,
                     unsigned int&               _nodeIdx,
                     unsigned int&               _targetIdx,
                     ACG::Vec3d*                 _hitPointPtr )
{
  if (sceneGraphRoot_)
  {
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
66
67
68
    // unsigned int node, target;
    // QTime time;
    // time.start ();
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
69
    int rv = pickColor (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
70
71
72
73
    // printf ("ColorPicking took %d msec\n",time.restart ());
    // rv = -1;
    // node = _nodeIdx;
    // target = _targetIdx;
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
74
75
    if (rv < 0)
      rv = pickGL (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
76
    // printf ("GLPicking took %d msec\n",time.restart ());
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
77

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
78
79
    // if (rv > 0 && (node != _nodeIdx || target != _targetIdx))
    //   printf ("***** Picking difference Color %d/%d GL %d/%d\n",node, target, _nodeIdx, _targetIdx);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
80
81
82
83
84
85
86
87
88
89
    if (rv > 0)
      return rv;
  }
  return false;
}


//-----------------------------------------------------------------------------

int glViewer::pickColor( ACG::SceneGraph::PickTarget _pickTarget,
Jan Möbius's avatar
 
Jan Möbius committed
90
91
92
93
94
                         const QPoint&               _mousePos,
                         unsigned int&               _nodeIdx,
                         unsigned int&               _targetIdx,
                         ACG::Vec3d*                 _hitPointPtr )
{
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
95

96
97
98
99
100
  GLint         w = glWidth(),
                h = glHeight(),
                l = scenePos().x(),
                b = scene()->height () - scenePos().y() - h,
                x = _mousePos.x(),
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
101
102
103
104
105
106
107
108
109
                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();

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
110
111
112
  ACG::Vec4f clear_color = properties_.glState().clear_color();
  properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0));

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
113
114
115
  // prepare GL state
  makeCurrent();

116
  glViewport (l, b, w, h);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
117
118
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
119

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
120
121
122
123
124
125
126
127
128
  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
Jan Möbius's avatar
Jan Möbius committed
129
130
  ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
  ACG::SceneGraph::traverse(sceneGraphRoot_, action);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
131
132
133
134
135
136
137
138

  // restore GL state
  glMatrixMode( GL_PROJECTION );
  glLoadMatrixd(projection.get_raw_data());
  glMatrixMode( GL_MODELVIEW );
  glLoadMatrixd(modelview.get_raw_data());
  glEnable(GL_LIGHTING);

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
139
140
  properties_.glState().set_clear_color (clear_color);

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
141
142
143
144
145
146
  if (properties_.glState().pick_error ())
    return -1;

  glPixelStorei(GL_PACK_ALIGNMENT, 1);
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
147
148
  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);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
149
150

  for (int i = 0; i < 9; i++)
Jan Möbius's avatar
 
Jan Möbius committed
151
  {
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
152
    if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0))
Jan Möbius's avatar
 
Jan Möbius committed
153
    {
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
154
155
156
157
158
159
160
      hit = order[i];
      break;
    }
  }

  if (hit < 0)
    return 0;
Jan Möbius's avatar
 
Jan Möbius committed
161
162


Jan Möbius's avatar
Dennis:    
Jan Möbius committed
163
164
165
166
  ACG::Vec3uc rgb;
  rgb[0] = pixels[hit][0];
  rgb[1] = pixels[hit][1];
  rgb[2] = pixels[hit][2];
Jan Möbius's avatar
 
Jan Möbius committed
167

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
168
  std::vector<unsigned int> rv = properties_.glState().pick_color_to_stack (rgb);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
169

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  // 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
Jan Möbius's avatar
Jan Möbius committed
222
223
  ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
  ACG::SceneGraph::traverse(sceneGraphRoot_, action);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  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<hits; ++i)
    {
      num_names = *ptr++;
      if ( num_names != NAME_STACK_SIZE )
      {
        std::cerr << "glViewer::pick() : namestack error\n\n";
        return false;
      }

      if ( (z = *ptr++) < min_z )
Jan Möbius's avatar
 
Jan Möbius committed
252
      {
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
253
254
255
256
        min_z = z;
        max_z = *ptr++;
        for (unsigned int j=0; j<num_names; ++j)
          nameBuffer[j] = *ptr++;
Jan Möbius's avatar
 
Jan Möbius committed
257
      }
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
258
259
260
261
262
      else ptr += 1+num_names;
    }

    _nodeIdx   = nameBuffer[0];
    _targetIdx = nameBuffer[1];
Jan Möbius's avatar
 
Jan Möbius committed
263

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
264
265
266
267
268
269
270
    if (_hitPointPtr)
    {
      GLuint zscale=~(0u);
      GLdouble min_zz = ((GLdouble)min_z) / ((GLdouble)zscale);
      GLdouble max_zz = ((GLdouble)max_z) / ((GLdouble)zscale);
      GLdouble zz     = 0.5F * (min_zz + max_zz);
      *_hitPointPtr = properties_.glState().unproject(ACG::Vec3d(x,y,zz));
Jan Möbius's avatar
 
Jan Möbius committed
271
    }
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
272
273

    return true;
Jan Möbius's avatar
 
Jan Möbius committed
274
  }
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
275
276
  else if (hits < 0)
    std::cerr << "glViewer::pick() : selection buffer overflow\n\n";
Jan Möbius's avatar
 
Jan Möbius committed
277
278
279
280
281
282

  return false;
}

//-----------------------------------------------------------------------------

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
bool glViewer::pick_region( ACG::SceneGraph::PickTarget                _pickTarget,
                            const QRegion&                             _region,
                            QList<QPair<unsigned int, unsigned int> >& _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();

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
298
299
300
  ACG::Vec4f clear_color = properties_.glState().clear_color();
  properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0));

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  // 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
Jan Möbius's avatar
Jan Möbius committed
317
318
  ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
  ACG::SceneGraph::traverse(sceneGraphRoot_, action);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
319
320
321
322
323
324
325
326

  // restore GL state
  glMatrixMode( GL_PROJECTION );
  glLoadMatrixd(projection.get_raw_data());
  glMatrixMode( GL_MODELVIEW );
  glLoadMatrixd(modelview.get_raw_data());
  glEnable(GL_LIGHTING);

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
327
328
  properties_.glState().set_clear_color (clear_color);

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  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<QPair<unsigned int, unsigned int> > 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<unsigned int> rv = properties_.glState().pick_color_to_stack (rgb);
          if (rv.size () < 2)
            continue;

          found << QPair<unsigned int, unsigned int>(rv[1], rv[0]);
        }
      }
    }

  delete buffer;
  _list = found.toList();

  return true;
}

//-----------------------------------------------------------------------------

Jan Möbius's avatar
 
Jan Möbius committed
372
bool
Jan Möbius's avatar
   
Jan Möbius committed
373
glViewer::
Jan Möbius's avatar
 
Jan Möbius committed
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
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)
  {
390
    _hitPoint = properties_.glState().unproject( ACG::Vec3d(x, y, z) );
Jan Möbius's avatar
 
Jan Möbius committed
391
392
393
394
395
396
397
398
399
    return true;
  }
  else return false;
}


//=============================================================================

//=============================================================================