]> Git trees. - libqmvoc.git/commitdiff
Prerequisite: you'll need OpenBabel SVN revision at least 1525.
authorBenoît Jacob <jacob.benoit.1@gmail.com>
Thu, 20 Jul 2006 12:39:14 +0000 (12:39 +0000)
committerBenoît Jacob <jacob.benoit.1@gmail.com>
Thu, 20 Jul 2006 12:39:14 +0000 (12:39 +0000)
Reorganization everywhere, especially:
 - Make much more use of OpenBabel, especially for the geometry-stuff
 - Molecule rendering style and related data is now stored using the
MolStyle struct.
 - Big reorganization in the way display lists are used, when this
option is enabled. It is currently disabled, though, because of what
might be a bug in Mesa3d.

New Features:
 - draw multiple bonds
 - support for van der Waals radius. Different atoms are now rendered
with different sizes.

Optimizations:
 - the sphere now uses 2x less memory when not using display
lists (achieved by using the same unique array as vertex&normal arrays)

Other changes:
 - improved specular color computation in Color::applyAsMaterials()
 - reorganized styles, removed "lines" style (looked useless, was
inconsistent with multiple bonds)
 - when the uses clicks "cancel" in the Load molecule dialog, don't try
to load the molecule with filename "".
 - lots more that I can't list

CCMAIL: geoff@geoffhutchison.net

M    src/kalziumglwidget.h
M    src/kalziumglhelperclasses.h
M    src/moleculeview.cpp
M    src/kalziumglwidget.cpp
M    src/kalziumglhelperclasses.cpp
M    src/moleculeviewerwidget.ui

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

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

index ebf826168b22ba91da84ed8467f563daaa687234..bb249bdec385044a3fabcdd39e11d89467b9022f 100644 (file)
 #include "kalziumglhelperclasses.h"
 #include <math.h>
 
-#ifdef USE_FPS_COUNTER
-#include <QTime>
-#endif
-
 using namespace KalziumGLHelpers;
+using namespace OpenBabel;
+
+void MolStyle::setup( BondStyle bondStyle, AtomStyle atomStyle,
+       double singleBondRadius,
+       double multipleBondRadius,
+       double multipleBondShift,
+       double atomRadiusFactor )
+{
+       m_bondStyle = bondStyle;
+       m_atomStyle = atomStyle;
+       m_singleBondRadius = singleBondRadius;
+       m_multipleBondRadius = multipleBondRadius;
+       m_multipleBondShift = multipleBondShift;
+       m_atomRadiusFactor = atomRadiusFactor;
+}
 
-Color::Color()
+double MolStyle::getAtomRadius( int atomicNumber )
 {
+       switch( m_atomStyle )
+       {
+               case ATOMS_USE_FIXED_RADIUS:
+                       return m_atomRadiusFactor;
+               case ATOMS_USE_VAN_DER_WAALS_RADIUS:
+                       return m_atomRadiusFactor
+                               * etab.GetVdwRad( atomicNumber );
+               default: return 0;
+       }
 }
 
 Color::Color( GLfloat red, GLfloat green, GLfloat blue,
@@ -32,6 +52,15 @@ Color::Color( GLfloat red, GLfloat green, GLfloat blue,
        m_alpha = alpha;
 }
 
+Color::Color( const OBAtom* atom )
+{
+       std::vector<double> rgb = etab.GetRGB( atom->GetAtomicNum() );
+       m_red = rgb[0];
+       m_green = rgb[1];
+       m_blue = rgb[2];
+       m_alpha = 1.0;
+}
+
 Color& Color::operator=( const Color& other )
 {
        m_red = other.m_red;
@@ -47,8 +76,16 @@ void Color::applyAsMaterials()
        GLfloat ambientColor [] = { m_red / 2, m_green / 2, m_blue / 2,
                                    m_alpha };
        GLfloat diffuseColor [] = { m_red, m_green, m_blue, m_alpha };
-       GLfloat specularColor [] = { (2.0 + m_red) / 3, (2.0 + m_green) / 3,
-               (2.0 + m_blue) / 3, m_alpha };
+
+       float s = ( 1.0 + fabsf( m_red - m_green )
+               + fabsf( m_blue - m_green ) + fabsf( m_blue - m_red ) ) / 3;
+
+       float t = 1.0 - s;
+
+       GLfloat specularColor [] = { s + t * m_red,
+               s + t * m_green,
+               s + t * m_blue,
+               m_alpha };
 
        glMaterialfv(GL_FRONT, GL_AMBIENT, ambientColor);
        glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseColor);
@@ -56,28 +93,29 @@ void Color::applyAsMaterials()
        glMaterialf(GL_FRONT, GL_SHININESS, 50.0);
 }
 
-VertexArray::VertexArray()
+VertexArray::VertexArray( GLenum mode,
+       bool hasIndexBuffer,
+       bool hasSeparateNormalBuffer )
 {
-       m_mode = GL_TRIANGLE_STRIP;
+       m_mode = mode;
        m_vertexBuffer = 0;
        m_normalBuffer = 0;
        m_indexBuffer = 0;
        m_displayList = 0;
+       m_hasIndexBuffer = hasIndexBuffer;
+       m_hasSeparateNormalBuffer = hasSeparateNormalBuffer;
+       m_isValid = false;
 }
 
 VertexArray::~VertexArray()
 {
-       if( m_indexBuffer ) delete [] m_indexBuffer;
-       if( m_vertexBuffer ) delete [] m_vertexBuffer;
-       if( m_normalBuffer ) delete [] m_normalBuffer;
+       freeBuffers();
        if( m_displayList )
                glDeleteLists( m_displayList, 1 );
 }
 
