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