00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00026
00027
00028 #include "glc_viewport.h"
00029 #include "../glc_openglexception.h"
00030 #include "../glc_ext.h"
00031 #include "../shading/glc_selectionmaterial.h"
00032 #include "../glc_state.h"
00033 #include "../sceneGraph/glc_3dviewinstance.h"
00034
00035 #include <QtDebug>
00036
00037 using namespace glc;
00039
00041
00042 GLC_Viewport::GLC_Viewport(QGLWidget *GLWidget)
00043
00044 : m_pViewCam(new GLC_Camera())
00045 , m_DistanceMax(500.0)
00046 , m_dDistanceMini(0.01)
00047 , m_ViewAngle(35)
00048 , m_ViewTangent(tan(glc::toRadian(m_ViewAngle)))
00049 , m_pImagePlane(NULL)
00050
00051 , m_WindowHSize(0)
00052 , m_WindowVSize(0)
00053 , m_AspectRatio(1.0)
00054 , m_pQGLWidget(GLWidget)
00055
00056 , m_BackgroundColor(Qt::black)
00057 , m_SelectionSquareSize(4)
00058 , m_ProjectionMatrix()
00059 , m_Frustum()
00060 , m_ClipPlanesHash()
00061 , m_UseClipPlane(false)
00062 , m_3DWidgetCollection()
00063 , m_UseParallelProjection(false)
00064 , m_MinimumStaticPixelSize(10)
00065 , m_MinimumStaticRatioSize(0.0)
00066 , m_MinimumDynamicRatioSize(0.0)
00067 {
00068 updateMinimumRatioSize();
00069 }
00070
00071 GLC_Viewport::~GLC_Viewport()
00072 {
00073 delete m_pViewCam;
00074
00075
00076 deleteBackGroundImage();
00077
00078
00079 QHash<GLenum, GLC_Plane*>::iterator iClip= m_ClipPlanesHash.begin();
00080 while (m_ClipPlanesHash.constEnd() != iClip)
00081 {
00082 delete iClip.value();
00083 ++iClip;
00084 }
00085 }
00086
00088
00090
00091 GLC_Vector3d GLC_Viewport::mapPosMouse( GLdouble Posx, GLdouble Posy) const
00092 {
00093
00094 Posx= Posx - static_cast<double>(m_WindowHSize) / 2.0;
00095 Posy= static_cast<double>(m_WindowVSize) / 2.0 - Posy;
00096
00097 GLC_Vector3d VectMouse(Posx, Posy,0);
00098
00099
00100 const double ChampsVision = m_pViewCam->distEyeTarget() * m_ViewTangent;
00101
00102
00103
00104 const double Ratio= ChampsVision / static_cast<double>(m_WindowVSize);
00105
00106 VectMouse= VectMouse * Ratio;
00107
00108 return VectMouse;
00109 }
00110
00112
00114
00115 void GLC_Viewport::initGl()
00116 {
00117
00118 m_pQGLWidget->qglClearColor(m_BackgroundColor);
00119 glClearDepth(1.0f);
00120 glShadeModel(GL_SMOOTH);
00121 glEnable(GL_DEPTH_TEST);
00122 glDepthFunc(GL_LEQUAL);
00123 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
00124 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00125
00126
00127 GLC_State::init();
00128 }
00129
00130 void GLC_Viewport::glExecuteCam(void)
00131 {
00132 m_pViewCam->glExecute();
00133 renderImagePlane();
00134 }
00135
00136 void GLC_Viewport::updateProjectionMat(void)
00137 {
00138
00139 m_pQGLWidget->makeCurrent();
00140
00141 glMatrixMode(GL_PROJECTION);
00142 glLoadIdentity();
00143
00144 if (m_UseParallelProjection)
00145 {
00146 const double ChampsVision = m_pViewCam->distEyeTarget() * m_ViewTangent;
00147 const double height= ChampsVision;
00148 const double with= ChampsVision * m_AspectRatio;
00149 const double left= -with * 0.5;
00150 const double right= -left;
00151 const double bottom= - height * 0.5;
00152 const double top= -bottom;
00153 glOrtho(left, right, bottom, top, m_dDistanceMini, m_DistanceMax);
00154 }
00155 else
00156 {
00157 gluPerspective(m_ViewAngle, m_AspectRatio, m_dDistanceMini, m_DistanceMax);
00158 }
00159
00160
00161 glGetDoublev(GL_PROJECTION_MATRIX, m_ProjectionMatrix.data());
00162
00163 glMatrixMode(GL_MODELVIEW);
00164 glLoadIdentity();
00165 }
00166
00167 void GLC_Viewport::forceAspectRatio(double ratio)
00168 {
00169 m_AspectRatio= ratio;
00170 updateProjectionMat();
00171 }
00172
00173 void GLC_Viewport::updateAspectRatio()
00174 {
00175
00176 m_AspectRatio= static_cast<double>(m_WindowHSize)/static_cast<double>(m_WindowVSize);
00177 }
00178 GLC_Frustum GLC_Viewport::selectionFrustum(int x, int y) const
00179 {
00180 const int halfSize= m_SelectionSquareSize / 2;
00181
00182
00183
00184
00185 QList<int> coordinates;
00186
00187 coordinates << (x - halfSize) << (y + halfSize);
00188
00189 coordinates << (x - halfSize) << (y - halfSize);
00190
00191 coordinates << (x + halfSize) << (y - halfSize);
00192
00193 coordinates << (x + halfSize) << (y + halfSize);
00194
00195
00196 QList<GLC_Point3d> listOfPoint= unproject(coordinates);
00197
00198 Q_ASSERT(4 == listOfPoint.size());
00199
00200 GLC_Point3d eye= m_pViewCam->eye();
00201 const GLC_Plane leftPlane(listOfPoint.at(0), listOfPoint.at(1), eye);
00202 const GLC_Plane rightPlane(listOfPoint.at(3), eye , listOfPoint.at(2));
00203 const GLC_Plane upPlane(listOfPoint.at(2), eye, listOfPoint.at(1));
00204 const GLC_Plane bottomPlane(listOfPoint.at(0), eye, listOfPoint.at(3));
00205
00206 GLC_Frustum selectionFrustum(m_Frustum);
00207 selectionFrustum.setLeftClippingPlane(leftPlane);
00208 selectionFrustum.setRightClippingPlane(rightPlane);
00209 selectionFrustum.setTopClippingPlane(upPlane);
00210 selectionFrustum.setBottomClippingPlane(bottomPlane);
00211
00212 return selectionFrustum;
00213 }
00214
00215 GLC_Point3d GLC_Viewport::unProject(int x, int y) const
00216 {
00217
00218 GLfloat Depth;
00219
00220 glReadPixels(x, m_WindowVSize - y , 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &Depth);
00221
00222
00223 GLint Viewport[4];
00224 glGetIntegerv(GL_VIEWPORT, Viewport);
00225
00226
00227 GLdouble pX, pY, pZ;
00228 gluUnProject((GLdouble) x, (GLdouble) (m_WindowVSize - y) , Depth
00229 , m_pViewCam->modelViewMatrix().data(), m_ProjectionMatrix.data(), Viewport, &pX, &pY, &pZ);
00230
00231 return GLC_Point3d(pX, pY, pZ);
00232 }
00233
00234 QList<GLC_Point3d> GLC_Viewport::unproject(const QList<int>& list)const
00235 {
00236 const int size= list.size();
00237 Q_ASSERT((size % 2) == 0);
00238
00239
00240 GLint Viewport[4];
00241 glGetIntegerv(GL_VIEWPORT, Viewport);
00242
00243
00244 GLfloat Depth;
00245
00246
00247 GLdouble pX, pY, pZ;
00248 QList<GLC_Point3d> unprojectedPoints;
00249 for (int i= 0; i < size; i+= 2)
00250 {
00251 const int x= list.at(i);
00252 const int y= m_WindowVSize - list.at(i + 1);
00253 glReadPixels(x, y , 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &Depth);
00254
00255 gluUnProject(static_cast<GLdouble>(x), static_cast<GLdouble>(y) , Depth , m_pViewCam->modelViewMatrix().data()
00256 , m_ProjectionMatrix.data(), Viewport, &pX, &pY, &pZ);
00257 unprojectedPoints.append(GLC_Point3d(pX, pY, pZ));
00258 }
00259
00260 return unprojectedPoints;
00261 }
00262
00264
00266
00267 void GLC_Viewport::renderImagePlane()
00268 {
00269
00270 if(!GLC_State::isInSelectionMode())
00271 {
00272 if (m_pImagePlane != NULL)
00273 {
00274 m_pImagePlane->render();
00275 }
00276 }
00277 }
00278
00279 void GLC_Viewport::render3DWidget()
00280 {
00281 m_3DWidgetCollection.render(0, glc::WireRenderFlag);
00282 m_3DWidgetCollection.render(0, glc::TransparentRenderFlag);
00283 }
00285
00287
00288 void GLC_Viewport::setWinGLSize(int HSize, int VSize)
00289 {
00290 m_WindowHSize= HSize;
00291 m_WindowVSize= VSize;
00292
00293
00294 if (m_WindowVSize == 0)
00295 {
00296 m_WindowVSize= 1;
00297 }
00298
00299 glViewport(0,0,m_WindowHSize,m_WindowVSize);
00300
00301 updateAspectRatio();
00302
00303 updateProjectionMat();
00304
00305 updateMinimumRatioSize();
00306 }
00307
00308 GLC_uint GLC_Viewport::renderAndSelect(int x, int y)
00309 {
00310
00311 m_pQGLWidget->qglClearColor(Qt::black);
00312 GLC_State::setSelectionMode(true);
00313
00314 m_pQGLWidget->updateGL();
00315 GLC_State::setSelectionMode(false);
00316
00317 return selectOnPreviousRender(x, y);
00318 }
00319
00320 GLC_uint GLC_Viewport::selectOnPreviousRender(int x, int y)
00321 {
00322 GLsizei width= m_SelectionSquareSize;
00323 GLsizei height= width;
00324 GLint newX= x - width / 2;
00325 GLint newY= (m_pQGLWidget->size().height() - y) - height / 2;
00326 if (newX < 0) newX= 0;
00327 if (newY < 0) newY= 0;
00328
00329 return meaningfulIdInsideSquare(newX, newY, width, height);
00330 }
00331 GLC_uint GLC_Viewport::selectBody(GLC_3DViewInstance* pInstance, int x, int y)
00332 {
00333 m_pQGLWidget->qglClearColor(Qt::black);
00334 GLC_State::setSelectionMode(true);
00335 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00336 glLoadIdentity();
00337
00338 glExecuteCam();
00339
00340
00341 glDisable(GL_BLEND);
00342 glDisable(GL_LIGHTING);
00343 glDisable(GL_TEXTURE_2D);
00344
00345 pInstance->renderForBodySelection();
00346 GLC_State::setSelectionMode(false);
00347
00348 GLsizei width= 6;
00349 GLsizei height= width;
00350 GLint newX= x - width / 2;
00351 GLint newY= (m_pQGLWidget->size().height() - y) - height / 2;
00352 if (newX < 0) newX= 0;
00353 if (newY < 0) newY= 0;
00354
00355 return meaningfulIdInsideSquare(newX, newY, width, height);
00356 }
00357
00358 QPair<int, GLC_uint> GLC_Viewport::selectPrimitive(GLC_3DViewInstance* pInstance, int x, int y)
00359 {
00360 QPair<int, GLC_uint> result;
00361
00362 m_pQGLWidget->qglClearColor(Qt::black);
00363 GLC_State::setSelectionMode(true);
00364 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00365 glLoadIdentity();
00366
00367 glExecuteCam();
00368
00369
00370 glDisable(GL_BLEND);
00371 glDisable(GL_LIGHTING);
00372 glDisable(GL_TEXTURE_2D);
00373
00374 pInstance->renderForBodySelection();
00375
00376
00377 GLsizei width= 6;
00378 GLsizei height= width;
00379 GLint newX= x - width / 2;
00380 GLint newY= (m_pQGLWidget->size().height() - y) - height / 2;
00381 if (newX < 0) newX= 0;
00382 if (newY < 0) newY= 0;
00383
00384 GLC_uint bodyId= meaningfulIdInsideSquare(newX, newY, width, height);
00385 if (bodyId == 0)
00386 {
00387 result.first= -1;
00388 result.second= 0;
00389 }
00390 else
00391 {
00392 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00393
00394 result.first= pInstance->renderForPrimitiveSelection(bodyId);
00395 result.second= meaningfulIdInsideSquare(newX, newY, width, height);
00396 }
00397 GLC_State::setSelectionMode(false);
00398 return result;
00399 }
00400
00401 QSet<GLC_uint> GLC_Viewport::selectInsideSquare(int x1, int y1, int x2, int y2)
00402 {
00403 if (x1 > x2)
00404 {
00405 int xTemp= x1;
00406 x1= x2;
00407 x2= xTemp;
00408 }
00409 if (y2 > y1)
00410 {
00411 int yTemp= y1;
00412 y1= y2;
00413 y2= yTemp;
00414 }
00415 m_pQGLWidget->qglClearColor(Qt::black);
00416 GLC_State::setSelectionMode(true);
00417
00418 m_pQGLWidget->updateGL();
00419 GLC_State::setSelectionMode(false);
00420
00421 GLsizei width= x2 - x1;
00422 GLsizei height= y1 - y2;
00423 GLint newX= x1;
00424 GLint newY= (m_pQGLWidget->size().height() - y1);
00425 if (newX < 0) newX= 0;
00426 if (newY < 0) newY= 0;
00427
00428 return listOfIdInsideSquare(newX, newY, width, height);
00429 }
00430
00431 GLC_uint GLC_Viewport::meaningfulIdInsideSquare(GLint x, GLint y, GLsizei width, GLsizei height)
00432 {
00433 const int squareSize= width * height;
00434 const GLsizei arraySize= squareSize * 4;
00435 QVector<GLubyte> colorId(arraySize);
00436
00437
00438 glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, colorId.data());
00439
00440
00441 m_pQGLWidget->qglClearColor(m_BackgroundColor);
00442
00443 QHash<GLC_uint, int> idHash;
00444 QList<int> idWeight;
00445
00446
00447 GLC_uint returnId= 0;
00448
00449 int maxWeight= 0;
00450 int currentIndex= 0;
00451 for (int i= 0; i < squareSize; ++i)
00452 {
00453 GLC_uint id= glc::decodeRgbId(&colorId[i * 4]);
00454 if (idHash.contains(id))
00455 {
00456 const int currentWeight= ++(idWeight[idHash.value(id)]);
00457 if (maxWeight < currentWeight)
00458 {
00459 returnId= id;
00460 maxWeight= currentWeight;
00461 }
00462 }
00463 else if (id != 0)
00464 {
00465 idHash.insert(id, currentIndex++);
00466 idWeight.append(1);
00467 if (maxWeight < 1)
00468 {
00469 returnId= id;
00470 maxWeight= 1;
00471 }
00472 }
00473 }
00474
00475 return returnId;
00476 }
00477
00478 QSet<GLC_uint> GLC_Viewport::listOfIdInsideSquare(GLint x, GLint y, GLsizei width, GLsizei height)
00479 {
00480 const int squareSize= width * height;
00481 const GLsizei arraySize= squareSize * 4;
00482 QVector<GLubyte> colorId(arraySize);
00483
00484
00485 glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, colorId.data());
00486
00487
00488 m_pQGLWidget->qglClearColor(m_BackgroundColor);
00489
00490 QSet<GLC_uint> idSet;
00491
00492
00493 for (int i= 0; i < squareSize; ++i)
00494 {
00495 GLC_uint id= glc::decodeRgbId(&colorId[i * 4]);
00496 idSet << id;
00497 }
00498
00499 return idSet;
00500 }
00501
00502 void GLC_Viewport::updateMinimumRatioSize()
00503 {
00504 int size= qMax(m_WindowHSize, m_WindowVSize);
00505 m_MinimumStaticRatioSize= static_cast<double>(m_MinimumStaticPixelSize) / static_cast<double>(size) * 100.0;
00506 m_MinimumDynamicRatioSize= m_MinimumStaticRatioSize * 2.0;
00507
00508 }
00509
00510 void GLC_Viewport::loadBackGroundImage(const QString& ImageFile)
00511 {
00512 delete m_pImagePlane;
00513 m_pImagePlane= new GLC_ImagePlane(m_pQGLWidget->context(), ImageFile);
00514 }
00515
00516 void GLC_Viewport::loadBackGroundImage(const QImage& image)
00517 {
00518 delete m_pImagePlane;
00519 m_pImagePlane= new GLC_ImagePlane(m_pQGLWidget->context(), image);
00520 }
00521
00522 void GLC_Viewport::deleteBackGroundImage()
00523 {
00524 delete m_pImagePlane;
00525 m_pImagePlane= NULL;
00526 }
00527
00528 void GLC_Viewport::setToOrtho(bool useOrtho)
00529 {
00530 if (m_UseParallelProjection != useOrtho)
00531 {
00532 m_UseParallelProjection= useOrtho;
00533 updateProjectionMat();
00534 }
00535
00536 }
00537
00538 void GLC_Viewport::reframe(const GLC_BoundingBox& box)
00539 {
00540 Q_ASSERT(!box.isEmpty());
00541
00542
00543 const GLC_Vector3d deltaVector(box.center() - m_pViewCam->target());
00544 m_pViewCam->translate(deltaVector);
00545
00546 double cameraCover= box.boundingSphereRadius() * 2.0;
00547
00548
00549 const double distance = cameraCover / m_ViewTangent;
00550
00551
00552 m_pViewCam->setDistEyeTarget(distance);
00553 }
00554
00555 bool GLC_Viewport::setDistMin(double DistMin)
00556 {
00557 DistMin= fabs(DistMin);
00558 if (DistMin < m_DistanceMax)
00559 {
00560 m_dDistanceMini= DistMin;
00561
00562 updateProjectionMat();
00563
00564 return true;
00565 }
00566 else
00567 {
00568 qDebug("GLC_Viewport::SetDistMin : KO");
00569 return false;
00570 }
00571
00572 }
00573
00574 bool GLC_Viewport::setDistMax(double DistMax)
00575 {
00576 DistMax= fabs(DistMax);
00577 if (DistMax > m_dDistanceMini)
00578 {
00579 m_DistanceMax= DistMax;
00580
00581
00582 updateProjectionMat();
00583
00584 return true;
00585 }
00586 else
00587 {
00588 qDebug("GLC_Viewport::SetDistMax : KO");
00589 return false;
00590 }
00591 }
00592
00593 void GLC_Viewport::setDistMinAndMax(const GLC_BoundingBox& bBox)
00594 {
00595 if(!bBox.isEmpty())
00596 {
00597
00598 GLC_Matrix4x4 matComp(m_pViewCam->modelViewMatrix());
00599
00600
00601 GLC_BoundingBox boundingBox(bBox);
00602 boundingBox.transform(matComp);
00603
00604
00605 const double increaseFactor= 1.1;
00606
00607 const double center= fabs(boundingBox.center().z());
00608 const double radius= boundingBox.boundingSphereRadius();
00609 const double min= center - radius * increaseFactor;
00610 const double max= center + radius * increaseFactor;
00611
00612 GLC_Point3d camEye(m_pViewCam->eye());
00613 camEye= matComp * camEye;
00614
00615 if (min > 0.0)
00616 {
00617
00618 m_dDistanceMini= min;
00619 m_DistanceMax= max;
00620
00621
00622 }
00623 else
00624 {
00625
00626 m_dDistanceMini= qMin(0.01 * radius, m_pViewCam->distEyeTarget() / 4.0);
00627 m_DistanceMax= max;
00628
00629
00630 }
00631 }
00632 else
00633 {
00634
00635 m_dDistanceMini= m_pViewCam->distEyeTarget() / 2.0;
00636 m_DistanceMax= m_pViewCam->distEyeTarget();
00637 }
00638
00639
00640 updateProjectionMat();
00641 }
00642
00643 void GLC_Viewport::setBackgroundColor(QColor setColor)
00644 {
00645 m_BackgroundColor= setColor;
00646 m_pQGLWidget->qglClearColor(m_BackgroundColor);
00647 }
00648
00649 void GLC_Viewport::addClipPlane(GLenum planeGlEnum,GLC_Plane* pPlane)
00650 {
00651 if (m_ClipPlanesHash.contains(planeGlEnum))
00652 {
00653 delete m_ClipPlanesHash.value(planeGlEnum);
00654 m_ClipPlanesHash.remove(planeGlEnum);
00655 }
00656 m_ClipPlanesHash.insert(planeGlEnum, pPlane);
00657 }
00658
00659 void GLC_Viewport::removeClipPlane(GLenum planeGlEnum)
00660 {
00661 if (m_ClipPlanesHash.contains(planeGlEnum))
00662 {
00663 delete m_ClipPlanesHash.value(planeGlEnum);
00664 m_ClipPlanesHash.remove(planeGlEnum);
00665 }
00666 else
00667 {
00668 qDebug() << "GLC_Viewport::removeClipPlane Clipp plane " << planeGlEnum << " Not found";
00669 }
00670 }
00671
00672 void GLC_Viewport::removeAllClipPlane()
00673 {
00674
00675 QHash<GLenum, GLC_Plane*>::iterator iClip= m_ClipPlanesHash.begin();
00676 while (m_ClipPlanesHash.constEnd() != iClip)
00677 {
00678 delete iClip.value();
00679 ++iClip;
00680 }
00681 }
00682
00683 void GLC_Viewport::useClipPlane(bool flag)
00684 {
00685 m_UseClipPlane= flag;
00686 if (m_UseClipPlane)
00687 {
00688 QHash<GLenum, GLC_Plane*>::iterator iClip= m_ClipPlanesHash.begin();
00689 while (m_ClipPlanesHash.constEnd() != iClip)
00690 {
00691 GLenum planeKey= iClip.key();
00692 GLC_Plane* pPlane= iClip.value();
00693
00694 glClipPlane (planeKey, pPlane->data());
00695 glEnable (planeKey);
00696 ++iClip;
00697 }
00698 }
00699 else
00700 {
00701 QHash<GLenum, GLC_Plane*>::iterator iClip= m_ClipPlanesHash.begin();
00702 while (m_ClipPlanesHash.constEnd() != iClip)
00703 {
00704 glDisable(iClip.key());
00705 ++iClip;
00706 }
00707 }
00708
00709 }