#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,
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;
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);
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;
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)
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 )
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()
}
}
-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 ¢er, 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();
}
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++ )
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;
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;
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++ )
}
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,
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 );
{
m_glwidget = 0;
m_isBetweenBeginAndEnd = false;
+ m_textureTarget = GL_TEXTURE_2D;
}
TextRenderer::~TextRenderer()
{
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 );
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 );
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();
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;
+}
+
***************************************************************************/
/***************************************************************************
- * *
+ * *
* 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
*/
{
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 );
/**
};
/**
-* 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.
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
}
};
protected:
int m_detail;
- GLfloat m_radius;
virtual int computeVertexCount();
virtual int computeIndexCount();
virtual void buildBuffers();
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 ¢er, double radius );
};
/**
{
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
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 );
///{ 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
* *
***************************************************************************/
#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 )
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()
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 };
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 );
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;
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;
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
}
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()
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();
//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 )
{
// 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 )
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;
#include <QGLWidget>
#include <QList>
#include <QFont>
-#include <openbabel/mol.h>
using namespace KalziumGLHelpers;
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
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.
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:
/**
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
* 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.
* 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,