/* * QGLViewer.cpp * $Id: QGLViewer.cpp,v 1.12 2001/11/20 16:23:49 guenth Exp $ * * Copyright (C) 1999, 2000 Markus Janich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * As a special exception to the GPL, the QGLViewer authors (Markus * Janich, Michael Meissner, Richard Guenther, Alexander Buck and Thomas * Woerner) give permission to link this program with Qt (non-)commercial * edition, and distribute the resulting executable, without including * the source code for the Qt (non-)commercial edition in the source * distribution. * */ // Qt /////// #include #include #include #include #include // System /////////// // Own /////////// #include "QGLViewer.h" #include "QGLSignalWidget.h" #include "CCamera.h" #include "QCameraDrag.h" #include "QStereoCtrl.h" #include "pictures/movecursor.xpm" #include "pictures/selectcursor.xpm" // Function : QGLViewer // Parameters: QWidget *parent, // const char *name, const QGLWidget *shareWidget, // WFlags f, bool viewertype, // const QGLFormat &format // Purpose : default constructor. // Comments : See docu for details. QGLViewer::QGLViewer(QWidget *parent, const char *name, const QGLWidget *shareWidget, WFlags f, bool viewertype, const QGLFormat &format) : QFrame(parent, name, f), m_eRenderMode(GL_RENDER), m_fFullViewer(viewertype), m_stereoMode(STEREO_OFF), m_fAllowStereoSimulation(false), m_pStereoCtrl(NULL), m_fRefresh(false), m_fHandleMouseEvents(true), m_nRefreshRate(25) /*********************************************************************/ { initQFrame(name, shareWidget, f, format); initCursors(); initPopupMenu(); initConnects(); setFocusPolicy(StrongFocus); setFrameStyle(Box|Sunken); m_nTimerID = startTimer(40); } // Function : QGLViewer // Parameters: const CCamera &homecam, QWidget *parent, // const char *name, const QGLWidget *shareWidget, // WFlags f, bool viewertype, // const QGLFormat &format // Purpose : Constructor including a camera for the home position box // of the scene. // NOTE: The current camera will also be set to the given homecam. // Comments : See docu for details. QGLViewer::QGLViewer(const CCamera &homecam, QWidget *parent, const char *name, const QGLWidget *shareWidget, WFlags f, bool viewertype, const QGLFormat &format) : QFrame(parent, name, f), m_cCurrentCamera(homecam), m_cHomeCamera(homecam), m_eRenderMode(GL_RENDER), m_fFullViewer(viewertype), m_stereoMode(STEREO_OFF), m_fAllowStereoSimulation(false), m_pStereoCtrl(NULL), m_fRefresh(false), m_fHandleMouseEvents(true), m_nRefreshRate(25) /*********************************************************************/ { initQFrame(name, shareWidget, f, format); initCursors(); initPopupMenu(); initConnects(); setFocusPolicy(StrongFocus); setFrameStyle(Box|Sunken); m_nTimerID = startTimer(40); } // Function : QGLViewer // Parameters: const CBoundingBox3D bbox, QWidget *parent, // const char *name, const QGLWidget *shareWidget, // WFlags f, bool viewertype, // const QGLFormat &format // Purpose : Constructor including a boundingbox // of the scene. // Comments : See docu for details. QGLViewer::QGLViewer(const CBoundingBox3D &bbox, QWidget *parent, const char *name, const QGLWidget *shareWidget, WFlags f, bool viewertype, const QGLFormat &format) : QFrame(parent, name, f), m_eRenderMode(GL_RENDER), m_fFullViewer(viewertype), m_stereoMode(STEREO_OFF), m_fAllowStereoSimulation(false), m_pStereoCtrl(NULL), m_fRefresh(false), m_fHandleMouseEvents(true), m_nRefreshRate(25) /*********************************************************************/ { m_cHomeCamera.setBoundingBox(bbox); m_cCurrentCamera.setBoundingBox(bbox); initQFrame(name, shareWidget, f, format); initCursors(); initPopupMenu(); initConnects(); setFocusPolicy(StrongFocus); setFrameStyle(Box|Sunken); m_nTimerID = startTimer(40); } // Function : setRefreshRate // Parameters: int nFramesPerSecond // Purpose : Sets the refresh rate of the context. // If there are more refresh calls like sltUpdateView() do // they were dropped. // Comments : See docu for details. void QGLViewer::setRefreshRate(int nFramesPerSecond) /*********************************************************************/ { m_nRefreshRate = nFramesPerSecond; killTimer(m_nTimerID); m_nTimerID = startTimer(1000.0/nFramesPerSecond); } // Function : setBoundingBox // Parameters: const CBoundingBox3D &cBBox, bool fUpdate // Purpose : Sets boundingbox of the entire scene and fits the scene // to the view area if 'fUpdate' is set to 'true'. // Comments : See docu for details. void QGLViewer::setBoundingBox(const CBoundingBox3D &cBBox, bool fUpdate) /*********************************************************************/ { m_cHomeCamera.setBoundingBox(cBBox, fUpdate); m_cCurrentCamera.setBoundingBox(cBBox, fUpdate); } // Function : setCamera // Parameters: const CCamera &cCamera, CameraType which // Purpose : Sets the specified camera(s) and updates the view if necessary // Comments : See docu for details. void QGLViewer::setCamera(const CCamera &cCamera, CameraType which) /*********************************************************************/ { if( which & HomeCam ) { m_cHomeCamera = cCamera; } if( which & CurrentCam ) { m_cCurrentCamera = cCamera; setVPRes(m_pQGLWidget->width(), m_pQGLWidget->height()); sltUpdateView(); emit(sigFovyChanged(cCamera.getFovy())); emit(sigRatioChanged(cCamera.getRatio())); } } // Function : sltSetProjectionMode // Parameters: // Purpose : Sets up the PROJECTION matrix depending on the projectionmode. // Comments : See docu for details. void QGLViewer::sltSetProjectionMode() /*********************************************************************/ { double ardVVolume[6]; m_cCurrentCamera.getVVolume(ardVVolume); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (m_cCurrentCamera.getCameraType() == CCamera::perspective) { // Perspective projection glFrustum(ardVVolume[0], ardVVolume[1], ardVVolume[2], ardVVolume[3], ardVVolume[4], ardVVolume[5]); } else { glOrtho(ardVVolume[0], ardVVolume[1], ardVVolume[2], ardVVolume[3], ardVVolume[4], ardVVolume[5]); } emit(sigProjModeToggled()); sltUpdateView(); } // Function : sltViewAll // Parameters: // Purpose : Modifies the camera that the entire scene resides // within the currently defined view frustum. // Comments : See docu for details. void QGLViewer::sltViewAll() /*********************************************************************/ { m_cCurrentCamera.viewAll(); sltSetProjectionMode(); } // Function : sltSetHome // Parameters: // Purpose : Sets home position. // Comments : See docu for details. void QGLViewer::sltSetHome() /*********************************************************************/ { m_cHomeCamera = m_cCurrentCamera; } // Function : sltGoHome // Parameters: // Purpose : The current camera is replaced by the home camera. // Comments : See docu for details. void QGLViewer::sltGoHome() /*********************************************************************/ { m_cCurrentCamera = m_cHomeCamera; sltUpdateView(); } // Function : sltToggleProjectionMode // Parameters: // Purpose : Toggles between parallel or perspective projection. // Comments : See docu for details. void QGLViewer::sltToggleProjectionMode() /*********************************************************************/ { if(m_cCurrentCamera.getCameraType() == CCamera::perspective) { m_cCurrentCamera.setCameraType(CCamera::orthographic); m_cHomeCamera.setCameraType(CCamera::orthographic); } else { m_cCurrentCamera.setCameraType(CCamera::perspective); m_cHomeCamera.setCameraType(CCamera::perspective); } sltUpdateView(); emit( sigProjModeToggled() ); }; // Function : sltSetVPRes // Parameters: int nWidth, int nHeight // Purpose : Sets the viewplane resolution of the current- and // homecamera according to the resolution of the viewport. // Comments : See docu for details. void QGLViewer::setVPRes(int nWidth, int nHeight) /*********************************************************************/ { double rdRatio = double(nWidth)/nHeight; // double rdFovy = (double(nHeight) / m_cCurrentCamera.getVPHeight()) * m_cCurrentCamera.getFovy(); m_cCurrentCamera.setVPHeight(nHeight); m_cCurrentCamera.setRatio(rdRatio); // m_cCurrentCamera.setFovy(rdFovy); m_cHomeCamera.setVPHeight(nHeight); m_cHomeCamera.setRatio(rdRatio); // m_cHomeCamera.setFovy(rdFovy); emit(sigRatioChanged(rdRatio)); } // Function : initQFrame // Parameters: const char *name, const QGLWidget *shareWidget, // WFlags f, const QGLFormat &format // Purpose : Instantiates the QGLWidget and place it in a QFrame. // The pointer of the QFrame can be read with the function // getQFrame(), see below. // Comments : See docu for details. void QGLViewer::initQFrame(const char *name, const QGLWidget *shareWidget, WFlags f, const QGLFormat &format) /*********************************************************************/ { m_pQFrame = new QFrame(this, "frame" ); if(m_pQFrame==0) { cerr << "Can't allocate QFrame where QGLSignalWidget is placed!!/n"; exit(17); } m_pQFrame->setFrameStyle( QFrame::Sunken | QFrame::Panel ); m_pQFrame->setLineWidth( 2 ); // Create a layout manager for the openGL widget m_pQHBoxLayout = new QHBoxLayout( m_pQFrame, 2, 2, "hlayout1"); if(m_pQFrame==0) { cerr << "Can't allocate horiz. layout for the QFrame!!/n"; exit(17); } // create widget and add it to the layout if(format==0) { m_pQGLWidget = new QGLSignalWidget(m_pQFrame, name, shareWidget, f); } else { m_pQGLWidget = new QGLSignalWidget(format, m_pQFrame, name, shareWidget, f); } if(m_pQGLWidget==0) { cerr << "Can't allocate drawing-area for OpenGL output!!/n"; exit(17); } m_pQHBoxLayout->addWidget( m_pQGLWidget, 1 ); m_pQHBoxLayout->activate(); m_pQGLWidget->setFocusProxy(this); } // Function : initCursors // Parameters: // Purpose : initializes the mousepointers. // Comments : void QGLViewer::initCursors() /*********************************************************************/ { // Initialize bitmaps for cursors m_qMovePix = QPixmap(movecursor_xpm); m_qSelectPix = QPixmap(selectcursor_xpm); m_qSelectMaskPix = QPixmap(selectcursor_mask_xpm); // make the cursors m_pqMoveCursor = new QCursor( QBitmap(32,32,true), m_qMovePix, 5, 3); Q_CHECK_PTR( m_pqMoveCursor ); m_pqSelectCursor = new QCursor( m_qSelectPix, m_qSelectMaskPix, 1, 1); Q_CHECK_PTR( m_pqSelectCursor ); m_pQGLWidget->setCursor( *m_pqMoveCursor ); } // Function : initConnects // Parameters: // Purpose : Makes all necessary connects. // Comments : See docu for details. void QGLViewer::initConnects() /*********************************************************************/ { connect(m_pQGLWidget, SIGNAL(sigMouseRelease(QMouseEvent *)), this, SLOT(sltSwitchMouseRelease(QMouseEvent *))); connect(m_pQGLWidget, SIGNAL(sigMouseMove(QMouseEvent *)), this, SLOT(sltSwitchMouseMove(QMouseEvent *))); connect(m_pQGLWidget, SIGNAL(sigMousePress(QMouseEvent *)), this, SLOT(sltSwitchMousePress(QMouseEvent *))); connect(m_pQGLWidget, SIGNAL(sigResizeGL(int, int)), this, SLOT(sltResizeGL(int, int))); connect(m_pQGLWidget, SIGNAL(sigInitGL()), this, SIGNAL(sigInitGL())); connect(m_pQGLWidget, SIGNAL(sigRedrawGL()), this, SLOT(sltPaintGL())); // drag'n drop stuff connect(m_pQGLWidget, SIGNAL(sigDragEnter(QDragEnterEvent *)), SLOT(sltManageDragEnter(QDragEnterEvent *))); connect(m_pQGLWidget, SIGNAL(sigDragLeave(QDragLeaveEvent *)), SLOT(sltManageDragLeave(QDragLeaveEvent *))); connect(m_pQGLWidget, SIGNAL(sigDrop(QDropEvent *)), SLOT(sltManageDrop(QDropEvent *))); emit(sigInitGL()); } // Function : setFrustum // Parameters: StereoBuffer buffer // Purpose : Sets the frustum in the current OpenGL context. // Comments : See docu for details. void QGLViewer::setFrustum(StereoBuffer buffer) /*********************************************************************/ { switch ( buffer ) { case MONO: setFrustumMono(); break; case STEREO_LEFT: setFrustumStereoLeft(); break; case STEREO_RIGHT: setFrustumStereoRight(); break; } } // Function : setFrustumStereoLeft // Parameters: // Purpose : Sets the left frustum for stereo simulation. // Comments : See docu for details. void QGLViewer::setFrustumStereoLeft() /*********************************************************************/ { if ( m_stereoMode == STEREO_ON || m_stereoMode == STEREO_SIMULATE ) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); m_pStereoCtrl->activateLeftStereoFrustum(); glMatrixMode(GL_MODELVIEW); if ( m_stereoMode == STEREO_ON ) { glDrawBuffer(GL_BACK_LEFT); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } else glDrawBuffer(GL_BACK); } else { cout<<"Not in stereo mode. Use mono frustum instead."<activateRightStereoFrustum(); glMatrixMode(GL_MODELVIEW); if ( m_stereoMode == STEREO_ON ) { glDrawBuffer(GL_BACK_RIGHT); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } else glDrawBuffer(GL_BACK); } else { cout<<"Not in stereo mode. Use mono frustum instead."<getVVolume( ardVVolume ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ( getCameraPtr()->getCameraType()==CCamera::perspective) glFrustum(ardVVolume[0], ardVVolume[1], ardVVolume[2], ardVVolume[3], ardVVolume[4], ardVVolume[5]); else glOrtho(ardVVolume[0], ardVVolume[1], ardVVolume[2], ardVVolume[3], ardVVolume[4], ardVVolume[5]); glMatrixMode(GL_MODELVIEW); glDrawBuffer(GL_BACK); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } // Function : setLookAt // Parameters: // Purpose : Sets the 'LookAt' parameters. // Comments : See docu for details. void QGLViewer::setLookAt() /*********************************************************************/ { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); CP3D eyePos = getCameraPtr()->getEyePos(); CP3D refPoint = getCameraPtr()->getRefPoint(); CV3D viewUp = getCameraPtr()->getViewUp(); gluLookAt( eyePos[0], eyePos[1], eyePos[2], refPoint[0], refPoint[1], refPoint[2], viewUp[0], viewUp[1], viewUp[2] ); } // Function : sltToggleStereo // Parameters: // Purpose : Toggles between stereo on and off (if available). // Initially stereo is off. // Comments : See docu for details. void QGLViewer::sltToggleStereo() /*********************************************************************/ { if ( m_stereoMode==STEREO_OFF ) { if ( getDrawArea()->format().stereo() ) { system("/usr/gfx/setmon -n 1024x768_96s"); cout<<"Stereo supported! Activate stereo mode!"<showDlg(); } else { if ( m_stereoMode == STEREO_SIMULATE ) { cout<<"Deactivate stereo simulation!"<hideDlg(); } sltUpdateView(); } // Function : sltToggleRenderMode // Parameters: // Purpose : toggles the render mode of the viewer. // Comments : See docu for details. void QGLViewer::sltToggleRenderMode() /*********************************************************************/ { if( m_eRenderMode == GL_RENDER) { m_eRenderMode = GL_SELECT; m_pQGLWidget->setCursor( *m_pqSelectCursor ); } else { m_eRenderMode = GL_RENDER; m_pQGLWidget->setCursor( *m_pqMoveCursor ); } emit(sigRenderModeChanged()); } // Function : sltManageDragEnter // Parameters: QDragEnterEvent *pqEvent // Purpose : // Comments : See docu for details. void QGLViewer::sltManageDragEnter(QDragEnterEvent *pqEvent) /*********************************************************************/ { if (QCameraDrag::canDecode(pqEvent)) { pqEvent->accept(); } } // Function : sltManageDragLeave // Parameters: QDragLeaveEvent *pqEvent // Purpose : // Comments : See docu for details. void QGLViewer::sltManageDragLeave(QDragLeaveEvent *pqEvent) /*********************************************************************/ { } // Function : sltManageDrop // Parameters: QDropEvent *pqEvent // Purpose : // Comments : See docu for details. void QGLViewer::sltManageDrop(QDropEvent *pqEvent) /*********************************************************************/ { CCamera cCamera; if (pqEvent->source() != this) { if (QCameraDrag::decode(pqEvent, cCamera)) { setCamera(cCamera); return; } } } // Function : initPopupMenu // Parameters: // Purpose : initializes the popup menu // Comments : See docu for details. void QGLViewer::initPopupMenu() /*********************************************************************/ { m_pqPopupMenu = new QPopupMenu( this ); Q_CHECK_PTR( m_pqPopupMenu ); connect(m_pQGLWidget, SIGNAL(sigMousePress(QMouseEvent *)), SLOT(sltPopMenu(QMouseEvent *))); } // Function : sltPopMenu // Parameters: QMouseEvent *pqEvent // Purpose : Pops up the menu. // Comments : See docu for details. void QGLViewer::sltPopMenu(QMouseEvent *pqEvent) /*********************************************************************/ { if ( pqEvent->button() == RightButton ) { m_pqPopupMenu->popup( pqEvent->globalPos() ); } } // Function : mousePressEvent // Parameters: QMouseEvent *pqEvent // Purpose : Reimplements the mouse-press event function // inherited from QWidget. // Comments : See docu for details. void QGLViewer::mousePressEvent(QMouseEvent *pqEvent) /*********************************************************************/ { sltPopMenu(pqEvent); } // Function : sltResizeGL // Parameters: int w, int h // Purpose : Does some initial stuff before calling the 'ResizeGl()' // function of the application by sending a 'sigResizeGL()' // signal. // Comments : See docu for details. void QGLViewer::sltResizeGL(int w, int h) /*********************************************************************/ { glViewport(0, 0, (GLint)w, (GLint)h); sltSetProjectionMode(); setVPRes(w, h); emit(sigResizeGL(w, h)); } // Function : sltPaintGL // Parameters: // Purpose : Does some initial stuff before calling the 'PaintGl()' // function of the application by sending a 'sigRedrawGL()' // signal. // Comments : See docu for details. void QGLViewer::sltPaintGL() /*********************************************************************/ { setLookAt(); if ( getStereoMode() == QGLViewer::STEREO_ON ) { setFrustum(QGLViewer::STEREO_RIGHT); emit(sigRedrawGL()); setFrustum(QGLViewer::STEREO_LEFT); emit(sigRedrawGL()); } else if ( getStereoMode() == QGLViewer::STEREO_OFF ) { setFrustum(); emit(sigRedrawGL()); } else if ( getStereoMode() == QGLViewer::STEREO_SIMULATE ) { glDrawBuffer(GL_BACK); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); setFrustum(QGLViewer::STEREO_RIGHT); emit(sigRedrawGL()); setFrustum(QGLViewer::STEREO_LEFT); emit(sigRedrawGL()); } }