QtBaseViewerPicking.cc 12.3 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);
70
std::cerr << "ColorPicking: " << rv << std::endl;
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
71
72
73
74
    // printf ("ColorPicking took %d msec\n",time.restart ());
    // rv = -1;
    // node = _nodeIdx;
    // target = _targetIdx;
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
75
76
    if (rv < 0)
      rv = pickGL (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
77
    // printf ("GLPicking took %d msec\n",time.restart ());
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
78

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
79
80
    // 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
81
82
83
84
85
86
87
88
89
90
    if (rv > 0)
      return rv;
  }
  return false;
}


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

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

97
98
99
100
101
  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
102
                y = scene()->height () - _mousePos.y();
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
103
  GLubyte       pixels[9][4];
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
104
105
106
107
108
109
110
  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
111
112
113
  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
114
115
116
  // prepare GL state
  makeCurrent();

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

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

  // 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
140
141
  properties_.glState().set_clear_color (clear_color);

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
142
143
144
145
146
147
  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
148
  glReadPixels (x - 1, y - 1, 3, 3, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
149
  glReadPixels (x - 1, y - 1, 3, 3, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
150
151

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

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


Jan Möbius's avatar
Dennis:    
Jan Möbius committed
164
165
166
167
168
  ACG::Vec4uc rgba;
  rgba[0] = pixels[hit][0];
  rgba[1] = pixels[hit][1];
  rgba[2] = pixels[hit][2];
  rgba[3] = pixels[hit][3];
Jan Möbius's avatar
   
Jan Möbius committed
169

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

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
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
  // 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);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
220
  glDisable(GL_BLEND);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
221
222
223
224
  glClear(GL_DEPTH_BUFFER_BIT);
  properties_.glState().pick_init (false);

  // do the picking
Jan Möbius's avatar
Jan Möbius committed
225
226
  ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
  ACG::SceneGraph::traverse(sceneGraphRoot_, action);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
227
228
229
230
231
232
233
234
  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);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
235
  glEnable(GL_BLEND);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

  // 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
256
      {
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
257
258
259
260
        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
261
      }
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
262
263
264
265
266
      else ptr += 1+num_names;
    }

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

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
268
269
270
271
272
273
274
    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
275
    }
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
276
277

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

  return false;
}

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

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
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
302
303
304
  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
305
306
307
308
309
310
311
312
313
314
315
  // 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);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
316
  glDisable(GL_BLEND);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
317
318
319
320
321
  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
322
323
  ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
  ACG::SceneGraph::traverse(sceneGraphRoot_, action);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
324
325
326
327
328
329
330

  // 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
331
  glEnable(GL_BLEND);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
332

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

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
335
336
337
  if (properties_.glState().pick_error ())
    return false;

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
338
  buffer = new GLubyte[4 * rect.width() * rect.height()];
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
339
340
341
342
343

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

  glReadPixels (rect.x(), scene()->height () - rect.bottom() , rect.width(),
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
344
                rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
345
346
347
348
349
350
351
352

  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)))
      {
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
353
354
        int bPos = (((rect.height () - (y + 1)) * rect.width ()) + x) * 4;
        if (buffer[bPos + 2] != 0 || buffer[bPos + 1] != 0 || buffer[bPos] != 0 || buffer[bPos + 3] != 0)
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
355
        {
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
356
357
358
359
360
          ACG::Vec4uc rgba;
          rgba[0] = buffer[bPos];
          rgba[1] = buffer[bPos + 1];
          rgba[2] = buffer[bPos + 2];
          rgba[3] = buffer[bPos + 3];
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
361

Jan Möbius's avatar
Dennis:    
Jan Möbius committed
362
          std::vector<unsigned int> rv = properties_.glState().pick_color_to_stack (rgba);
Jan Möbius's avatar
Dennis:    
Jan Möbius committed
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
          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
379
bool
Jan Möbius's avatar
   
Jan Möbius committed
380
glViewer::
Jan Möbius's avatar
   
Jan Möbius committed
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
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)
  {
397
    _hitPoint = properties_.glState().unproject( ACG::Vec3d(x, y, z) );
Jan Möbius's avatar
   
Jan Möbius committed
398
399
400
401
402
403
404
405
406
    return true;
  }
  else return false;
}


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

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