-bool VertexArray::allocateBuffers()
+void VertexArray::freeBuffers()
 {
-       if( m_vertexCount > 65536 ) return false;
-
        if( m_indexBuffer )
        {
                delete [] m_indexBuffer;
@@ -88,73 +126,80 @@ bool VertexArray::allocateBuffers()
                delete [] m_vertexBuffer;
                m_vertexBuffer = 0;
        }
-       if( m_normalBuffer ) 
+       if( m_normalBuffer && m_hasSeparateNormalBuffer 
        {
                delete [] m_normalBuffer;
                m_normalBuffer = 0;
        }
+}
+
+bool VertexArray::allocateBuffers()
+{
+       if( m_vertexCount > 65536 ) return false;
 
-       m_vertexBuffer = new Vector3<GLfloat>[m_vertexCount];
+       freeBuffers();
+
+       m_vertexBuffer = new Vector[m_vertexCount];
        if( ! m_vertexBuffer ) return false;
-       m_normalBuffer = new Vector3<GLfloat>[m_vertexCount];
-       if( ! m_normalBuffer ) return false;
-       m_indexBuffer = new unsigned short[m_indexCount];
-       if( ! m_indexBuffer ) return false;
+       
+       if( m_hasSeparateNormalBuffer )
+       {
+               m_normalBuffer = new Vector[m_vertexCount];
+               if( ! m_normalBuffer ) return false;
+       }
+       else m_normalBuffer = m_vertexBuffer;
+
+       if( m_hasIndexBuffer )
+       {
+               m_indexBuffer = new unsigned short[m_indexCount];
+               if( ! m_indexBuffer ) return false;
+       }
+
+       return true;
 }
 
 void VertexArray::do_draw()
 {
-       glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
-       glEnableClientState( GL_VERTEX_ARRAY );
-       glEnableClientState( GL_NORMAL_ARRAY );
-       glDisableClientState( GL_COLOR_ARRAY );
-       glDisableClientState( GL_EDGE_FLAG_ARRAY );
-       glDisableClientState( GL_INDEX_ARRAY );
-       glDisableClientState( GL_TEXTURE_COORD_ARRAY );
        glVertexPointer( 3, GL_FLOAT, 0, m_vertexBuffer );
        glNormalPointer( GL_FLOAT, 0, m_normalBuffer );
-       if( m_indexCount )
+       if( m_hasIndexBuffer )
                glDrawElements( m_mode, m_indexCount,
                        GL_UNSIGNED_SHORT, m_indexBuffer );
        else
                glDrawArrays( m_mode, 0, m_vertexCount );
-       glPopClientAttrib();
 }
 
-void VertexArray::compileDisplayListIfNeeded()
+void VertexArray::compileDisplayList()
 {
 #ifdef USE_DISPLAY_LISTS
        if( ! m_displayList )
                m_displayList = glGenLists( 1 );
        if( ! m_displayList ) return;
+       
        glNewList( m_displayList, GL_COMPILE );
        do_draw();
        glEndList();
 
-       delete [] m_vertexBuffer;
-       m_vertexBuffer = 0;
-       delete [] m_normalBuffer;
-       m_normalBuffer = 0;
-       if( m_indexBuffer ) delete [] m_indexBuffer;
-       m_indexBuffer = 0;
+       freeBuffers();
 #endif
 }
 
 void VertexArray::initialize()
 {
+       m_isValid = false;
        m_vertexCount = computeVertexCount();
        m_indexCount = computeIndexCount();
        if( m_indexCount < 0 || m_vertexCount < 0 ) return;
-       allocateBuffers();
+       if( ! allocateBuffers() ) return;
        buildBuffers();
-       compileDisplayListIfNeeded();
+       compileDisplayList();
+       m_isValid = true;
 }
 
 Sphere::Sphere()
-       : VertexArray()
+       : VertexArray( GL_TRIANGLE_STRIP, true, false )
 {
        m_detail = 0;
-       m_radius = -1.0;
 }
 
 unsigned short Sphere::indexOfVertex( int strip, int column, int row)
@@ -167,31 +212,27 @@ void Sphere::computeVertex( int strip, int column, int row)
        strip %= 5;
        int next_strip = (strip + 1) % 5;
 
-       Vector3<GLfloat> *vertex =
-               &m_vertexBuffer[ indexOfVertex( strip, column, row ) ];
-
-       Vector3<GLfloat> *normal =
-               &m_normalBuffer[ indexOfVertex( strip, column, row ) ];
-
-       const GLfloat phi = ( 1 + sqrt(5) ) / 2;
-
-       const Vector3<GLfloat> northPole( 0, 1, phi );
-       const Vector3<GLfloat> northVertex[5] = {
-               Vector3<GLfloat>( 0, -1, phi ),
-               Vector3<GLfloat>( phi, 0, 1 ),
-               Vector3<GLfloat>( 1, phi, 0 ),
-               Vector3<GLfloat>( -1, phi, 0 ),
-               Vector3<GLfloat>( -phi, 0, 1 ) };
-       const Vector3<GLfloat> southVertex[5] = {
-               Vector3<GLfloat>( -1, -phi, 0 ),
-               Vector3<GLfloat>( 1, -phi, 0 ),
-               Vector3<GLfloat>( phi, 0, -1 ),
-               Vector3<GLfloat>( 0, 1, -phi ),
-               Vector3<GLfloat>( -phi, 0, -1 )
+       unsigned short index = indexOfVertex( strip, column, row );
+
+       const double phi = ( 1 + sqrt(5) ) / 2;
+
+       const vector3 northPole( 0, 1, phi );
+       const vector3 northVertices[5] = {
+               vector3( 0, -1, phi ),
+               vector3( phi, 0, 1 ),
+               vector3( 1, phi, 0 ),
+               vector3( -1, phi, 0 ),
+               vector3( -phi, 0, 1 ) };
+       const vector3 southVertices[5] = {
+               vector3( -1, -phi, 0 ),
+               vector3( 1, -phi, 0 ),
+               vector3( phi, 0, -1 ),
+               vector3( 0, 1, -phi ),
+               vector3( -phi, 0, -1 )
                 };
-       const Vector3<GLfloat> southPole( 0, -1, -phi );
+       const vector3 southPole( 0, -1, -phi );
 
-       const Vector3<GLfloat> *v0, *v1, *v2;
+       const vector3 *v0, *v1, *v2;
        int  c1, c2;
 
        if( row >= 2 * m_detail && column == 0 )
@@ -205,51 +246,51 @@ void Sphere::computeVertex( int strip, int column, int row)
 
        if( row  <= m_detail )
        {
-               v0 = &northVertex[strip];
+               v0 = &northVertices[strip];
                v1 = &northPole;
-               v2 = &northVertex[next_strip];
+               v2 = &northVertices[next_strip];
                c1 = m_detail - row;
                c2 = column;
        }
        else if( row >= 2 * m_detail )
        {
-               v0 = &southVertex[next_strip];
+               v0 = &southVertices[next_strip];
                v1 = &southPole;
-               v2 = &southVertex[strip];
+               v2 = &southVertices[strip];
                c1 = row - 2 * m_detail;
                c2 = m_detail - column;
        }
        else if( row <= m_detail + column )
        {
-               v0 = &northVertex[next_strip];
-               v1 = &southVertex[next_strip];
-               v2 = &northVertex[strip];
+               v0 = &northVertices[next_strip];
+               v1 = &southVertices[next_strip];
+               v2 = &northVertices[strip];
                c1 = row - m_detail;
                c2 = m_detail - column;
        }
        else
        {
-               v0 = &southVertex[strip];
-               v1 = &southVertex[next_strip];
-               v2 = &northVertex[strip];
+               v0 = &southVertices[strip];
+               v1 = &southVertices[next_strip];
+               v2 = &northVertices[strip];
                c1 = column;
                c2 = 2 * m_detail - row;
        }
 
-       GLfloat u1 = GLfloat(c1) / m_detail;
-       GLfloat u2 = GLfloat(c2) / m_detail;
+       double u1 = double(c1) / m_detail;
+       double u2 = double(c2) / m_detail;
 
-       vertex->x = v0->x + u1 * (v1->x - v0->x) + u2 * (v2->x - v0->x);
-       vertex->y = v0->y + u1 * (v1->y - v0->y) + u2 * (v2->y - v0->y);
-       vertex->z = v0->z + u1 * (v1->z - v0->z) + u2 * (v2->z - v0->z);
+       vector3 v;
+       v.SetX( v0->x() + u1 * (v1->x() - v0->x()) + u2 * (v2->x() - v0->x()) );
+       v.SetY( v0->y() + u1 * (v1->y() - v0->y()) + u2 * (v2->y() - v0->y()) );
+       v.SetZ( v0->z() + u1 * (v1->z() - v0->z()) + u2 * (v2->z() - v0->z()) );
+       v.normalize();
 
-       vertex->normalize();
-
-       *normal = *vertex;
-
-       vertex->x *= m_radius;
-       vertex->y *= m_radius;
-       vertex->z *= m_radius;
+       Vector *vertex =
+               &m_vertexBuffer[ index ];
+       vertex->x = v.x();
+       vertex->y = v.y();
+       vertex->z = v.z();
 }
 
 int Sphere::computeVertexCount()
@@ -299,46 +340,32 @@ void Sphere::buildBuffers()
        }
 }
 
-void Sphere::setup( int detail, GLfloat radius )
+void Sphere::setup( int detail )
 {
-       if( detail == m_detail && radius == m_radius ) return;
+       if( detail == m_detail ) return;
        m_detail = detail;
-       m_radius = radius;
        initialize();
 }
 
-void Sphere::drawScaled( GLfloat radius )
+void Sphere::draw( const vector3 &center, double radius )
 {
-       const GLfloat precision = 0.001;
-
-       if( approx_equal( radius, m_radius, precision ) )
-       {
-               draw();
-               return;
-       }
-
-       GLfloat factor = radius / m_radius;
-//     glEnable( GL_NORMALIZE );
        glPushMatrix();
-       glScalef( factor, factor, factor );
-       draw();
+       glTranslated( center.x(), center.y(), center.z() );
+       glScaled( radius, radius, radius );
+       VertexArray::draw();
        glPopMatrix();
-//     glDisable( GL_NORMALIZE );
 }
 
 Cylinder::Cylinder()
-       : VertexArray()
+       : VertexArray( GL_QUAD_STRIP, false, true )
 {
-       m_mode = GL_QUAD_STRIP;
        m_faces = 0;
-       m_radius = -1.0;
 }
 
-void Cylinder::setup( int faces, GLfloat radius )
+void Cylinder::setup( int faces )
 {
-       if( faces == m_faces && radius == m_radius ) return;
+       if( faces == m_faces ) return;
        m_faces = faces;
-       m_radius = radius;
        initialize();
 }
 
@@ -348,13 +375,6 @@ int Cylinder::computeVertexCount()
        return 2 * m_faces + 2;
 }
 
