From 2ba6780b250760add4024dd2efb03d14eba6c359 Mon Sep 17 00:00:00 2001 From: Carsten Niehaus Date: Mon, 26 Jun 2006 13:47:58 +0000 Subject: [PATCH] Benoit, kalziumglwidget.h/cpp grew just to big, that is why I moved the code into kalziumglhelperclasses.h/cpp, onle the GLWidget itself stays in src/kalziumglwidget.cpp. But for some cpp-magic-reasons I needed to remove two inline-calls, don't ask me why. Furhtermore, template void GLVector3::construct_ortho_basis_given_first_vector is not longer found when linking, not the slightest idea why... The other methods of GLVector are found when linking... CCMAIL:jacob@math.jussieu.fr svn path=/trunk/KDE/kdeedu/kalzium/src/kalziumglwidget.h; revision=555148 --- kalzium/kalziumglhelperclasses.cpp | 429 +++++++++++++++++++++++++++++ kalzium/kalziumglhelperclasses.h | 212 ++++++++++++++ kalzium/kalziumglwidget.cpp | 418 +--------------------------- kalzium/kalziumglwidget.h | 225 +-------------- kalzium/widgets/CMakeLists.txt | 1 + 5 files changed, 661 insertions(+), 624 deletions(-) create mode 100644 kalzium/kalziumglhelperclasses.cpp create mode 100644 kalzium/kalziumglhelperclasses.h diff --git a/kalzium/kalziumglhelperclasses.cpp b/kalzium/kalziumglhelperclasses.cpp new file mode 100644 index 0000000..425cb5b --- /dev/null +++ b/kalzium/kalziumglhelperclasses.cpp @@ -0,0 +1,429 @@ +/*************************************************************************** + copyright : (C) 2006 by Benoit Jacob + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include "kalziumglhelperclasses.h" +#include + +#ifdef USE_FPS_COUNTER +#include +#endif + +template bool GLVector3::approx_equal( + FLOAT a, FLOAT b, FLOAT precision ) +{ + FLOAT abs_a = GLFABS( a ); + FLOAT abs_b = GLFABS( b ); + + FLOAT max_abs; + if( abs_a < abs_b ) + max_abs = abs_b; + else + max_abs = abs_a; + return( GLFABS( a - b ) <= precision * max_abs ); +} + +template void GLVector3::construct_ortho_basis_given_first_vector( + GLVector3 &v, GLVector3 &w ) +{ + if( norm() == 0 ) return; + + // let us first make a normalized copy of *this + GLVector3 u = *this; + 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 ) ) + { + FLOAT tmp = v.x; + v.x = v.y; + v.y = tmp; + } + else if( ! approx_equal( v.y, v.z, 0.1 ) ) + { + FLOAT 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 = GLVector3( 0, 0, 1 ); + } + + // now, v is not colinear to u. We compute its dot product with u + FLOAT 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; +} + +GLColor::GLColor() +{ +} + +GLColor::GLColor( GLfloat red, GLfloat green, GLfloat blue, + GLfloat alpha ) +{ + m_red = red; + m_green = green; + m_blue = blue; + m_alpha = alpha; +} + +GLColor& GLColor::operator=( const GLColor& other ) +{ + m_red = other.m_red; + m_green = other.m_green; + m_blue = other.m_blue; + m_alpha = other.m_alpha; + + return *this; +} + +void GLColor::apply() +{ + glColor4fv( reinterpret_cast( this ) ); +} + +void GLColor::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 }; + + glMaterialfv(GL_FRONT, GL_AMBIENT, ambientColor); + glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseColor); + glMaterialfv(GL_FRONT, GL_SPECULAR, specularColor); + glMaterialf(GL_FRONT, GL_SHININESS, 50.0); +} + +GLVertexArray::GLVertexArray() +{ + allocateId(); + m_mode = GL_TRIANGLE_STRIP; + m_vertexBuffer = 0; + m_normalBuffer = 0; + m_indexBuffer = 0; + m_isInitialized = false; +} + +GLVertexArray::~GLVertexArray() +{ + if( m_indexBuffer ) delete [] m_indexBuffer; + if( m_vertexBuffer ) delete [] m_vertexBuffer; + if( m_normalBuffer ) delete [] m_normalBuffer; +} + +void GLVertexArray::allocateId() +{ + static int counter = 0; + m_id = counter++; +} + + +void GLVertexArray::select() +{ + static int selected_id = -1; + + if( selected_id == m_id ) return; + + glEnableClientState( GL_VERTEX_ARRAY ); + glEnableClientState( GL_NORMAL_ARRAY ); + glVertexPointer( 3, GL_FLOAT, 0, m_vertexBuffer ); + glNormalPointer( GL_FLOAT, 0, m_normalBuffer ); + selected_id = m_id; +} + +void GLVertexArray::draw() +{ + if( ! m_isInitialized ) return; + select(); + glDrawElements( m_mode, m_indexCount, + GL_UNSIGNED_SHORT, m_indexBuffer ); +} + +bool GLVertexArray::allocateBuffers() +{ + if( m_vertexCount > 65536 ) return false; + + m_isInitialized = false; + + if( m_indexBuffer ) + { + delete [] m_indexBuffer; + m_indexBuffer = 0; + } + if( m_vertexBuffer ) + { + delete [] m_vertexBuffer; + m_vertexBuffer = 0; + } + if( m_normalBuffer ) + { + delete [] m_normalBuffer; + m_normalBuffer = 0; + } + + m_vertexBuffer = new GLVector3[m_vertexCount]; + if( ! m_vertexBuffer ) return false; + m_normalBuffer = new GLVector3[m_vertexCount]; + if( ! m_normalBuffer ) return false; + m_indexBuffer = new unsigned short[m_indexCount]; + if( ! m_indexBuffer ) return false; + + return true; +} + +GLSphere::GLSphere() + : GLVertexArray() +{ + m_detail = 0; + m_radius = -1.0; +} + +unsigned short GLSphere::indexOfVertex( int strip, int column, int row) +{ + return ( row + ( 3 * m_detail + 1 ) * ( column + m_detail * strip ) ); +} + +void GLSphere::computeVertex( int strip, int column, int row) +{ + strip %= 5; + int next_strip = (strip + 1) % 5; + + GLVector3 *vertex = + &m_vertexBuffer[ indexOfVertex( strip, column, row ) ]; + + GLVector3 *normal = + &m_normalBuffer[ indexOfVertex( strip, column, row ) ]; + + const GLfloat phi = ( 1 + sqrt(5) ) / 2; + + const GLVector3 northPole( 0, 1, phi ); + const GLVector3 northVertex[5] = { + GLVector3( 0, -1, phi ), + GLVector3( phi, 0, 1 ), + GLVector3( 1, phi, 0 ), + GLVector3( -1, phi, 0 ), + GLVector3( -phi, 0, 1 ) }; + const GLVector3 southVertex[5] = { + GLVector3( -1, -phi, 0 ), + GLVector3( 1, -phi, 0 ), + GLVector3( phi, 0, -1 ), + GLVector3( 0, 1, -phi ), + GLVector3( -phi, 0, -1 ) + }; + const GLVector3 southPole( 0, -1, -phi ); + + const GLVector3 *v0, *v1, *v2; + int c1, c2; + + if( row >= 2 * m_detail && column == 0 ) + { + strip--; + if( strip < 0 ) strip += 5; + next_strip--; + if( next_strip < 0 ) next_strip += 5; + column = m_detail; + } + + if( row <= m_detail ) + { + v0 = &northVertex[strip]; + v1 = &northPole; + v2 = &northVertex[next_strip]; + c1 = m_detail - row; + c2 = column; + } + else if( row >= 2 * m_detail ) + { + v0 = &southVertex[next_strip]; + v1 = &southPole; + v2 = &southVertex[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]; + c1 = row - m_detail; + c2 = m_detail - column; + } + else + { + v0 = &southVertex[strip]; + v1 = &southVertex[next_strip]; + v2 = &northVertex[strip]; + c1 = column; + c2 = 2 * m_detail - row; + } + + GLfloat u1 = GLfloat(c1) / m_detail; + GLfloat u2 = GLfloat(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); + + vertex->normalize(); + + *normal = *vertex; + + vertex->x *= m_radius; + vertex->y *= m_radius; + vertex->z *= m_radius; +} + + +void GLSphere::initialize() +{ + if( m_detail < 1 ) return; + m_vertexCount = ( 3 * m_detail + 1 ) * ( 5 * m_detail + 1 ); + m_indexCount = (2 * ( 2 * m_detail + 1 ) + 2 ) * 5 * m_detail; + + if( ! allocateBuffers() ) return; + + for( int strip = 0; strip < 5; strip++ ) + for( int column = 1; column < m_detail; column++ ) + for( int row = column; row <= 2 * m_detail + column; row++ ) + computeVertex( strip, column, row ); + + for( int strip = 1; strip < 5; strip++ ) + for( int row = 0; row <= 3 * m_detail; row++ ) + computeVertex( strip, 0, row ); + + for( int row = 0; row <= 2 * m_detail; row++ ) + computeVertex( 0, 0, row ); + + for( int row = m_detail; row <= 3 * m_detail; row++ ) + computeVertex( 4, m_detail, row ); + + unsigned int i = 0; + for( int strip = 0; strip < 5; strip++ ) + for( int column = 0; column < m_detail; column++ ) + { + int row = column; + m_indexBuffer[i++] = indexOfVertex( strip, column, row ); + for( ; row <= 2 * m_detail + column; row++ ) + { + m_indexBuffer[i++] = + indexOfVertex( strip, column, row ); + m_indexBuffer[i++] = + indexOfVertex( strip, column + 1, row + 1 ); + } + m_indexBuffer[i++] = indexOfVertex( strip, column + 1, + 2 * m_detail + column + 1); + } + + m_isInitialized = true; +} + +void GLSphere::setup( int detail, GLfloat radius ) +{ + if( detail == m_detail && radius == m_radius ) return; + m_detail = detail; + m_radius = radius; + allocateId(); + initialize(); +} + +void GLSphere::drawScaled( GLfloat radius ) +{ + const GLfloat precision = 0.001; + + if( GLVector3::approx_equal( radius, m_radius, precision ) ) + { + draw(); + return; + } + + GLfloat factor = radius / m_radius; + glEnable( GL_NORMALIZE ); + glPushMatrix(); + glScalef( factor, factor, factor ); + draw(); + glPopMatrix(); + glDisable( GL_NORMALIZE ); +} + +GLCylinder::GLCylinder() + : GLVertexArray() +{ + m_mode = GL_QUAD_STRIP; + m_faces = 0; + m_radius = -1.0; +} + +void GLCylinder::setup( int faces, GLfloat radius ) +{ + if( faces == m_faces && radius == m_radius ) return; + m_faces = faces; + m_radius = radius; + allocateId(); + initialize(); +} + +void GLCylinder::initialize() +{ + if( m_faces < 3 ) return; + + m_vertexCount = 2 * m_faces + 2; // we will use a redundant vertex array + m_indexCount = 0; // we won't use it. + + if( ! allocateBuffers() ) return; + + for( int i = 0; i <= m_faces; i++) + { + float angle = 2 * M_PI * i / m_faces; + float x = cosf( angle ); + float y = sinf( angle ); + + m_normalBuffer[ 2 * i ].x = x; + 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 ].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].z = 0.0; + } + + m_isInitialized = true; +} + +void GLCylinder::draw() +{ + if ( ! m_isInitialized ) return; + select(); + glDrawArrays( m_mode, 0, m_vertexCount ); +} diff --git a/kalzium/kalziumglhelperclasses.h b/kalzium/kalziumglhelperclasses.h new file mode 100644 index 0000000..4c47568 --- /dev/null +++ b/kalzium/kalziumglhelperclasses.h @@ -0,0 +1,212 @@ +#ifndef KALZIUMGLHELPERCLASSES_H +#define KALZIUMGLHELPERCLASSES_H +/*************************************************************************** + copyright : (C) 2006 by Benoit Jacob + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include + +#define USE_DOUBLE_PRECISION +#define USE_DISPLAY_LIST +#define USE_FPS_COUNTER + +#ifdef USE_DOUBLE_PRECISION +#define FLOAT double +#define GLFLOAT GLdouble +#else +#define FLOAT float +#define GLFLOAT GLfloat +#endif + +inline float GLSQRT( float x ) { return sqrtf( x ); } +inline double GLSQRT( double x ) { return sqrt( x ); } +inline float GLSIN( float x ) { return sinf( x ); } +inline double GLSIN( double x ) { return sin( x ); } +inline float GLCOS( float x ) { return cosf( x ); } +inline double GLCOS( double x ) { return cos( x ); } +inline float GLFABS( float x ) { return fabsf( x ); } +inline double GLFABS( 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 ); } + +/** + * This class represents a color in OpenGL float red-green-blue format. + * + * @author Benoit Jacob + */ +struct GLColor +{ + GLfloat m_red, m_green, m_blue, m_alpha; + + GLColor(); + GLColor( GLfloat red, GLfloat green, GLfloat blue, + GLfloat alpha = 1.0 ); + + GLColor& operator=( const GLColor& other ); + + /** + * Sets this color to be the one used by OpenGL for rendering + * when lighting is disabled. It just calls glColor4fv. + */ + //TODO inline? + void apply(); + + /** + * Applies nice OpenGL materials using this color as the + * diffuse color while using different shades for the ambient and + * specular colors. This is only useful if GL lighting is enabled. + */ + void applyAsMaterials(); +}; + +/** + * 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 GLVector3 +{ + public: + T x, y, z; + GLVector3() {} + GLVector3( T _x, T _y, T _z) + { x = _x; y = _y; z = _z; } + + /** + * Tests whether two FLOATs are approximately equal. + * Recall that operator == between floating-point types + * is broken. + * returns true if abs( a - b ) <= c * precision + * where c = max( abs( a ), abs( b ) ) + */ + static bool approx_equal( FLOAT a, FLOAT b, FLOAT precision ); + + GLVector3& operator= ( const GLVector3& 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() { return GLSQRT( 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; + } + + /** + * Constructs two vectors v and w + * such that (*this, v, w) is a direct orthogonal basis. + * v and w are not getting normalized. + */ + void construct_ortho_basis_given_first_vector( + GLVector3 & v, GLVector3 & w ); +}; + +/** + * This is an abstract base class for an OpenGL vertex array. + * + * @author Benoit Jacob + */ +class GLVertexArray +{ + private: + int m_id; + + protected: + GLenum m_mode; + GLVector3 *m_vertexBuffer; + GLVector3 *m_normalBuffer; + unsigned int m_vertexCount; + unsigned short *m_indexBuffer; + unsigned int m_indexCount; + + bool m_isInitialized; + + virtual void initialize() = 0; + virtual bool allocateBuffers(); + virtual void allocateId(); + virtual void select(); + + public: + GLVertexArray(); + virtual ~GLVertexArray(); + //inline? + virtual void draw(); +}; + +/** + * This class represents and draws a sphere + * + * @author Benoit Jacob + */ +class GLSphere : public GLVertexArray +{ + private: + inline unsigned short indexOfVertex( + int strip, int column, int row); + void computeVertex( int strip, int column, int row ); + + protected: + int m_detail; + GLfloat m_radius; + + virtual void initialize(); + + public: + GLSphere(); + virtual ~GLSphere() {} + virtual void setup( int detail, GLfloat radius ); + virtual void drawScaled( GLfloat radius ); +}; + +/** + * This class represents and draws a cylinder + * + * @author Benoit Jacob + */ +class GLCylinder : public GLVertexArray +{ + protected: + int m_faces; + GLfloat m_radius; + + virtual void initialize(); + + public: + GLCylinder(); + virtual ~GLCylinder() {} + virtual void setup( int detail, GLfloat radius ); + virtual inline void draw(); +}; + +#endif // KALZIUMGLHELPERCLASSES_H + diff --git a/kalzium/kalziumglwidget.cpp b/kalzium/kalziumglwidget.cpp index 15543d5..52ea5d9 100644 --- a/kalzium/kalziumglwidget.cpp +++ b/kalzium/kalziumglwidget.cpp @@ -12,6 +12,7 @@ * * ***************************************************************************/ #include "kalziumglwidget.h" +#include "kalziumglhelperclasses.h" #include @@ -376,7 +377,7 @@ void KalziumGLWidget::drawBond( FLOAT x1, FLOAT y1, FLOAT z1, // find two vectors v, w such that (axis,v,w) is an orthogonal basis. GLVector3 v, w; - axis.construct_ortho_basis_given_first_vector( v, w ); +// axis.construct_ortho_basis_given_first_vector( v, w ); // normalize v and w. We DON'T want to normalize axis v.normalize(); @@ -529,88 +530,6 @@ void KalziumGLWidget::slotSetDetail( int detail ) updateGL(); } -template bool GLVector3::approx_equal( - FLOAT a, FLOAT b, FLOAT precision ) -{ - FLOAT abs_a = GLFABS( a ); - FLOAT abs_b = GLFABS( b ); - - FLOAT max_abs; - if( abs_a < abs_b ) - max_abs = abs_b; - else - max_abs = abs_a; - return( GLFABS( a - b ) <= precision * max_abs ); -} - -template void GLVector3::construct_ortho_basis_given_first_vector( - GLVector3 &v, GLVector3 &w ) -{ - if( norm() == 0 ) return; - - // let us first make a normalized copy of *this - GLVector3 u = *this; - 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 ) ) - { - FLOAT tmp = v.x; - v.x = v.y; - v.y = tmp; - } - else if( ! approx_equal( v.y, v.z, 0.1 ) ) - { - FLOAT 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 = GLVector3( 0, 0, 1 ); - } - - // now, v is not colinear to u. We compute its dot product with u - FLOAT 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; -} - -GLColor::GLColor() -{ -} - -GLColor::GLColor( GLfloat red, GLfloat green, GLfloat blue, - GLfloat alpha ) -{ - m_red = red; - m_green = green; - m_blue = blue; - m_alpha = alpha; -} - -GLColor& GLColor::operator=( const GLColor& other ) -{ - m_red = other.m_red; - m_green = other.m_green; - m_blue = other.m_blue; - m_alpha = other.m_alpha; - - return *this; -} - GLColor& KalziumGLWidget::getAtomColor( OpenBabel::OBAtom* atom ) { static GLColor c; @@ -655,6 +574,10 @@ GLColor& KalziumGLWidget::getAtomColor( OpenBabel::OBAtom* atom ) return c; } +void KalziumGLWidget::slotAtomsSelected( QList atoms ) +{ + +} void KalziumGLWidget::slotAtomSelected( OpenBabel::OBAtom* atom ) { @@ -663,333 +586,4 @@ void KalziumGLWidget::slotAtomSelected( OpenBabel::OBAtom* atom ) updateGL(); } -inline void GLColor::apply() -{ - glColor4fv( reinterpret_cast( this ) ); -} - -void GLColor::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 }; - - glMaterialfv(GL_FRONT, GL_AMBIENT, ambientColor); - glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseColor); - glMaterialfv(GL_FRONT, GL_SPECULAR, specularColor); - glMaterialf(GL_FRONT, GL_SHININESS, 50.0); -} - -GLVertexArray::GLVertexArray() -{ - allocateId(); - m_mode = GL_TRIANGLE_STRIP; - m_vertexBuffer = 0; - m_normalBuffer = 0; - m_indexBuffer = 0; - m_isInitialized = false; -} - -GLVertexArray::~GLVertexArray() -{ - if( m_indexBuffer ) delete [] m_indexBuffer; - if( m_vertexBuffer ) delete [] m_vertexBuffer; - if( m_normalBuffer ) delete [] m_normalBuffer; -} - -void GLVertexArray::allocateId() -{ - static int counter = 0; - m_id = counter++; -} - - -void GLVertexArray::select() -{ - static int selected_id = -1; - - if( selected_id == m_id ) return; - - glEnableClientState( GL_VERTEX_ARRAY ); - glEnableClientState( GL_NORMAL_ARRAY ); - glVertexPointer( 3, GL_FLOAT, 0, m_vertexBuffer ); - glNormalPointer( GL_FLOAT, 0, m_normalBuffer ); - selected_id = m_id; -} - -void GLVertexArray::draw() -{ - if( ! m_isInitialized ) return; - select(); - glDrawElements( m_mode, m_indexCount, - GL_UNSIGNED_SHORT, m_indexBuffer ); -} - -bool GLVertexArray::allocateBuffers() -{ - if( m_vertexCount > 65536 ) return false; - - m_isInitialized = false; - - if( m_indexBuffer ) - { - delete [] m_indexBuffer; - m_indexBuffer = 0; - } - if( m_vertexBuffer ) - { - delete [] m_vertexBuffer; - m_vertexBuffer = 0; - } - if( m_normalBuffer ) - { - delete [] m_normalBuffer; - m_normalBuffer = 0; - } - - m_vertexBuffer = new GLVector3[m_vertexCount]; - if( ! m_vertexBuffer ) return false; - m_normalBuffer = new GLVector3[m_vertexCount]; - if( ! m_normalBuffer ) return false; - m_indexBuffer = new unsigned short[m_indexCount]; - if( ! m_indexBuffer ) return false; - - return true; -} - -GLSphere::GLSphere() - : GLVertexArray() -{ - m_detail = 0; - m_radius = -1.0; -} - -unsigned short GLSphere::indexOfVertex( int strip, int column, int row) -{ - return ( row + ( 3 * m_detail + 1 ) * ( column + m_detail * strip ) ); -} - -void GLSphere::computeVertex( int strip, int column, int row) -{ - strip %= 5; - int next_strip = (strip + 1) % 5; - - GLVector3 *vertex = - &m_vertexBuffer[ indexOfVertex( strip, column, row ) ]; - - GLVector3 *normal = - &m_normalBuffer[ indexOfVertex( strip, column, row ) ]; - - const GLfloat phi = ( 1 + sqrt(5) ) / 2; - - const GLVector3 northPole( 0, 1, phi ); - const GLVector3 northVertex[5] = { - GLVector3( 0, -1, phi ), - GLVector3( phi, 0, 1 ), - GLVector3( 1, phi, 0 ), - GLVector3( -1, phi, 0 ), - GLVector3( -phi, 0, 1 ) }; - const GLVector3 southVertex[5] = { - GLVector3( -1, -phi, 0 ), - GLVector3( 1, -phi, 0 ), - GLVector3( phi, 0, -1 ), - GLVector3( 0, 1, -phi ), - GLVector3( -phi, 0, -1 ) - }; - const GLVector3 southPole( 0, -1, -phi ); - - const GLVector3 *v0, *v1, *v2; - int c1, c2; - - if( row >= 2 * m_detail && column == 0 ) - { - strip--; - if( strip < 0 ) strip += 5; - next_strip--; - if( next_strip < 0 ) next_strip += 5; - column = m_detail; - } - - if( row <= m_detail ) - { - v0 = &northVertex[strip]; - v1 = &northPole; - v2 = &northVertex[next_strip]; - c1 = m_detail - row; - c2 = column; - } - else if( row >= 2 * m_detail ) - { - v0 = &southVertex[next_strip]; - v1 = &southPole; - v2 = &southVertex[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]; - c1 = row - m_detail; - c2 = m_detail - column; - } - else - { - v0 = &southVertex[strip]; - v1 = &southVertex[next_strip]; - v2 = &northVertex[strip]; - c1 = column; - c2 = 2 * m_detail - row; - } - - GLfloat u1 = GLfloat(c1) / m_detail; - GLfloat u2 = GLfloat(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); - - vertex->normalize(); - - *normal = *vertex; - - vertex->x *= m_radius; - vertex->y *= m_radius; - vertex->z *= m_radius; -} - - -void GLSphere::initialize() -{ - if( m_detail < 1 ) return; - m_vertexCount = ( 3 * m_detail + 1 ) * ( 5 * m_detail + 1 ); - m_indexCount = (2 * ( 2 * m_detail + 1 ) + 2 ) * 5 * m_detail; - - if( ! allocateBuffers() ) return; - - for( int strip = 0; strip < 5; strip++ ) - for( int column = 1; column < m_detail; column++ ) - for( int row = column; row <= 2 * m_detail + column; row++ ) - computeVertex( strip, column, row ); - - for( int strip = 1; strip < 5; strip++ ) - for( int row = 0; row <= 3 * m_detail; row++ ) - computeVertex( strip, 0, row ); - - for( int row = 0; row <= 2 * m_detail; row++ ) - computeVertex( 0, 0, row ); - - for( int row = m_detail; row <= 3 * m_detail; row++ ) - computeVertex( 4, m_detail, row ); - - unsigned int i = 0; - for( int strip = 0; strip < 5; strip++ ) - for( int column = 0; column < m_detail; column++ ) - { - int row = column; - m_indexBuffer[i++] = indexOfVertex( strip, column, row ); - for( ; row <= 2 * m_detail + column; row++ ) - { - m_indexBuffer[i++] = - indexOfVertex( strip, column, row ); - m_indexBuffer[i++] = - indexOfVertex( strip, column + 1, row + 1 ); - } - m_indexBuffer[i++] = indexOfVertex( strip, column + 1, - 2 * m_detail + column + 1); - } - - m_isInitialized = true; -} - -void GLSphere::setup( int detail, GLfloat radius ) -{ - if( detail == m_detail && radius == m_radius ) return; - m_detail = detail; - m_radius = radius; - allocateId(); - initialize(); -} - -void GLSphere::drawScaled( GLfloat radius ) -{ - const GLfloat precision = 0.001; - - if( GLVector3::approx_equal( radius, m_radius, precision ) ) - { - draw(); - return; - } - - GLfloat factor = radius / m_radius; - glEnable( GL_NORMALIZE ); - glPushMatrix(); - glScalef( factor, factor, factor ); - draw(); - glPopMatrix(); - glDisable( GL_NORMALIZE ); -} - -GLCylinder::GLCylinder() - : GLVertexArray() -{ - m_mode = GL_QUAD_STRIP; - m_faces = 0; - m_radius = -1.0; -} - -void GLCylinder::setup( int faces, GLfloat radius ) -{ - if( faces == m_faces && radius == m_radius ) return; - m_faces = faces; - m_radius = radius; - allocateId(); - initialize(); -} - -void GLCylinder::initialize() -{ - if( m_faces < 3 ) return; - - m_vertexCount = 2 * m_faces + 2; // we will use a redundant vertex array - m_indexCount = 0; // we won't use it. - - if( ! allocateBuffers() ) return; - - for( int i = 0; i <= m_faces; i++) - { - float angle = 2 * M_PI * i / m_faces; - float x = cosf( angle ); - float y = sinf( angle ); - - m_normalBuffer[ 2 * i ].x = x; - 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 ].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].z = 0.0; - } - - m_isInitialized = true; -} - -void GLCylinder::draw() -{ - if ( ! m_isInitialized ) return; - select(); - glDrawArrays( m_mode, 0, m_vertexCount ); -} - #include "kalziumglwidget.moc" diff --git a/kalzium/kalziumglwidget.h b/kalzium/kalziumglwidget.h index 3e046a6..a420755 100644 --- a/kalzium/kalziumglwidget.h +++ b/kalzium/kalziumglwidget.h @@ -2,7 +2,6 @@ #define KALZIUMGLWIDGET_H /*************************************************************************** copyright : (C) 2006 by Benoit Jacob - email : cniehaus@kde.org ***************************************************************************/ /*************************************************************************** @@ -14,200 +13,12 @@ * * ***************************************************************************/ +#include "kalziumglhelperclasses.h" + #include +#include #include -#define USE_DOUBLE_PRECISION -#define USE_DISPLAY_LIST -#define USE_FPS_COUNTER - -#ifdef USE_DOUBLE_PRECISION -#define FLOAT double -#define GLFLOAT GLdouble -#else -#define FLOAT float -#define GLFLOAT GLfloat -#endif - -inline float GLSQRT( float x ) { return sqrtf( x ); } -inline double GLSQRT( double x ) { return sqrt( x ); } -inline float GLSIN( float x ) { return sinf( x ); } -inline double GLSIN( double x ) { return sin( x ); } -inline float GLCOS( float x ) { return cosf( x ); } -inline double GLCOS( double x ) { return cos( x ); } -inline float GLFABS( float x ) { return fabsf( x ); } -inline double GLFABS( 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 ); } - -/** - * This class represents a color in OpenGL float red-green-blue format. - * - * @author Benoit Jacob - */ -struct GLColor -{ - GLfloat m_red, m_green, m_blue, m_alpha; - - GLColor(); - GLColor( GLfloat red, GLfloat green, GLfloat blue, - GLfloat alpha = 1.0 ); - - GLColor& operator=( const GLColor& other ); - - /** - * Sets this color to be the one used by OpenGL for rendering - * when lighting is disabled. It just calls glColor4fv. - */ - inline void apply(); - - /** - * Applies nice OpenGL materials using this color as the - * diffuse color while using different shades for the ambient and - * specular colors. This is only useful if GL lighting is enabled. - */ - void applyAsMaterials(); -}; - -/** - * 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 GLVector3 -{ - public: - T x, y, z; - GLVector3() {} - GLVector3( T _x, T _y, T _z) - { x = _x; y = _y; z = _z; } - - /** - * Tests whether two FLOATs are approximately equal. - * Recall that operator == between floating-point types - * is broken. - * returns true if abs( a - b ) <= c * precision - * where c = max( abs( a ), abs( b ) ) - */ - static bool approx_equal( FLOAT a, FLOAT b, FLOAT precision ); - - GLVector3& operator= ( const GLVector3& 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() { return GLSQRT( 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; - } - - /** - * Constructs two vectors v and w - * such that (*this, v, w) is a direct orthogonal basis. - * v and w are not getting normalized. - */ - void construct_ortho_basis_given_first_vector( - GLVector3 & v, GLVector3 & w ); -}; - -/** - * This is an abstract base class for an OpenGL vertex array. - * - * @author Benoit Jacob - */ -class GLVertexArray -{ - private: - int m_id; - - protected: - GLenum m_mode; - GLVector3 *m_vertexBuffer; - GLVector3 *m_normalBuffer; - unsigned int m_vertexCount; - unsigned short *m_indexBuffer; - unsigned int m_indexCount; - - bool m_isInitialized; - - virtual void initialize() = 0; - virtual bool allocateBuffers(); - virtual void allocateId(); - virtual void select(); - - public: - GLVertexArray(); - virtual ~GLVertexArray(); - virtual inline void draw(); -}; - -/** - * This class represents and draws a sphere - * - * @author Benoit Jacob - */ -class GLSphere : public GLVertexArray -{ - private: - inline unsigned short indexOfVertex( - int strip, int column, int row); - void computeVertex( int strip, int column, int row ); - - protected: - int m_detail; - GLfloat m_radius; - - virtual void initialize(); - - public: - GLSphere(); - virtual ~GLSphere() {} - virtual void setup( int detail, GLfloat radius ); - virtual void drawScaled( GLfloat radius ); -}; - -/** - * This class represents and draws a cylinder - * - * @author Benoit Jacob - */ -class GLCylinder : public GLVertexArray -{ - protected: - int m_faces; - GLfloat m_radius; - - virtual void initialize(); - - public: - GLCylinder(); - virtual ~GLCylinder() {} - virtual void setup( int detail, GLfloat radius ); - virtual inline void draw(); -}; - /** * This class displays the 3D-view of a molecule * @@ -374,6 +185,8 @@ class KalziumGLWidget : public QGLWidget * The atom @p atom was selected by the user */ void slotAtomSelected( OpenBabel::OBAtom* atom ); + + void slotAtomsSelected( QList atoms ); protected: /** @@ -402,16 +215,6 @@ class KalziumGLWidget : public QGLWidget */ void prepareMoleculeData(); - /** - * This method draws a sphere - * @param x - * @param y - * @param z - * @param red - * @param green - * @param blue - */ - virtual void drawSphere( GLFLOAT x, GLFLOAT y, @@ -421,15 +224,14 @@ class KalziumGLWidget : public QGLWidget /** * This method draws a bond - * @param x - * @param y - * @param z - * @param radius - * @param red - * @param green - * @param blue + * @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, GLColor &color ); @@ -465,6 +267,5 @@ class KalziumGLWidget : public QGLWidget */ virtual void setupObjects(); }; - - #endif // KALZIUMGLWIDGET_H + diff --git a/kalzium/widgets/CMakeLists.txt b/kalzium/widgets/CMakeLists.txt index a58fceb..fdefbfa 100644 --- a/kalzium/widgets/CMakeLists.txt +++ b/kalzium/widgets/CMakeLists.txt @@ -7,6 +7,7 @@ if(OPENBABEL2_FOUND) endif(OPENBABEL2_FOUND) set(kalziumui_PART_SRCS + ${CMAKE_SOURCE_DIR}/kalzium/src/kalziumglhelperclasses.cpp ${CMAKE_SOURCE_DIR}/kalzium/src/kalziumglwidget.cpp ) -- 2.47.3