]> Git trees. - libqmvoc.git/commitdiff
Added OpenGL selection code.
authorBenoît Jacob <jacob.benoit.1@gmail.com>
Tue, 25 Jul 2006 13:18:32 +0000 (13:18 +0000)
committerBenoît Jacob <jacob.benoit.1@gmail.com>
Tue, 25 Jul 2006 13:18:32 +0000 (13:18 +0000)
Single left click on an atom now selects/deselects it, if the mouse
didn't move between button press and button release. Some tolerance (2
pixels) added to make that usable with imprecise pointing devices.

TODO: notify the treeview (currently it doesn't get updated).

M    kalzium/src/kalziumglwidget.h
M    kalzium/src/kalziumglhelperclasses.h
M    kalzium/src/kalziumglwidget.cpp
M    kalzium/src/kalziumglhelperclasses.cpp

svn path=/trunk/KDE/kdeedu/kalzium/src/kalziumglwidget.h; revision=566121

kalzium/kalziumglhelperclasses.cpp
kalzium/kalziumglhelperclasses.h
kalzium/kalziumglwidget.cpp
kalzium/kalziumglwidget.h

index 6b250f0064fc8dacf3f8baabc95ba399f804ba6b..1bb854b1647a715dec9810e563725e84540ed95e 100644 (file)
@@ -657,4 +657,36 @@ bool KalziumGLHelpers::createOrthoBasisGivenFirstVector
        w.normalize();
        return true;
 }
+/*
+void LinearRegression( const std::list<vector3 *> & points,
+       vector3 & ret_plane_base_point, vector3 & ret_plane_normal_vector )
+{
+       double sum_x = 0.0;
+       double sum_y = 0.0;
+       double sum_z = 0.0;
+       double sum_xx = 0.0;
+       double sum_xy = 0.0;
+       double sum_xz = 0.0;
+       double sum_yy = 0.0;
+       double sum_yz = 0.0;
+       double sum_zz = 0.0;
+
+       for( std::list<vector3 *>::const_iterator iter = points.begin();
+               iter != points.end(); iter++ )
+       {
+               double x = iter->x();
+               double y = iter->y();
+               double z = iter->z();
+               sum_x += x;
+               sum_y += y;
+               sum_z += z;
+               sum_xx += x * x;
+               sum_xy += x * y;
+               sum_xz += x * z;
+               sum_yy += y * y;
+               sum_yz += y * z;
+               sum_zz += z * z;
+       }
 
+       
+}*/
index c5a546b9923a11540ecc5e0a6be1a2d7f29b80e3..e027b21937f0616a5a489a31a1fb99a1ef8ea5ff 100644 (file)
@@ -159,6 +159,10 @@ struct Color
 */
 bool createOrthoBasisGivenFirstVector( const OpenBabel::vector3 &U, OpenBabel::vector3 & v, OpenBabel::vector3 & w );
 
