00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include "QtBaseViewer.hh"
00056 #include "QtGLGraphicsScene.hh"
00057 #include "QtGLGraphicsView.hh"
00058
00059 #include <QGLFramebufferObject>
00060
00061
00062
00063
00064
00065 static const unsigned int SELECTION_BUFFER_SIZE = 10000;
00066 static const unsigned int NAME_STACK_SIZE = 2;
00067
00068
00069
00070
00071 bool glViewer::pick( ACG::SceneGraph::PickTarget _pickTarget,
00072 const QPoint& _mousePos,
00073 unsigned int& _nodeIdx,
00074 unsigned int& _targetIdx,
00075 ACG::Vec3d* _hitPointPtr )
00076 {
00077 if (sceneGraphRoot_)
00078 {
00079
00080
00081
00082 int rv = pickFromCache (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
00083
00084
00085 if (rv < 0)
00086 rv = pickColor (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
00087
00088
00089
00090
00091
00092 if (rv < 0)
00093 rv = pickGL (_pickTarget, _mousePos, _nodeIdx, _targetIdx, _hitPointPtr);
00094
00095
00096
00097
00098 if (rv > 0)
00099 return rv;
00100 }
00101 return false;
00102 }
00103
00104
00105
00106
00107 int glViewer::pickColor( ACG::SceneGraph::PickTarget _pickTarget,
00108 const QPoint& _mousePos,
00109 unsigned int& _nodeIdx,
00110 unsigned int& _targetIdx,
00111 ACG::Vec3d* _hitPointPtr )
00112 {
00113 GLint w = glWidth(),
00114 h = glHeight(),
00115 l = scenePos().x(),
00116 b = scene()->height () - scenePos().y() - h,
00117 x = _mousePos.x(),
00118 y = scene()->height () - _mousePos.y(),
00119 pW = 1,
00120 pH = 1;
00121 GLubyte pixels[9][4];
00122 GLfloat depths[9];
00123 int hit = -1;
00124
00125
00126 unsigned char order[9] = { 4, 7, 1, 3, 5, 0, 2, 6, 8 };
00127
00128 if (pickCacheSupported_)
00129 {
00130
00131 if (pickCache_ && pickCache_->size () != QSize (glWidth (), glHeight ()))
00132 {
00133 delete pickCache_;
00134 pickCache_ = NULL;
00135 }
00136
00137 if (!pickCache_)
00138 {
00139 pickCache_ = new QGLFramebufferObject (glWidth (), glHeight (), QGLFramebufferObject::Depth);
00140 if (!pickCache_->isValid ())
00141 {
00142 pickCacheSupported_ = false;
00143 delete pickCache_;
00144 pickCache_ = NULL;
00145 }
00146 }
00147 if (pickCache_)
00148 {
00149
00150 l = 0;
00151 b = 0;
00152 x = _mousePos.x() - scenePos().x();
00153 y = glHeight() - (_mousePos.y() - scenePos().y());
00154
00155
00156 if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
00157 return 0;
00158
00159 pickCache_->bind ();
00160 }
00161 }
00162
00163 const ACG::GLMatrixd& modelview = properties_.glState().modelview();
00164 const ACG::GLMatrixd& projection = properties_.glState().projection();
00165
00166 ACG::Vec4f clear_color = properties_.glState().clear_color();
00167 properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0));
00168
00169
00170 makeCurrent();
00171
00172 glViewport (l, b, w, h);
00173 glMatrixMode(GL_PROJECTION);
00174 glLoadIdentity();
00175
00176 glMultMatrixd(projection.get_raw_data());
00177 glMatrixMode(GL_MODELVIEW);
00178 glLoadMatrixd(modelview.get_raw_data());
00179 glDisable(GL_LIGHTING);
00180 glDisable(GL_BLEND);
00181 glEnable(GL_DEPTH_TEST);
00182 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00183 properties_.glState().pick_init (true);
00184
00185
00186 ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
00187 ACG::SceneGraph::traverse(sceneGraphRoot_, action);
00188
00189
00190 glMatrixMode( GL_PROJECTION );
00191 glLoadMatrixd(projection.get_raw_data());
00192 glMatrixMode( GL_MODELVIEW );
00193 glLoadMatrixd(modelview.get_raw_data());
00194 glEnable(GL_LIGHTING);
00195
00196 properties_.glState().set_clear_color (clear_color);
00197
00198 if (properties_.glState().pick_error ())
00199 {
00200 if (pickCache_ && pickCache_->isBound ())
00201 pickCache_->release ();
00202 return -1;
00203 }
00204
00205 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00206 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00207
00208
00209 if (x + 1 < w)
00210 pW++;
00211
00212 if (y + 1 < h)
00213 pH++;
00214
00215 if (x > 0)
00216 {
00217 x--;
00218 pW++;
00219 }
00220 if (y > 0)
00221 {
00222 y--;
00223 pH++;
00224 }
00225
00226 if (pH != 3 || pW != 3)
00227 {
00228
00229 for (int i = 0; i < 9; i++)
00230 {
00231 pixels[i][0] = 0;
00232 pixels[i][1] = 0;
00233 pixels[i][2] = 0;
00234 pixels[i][3] = 0;
00235 depths[i] = 0.0;
00236 }
00237 }
00238
00239
00240 glReadPixels (x, y, pW, pH, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
00241 glReadPixels (x, y, pW, pH, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
00242
00243
00244 if (pickCache_ && pickCache_->isBound ())
00245 {
00246 pickCache_->release ();
00247 updatePickCache_ = false;
00248 pickCacheTarget_ = _pickTarget;
00249 }
00250
00251
00252 for (int i = 0; i < 9; i++)
00253 {
00254 if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0 || pixels[order[i]][3] != 0))
00255 {
00256 hit = order[i];
00257 break;
00258 }
00259 }
00260
00261 if (hit < 0)
00262 return 0;
00263
00264
00265 ACG::Vec4uc rgba;
00266 rgba[0] = pixels[hit][0];
00267 rgba[1] = pixels[hit][1];
00268 rgba[2] = pixels[hit][2];
00269 rgba[3] = pixels[hit][3];
00270
00271 std::vector<unsigned int> rv = properties_.glState().pick_color_to_stack (rgba);
00272
00273
00274 if (rv.size () < 2)
00275 return -1;
00276
00277 _nodeIdx = rv[1];
00278 _targetIdx = rv[0];
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 if (_hitPointPtr)
00292 {
00293 *_hitPointPtr = properties_.glState().unproject (
00294 ACG::Vec3d(_mousePos.x(), scene()->height () - _mousePos.y(),depths[hit]));
00295 }
00296
00297 return 1;
00298 }
00299
00300
00301
00302 int glViewer::pickFromCache( ACG::SceneGraph::PickTarget _pickTarget,
00303 const QPoint& _mousePos,
00304 unsigned int& _nodeIdx,
00305 unsigned int& _targetIdx,
00306 ACG::Vec3d* _hitPointPtr )
00307 {
00308
00309 if (!pickCacheSupported_ || updatePickCache_ || !pickCache_ ||
00310 pickCacheTarget_ != _pickTarget)
00311 return -1;
00312
00313 GLint x = _mousePos.x() - scenePos().x(),
00314 y = glHeight() - (_mousePos.y() - scenePos().y()),
00315 pW = 1,
00316 pH = 1;
00317 GLubyte pixels[9][4];
00318 GLfloat depths[9];
00319 int hit = -1;
00320
00321
00322 unsigned char order[9] = { 4, 7, 1, 3, 5, 0, 2, 6, 8 };
00323
00324
00325 if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
00326 return 0;
00327
00328
00329 pickCache_->bind ();
00330
00331 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00332 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00333
00334
00335 if (x + 1 < (int)glWidth ())
00336 pW++;
00337
00338 if (y + 1 < (int)glHeight ())
00339 pH++;
00340
00341 if (x > 0)
00342 {
00343 x--;
00344 pW++;
00345 }
00346 if (y > 0)
00347 {
00348 y--;
00349 pH++;
00350 }
00351
00352 if (pH != 3 || pW != 3)
00353 {
00354
00355 for (int i = 0; i < 9; i++)
00356 {
00357 pixels[i][0] = 0;
00358 pixels[i][1] = 0;
00359 pixels[i][2] = 0;
00360 pixels[i][3] = 0;
00361 depths[i] = 0.0;
00362 }
00363 }
00364
00365
00366 glReadPixels (x, y, pW, pH, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
00367 glReadPixels (x, y, pW, pH, GL_DEPTH_COMPONENT, GL_FLOAT, depths);
00368
00369
00370 pickCache_->release ();
00371
00372
00373 for (int i = 0; i < 9; i++)
00374 {
00375 if (hit < 0 && (pixels[order[i]][2] != 0 || pixels[order[i]][1] != 0 || pixels[order[i]][0] != 0 || pixels[order[i]][3] != 0))
00376 {
00377 hit = order[i];
00378 break;
00379 }
00380 }
00381
00382 if (hit < 0)
00383 return 0;
00384
00385
00386 ACG::Vec4uc rgba;
00387 rgba[0] = pixels[hit][0];
00388 rgba[1] = pixels[hit][1];
00389 rgba[2] = pixels[hit][2];
00390 rgba[3] = pixels[hit][3];
00391
00392 std::vector<unsigned int> rv = properties_.glState().pick_color_to_stack (rgba);
00393
00394
00395 if (rv.size () < 2)
00396 return -1;
00397
00398 _nodeIdx = rv[1];
00399 _targetIdx = rv[0];
00400
00401 if (_hitPointPtr)
00402 {
00403 *_hitPointPtr = properties_.glState().unproject(
00404 ACG::Vec3d(_mousePos.x(), scene()->height () - _mousePos.y(),depths[hit]));
00405 }
00406
00407 return 1;
00408 }
00409
00410
00411
00412 bool glViewer::pickGL( ACG::SceneGraph::PickTarget _pickTarget,
00413 const QPoint& _mousePos,
00414 unsigned int& _nodeIdx,
00415 unsigned int& _targetIdx,
00416 ACG::Vec3d* _hitPointPtr )
00417 {
00418 GLint w = glWidth(),
00419 h = glHeight(),
00420 l = scenePos().x(),
00421 b = scene()->height () - scenePos().y() - h,
00422 x = _mousePos.x(),
00423 y = scene()->height () - _mousePos.y();
00424 GLint viewport[4] = {l,b,w,h};
00425 GLuint selectionBuffer[ SELECTION_BUFFER_SIZE ],
00426 nameBuffer[ NAME_STACK_SIZE ];
00427
00428 const ACG::GLMatrixd& modelview = properties_.glState().modelview();
00429 const ACG::GLMatrixd& projection = properties_.glState().projection();
00430
00431
00432 makeCurrent();
00433
00434 glSelectBuffer( SELECTION_BUFFER_SIZE, selectionBuffer );
00435 glRenderMode(GL_SELECT);
00436 glMatrixMode(GL_PROJECTION);
00437 glLoadIdentity();
00438 gluPickMatrix((GLdouble) x, (GLdouble) y, 3, 3, viewport);
00439 glMultMatrixd(projection.get_raw_data());
00440 glMatrixMode(GL_MODELVIEW);
00441 glLoadMatrixd(modelview.get_raw_data());
00442 glDisable(GL_LIGHTING);
00443 glDisable(GL_BLEND);
00444 glClear(GL_DEPTH_BUFFER_BIT);
00445 properties_.glState().pick_init (false);
00446
00447
00448 ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
00449 ACG::SceneGraph::traverse(sceneGraphRoot_, action);
00450 int hits = glRenderMode(GL_RENDER);
00451
00452
00453 glMatrixMode( GL_PROJECTION );
00454 glLoadMatrixd(projection.get_raw_data());
00455 glMatrixMode( GL_MODELVIEW );
00456 glLoadMatrixd(modelview.get_raw_data());
00457 glEnable(GL_LIGHTING);
00458 glEnable(GL_BLEND);
00459
00460
00461 if ( hits > 0 )
00462 {
00463 GLuint *ptr = selectionBuffer,
00464 num_names,
00465 z,
00466 min_z=~(0u),
00467 max_z=0;
00468
00469 for (int i=0; i<hits; ++i)
00470 {
00471 num_names = *ptr++;
00472 if ( num_names != NAME_STACK_SIZE )
00473 {
00474 std::cerr << "glViewer::pick() : namestack error\n\n";
00475 return false;
00476 }
00477
00478 if ( (z = *ptr++) < min_z )
00479 {
00480 min_z = z;
00481 max_z = *ptr++;
00482 for (unsigned int j=0; j<num_names; ++j)
00483 nameBuffer[j] = *ptr++;
00484 }
00485 else ptr += 1+num_names;
00486 }
00487
00488 _nodeIdx = nameBuffer[0];
00489 _targetIdx = nameBuffer[1];
00490
00491 if (_hitPointPtr)
00492 {
00493 GLuint zscale=~(0u);
00494 GLdouble min_zz = ((GLdouble)min_z) / ((GLdouble)zscale);
00495 GLdouble max_zz = ((GLdouble)max_z) / ((GLdouble)zscale);
00496 GLdouble zz = 0.5F * (min_zz + max_zz);
00497 *_hitPointPtr = properties_.glState().unproject(ACG::Vec3d(x,y,zz));
00498 }
00499
00500 return true;
00501 }
00502 else if (hits < 0)
00503 std::cerr << "glViewer::pick() : selection buffer overflow\n\n";
00504
00505 return false;
00506 }
00507
00508
00509
00510 bool glViewer::pick_region( ACG::SceneGraph::PickTarget _pickTarget,
00511 const QRegion& _region,
00512 QList<QPair<unsigned int, unsigned int> >& _list)
00513 {
00514 QRect rect = _region.boundingRect();
00515 GLint w = glWidth(),
00516 h = glHeight(),
00517 l = scenePos().x(),
00518 b = scene()->height () - scenePos().y() - h,
00519 x = rect.x(),
00520 y = scene()->height () - rect.bottom();
00521 GLubyte* buffer;
00522
00523 if (pickCacheSupported_)
00524 {
00525
00526 if (pickCache_ && pickCache_->size () != QSize (glWidth (), glHeight ()))
00527 {
00528 delete pickCache_;
00529 pickCache_ = NULL;
00530 }
00531
00532 if (!pickCache_)
00533 {
00534 pickCache_ = new QGLFramebufferObject (glWidth (), glHeight (), QGLFramebufferObject::Depth);
00535 if (!pickCache_->isValid ())
00536 {
00537 pickCacheSupported_ = false;
00538 delete pickCache_;
00539 pickCache_ = NULL;
00540 }
00541 }
00542 if (pickCache_)
00543 {
00544
00545 l = 0;
00546 b = 0;
00547 x = rect.x() - scenePos().x();
00548 y = glHeight() - (rect.bottom() - scenePos().y());
00549
00550
00551 if (x < 0 || y < 0 || x >= (int)glWidth() || y >= (int)glHeight())
00552 return 0;
00553
00554 pickCache_->bind ();
00555 }
00556 }
00557
00558 const ACG::GLMatrixd& modelview = properties_.glState().modelview();
00559 const ACG::GLMatrixd& projection = properties_.glState().projection();
00560
00561 ACG::Vec4f clear_color = properties_.glState().clear_color();
00562 properties_.glState().set_clear_color (ACG::Vec4f (0.0, 0.0, 0.0, 0.0));
00563
00564
00565 makeCurrent();
00566
00567 glViewport (l, b, w, h);
00568 glMatrixMode(GL_PROJECTION);
00569 glLoadIdentity();
00570
00571 glMultMatrixd(projection.get_raw_data());
00572 glMatrixMode(GL_MODELVIEW);
00573 glLoadMatrixd(modelview.get_raw_data());
00574 glDisable(GL_LIGHTING);
00575 glDisable(GL_BLEND);
00576 glEnable(GL_DEPTH_TEST);
00577 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00578 properties_.glState().pick_init (true);
00579
00580
00581 ACG::SceneGraph::PickAction action(properties_.glState(), _pickTarget, properties_.drawMode());
00582 ACG::SceneGraph::traverse(sceneGraphRoot_, action);
00583
00584
00585 glMatrixMode( GL_PROJECTION );
00586 glLoadMatrixd(projection.get_raw_data());
00587 glMatrixMode( GL_MODELVIEW );
00588 glLoadMatrixd(modelview.get_raw_data());
00589 glEnable(GL_LIGHTING);
00590 glEnable(GL_BLEND);
00591
00592 properties_.glState().set_clear_color (clear_color);
00593
00594 if (properties_.glState().pick_error ())
00595 {
00596 if (pickCache_ && pickCache_->isBound ())
00597 pickCache_->release ();
00598 return -1;
00599 }
00600
00601 buffer = new GLubyte[4 * rect.width() * rect.height()];
00602
00603 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00604 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00605
00606 glReadPixels (x, y, rect.width(),
00607 rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer);
00608
00609 QSet<QPair<unsigned int, unsigned int> > found;
00610
00611 for (int y = 0; y < rect.height (); y++)
00612 for (int x = 0; x < rect.width (); x++)
00613 {
00614 if (_region.contains (QPoint (rect.x() + x, rect.y() + y)))
00615 {
00616 int bPos = (((rect.height () - (y + 1)) * rect.width ()) + x) * 4;
00617 if (buffer[bPos + 2] != 0 || buffer[bPos + 1] != 0 || buffer[bPos] != 0 || buffer[bPos + 3] != 0)
00618 {
00619 ACG::Vec4uc rgba;
00620 rgba[0] = buffer[bPos];
00621 rgba[1] = buffer[bPos + 1];
00622 rgba[2] = buffer[bPos + 2];
00623 rgba[3] = buffer[bPos + 3];
00624
00625 std::vector<unsigned int> rv = properties_.glState().pick_color_to_stack (rgba);
00626 if (rv.size () < 2)
00627 continue;
00628
00629 found << QPair<unsigned int, unsigned int>(rv[1], rv[0]);
00630 }
00631 }
00632 }
00633
00634 delete buffer;
00635 _list = found.toList();
00636
00637
00638 if (pickCache_ && pickCache_->isBound ())
00639 {
00640 pickCache_->release ();
00641 updatePickCache_ = false;
00642 pickCacheTarget_ = _pickTarget;
00643 }
00644
00645 return true;
00646 }
00647
00648
00649
00650 bool
00651 glViewer::
00652 fast_pick( const QPoint& _mousePos,
00653 ACG::Vec3d& _hitPoint )
00654 {
00655
00656 GLint x(_mousePos.x()), y(glHeight() - _mousePos.y());
00657 GLfloat z;
00658
00659
00660 makeCurrent();
00661 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00662 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00663 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
00664
00665
00666 if (z < 0.99999)
00667 {
00668 _hitPoint = properties_.glState().unproject( ACG::Vec3d(x, y, z) );
00669 return true;
00670 }
00671 else return false;
00672 }
00673
00674
00675
00676
00677