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