+/*void LinearRegression( const std::list<vector3 *> & points,
+       vector3 & ret_plane_base_point, vector3 & ret_plane_normal_vector );
+*/
+
 /**
 * This is an abstract base class for an OpenGL vertex array, with an option
 * (controlled by USE_DISPLAY_LISTS) to compile a display list from it, in which
index 51a09e7d797285f659d45e728c9104ce4281c128..2c7d3d1c5b2bd56c23e592f5b7e1989e19d4d6a2 100644 (file)
@@ -33,7 +33,8 @@ using namespace OpenBabel;
 KalziumGLWidget::KalziumGLWidget( QWidget * parent )
        : QGLWidget( parent )
 {
-       m_isDragging = false;
+       m_isLeftButtonPressed = false;
+       m_movedSinceLeftButtonPressed = false;
        m_molecule = 0;
        m_detail = 0;
        m_displayList = 0;
@@ -110,13 +111,57 @@ void KalziumGLWidget::paintGL()
                return;
        }
 
+       renderScene();
+
+#ifdef USE_FPS_COUNTER
+       FPSCounter();
+       update();
+#endif
+}
+
+void KalziumGLWidget::renderScene( GLenum renderMode,
+                       const QPoint *mousePosition,
+                       GLsizei selectionBufferSize,
+                       GLuint *selectionBuffer,
+                       GLint *numberOfHits )
+{
+       // if renderMode is not GL_RENDER, check that it is GL_SELECT and that
+       // the required arguments have been passed
+       if( renderMode != GL_RENDER )
+       {
+               if( renderMode != GL_SELECT
+                || ! mousePosition
+                || ! selectionBufferSize
+                || ! selectionBuffer
+                || ! numberOfHits ) return;
+       }
+
+       if( renderMode == GL_SELECT )
+       {
+               glSelectBuffer( selectionBufferSize, selectionBuffer );
+               glRenderMode( GL_SELECT );
+       }
+
+       // set up the projection matrix
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
+       if( renderMode == GL_SELECT )
+       {
+               // in GL_SELECT mode, we only want to render a tiny area around
+               // the mouse pointer
+               GLint viewport[4];
+               glGetIntegerv( GL_VIEWPORT, viewport );
+               gluPickMatrix( mousePosition->x(),
+                       viewport[3] - mousePosition->y(),
+                       3, 3, viewport);
+       }
        gluPerspective( 40.0, float( width() ) / height(),
                getMolRadius(), 5.0 * getMolRadius() );
        glMatrixMode( GL_MODELVIEW );
 
-       glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+       // clear the buffers when in GL_RENDER mode
+       if( renderMode == GL_RENDER )
+               glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
        // set up the camera
        glLoadIdentity();
@@ -124,7 +169,7 @@ void KalziumGLWidget::paintGL()
        glMultMatrixd ( m_RotationMatrix );
 
        // set up fog
-       if( m_useFog )
+       if( m_useFog && renderMode == GL_RENDER )
        {
                glEnable( GL_FOG );
                GLfloat fogColor[] = { 0.0, 0.0, 0.0, 1.0 };
@@ -136,6 +181,13 @@ void KalziumGLWidget::paintGL()
        }
        else glDisable( GL_FOG );
 
+       // initialize the name stack when in GL_SELECT mode
+       if( renderMode == GL_SELECT )
+       {
+               glInitNames();
+               glPushName( 0 );
+       }
+
 #ifdef USE_DISPLAY_LISTS
        if( m_haveToRecompileDisplayList )
        {
@@ -153,12 +205,14 @@ void KalziumGLWidget::paintGL()
        }
        glCallList( m_displayList );
 #endif
+
        renderSelection();
 
-#ifdef USE_FPS_COUNTER
-       FPSCounter();
-       update();
-#endif
+       if( renderMode == GL_SELECT )
+       {
+               glFlush();
+               *numberOfHits = glRenderMode( GL_RENDER );
+       }
 }
 
 void KalziumGLWidget::renderAtoms()
@@ -197,6 +251,7 @@ void KalziumGLWidget::renderSelection()
        glEnable( GL_BLEND );
        foreach(OpenBabel::OBAtom* atom, m_selectedAtoms)
        {
+               glLoadName( atom->GetIdx() );
                m_sphere.draw( atom->GetVector(),
                        0.18 + m_molStyle.getAtomRadius( atom ) );
        }
@@ -249,8 +304,11 @@ void KalziumGLWidget::mousePressEvent( QMouseEvent * event )
 {
        if( event->buttons() & Qt::LeftButton )
        {       
-               m_isDragging = true;
+               m_isLeftButtonPressed = true;
+               m_movedSinceLeftButtonPressed = false;
                m_lastDraggingPosition = event->pos ();
+               m_initialDraggingPosition = event->pos ();
+
        }
 }
 
@@ -258,17 +316,35 @@ void KalziumGLWidget::mouseReleaseEvent( QMouseEvent * event )
 {
        if( !( event->buttons() & Qt::LeftButton ) )
        {
-               m_isDragging = false;
-               updateGL();
+               m_isLeftButtonPressed = false;
+
+               if( ! m_movedSinceLeftButtonPressed )
+               {
+                       OBAtom *atomUnderMouse =
+                               getAtomUnderMouse( event->pos() );
+                       if( atomUnderMouse )
+                       {
+                               if( m_selectedAtoms.contains( atomUnderMouse ) )
+                               {
+                                       m_selectedAtoms.removeAll(
+                                               atomUnderMouse );
+                               }
+                               else m_selectedAtoms.append( atomUnderMouse );
+                       }
+                       updateGL();
+               }
        }
 }
 
 void KalziumGLWidget::mouseMoveEvent( QMouseEvent * event )
 {
-       if( m_isDragging )
+       if( m_isLeftButtonPressed )
        {
                QPoint deltaDragging = event->pos() - m_lastDraggingPosition;
                m_lastDraggingPosition = event->pos();
+               if( ( event->pos()
+                       - m_initialDraggingPosition ).manhattanLength() > 2 )
+                       m_movedSinceLeftButtonPressed = true;
 
                glPushMatrix();
                glLoadIdentity();
@@ -339,6 +415,7 @@ void KalziumGLWidget::setupObjects()
 
 void KalziumGLWidget::drawAtom( OBAtom *atom )
 {
+       glLoadName( atom->GetIdx() );
        Color( atom ).applyAsMaterials();
        m_sphere.draw( atom->GetVector(), m_molStyle.getAtomRadius( atom ) );
 }
@@ -366,15 +443,18 @@ void KalziumGLWidget::drawBond( OBBond *bond )
        switch( m_molStyle.m_bondStyle )
        {
                case MolStyle::BONDS_GRAY:
+                       glLoadName( 0 );
                        Color( 0.55, 0.55, 0.55 ).applyAsMaterials();
                        m_cylinder.draw( v1, v2, radius, order,
                                m_molStyle.m_multipleBondShift );
                        break;
 
                case MolStyle::BONDS_USE_ATOMS_COLORS:
+                       glLoadName( atom1->GetIdx() );
                        Color( atom1 ).applyAsMaterials();
                        m_cylinder.draw( v1, v3, radius, order,
                                m_molStyle.m_multipleBondShift );
+                       glLoadName( atom2->GetIdx() );
                        Color( atom2 ).applyAsMaterials();
                        m_cylinder.draw( v2, v3, radius, order,
                                m_molStyle.m_multipleBondShift );
@@ -489,4 +569,44 @@ void KalziumGLWidget::slotAtomsSelected( QList<OpenBabel::OBAtom*> atoms )
        updateGL();
 }
 
+OpenBabel::OBAtom * KalziumGLWidget::getAtomUnderMouse(
+       const QPoint & mousePosition )
+{
+       if( ! m_molecule ) return 0;
+
+       const GLsizei selectionBufferSize = 1024;
+       GLuint selectionBuffer[selectionBufferSize];
+       GLint numberOfHits;
+
+       renderScene( GL_SELECT,
+               &mousePosition,
+               selectionBufferSize,
+               selectionBuffer,
+               &numberOfHits );
+
+       unsigned int i, j;
+       GLuint names, *ptr = selectionBuffer,
+               minZ = 0xffffffff,
+               *ptrNames,
+               numberOfNames = 0;
+       printf ("hits = %d\n", numberOfHits);
+       for( i = 0; i < numberOfHits; i++ )
+       {
+               names = *ptr;
+               ptr++;
+               if( *ptr < minZ )
+               {
+                       numberOfNames = names;
+                       minZ = *ptr;
+                       ptrNames = ptr+2;
+               }
+               ptr += names+2;
+       }
+
+       for( j = 0, ptr = ptrNames; j < numberOfNames; j++, ptr++ )
+               if( *ptr ) return m_molecule->GetAtom( *ptr );
+
+       return 0;
+}
+
 #include "kalziumglwidget.moc"
index 10b7e1f16e7e1956caf04c3f2f19ab996a875a62..f5f04b93d6810b99f6123da6037d59bdb8304309 100644 (file)
@@ -50,9 +50,12 @@ class KalziumGLWidget : public QGLWidget
                 * equals true if the user is currently dragging (rotating)
                 * the view
                 */
-               bool m_isDragging;
+               bool m_isLeftButtonPressed;
+
+               bool m_movedSinceLeftButtonPressed;
 
                QPoint m_lastDraggingPosition;
+               QPoint m_initialDraggingPosition;
 
                /**
                 * Stores the rotation that is applied to the model.
@@ -217,6 +220,12 @@ class KalziumGLWidget : public QGLWidget
 
                void drawBond( OpenBabel::OBBond *bond );
 
+               void renderScene( GLenum renderMode = GL_RENDER,
+                       const QPoint * mousePosition = 0,
+                       GLsizei selectionBufferSize = 0,
+                       GLuint * selectionBuffer = 0,
+                       GLint * numberOfHits = 0 );
+
                /**
                 * recomputes the geometry of the geometric objects ( sphere,
                 * cylinder ).
@@ -231,6 +240,9 @@ class KalziumGLWidget : public QGLWidget
                 * @param style the wanted molecule style
                 */
                void setMolStyle( int style );
+
+               OpenBabel::OBAtom * getAtomUnderMouse(
+                       const QPoint & mousePosition );
 };
 #endif // KALZIUMGLWIDGET_H