-int Cylinder::computeIndexCount()
-{
-       if( m_faces < 3 ) return -1;
-       return 0;
-}
-
-
 void Cylinder::buildBuffers()
 {
        for( int i = 0; i <= m_faces; i++ )
@@ -367,20 +387,74 @@ void Cylinder::buildBuffers()
                m_normalBuffer[ 2 * i ].y = y;
                m_normalBuffer[ 2 * i ].z = 0.0;
 
-               m_vertexBuffer[ 2 * i ].x = x * m_radius;
-               m_vertexBuffer[ 2 * i ].y = y * m_radius;
+               m_vertexBuffer[ 2 * i ].x = x;
+               m_vertexBuffer[ 2 * i ].y = y;
                m_vertexBuffer[ 2 * i ].z = 1.0;
 
                m_normalBuffer[ 2 * i + 1 ].x = x;
                m_normalBuffer[ 2 * i + 1 ].y = y;
                m_normalBuffer[ 2 * i + 1 ].z = 0.0;
 
-               m_vertexBuffer[ 2 * i + 1 ].x = x * m_radius;
-               m_vertexBuffer[ 2 * i + 1 ].y = y * m_radius;
+               m_vertexBuffer[ 2 * i + 1 ].x = x;
+               m_vertexBuffer[ 2 * i + 1 ].y = y;
                m_vertexBuffer[ 2 * i + 1 ].z = 0.0;
        }
 }
 
+void Cylinder::draw( const vector3 &end1, const vector3 &end2,
+       double radius, int order, double shift )
+{
+       // the "axis vector" of the cylinder
+       vector3 axis = end2 - end1;
+       
+       // find two unit vectors v, w such that
+       // (axis,v,w) is an orthogonal basis
+       vector3 v, w;
+       createOrthoBasisGivenFirstVector( axis, v, w );
+
+       // construct the 4D transformation matrix
+       GLdouble matrix[16];
+
+       // column 1
+       matrix[0] = v.x() * radius;
+       matrix[1] = v.y() * radius;
+       matrix[2] = v.z() * radius;
+       matrix[3] = 0.0;
+
+       // column 2
+       matrix[4] = w.x() * radius;
+       matrix[5] = w.y() * radius;
+       matrix[6] = w.z() * radius;
+       matrix[7] = 0.0;
+
+       // column 3
+       matrix[8] = axis.x();
+       matrix[9] = axis.y();
+       matrix[10] = axis.z();
+       matrix[11] = 0.0;
+
+       // column 4
+       matrix[12] = end1.x();
+       matrix[13] = end1.y();
+       matrix[14] = end1.z();
+       matrix[15] = 1.0;
+
+       //now we can do the actual drawing !
+       glPushMatrix();
+       glMultMatrixd( matrix );
+
+       if( order == 1 ) VertexArray::draw();
+       else for( int i = 0; i < order; i++)
+       {
+               glPushMatrix();
+               glRotated( 360.0 * i / order, 0.0, 0.0, 1.0 );
+               glTranslated( shift / radius, 0.0, 0.0 );
+               VertexArray::draw();
+               glPopMatrix();
+       }
+       glPopMatrix();
+}
+
 CharRenderer::CharRenderer()
 {
        m_texture = 0;
@@ -392,14 +466,15 @@ CharRenderer::~CharRenderer()
        if( m_texture ) glDeleteTextures( 1, &m_texture );
        if( m_displayList ) glDeleteLists( m_displayList, 1 );
 }
-bool CharRenderer::initialize( QChar c, const QFont &font )
+
+bool CharRenderer::initialize( QChar c, const QFont &font, GLenum textureTarget )
 {
        if( m_displayList ) return true;
        
        QFontMetrics fontMetrics ( font );
        m_width = fontMetrics.width( c );
        m_height = fontMetrics.height();
-       if( m_width == 0 || m_height == 0 ) return false;
+       if( m_width <= 0 || m_height <= 0 ) return false;
        QImage image( m_width, m_height, QImage::Format_RGB32 );
        
        QPainter painter;
@@ -413,7 +488,7 @@ bool CharRenderer::initialize( QChar c, const QFont &font )
        painter.end();
 
        GLubyte *bitmap = new GLubyte[ m_width * m_height ];
-       if( bitmap == 0 ) return false;
+       if( ! bitmap ) return false;
 
        for( int j = m_height - 1, n = 0; j >= 0; j-- )
        for( int i = 0; i < m_width; i++, n++ )
@@ -422,12 +497,12 @@ bool CharRenderer::initialize( QChar c, const QFont &font )
        }
 
        glGenTextures( 1, &m_texture );
-       if( m_texture == 0 ) return false;
+       if( ! m_texture ) return false;
 
-       glBindTexture( GL_TEXTURE_2D, m_texture );
+       glBindTexture( textureTarget, m_texture );
        glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
        glTexImage2D(
-               GL_TEXTURE_2D,
+               textureTarget,
                0,
                GL_ALPHA,
                m_width,
@@ -436,16 +511,16 @@ bool CharRenderer::initialize( QChar c, const QFont &font )
                GL_ALPHA,
                GL_UNSIGNED_BYTE,
                bitmap );
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       glTexParameteri( textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+       glTexParameteri( textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
 
        delete [] bitmap;
 
        m_displayList = glGenLists(1);
-       if( m_displayList == 0 ) return false;
+       if( ! m_displayList ) return false;
 
        glNewList( m_displayList, GL_COMPILE );
-       glBindTexture( GL_TEXTURE_2D, m_texture );
+       glBindTexture( textureTarget, m_texture );
        glBegin( GL_QUADS );
        glTexCoord2f( 0, 0);
        glVertex2f( 0 , 0 );
@@ -465,6 +540,7 @@ TextRenderer::TextRenderer()
 {
        m_glwidget = 0;
        m_isBetweenBeginAndEnd = false;
+       m_textureTarget = GL_TEXTURE_2D;
 }
 
 TextRenderer::~TextRenderer()
@@ -488,12 +564,13 @@ void TextRenderer::do_begin()
 {
        m_wasEnabled_LIGHTING = glIsEnabled( GL_LIGHTING );
        m_wasEnabled_FOG = glIsEnabled( GL_FOG );
-       m_wasEnabled_TEXTURE_2D = glIsEnabled( GL_TEXTURE_2D );
+       m_wasEnabled_textureTarget
+               = glIsEnabled( m_textureTarget );
        m_wasEnabled_BLEND = glIsEnabled( GL_BLEND );
        m_wasEnabled_DEPTH_TEST = glIsEnabled( GL_DEPTH_TEST );
        glDisable( GL_LIGHTING );
        glDisable( GL_FOG );
-       glEnable( GL_TEXTURE_2D );
+       glEnable( m_textureTarget );
        glEnable( GL_BLEND );
        glDisable( GL_DEPTH_TEST );
        glMatrixMode( GL_PROJECTION );
@@ -513,7 +590,8 @@ void TextRenderer::begin()
 
 void TextRenderer::do_end()
 {
-       if( ! m_wasEnabled_TEXTURE_2D ) glDisable( GL_TEXTURE_2D);
+       if( ! m_wasEnabled_textureTarget )
+               glDisable( m_textureTarget );
        if( ! m_wasEnabled_BLEND ) glDisable( GL_BLEND );
        if( m_wasEnabled_DEPTH_TEST ) glEnable( GL_DEPTH_TEST );
        if( m_wasEnabled_LIGHTING ) glEnable( GL_LIGHTING );
@@ -546,7 +624,7 @@ void TextRenderer::print( int x, int y, const QString &string )
                else
                {
                        CharRenderer *c = new CharRenderer;
-                       if( c->initialize( string[i], m_font ) )
+                       if( c->initialize( string[i], m_font, m_textureTarget ) )
                        {
                                m_charTable.insert( string[i], c);
                                c->draw();
@@ -558,3 +636,13 @@ void TextRenderer::print( int x, int y, const QString &string )
 
        if( ! m_isBetweenBeginAndEnd ) do_end();
 }
+
+bool KalziumGLHelpers::createOrthoBasisGivenFirstVector
+       ( const vector3 &U, vector3 & v, vector3 & w )
+{
+       if( ! U.createOrthoVector( v ) ) return false;
+       w = cross( U, v );
+       w.normalize();
+       return true;
+}
+
index 45351d754fa65bb243c2ea7bc7cc9c971c25bcc4..224f9b77b2d266a1ed51d454ebcc8f0db977c098 100644 (file)
@@ -5,12 +5,12 @@
  ***************************************************************************/
 
 /***************************************************************************
- *                                                                         *
+ *         *
  *   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.                                   *
- *                                                                         *
+ *   (at your option) any later version.   *
+ *         *
  ***************************************************************************/
 #include <math.h>
 #include <QGLWidget>
 #include <QHash>
 #include <kdebug.h>
 
-/** USE_DOUBLE_PRECISION: if defined, use doubles instead of floats for
- * handling the model's geometric data. This does not seem to impact
- * significantly the performance. The vertex arrays are unaffected: they
- * always use floats.
- */
-#define USE_DOUBLE_PRECISION
+#include <openbabel/mol.h>
+#include <openbabel/obiter.h>
 
 /** USE_FPS_COUNTER: if defined, the GL Widget will show a frames-per-second
  * counter. Use only for testing: this makes the GL Widget constantly
 #define USE_FPS_COUNTER 
 
 /** USE_DISPLAY_LISTS: if defined, the whole scene will be stored in
- * an OpenGL display list. The vertex arrays will then also be converted to
- * display lists, in order to avoid problems. This option improves performance,
- * especially when rendering complex models, but increases memory usage.
+ * an OpenGL display list. The vertex arrays will then be converted into
+ * (nested) display lists, in order to avoid replication of geometric data.
+ * This option improves performance, especially when rendering complex models,
+ * but increases memory usage.
  */
-#define USE_DISPLAY_LISTS
+//#define USE_DISPLAY_LISTS
 
 namespace KalziumGLHelpers
 {
 
-#ifdef USE_DOUBLE_PRECISION
-typedef double FLOAT;
-typedef GLdouble GLFLOAT;
-#else
-typedef float FLOAT;
-typedef GLfloat GLFLOAT;
-#endif
+/**
+ * This struct represents a style in which to render a molecule
+ *
+ * @author Benoit Jacob
+ */
+struct MolStyle
+{
+       enum BondStyle
+       {
+               BONDS_DISABLED,
+               BONDS_GRAY,
+               BONDS_USE_ATOMS_COLORS
+       } m_bondStyle;
 
-inline float SQRT( float x ) { return sqrtf( x ); }
-inline double SQRT( double x ) { return sqrt( x ); }
-inline float SIN( float x ) { return sinf( x ); }
-inline double SIN( double x ) { return sin( x ); }
-inline float COS( float x ) { return cosf( x ); }
-inline double COS( double x ) { return cos( x ); }
-inline float FABS( float x ) { return fabsf( x ); }
-inline double FABS( double x ) { return fabs( x ); }
-inline void GLMULTMATRIX( const GLfloat *m ) { glMultMatrixf(m); }
-inline void GLMULTMATRIX( const GLdouble *m ) { glMultMatrixd(m); }
-inline void GLTRANSLATE( GLfloat x, GLfloat y, GLfloat z ) \
-       { glTranslatef( x, y, z ); }
-inline void GLTRANSLATE( GLdouble x, GLdouble y, GLdouble z ) \
-       { glTranslated( x, y, z ); }
+       enum AtomStyle
+       {
+               ATOMS_DISABLED,
+               ATOMS_USE_FIXED_RADIUS,
+               ATOMS_USE_VAN_DER_WAALS_RADIUS,
+       } m_atomStyle;
+
+       double m_singleBondRadius;
+       double m_multipleBondRadius;
+       double m_multipleBondShift;
+       double m_atomRadiusFactor;
+
+       void setup( BondStyle bondStyle, AtomStyle atomStyle,
+               double singleBondRadius,
+               double multipleBondRadius,
+               double multipleBondShift,
+               double atomRadiusFactor );
+
+       double getAtomRadius( int atomicNumber );
+       inline double getAtomRadius( const OpenBabel::OBAtom *atom )
+       { return getAtomRadius( atom->GetAtomicNum() ); }
+};
 
 /**
-* This class represents a color in OpenGL float red-green-blue format.
+* This class represents a color in OpenGL float red-green-blue-alpha format.
 *
 * @author Benoit Jacob
 */
@@ -75,10 +86,23 @@ struct Color
 {
        GLfloat m_red, m_green, m_blue, m_alpha;
 
-       Color();
+       Color() {}
+
+       /**
+        * This constructor sets the four components of the color
+        * individually. Each one ranges from 0.0 (lowest intensity) to
+        * 1.0 (highest intensity). For the alpha component, 0.0 means fully
+        * transparent and 1.0 (the default) means fully opaque.
+        */
        Color( GLfloat red, GLfloat green, GLfloat blue,
                GLfloat alpha = 1.0 );
 
+       /**
+        * This constructor uses OpenBabel to retrieve the color in which
+        * the atom should be rendered.
+        */
+       Color( const OpenBabel::OBAtom *atom );
+
        Color& operator=( const Color& other );
 
        /**
@@ -99,115 +123,13 @@ struct Color
 };
 
 /**
-* Tests whether two Ts are approximately equal. Here T is assumed to be
-* a floating-point type. Recall that operator== between floating-point
-* types is broken.
-* returns true if abs( a - b ) <= c * precision
-* where c = max( abs( a ), abs( b ) )
-*/
-template<class T> bool approx_equal( T a, T b, T precision )
-{
-       T abs_a = FABS( a );
-       T abs_b = FABS( b );
-
-       T max_abs;
-       if( abs_a <= abs_b )
-               max_abs = abs_b;
-       else
-               max_abs = abs_a;
-       return( FABS( a - b ) <= precision * max_abs );
-}
-
-/**
-* This template class represents a vector in 3-space. It is meant to be
-* used with T = a floating-point type.
-*
-* @author Benoit Jacob
-*/
-template<class T> class Vector3
-{
-       public:
-               T x, y, z;
-               Vector3() {}
-               Vector3( T _x, T _y, T _z)
-               { x = _x; y = _y; z = _z; }
-
-               Vector3<T>& operator= ( const Vector3<T>& other )
-               {
-                       x = other.x;
-                       y = other.y;
-                       z = other.z;
-                       return *this;
-               }
-
-               /**
-               * returns the norm of the vector, that is, its length
-               */
-               inline T norm() const { return SQRT( x * x + y * y + z * z ); }
-
-               /**
-               * normalizes the vector, that is, scales it so that its norm
-               * becomes 1.
-               */
-               void normalize()
-               {
-                       T n = norm();
-                       if( n == 0.0 ) return;
-                       x /= n;
-                       y /= n;
-                       z /= n;
-               }
-};
-
-/**
-* Given a vector U, constructs two vectors v and w
-* such that (U, v, w) is a direct orthogonal basis.
+* Given a vector U, constructs two unit vectors v and w
+* such that (U, v, w) is an orthogonal basis.
 * U is not supposed to be normalized.
-* v and w are not getting normalized.
+*
+* Returns false if something went wrong.
 */
-template<class T> void construct_ortho_basis_given_first_vector(
-       const Vector3<T> &U, Vector3<T> & v, Vector3<T> & w )
-{
-       if( U.norm() == 0 ) return;
-
-       // let us first make a normalized copy of U
-       Vector3<T> u = U;
-       u.normalize();
-
-       // first we want to set v to be non-colinear to u
-       v = u;
-
-       if( ! approx_equal( v.x, v.y, 0.1 ) )
-       {
-               T tmp = v.x;
-               v.x = v.y;
-               v.y = tmp;
-       }
-       else if( ! approx_equal( v.y, v.z, 0.1 ) )
-       {
-               T tmp = v.z;
-               v.z = v.y;
-               v.y = tmp;
-       }
-       else // the 3 coords of v are approximately equal
-       {    // which implies that v is not colinear to (0,0,1)
-               v = Vector3<T>( 0, 0, 1 );
-       }
-
-       // now, v is not colinear to u. We compute its dot product with u
-       T u_dot_v = u.x * v.x + u.y * v.y + u.z * v.z;
-
-       // now we change v so that it becomes orthogonal to u
-       v.x -= u.x * u_dot_v;
-       v.y -= u.y * u_dot_v;
-       v.z -= u.z * u_dot_v;
-
-       // now that u and v are orthogonal, w can be constructed as
-       // their crossed product
-       w.x = u.y * v.z - u.z * v.y;
-       w.y = u.z * v.x - u.x * v.z;
-       w.z = u.x * v.y - u.y * v.x;
-}
+bool createOrthoBasisGivenFirstVector( const OpenBabel::vector3 &U, OpenBabel::vector3 & v, OpenBabel::vector3 & w );
 
 /**
 * This is an abstract base class for an OpenGL vertex array.
@@ -217,33 +139,45 @@ template<class T> void construct_ortho_basis_given_first_vector(
 class VertexArray
 {
        protected:
+
+               struct Vector
+               {
+                       GLfloat x, y, z;
+               };
+
+               Vector *m_vertexBuffer;
+               Vector *m_normalBuffer;
+               unsigned short *m_indexBuffer;
                GLenum m_mode;
-               Vector3<GLfloat> *m_vertexBuffer;
-               Vector3<GLfloat> *m_normalBuffer;
                int m_vertexCount;
-               unsigned short *m_indexBuffer;
                int m_indexCount;
                GLuint m_displayList;
-                               
+               bool m_hasIndexBuffer;
+               bool m_hasSeparateNormalBuffer;
+               bool m_isValid;
+               
                virtual int computeVertexCount() = 0;
-               virtual int computeIndexCount() = 0;
+               virtual int computeIndexCount() { return 0; }
                virtual void buildBuffers() = 0;
-               virtual bool allocateBuffers();
-               virtual void compileDisplayListIfNeeded();
+               bool allocateBuffers();
+               void freeBuffers();
+               void compileDisplayList();
 
-               virtual void initialize();
+               void initialize();
 
        public:
-               VertexArray();
+               VertexArray( GLenum mode,
+                       bool hasIndexBuffer,
+                       bool hasSeparateNormalBuffer );
                virtual ~VertexArray();
 
-               virtual void do_draw();
-               virtual inline void draw()
+               void do_draw();
+               inline void draw()
                {
 #ifdef USE_DISPLAY_LISTS
-                       glCallList( m_displayList );
+                       if( m_isValid ) glCallList( m_displayList );
 #else
-                       do_draw();
+                       if( m_isValid ) do_draw();
 #endif
                }
 };
@@ -262,7 +196,6 @@ class Sphere : public VertexArray
 
        protected:
                int m_detail;
-               GLfloat m_radius;
                virtual int computeVertexCount();
                virtual int computeIndexCount();
                virtual void buildBuffers();
@@ -270,8 +203,8 @@ class Sphere : public VertexArray
        public:
                Sphere();
                virtual ~Sphere() {}
-               virtual void setup( int detail, GLfloat radius );
-               virtual void drawScaled( GLfloat radius );
+               virtual void setup( int detail );
+               virtual void draw( const OpenBabel::vector3 &center, double radius );
 };
 
 /**
@@ -283,16 +216,16 @@ class Cylinder : public VertexArray
 {
        protected:
                int m_faces;
-               GLfloat m_radius;
 
                virtual int computeVertexCount();
-               virtual int computeIndexCount();
                virtual void buildBuffers();
 
        public:
                Cylinder();
                virtual ~Cylinder() {}
-               virtual void setup( int detail, GLfloat radius );
+               virtual void setup( int detail );
+               virtual void draw( const OpenBabel::vector3 &end1, const OpenBabel::vector3 &end2,
+                       double radius, int order = 1, double shift = 0.0 );
 };
 
 /** This is a helper class for TextRenderer, and should probably never be
@@ -326,7 +259,8 @@ class CharRenderer
        public:
                CharRenderer();
                ~CharRenderer();
-               bool initialize( QChar c, const QFont &font );
+               bool initialize( QChar c, const QFont &font,
+                       GLenum textureTarget );
                inline void draw()
                {
                        glCallList( m_displayList );
@@ -452,12 +386,14 @@ class TextRenderer
 
                ///{ Members used to remember the OpenGL state in order to be able to restore it after rendering. See do_end().
                GLboolean m_wasEnabled_LIGHTING;
-               GLboolean m_wasEnabled_TEXTURE_2D;
+               GLboolean m_wasEnabled_textureTarget;
                GLboolean m_wasEnabled_FOG;
                GLboolean m_wasEnabled_BLEND;
                GLboolean m_wasEnabled_DEPTH_TEST;
                ///}
 
+               GLenum m_textureTarget;
+
                /**
                 * Stores the relevant part of the OpenGL state, and prepares
                 * for rendering
index 79976d93e78a3f5e02c9c3c210ae380d1e94bbda..9432336ec883a7baeb8e72d13e2db395b5fd6c46 100644 (file)
@@ -12,7 +12,6 @@
  *                                                                         *
  ***************************************************************************/
 #include "kalziumglwidget.h"
-#include "kalziumglhelperclasses.h"
 
 #include <math.h>
 
 
 #include <QMouseEvent>
 #include <QListWidget>
-#include <QTimer>
-
 
 #ifdef USE_FPS_COUNTER
 #include <QTime>
 #endif
 
 #include <openbabel/mol.h>
-#include <openbabel/obiter.h>
 
+using namespace KalziumGLHelpers;
 using namespace OpenBabel;
 
 KalziumGLWidget::KalziumGLWidget( QWidget * parent )
@@ -45,18 +42,13 @@ KalziumGLWidget::KalziumGLWidget( QWidget * parent )
        m_inZoom = false;
        m_inMeasure = false;
 
+       slotSetMolStyle( 0 );
+
        QFont f;
        f.setStyleHint( QFont::SansSerif, QFont::PreferAntialias );
        m_textRenderer.setup( this, f );
-
-
-       ChooseStylePreset( PRESET_SPHERES_AND_BICOLOR_BONDS );
        
        setMinimumSize( 100,100 );
-
-       QTimer *timer = new QTimer( this );
-       connect( timer, SIGNAL( timeout() ), this, SLOT( rotate() ) );
-       timer->start( 50 );
 }
 
 KalziumGLWidget::~KalziumGLWidget()
@@ -77,9 +69,9 @@ void KalziumGLWidget::initializeGL()
        glGetDoublev( GL_MODELVIEW_MATRIX, m_RotationMatrix );
        glPopMatrix();
 
-       //glEnable( GL_RESCALE_NORMAL_EXT );
-
-       glEnable(GL_LIGHT0);
+       glEnable( GL_NORMALIZE );
+       glEnable( GL_LIGHTING );
+       glEnable( GL_LIGHT0 );
 
        GLfloat ambientLight[] = { 0.4, 0.4, 0.4, 1.0 };
        GLfloat diffuseLight[] = { 0.8, 0.8, 0.8, 1.0 };
@@ -95,48 +87,53 @@ void KalziumGLWidget::initializeGL()
        glFogfv( GL_FOG_COLOR, fogColor );
        glFogi( GL_FOG_MODE, GL_LINEAR );
        glFogf( GL_FOG_DENSITY, 0.45 );
-       glFogf( GL_FOG_START, 2.7 * m_molRadius );
-       glFogf( GL_FOG_END, 5.0 * m_molRadius );
+       glFogf( GL_FOG_START, 2.7 * getMolRadius() );
+       glFogf( GL_FOG_END, 5.0 * getMolRadius() );
 
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
 
        glEnable( GL_COLOR_SUM_EXT );
        glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL_EXT,
                GL_SEPARATE_SPECULAR_COLOR_EXT );
+
+       glEnableClientState( GL_VERTEX_ARRAY );
+       glEnableClientState( GL_NORMAL_ARRAY );
 }
 
 void KalziumGLWidget::paintGL()
 {
        if( ! m_molecule )
        {
-               glColor3f( 0.0, 1.0, 0.6 );
                glClear( GL_COLOR_BUFFER_BIT );
-               m_textRenderer.print( 20, height() - 40, i18n("Please load a molecule") );
+               glColor3f( 0.0, 1.0, 0.6 );
+               m_textRenderer.print( 20, height() - 40,
+                       i18n("Please load a molecule") );
                return;
        }
 
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
-       gluPerspective( 40.0, float( width() ) / height(), m_molRadius, 5.0 * (m_molRadius + atomRadius ()));
+       gluPerspective( 40.0, float( width() ) / height(),
+               getMolRadius(), 5.0 * getMolRadius() );
        glMatrixMode( GL_MODELVIEW );
 
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
        // set up the camera
        glLoadIdentity();
-       GLTRANSLATE ( 0.0, 0.0, -3.0 * (m_molRadius + atomRadius () ) );
-       GLMULTMATRIX ( m_RotationMatrix );
+       glTranslated ( 0.0, 0.0, -3.0 * getMolRadius() );
+       glMultMatrixd ( m_RotationMatrix );
 
        // set up fog
-       if( m_useFog == true )
+       if( m_useFog )
        {
                glEnable( GL_FOG );
                GLfloat fogColor[] = { 0.0, 0.0, 0.0, 1.0 };
                glFogfv( GL_FOG_COLOR, fogColor );
                glFogi( GL_FOG_MODE, GL_LINEAR );
                glFogf( GL_FOG_DENSITY, 0.45 );
-               glFogf( GL_FOG_START, 2.7 * ( m_molRadius + atomRadius() ) );
-               glFogf( GL_FOG_END, 5.0 * ( m_molRadius + atomRadius() ) );
+               glFogf( GL_FOG_START, 2.7 * getMolRadius() );
+               glFogf( GL_FOG_END, 5.0 * getMolRadius()  );
        }
        else glDisable( GL_FOG );
 
@@ -148,101 +145,9 @@ void KalziumGLWidget::paintGL()
        glNewList( m_displayList, GL_COMPILE );
 #endif
 
-       // prepare for rendering the spheres
-       if( m_atomStyle == ATOM_SPHERE )
-       {
-               glEnable( GL_LIGHTING );
-       }
-       else glDisable( GL_LIGHTING );
+       renderAtoms();
+       renderBonds();
 
-       if( m_atomStyle != ATOM_DISABLED )
-       {
-               // render the atoms
-               if( m_atomStyle == ATOM_SPHERE )
-               {
-                       FOR_ATOMS_OF_MOL( a, m_molecule )
-                       {
-                               GLFLOAT x = (GLFLOAT) a->GetX();
-                               GLFLOAT y = (GLFLOAT) a->GetY();
-                               GLFLOAT z = (GLFLOAT) a->GetZ();
-                       
-                               Color c = getAtomColor( &*a );
-                       
-                               drawSphere(
-                                       x, y, z,
-                                       atomRadius(),
-                                       c);
-                       }
-               }
-       }
-
-       // prepare for rendering the bonds
-       switch( m_bondStyle )
-       {
-               case BOND_LINE:
-                       glDisable( GL_LIGHTING );
-                       break;
-               
-               case BOND_CYLINDER_GRAY:
-               case BOND_CYLINDER_BICOLOR:
-                       glEnable( GL_LIGHTING );
-                       break;
-               case BOND_DISABLED: break;
-       }
-
-       if( m_bondStyle != BOND_DISABLED )
-       {
-               // render the bonds
-               FOR_BONDS_OF_MOL( bond, m_molecule )
-               {
-                       GLFLOAT x1 = (GLFLOAT)
-                               static_cast<OBAtom*>(bond->GetBgn())->GetX();
-                       GLFLOAT y1 = (GLFLOAT)
-                               static_cast<OBAtom*>(bond->GetBgn())->GetY();
-                       GLFLOAT z1 = (GLFLOAT)
-                               static_cast<OBAtom*>(bond->GetBgn())->GetZ();
-                       GLFLOAT x2 = (GLFLOAT)
-                               static_cast<OBAtom*>(bond->GetEnd())->GetX();
-                       GLFLOAT y2 = (GLFLOAT)
-                               static_cast<OBAtom*>(bond->GetEnd())->GetY();
-                       GLFLOAT z2 = (GLFLOAT)
-                               static_cast<OBAtom*>(bond->GetEnd())->GetZ();
-                       
-                       GLFLOAT x3 = (x1 + x2) / 2;
-                       GLFLOAT y3 = (y1 + y2) / 2;
-                       GLFLOAT z3 = (z1 + z2) / 2;
-                       
-                       Color c1, c2;
-                       c1 = getAtomColor( static_cast<OBAtom*>(bond->GetBgn()) );
-                       c2 = getAtomColor( static_cast<OBAtom*>(bond->GetEnd()) );
-                       Color gray( 0.5, 0.5, 0.5 );
-                       
-                       switch( m_bondStyle )
-                       {
-                               case BOND_LINE:
-                                       glBegin( GL_LINES );
-                                       c1.apply();
-                                       glVertex3f( x1, y1, z1 );
-                                       glVertex3f( x3, y3, z3 );
-                                       c2.apply();
-                                       glVertex3f( x3, y3, z3 );
-                                       glVertex3f( x2, y2, z2 );
-                                       glEnd();
-                                       break;
-                               
-                               case BOND_CYLINDER_GRAY:
-                                       drawBond( x1, y1, z1, x2, y2, z2, gray );
-                                       break;
-       
-                               case BOND_CYLINDER_BICOLOR:
-                                       drawBond( x1, y1, z1, x3, y3, z3, c1 );
-                                       drawBond( x2, y2, z2, x3, y3, z3, c2 );
-                                       break;
-       
-                               case BOND_DISABLED: break;
-                       }
-               }
-       }
 #ifdef USE_DISPLAY_LISTS
        glEndList();
        m_haveToRecompileDisplayList = false;
@@ -250,34 +155,63 @@ void KalziumGLWidget::paintGL()
        glCallList( m_displayList );
 #endif
 
-       // now, paint a semitransparent sphere around the selected atoms
-       if( m_selectedAtoms.count() > 0 )//there are items selected
+       renderSelection();
+
+#ifdef USE_FPS_COUNTER
+       FPSCounter();
+       update();
+#endif
+}
+
+void KalziumGLWidget::renderAtoms()
+{
+       if( m_molStyle.m_atomStyle == MolStyle::ATOMS_DISABLED ) return;
+
+       FOR_ATOMS_OF_MOL( atom, m_molecule )
        {
-               Color c( 0.4, 0.4, 1.0, 0.7 );
+                       drawAtom( &*atom );
+       }
+}
 
-               GLFLOAT radius = m_molMinBondLength * 0.35;
-               const GLFLOAT min_radius = (GLFLOAT) atomRadius () * 1.25;
-               if( radius < min_radius ) radius = min_radius;
+void KalziumGLWidget::renderBonds()
+{
+       if( m_molStyle.m_bondStyle == MolStyle::BONDS_DISABLED ) return;
 
-               foreach(OpenBabel::OBAtom* atom, m_selectedAtoms)
-               {//iterate through all OBAtoms and highlight one after eachother
-                       GLFLOAT x = (GLFLOAT) atom->GetX();
-                       GLFLOAT y = (GLFLOAT) atom->GetY();
-                       GLFLOAT z = (GLFLOAT) atom->GetZ();
+       // render the bonds
+       FOR_BONDS_OF_MOL( bond, m_molecule )
+       {
+               drawBond( &*bond );
+       }
+}
 
-                       glEnable( GL_BLEND );
+void KalziumGLWidget::renderSelection()
+{
+/*     if( ! m_selectedAtoms.count() ) return;
+       
+       Color c( 0.4, 0.4, 1.0, 0.7 );
 
-                       glEnable( GL_LIGHTING );
+       GLdouble radius = m_molMinBondLength * 0.35;
+       const GLdouble min_radius = (GLdouble) atomRadius () * 1.25;
+       if( radius < min_radius ) radius = min_radius;
 
-                       drawSphere(
-                                       x, y, z,
-                                       radius,
-                                       c);
+       glEnable( GL_BLEND );
+       glEnable( GL_LIGHTING );
+*/
+/*     foreach(OpenBabel::OBAtom* atom, m_selectedAtoms)
+       {//iterate through all OBAtoms and highlight one after eachother
 
-                       glDisable( GL_BLEND );
-               }
+               drawSphere(
+                               x, y, z,
+                               radius,
+                               c);
        }
+*/
+
+       glDisable( GL_BLEND );
+}
 
+void KalziumGLWidget::FPSCounter()
+{
 #ifdef USE_FPS_COUNTER
        QTime t;
 
@@ -303,15 +237,13 @@ void KalziumGLWidget::paintGL()
                s = QString::number( 1000 * frames /
                        double( new_time - old_time ),
                        'f', 1 );
-               s += " FPS";
+               s += QString(" FPS");
                frames = 0;
                old_time = new_time;
        }
 
        glColor3f( 1.0, 1.0, 0.0 );
        m_textRenderer.print( 20, 20, s );
-
-       update();
 #endif
 }
 
@@ -385,94 +317,91 @@ void KalziumGLWidget::rotate( )
 
 void KalziumGLWidget::setupObjects()
 {
-       int sphere_detail, cylinder_faces;
+       int sphere_detail = 1, cylinder_faces = 2;
 
-       if( m_atomRadiusCoeff < 0.05) sphere_detail = 1;
-       else if( m_atomRadiusCoeff < 0.30) sphere_detail = 2;
-       else sphere_detail = 3;
+       double typicalAtomRadius = m_molStyle.getAtomRadius( 6 );
+       double typicalBondRadius = m_molStyle.m_singleBondRadius;
 
-       sphere_detail *= ( m_detail + 1 );
-
-       if( m_bondRadiusCoeff < 0.02) cylinder_faces = 4;
-       else if( m_bondRadiusCoeff < 0.10) cylinder_faces = 6;
-       else cylinder_faces = 8;
+       if( m_molStyle.m_atomStyle != MolStyle::ATOMS_DISABLED )
+       {
+               if( typicalAtomRadius < 0.50 )
+                       sphere_detail = 2 + 2 * m_detail;
+               else if( typicalAtomRadius < 1.00 )
+                       sphere_detail = 3 + 2 * m_detail;
+               else sphere_detail = 4 + 3 * m_detail;
+       }
 
-       cylinder_faces *= ( m_detail + 1 );
+       if( m_molStyle.m_bondStyle != MolStyle::BONDS_DISABLED )
+       {
+               if( typicalBondRadius < 0.10 )
+                       cylinder_faces = 6 + 6 * m_detail;
+               else if( typicalBondRadius < 0.20 )
+                       cylinder_faces = 8 + 8 * m_detail;
+               else cylinder_faces = 10 + 8 * m_detail;
+       }
 
-       m_sphere.setup( sphere_detail, atomRadius() );
-       m_cylinder.setup( cylinder_faces, bondRadius() );
+       m_sphere.setup( sphere_detail );
+       m_cylinder.setup( cylinder_faces );
 }
 
-void KalziumGLWidget::drawSphere( GLdouble x, GLdouble y, GLdouble z,
-       GLfloat radius, Color &color )
+void KalziumGLWidget::drawAtom( OBAtom *atom )
 {
-       color.applyAsMaterials();
-       
-       glPushMatrix();
-       glTranslated( x, y, z );
-       m_sphere.drawScaled( radius );
-       glPopMatrix();
+       Color( atom ).applyAsMaterials();
+       m_sphere.draw( atom->GetVector(), m_molStyle.getAtomRadius( atom ) );
 }
 
-void KalziumGLWidget::drawBond( FLOAT x1, FLOAT y1, FLOAT z1,
-       FLOAT x2, FLOAT y2, FLOAT z2, Color &color )
+void KalziumGLWidget::drawBond( OBBond *bond )
 {
-       color.applyAsMaterials();
+       OBAtom *atom1 = static_cast<OBAtom *>( bond->GetBgn() );
+       OBAtom *atom2 = static_cast<OBAtom *>( bond->GetEnd() );
+
+       vector3 v1 = atom1->GetVector();
+       vector3 v2 = atom2->GetVector();
+       vector3 v3 = ( v1 + v2 ) / 2;
+
+       int order;
+       if( bond->IsSingle() ) order = 1;
+       else if( bond->IsDouble() ) order = 2;
+       else if( bond->IsTriple() ) order = 3;
+       else
+       {
+               order = bond->GetBondOrder();
+               if( order > 12 ) // probably a bogus molecule file!
+                       // according to the element.txt file in OB,
+                       // no element can have more than 12 bonds
+               {
+                       order = 1;
+                       kDebug()<<"Umm, some bond pretends to have "
+                               "order "<<bond->GetBondOrder()<<endl;
+                       kDebug()<<"I'd better close now, 'cause I feel "
+                               "like I might segfault any time!"<<endl;
+                       parentWidget()->parentWidget()->close();
+               }
+       }
 
-       // the "axis vector" of the cylinder
-       Vector3<FLOAT> axis( x2 - x1, y2 - y1, z2 - z1 );
-       
-       // find two vectors v, w such that (axis,v,w) is an orthogonal basis.
-       Vector3<FLOAT> v, w;
-       construct_ortho_basis_given_first_vector( axis, v, w );
-
-       // normalize v and w. We DON'T want to normalize axis
-       v.normalize();
-       w.normalize();
-
-       // construct the 4D transformation matrix
-       FLOAT matrix[16];
-
-       // column 1
-       matrix[0] = v.x;
-       matrix[1] = v.y;
-       matrix[2] = v.z;
-       matrix[3] = 0.0;
-
-       // column 2
-       matrix[4] = w.x;
-       matrix[5] = w.y;
-       matrix[6] = w.z;
-       matrix[7] = 0.0;
-
-       // column 3
-       matrix[8] = axis.x;
-       matrix[9] = axis.y;
-       matrix[10] = axis.z;
-       matrix[11] = 0.0;
-
-       // column 4
-       matrix[12] = x1;
-       matrix[13] = y1;
-       matrix[14] = z1;
-       matrix[15] = 1.0;
-
-       //now we can do the actual drawing !
-       glPushMatrix();
-       GLMULTMATRIX( matrix );
-       m_cylinder.draw();
-       glPopMatrix();
-}
+       double radius;
+       if( order == 1 ) radius = m_molStyle.m_singleBondRadius;
+       else radius = m_molStyle.m_multipleBondRadius;
 
+       switch( m_molStyle.m_bondStyle )
+       {
+               case MolStyle::BONDS_GRAY:
+                       Color( 0.5, 0.5, 0.5 ).applyAsMaterials();
+                       m_cylinder.draw( v1, v2, radius, order,
+                               m_molStyle.m_multipleBondShift );
+                       break;
 
-inline GLFLOAT KalziumGLWidget::bondRadius()
-{
-       return m_bondRadiusCoeff * m_molMinBondLength;
-       
-}
-inline GLFLOAT KalziumGLWidget::atomRadius()
-{
-       return m_atomRadiusCoeff * m_molMinBondLength;
+               case MolStyle::BONDS_USE_ATOMS_COLORS:
+                       Color( atom1 ).applyAsMaterials();
+                       m_cylinder.draw( v1, v3, radius, order,
+                               m_molStyle.m_multipleBondShift );
+                       Color( atom2 ).applyAsMaterials();
+                       m_cylinder.draw( v2, v3, radius, order,
+                               m_molStyle.m_multipleBondShift );
+                       break;
+
+               default: break;
+       }
 }
 
 void KalziumGLWidget::slotZoomIn()
@@ -503,47 +432,33 @@ void KalziumGLWidget::slotSetMolecule( OpenBabel::OBMol* molecule )
        updateGL();
 }
 
-void KalziumGLWidget::ChooseStylePreset( StylePreset stylePreset )
+void KalziumGLWidget::slotSetMolStyle( int style )
 {
-       switch( stylePreset )
+       switch( style )
        {
-               case PRESET_LINES:
-                       m_atomStyle = ATOM_DISABLED;
-                       m_bondStyle = BOND_LINE;
-                       m_atomRadiusCoeff = 0.0;
-                       m_bondRadiusCoeff = 0.0;
+               case 0: // sticks-style
+                       m_molStyle.setup( MolStyle::BONDS_USE_ATOMS_COLORS,
+                               MolStyle::ATOMS_USE_FIXED_RADIUS,
+                               0.20, 0.06, 0.14, 0.20 );
                        break;
-               case PRESET_STICKS:
-                       m_atomStyle = ATOM_SPHERE;
-                       m_bondStyle = BOND_CYLINDER_BICOLOR;
-                       m_atomRadiusCoeff = 0.13;
-                       m_bondRadiusCoeff = 0.13;
+               case 1: // atoms: smaller van der Waals, bonds: gray
+                       m_molStyle.setup( MolStyle::BONDS_GRAY,
+                               MolStyle::ATOMS_USE_VAN_DER_WAALS_RADIUS,
+                               0.08, 0.08, 0.14, 0.20 );
                        break;
-               case PRESET_SPHERES_AND_GRAY_BONDS:
-                       m_atomStyle = ATOM_SPHERE;
-                       m_bondStyle = BOND_CYLINDER_GRAY;
-                       m_atomRadiusCoeff = 0.20;
-                       m_bondRadiusCoeff = 0.05;
+               case 2: // atoms: smaller van der Waals, bonds: use atom colors
+                       m_molStyle.setup( MolStyle::BONDS_USE_ATOMS_COLORS,
+                               MolStyle::ATOMS_USE_VAN_DER_WAALS_RADIUS,
+                               0.08, 0.08, 0.14, 0.20 );
                        break;
-               case PRESET_SPHERES_AND_BICOLOR_BONDS:
-                       m_atomStyle = ATOM_SPHERE;
-                       m_bondStyle = BOND_CYLINDER_BICOLOR;
-                       m_atomRadiusCoeff = 0.20;
-                       m_bondRadiusCoeff = 0.05;
+               case 3: // atoms: real van der Waals, bonds: disabled
+                       m_molStyle.setup( MolStyle::BONDS_DISABLED,
+                               MolStyle::ATOMS_USE_VAN_DER_WAALS_RADIUS,
+                               0.00, 0.00, 0.00, 1.00 );
                        break;
-               case PRESET_BIG_SPHERES:
-                       m_atomStyle = ATOM_SPHERE;
-                       m_bondStyle = BOND_DISABLED;
-                       m_atomRadiusCoeff = 1.0;
-                       m_bondRadiusCoeff = 0.0;
-                       break;
-       }
-}
-
 
-void KalziumGLWidget::slotChooseStylePreset( int stylePreset )
-{
-       ChooseStylePreset( (StylePreset) stylePreset );
+               default: break;
+       }
        m_haveToRecompileDisplayList = true;
        setupObjects();
        updateGL();
@@ -557,7 +472,7 @@ void KalziumGLWidget::prepareMoleculeData()
        //perhaps I'm stupid (Benoit 03/07/06)
 
        //first, calculate the coords of the center of the molecule
-       vector3 center( 0.0, 0.0, 0.0);
+       vector3 center( 0.0, 0.0, 0.0 );
        int number_of_atoms = 0;
        FOR_ATOMS_OF_MOL( a, m_molecule )
        {
@@ -578,36 +493,19 @@ void KalziumGLWidget::prepareMoleculeData()
        // calculate the radius of the molecule
        // that is, the maximal distance between an atom of the molecule
        // and the center of the molecule
-       m_molRadius = 0.0;
+       m_molRadiusWithoutElectrons = 0.0;
        FOR_ATOMS_OF_MOL( a, m_molecule )
        {
-               FLOAT x = (FLOAT) a->GetX();
-               FLOAT y = (FLOAT) a->GetY();
-               FLOAT z = (FLOAT) a->GetZ();
-               FLOAT rad = SQRT(x*x + y*y + z*z);
-               if( rad > m_molRadius )
-                       m_molRadius = rad;
+               vector3 v = a->GetVector();
+               double rad = v.length();
+               if( rad > m_molRadiusWithoutElectrons )
+                       m_molRadiusWithoutElectrons = rad;
        }
+}
 
-       // calculate the length of the shortest bond, of the longest bond
-       m_molMinBondLength = 2 * m_molRadius;
-       m_molMaxBondLength = 0.0;
-       FOR_BONDS_OF_MOL( b, m_molecule )
-       {
-               FLOAT x1 = (FLOAT) static_cast<OBAtom*>(b->GetBgn())->GetX();
-               FLOAT y1 = (FLOAT) static_cast<OBAtom*>(b->GetBgn())->GetY();
-               FLOAT z1 = (FLOAT) static_cast<OBAtom*>(b->GetBgn())->GetZ();
-               FLOAT x2 = (FLOAT) static_cast<OBAtom*>(b->GetEnd())->GetX();
-               FLOAT y2 = (FLOAT) static_cast<OBAtom*>(b->GetEnd())->GetY();
-               FLOAT z2 = (FLOAT) static_cast<OBAtom*>(b->GetEnd())->GetZ();
-               FLOAT len = SQRT ( (x1 - x2) * (x1 - x2)
-                                  + (y1 - y2) * (y1 - y2)
-                                  + (z1 - z2) * (z1 - z2) );
-               if( len > m_molMaxBondLength )
-                       m_molMaxBondLength = len;
-               if( len < m_molMinBondLength )
-                       m_molMinBondLength = len;
-       }
+double KalziumGLWidget::getMolRadius()
+{
+       return m_molRadiusWithoutElectrons + m_molStyle.getAtomRadius( 6 );
 }
 
 void KalziumGLWidget::slotSetDetail( int detail )
@@ -619,17 +517,6 @@ void KalziumGLWidget::slotSetDetail( int detail )
        updateGL();
 }
 
-Color& KalziumGLWidget::getAtomColor( OpenBabel::OBAtom* atom )
-{
-       // thanks to Geoffrey Hutchison from OpenBabel for
-       // this simplified getAtomColor method
-       static Color c;
-       c.m_red = etab.GetRGB(atom->GetAtomicNum())[0];
-       c.m_green = etab.GetRGB(atom->GetAtomicNum())[1];
-       c.m_blue = etab.GetRGB(atom->GetAtomicNum())[2];
-       return c;
-}
-
 void KalziumGLWidget::slotAtomsSelected( QList<OpenBabel::OBAtom*> atoms )
 {
        kDebug() << "KalziumGLWidget::slotAtomsSelected() with " << atoms.count() << " atoms" << endl;
index 87bda6e770e7158cf1bffd8c6f1e5097729f57c2..bbd124652a125fc1c6c4c8888996a30ee6de4dc9 100644 (file)
@@ -18,7 +18,6 @@
 #include <QGLWidget>
 #include <QList>
 #include <QFont>
-#include <openbabel/mol.h>
 
 using namespace KalziumGLHelpers;
 
@@ -55,11 +54,10 @@ class KalziumGLWidget : public QGLWidget
 
                QPoint m_lastDraggingPosition;
 
-
                /**
                 * Stores the rotation that is applied to the model.
                 */
-               GLFLOAT m_RotationMatrix[16];
+               GLdouble m_RotationMatrix[16];
 
                /**
                 * The molecule which is displayed
@@ -67,34 +65,10 @@ class KalziumGLWidget : public QGLWidget
                OpenBabel::OBMol* m_molecule;
 
                /**
-                * approximate radius of the molecule
-                */
-               GLFLOAT m_molRadius;
-
-               /**
-                * length of the shortest bond in the molecule
-                */
-               GLFLOAT m_molMinBondLength;
-
-               /**
-                * length of the longest bond in the molecule
-                */
-               GLFLOAT m_molMaxBondLength;
-
-               /**
-                * The coefficient set by the user, determining the
-                * radius of atoms.
-                * WARNING: its meaning has just changed! (june 17)
-                * Now the actual radius is proportional to
-                * m_atomRadiusCoeff.
-                */
-               float m_atomRadiusCoeff;
-
-               /**
-                * The coefficient set by the user, determining the
-                * radius (that is, half the thickness) of bonds.
+                * approximate radius of the molecule,
+                * without the electrons.
                 */
-               float m_bondRadiusCoeff;
+               GLdouble m_molRadiusWithoutElectrons;
 
                /**
                 * The detail-grade from 0 to 2.
@@ -112,36 +86,9 @@ class KalziumGLWidget : public QGLWidget
                QList<OpenBabel::OBAtom*> m_selectedAtoms;
 
                /**
-                * The style in which the atoms are rendered.
-                */
-               enum AtomStyle
-               {
-                       ATOM_DISABLED,
-                       ATOM_SPHERE
-               } m_atomStyle;
-
-               /**
-                * The style in which the bonds are rendered.
+                * The style in which the molecule is rendered
                 */
-               enum BondStyle
-               {
-                       BOND_DISABLED,
-                       BOND_LINE,
-                       BOND_CYLINDER_GRAY,
-                       BOND_CYLINDER_BICOLOR
-               } m_bondStyle;
-
-               /**
-                * Some style presets
-                */
-               enum StylePreset
-               {
-                       PRESET_LINES,
-                       PRESET_STICKS,
-                       PRESET_SPHERES_AND_GRAY_BONDS,
-                       PRESET_SPHERES_AND_BICOLOR_BONDS,
-                       PRESET_BIG_SPHERES
-               };
+               MolStyle m_molStyle;
 
        public:
                /**
@@ -198,10 +145,10 @@ class KalziumGLWidget : public QGLWidget
                void slotSetDetail( int detail );
 
                /**
-                * Chooses the style of rendering among some presets
-                * @param stylePreset the wanted style preset
+                * Sets the molecule style
+                * @param style the wanted molecule style
                 */
-               void slotChooseStylePreset( int stylePreset );
+               void slotSetMolStyle( int style );
 
                /**
                 * The atoms @p atoms was selected by the user
@@ -243,6 +190,10 @@ class KalziumGLWidget : public QGLWidget
                 * This method does the painting. Automatically called by Qt
                 */
                virtual void paintGL();
+               virtual void renderAtoms();
+               virtual void renderBonds();
+               virtual void renderSelection();
+               virtual void FPSCounter();
 
                /**
                 * This method is called by Qt whenever the widget is resized.
@@ -259,52 +210,12 @@ class KalziumGLWidget : public QGLWidget
                 * it.
                 */
                void prepareMoleculeData();
-               
-               virtual void drawSphere( 
-                               GLFLOAT x, 
-                               GLFLOAT y, 
-                               GLFLOAT z, 
-                               GLfloat radius,
-                               Color &color );
-
-               /**
-                * This method draws a bond
-                * @param x1
-                * @param y1
-                * @param z1
-                * @param x2
-                * @param y2
-                * @param z2
-                * @param color
-                */
-               virtual void drawBond( GLFLOAT x1, GLFLOAT y1, GLFLOAT z1,
-                       GLFLOAT x2, GLFLOAT y2, GLFLOAT z2,
-                       Color &color );
-
-               /**
-                * returns the radius ( = half-thickness ) with which the
-                * bonds are drawn
-                */
-               inline GLFLOAT bondRadius();
 
-               /**
-                * returns the radius with which the atoms are drawn
-                * (currently all atoms are drawn with the same radius.
-                * when we'll have a better model taking van der Waals radii
-                * into account, we'll remove this member).
-                */
-               inline GLFLOAT atomRadius();
+               double getMolRadius();
 
-               /**
-                * Chooses the style of rendering among some presets
-                * @param stylePreset the wanted style preset
-                */
-               virtual void ChooseStylePreset( StylePreset stylePreset );
+               void drawAtom( OpenBabel::OBAtom *atom );
 
-               /**
-                * returns the color which a given atom should be painted
-                */
-               Color& getAtomColor( OpenBabel::OBAtom* atom );
+               void drawBond( OpenBabel::OBBond *bond );
 
                /**
                 * recomputes the geometry of the geometric objects ( sphere,