glMaterialf( GL_FRONT, GL_SHININESS, 50.0 );
}
-VertexArray::VertexArray( GLenum mode,
- bool hasIndexBuffer,
- bool hasSeparateNormalBuffer )
+Sphere::Sphere()
{
- m_mode = mode;
m_vertexBuffer = 0;
- m_normalBuffer = 0;
m_indexBuffer = 0;
m_displayList = 0;
- m_hasIndexBuffer = hasIndexBuffer;
- m_hasSeparateNormalBuffer = hasSeparateNormalBuffer;
- m_isValid = false;
+ m_detail = 0;
}
-VertexArray::~VertexArray()
+Sphere::~Sphere()
{
freeBuffers();
if( m_displayList )
glDeleteLists( m_displayList, 1 );
}
-void VertexArray::freeBuffers()
+void Sphere::freeBuffers()
{
if( m_indexBuffer )
{
delete [] m_vertexBuffer;
m_vertexBuffer = 0;
}
- if( m_normalBuffer && m_hasSeparateNormalBuffer )
- {
- delete [] m_normalBuffer;
- m_normalBuffer = 0;
- }
}
-bool VertexArray::allocateBuffers()
+void Sphere::do_draw() const
+{
+ glVertexPointer( 3, GL_FLOAT, 0, m_vertexBuffer );
+ glNormalPointer( GL_FLOAT, 0, m_vertexBuffer );
+ glDrawElements( GL_TRIANGLE_STRIP, m_indexCount,
+ GL_UNSIGNED_SHORT, m_indexBuffer );
+}
+
+void Sphere::draw( const Eigen::Vector3d ¢er, double radius ) const
+{
+ glPushMatrix();
+ glTranslated( center.x(), center.y(), center.z() );
+ glScaled( radius, radius, radius );
+#ifdef USE_DISPLAY_LISTS
+ glCallList( m_displayList );
+#else
+ do_draw();
+#endif
+ glPopMatrix();
+}
+
+void Sphere::initialize()
{
- if( m_vertexCount > 65536 ) return false;
+ if( m_detail < 1 ) return;
+
+ // compute number of vertices and indices
+ m_vertexCount = ( 3 * m_detail + 1 ) * ( 5 * m_detail + 1 );
+ m_indexCount = (2 * ( 2 * m_detail + 1 ) + 2 ) * 5 * m_detail;
+ // deallocate any previously allocated buffer
freeBuffers();
+ // allocate memory for buffers
m_vertexBuffer = new Vector3f[m_vertexCount];
- if( ! m_vertexBuffer ) return false;
-
- if( m_hasSeparateNormalBuffer )
- {
- m_normalBuffer = new Vector3f[m_vertexCount];
- if( ! m_normalBuffer ) return false;
- }
- else m_normalBuffer = m_vertexBuffer;
+ if( ! m_vertexBuffer ) return;
+ m_indexBuffer = new unsigned short[m_indexCount];
+ if( ! m_indexBuffer ) return;
- if( m_hasIndexBuffer )
- {
- m_indexBuffer = new unsigned short[m_indexCount];
- if( ! m_indexBuffer ) return false;
- }
+ // build vertex buffer
+ 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 );
- return true;
-}
+ for( int strip = 1; strip < 5; strip++ )
+ for( int row = 0; row <= 3 * m_detail; row++ )
+ computeVertex( strip, 0, row );
-void VertexArray::do_draw()
-{
- glVertexPointer( 3, GL_FLOAT, 0, m_vertexBuffer );
- glNormalPointer( GL_FLOAT, 0, m_normalBuffer );
- if( m_hasIndexBuffer )
- glDrawElements( m_mode, m_indexCount,
- GL_UNSIGNED_SHORT, m_indexBuffer );
- else
- glDrawArrays( m_mode, 0, m_vertexCount );
-}
+ 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 );
+
+ // build index buffer
+ 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);
+ }
-void VertexArray::compileDisplayList()
-{
#ifdef USE_DISPLAY_LISTS
- if( ! m_displayList )
- m_displayList = glGenLists( 1 );
+ // compile display list and free buffers
+ if( ! m_displayList ) m_displayList = glGenLists( 1 );
if( ! m_displayList ) return;
-
glNewList( m_displayList, GL_COMPILE );
do_draw();
glEndList();
-
freeBuffers();
#endif
}
-void VertexArray::initialize()
-{
- m_isValid = false;
- m_vertexCount = getVertexCount();
- m_indexCount = getIndexCount();
- if( m_indexCount < 0 || m_vertexCount < 0 ) return;
- if( ! allocateBuffers() ) return;
- buildBuffers();
- compileDisplayList();
- m_isValid = true;
-}
-
-Sphere::Sphere()
- : VertexArray( GL_TRIANGLE_STRIP, true, false )
-{
- m_detail = 0;
-}
-
unsigned short Sphere::indexOfVertex( int strip, int column, int row)
{
return ( row + ( 3 * m_detail + 1 ) * ( column + m_detail * strip ) );
vertex.normalize();
}
-int Sphere::getVertexCount()
-{
- if( m_detail < 1 ) return -1;
- return ( 3 * m_detail + 1 ) * ( 5 * m_detail + 1 );
-}
-
-int Sphere::getIndexCount()
-{
- if( m_detail < 1 ) return -1;
- return (2 * ( 2 * m_detail + 1 ) + 2 ) * 5 * m_detail;
-}
-
-void Sphere::buildBuffers()
-{
- 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);
- }
-}
-
void Sphere::setup( int detail )
{
if( detail == m_detail ) return;
initialize();
}
-void Sphere::draw( const Vector3d ¢er, double radius )
+Cylinder::Cylinder()
{
- glPushMatrix();
- glTranslated( center.x(), center.y(), center.z() );
- glScaled( radius, radius, radius );
- VertexArray::draw();
- glPopMatrix();
+ m_vertexBuffer = 0;
+ m_normalBuffer = 0;
+ m_displayList = 0;
+ m_faces = 0;
}
-Cylinder::Cylinder()
- : VertexArray( GL_QUAD_STRIP, false, true )
+Cylinder::~Cylinder()
{
- m_faces = 0;
+ freeBuffers();
+ if( m_displayList )
+ glDeleteLists( m_displayList, 1 );
+}
+
+void Cylinder::freeBuffers()
+{
+ if( m_normalBuffer )
+ {
+ delete [] m_normalBuffer;
+ m_normalBuffer = 0;
+ }
+ if( m_vertexBuffer )
+ {
+ delete [] m_vertexBuffer;
+ m_vertexBuffer = 0;
+ }
}
void Cylinder::setup( int faces )
initialize();
}
-int Cylinder::getVertexCount()
+void Cylinder::initialize()
{
- if( m_faces < 3 ) return -1;
- return 2 * m_faces + 2;
-}
+ if( m_faces < 3 ) return;
-void Cylinder::buildBuffers()
-{
+ // compute number of vertices
+ m_vertexCount = 2 * m_faces + 2;
+
+ // deallocate any previously allocated buffer
+ freeBuffers();
+
+ // allocate memory for buffers
+ m_vertexBuffer = new Vector3f[m_vertexCount];
+ if( ! m_vertexBuffer ) return;
+ m_normalBuffer = new Vector3f[m_vertexCount];
+ if( ! m_normalBuffer ) return;
+
+ // build vertex and normal buffers
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_normalBuffer[ 2 * i + 1 ] = m_normalBuffer[ 2 * i ];
+ Vector3f v( cosf(angle), sinf(angle), 0.0f );
+ m_normalBuffer[ 2 * i ] = v;
+ m_normalBuffer[ 2 * i + 1 ] = v;
+ m_vertexBuffer[ 2 * i ] = v;
+ m_vertexBuffer[ 2 * i + 1 ] = v;
+ m_vertexBuffer[ 2 * i ].z() = 1.0f;
+ }
- m_vertexBuffer[ 2 * i ].x() = x;
- m_vertexBuffer[ 2 * i ].y() = y;
- m_vertexBuffer[ 2 * i ].z() = 1.0;
+#ifdef USE_DISPLAY_LISTS
+ // compile display list and free buffers
+ if( ! m_displayList ) m_displayList = glGenLists( 1 );
+ if( ! m_displayList ) return;
+ glNewList( m_displayList, GL_COMPILE );
+ do_draw();
+ glEndList();
+ freeBuffers();
+#endif
+}
- m_vertexBuffer[ 2 * i + 1 ].x() = x;
- m_vertexBuffer[ 2 * i + 1 ].y() = y;
- m_vertexBuffer[ 2 * i + 1 ].z() = 0.0;
- }
+void Cylinder::do_draw() const
+{
+ glVertexPointer( 3, GL_FLOAT, 0, m_vertexBuffer );
+ glNormalPointer( GL_FLOAT, 0, m_normalBuffer );
+ glDrawArrays( GL_QUAD_STRIP, 0, m_vertexCount );
}
void Cylinder::draw( const Vector3d &end1, const Vector3d &end2,
- double radius, int order, double shift )
+ double radius, int order, double shift ) const
{
// the "axis vector" of the cylinder
Vector3d axis = end2 - end1;
//now we can do the actual drawing !
glPushMatrix();
glMultMatrixd( matrix.array() );
- if( order == 1 ) VertexArray::draw();
+ if( order == 1 )
+# ifdef USE_DISPLAY_LISTS
+ glCallList( m_displayList );
+# else
+ do_draw();
+# endif
else
{
double angleOffset = 0.0;
glRotated( angleOffset + 360.0 * i / order,
0.0, 0.0, 1.0 );
glTranslated( displacementFactor, 0.0, 0.0 );
- VertexArray::draw();
+# ifdef USE_DISPLAY_LISTS
+ glCallList( m_displayList );
+# else
+ do_draw();
+# endif
glPopMatrix();
}
}
if( ! m_isBetweenBeginAndEnd ) do_end();
}
-void createOrthoBasisGivenFirstVector
- ( const Vector3d &U, Vector3d * v, Vector3d * w )
-{
- U.makeOrthoVector(v);
- *w = cross( U, *v );
- w->normalize();
-}
-
} // namespace KalziumGLHelpers
* counter. Use only for testing: this makes the GL Widget constantly
* redraw, which under normal circumstances is a waste of CPU time.
*/
-//#define USE_FPS_COUNTER
+#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 be converted into
void applyAsMaterials();
};
-/**
-* 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.
-*
-* Returns false if something went wrong.
-*/
-void createOrthoBasisGivenFirstVector( const Eigen::Vector3d & U,
- Eigen::Vector3d * v,
- Eigen::Vector3d * w );
-
-/**
-* This is an abstract base class for an OpenGL vertex array, with an option
-* (controlled by USE_DISPLAY_LISTS) to compile a display list from it, in which
-* case the vertex array is freed and only the display list is kept.
-*
-* @author Benoit Jacob
-*/
-class VertexArray
-{
- protected:
- /** Pointer to the buffer storing the vertex array */
- Eigen::Vector3f *m_vertexBuffer;
- /** Pointer to the buffer storing the normal array.
- * If m_hasSeparateNormalBuffer is false, then this is equal
- * to m_vertexBuffer. */
- Eigen::Vector3f *m_normalBuffer;
- /** Pointer to the buffer storing the indices */
- unsigned short *m_indexBuffer;
- /** The mode in which OpenGL should interpred the vertex arrays
- * (for example, this could be GL_TRIANGLE_STRIP) */
- GLenum m_mode;
- /** The number of vertices, i.e. the size of m_vertexBuffer
- * or equivalently m_normalBuffer */
- int m_vertexCount;
- /** The number of indices, i.e. the size of m_indexBuffer */
- int m_indexCount;
- /** The id of the OpenGL display list (used only if this option
- * is turned on) */
- GLuint m_displayList;
- /** Equals true if there is an index buffer, i.e. if this is an
- * indexed vertex array */
- bool m_hasIndexBuffer;
- /** If this equals false, then the vertex buffer will also be
- * used as normal buffer. This allows to divide by 2 the space
- * taken by a sphere vertex array. For most objects other than
- * spheres, this should equal true. */
- bool m_hasSeparateNormalBuffer;
- /** Equals true if this is a valid, well-initialized vertex
- * array */
- bool m_isValid;
-
- /** This pure virtual method should return the number of
- * vertices, as computed from certain properties determining
- * the level of detail */
- virtual int getVertexCount() = 0;
- /** This virtual method returns 0, and should be reimplemented
- * in child classes to return the number of indices
- * as computed from certain properties determining
- * the level of detail */
- virtual int getIndexCount() { return 0; }
- /** This method allocates enough memory for the buffers. It
- * should only be called once m_vertexCount and m_indexCount
- * have been set. */
- bool allocateBuffers();
- /** This method frees the buffers. If display list compilation
- * is enabled, then it is safe to call it once the display list
- * has been compiled.
- */
- void freeBuffers();
- /** This pure virtual method should fill the buffers with the
- * geometric data. It should be called only after
- * allocateBuffers() */
- virtual void buildBuffers() = 0;
- /** If display list compilation is enabled, then this method
- * compiles the display list and then calls freeBuffers().
- * It should only be called after buildBuffers(). */
- void compileDisplayList();
- /** This is a convenient method calling getVertexCount(),
- * getIndexCount(), allocateBuffers(), buildBuffers() and
- * compileDisplayList() in that order, thus doing all the
- * initialization, whether or not display list compilation is
- * enabled. */
- void initialize();
- /** This function draws the vertex array using OpenGL. */
- void do_draw();
-
- public:
- /** This constructors only sets the values of the member data to
- * some pre-initialization state. See the initialize() method
- * for actual initialization. */
- VertexArray( GLenum mode,
- bool hasIndexBuffer,
- bool hasSeparateNormalBuffer );
- /** This destructor frees the buffers if necessary, and also
- * deletes the display list if it has been compiled. */
- virtual ~VertexArray();
-
- /** If display list compilation is enabled, then this function
- * just calls the display list. Otherwise, it calls do_draw().
- */
- inline void draw()
- {
-#ifdef USE_DISPLAY_LISTS
- if( m_isValid ) glCallList( m_displayList );
-#else
- if( m_isValid ) do_draw();
-#endif
- }
-};
-
/**
* This class represents and draws a sphere. The sphere is computed as a
* "geosphere", that is, one starts with an icosahedron, which is the regular
*
* @author Benoit Jacob
*/
-class Sphere : public VertexArray
+class Sphere
{
- private:
- /** computes the index (position inside the index buffer)
- * of a vertex given by its position (strip, column, row)
- * inside a certain flat model of the sub-tesselated
- * icosahedron */
- inline unsigned short indexOfVertex(
- int strip, int column, int row);
- /** computes the coordinates
- * of a vertex given by its position (strip, column, row)
- * inside a certain flat model of the sub-tesselated
- * icosahedron */
- void computeVertex( int strip, int column, int row );
-
- protected:
- /** the detail-level of the sphere. Must be at least 1.
- * This is interpreted as the number of sub-edges into which
- * each edge of the icosahedron must be split. So the
- * number of faces of the sphere is simply:
- * 20 * detail^2. When detail==1, the sphere is just the
- * icosahedron */
- int m_detail;
-
- int getVertexCount();
- int getIndexCount();
- void buildBuffers();
-
- public:
- Sphere();
- ~Sphere() {}
-
- /** initializes the sphere with given level of detail. If the
- * sphere was already initialized, any pre-allocated buffers
- * are freed and then re-allocated.
- @param detail the wanted level of detail. See m_detail member */
- void setup( int detail );
-
- /** draws the sphere at specifiec position and with
- * specified radius */
- void draw( const Eigen::Vector3d ¢er, double radius );
+protected:
+ /** Pointer to the buffer storing the vertex array */
+ Eigen::Vector3f *m_vertexBuffer;
+ /** Pointer to the buffer storing the indices */
+ unsigned short *m_indexBuffer;
+ /** The number of vertices, i.e. the size of m_vertexBuffer */
+ int m_vertexCount;
+ /** The number of indices, i.e. the size of m_indexBuffer */
+ int m_indexCount;
+ /** The id of the OpenGL display list (used only if this option
+ * is turned on) */
+ GLuint m_displayList;
+
+ /** computes the index (position inside the index buffer)
+ * of a vertex given by its position (strip, column, row)
+ * inside a certain flat model of the sub-tesselated
+ * icosahedron */
+ inline unsigned short indexOfVertex(
+ int strip, int column, int row);
+ /** computes the coordinates
+ * of a vertex given by its position (strip, column, row)
+ * inside a certain flat model of the sub-tesselated
+ * icosahedron */
+ void computeVertex( int strip, int column, int row );
+ /** the detail-level of the sphere. Must be at least 1.
+ * This is interpreted as the number of sub-edges into which
+ * each edge of the icosahedron must be split. So the
+ * number of faces of the sphere is simply:
+ * 20 * detail^2. When detail==1, the sphere is just the
+ * icosahedron */
+ int m_detail;
+
+ void freeBuffers();
+ void initialize();
+ void do_draw() const;
+
+public:
+ Sphere();
+ ~Sphere();
+
+ /** initializes the sphere with given level of detail. If the
+ * sphere was already initialized, any pre-allocated buffers
+ * are freed and then re-allocated.
+ @param detail the wanted level of detail. See m_detail member */
+ void setup( int detail );
+
+ /** draws the sphere at specified position and with
+ * specified radius */
+ void draw( const Eigen::Vector3d ¢er, double radius ) const;
};
/**
*
* @author Benoit Jacob
*/
-class Cylinder : public VertexArray
+class Cylinder
{
- protected:
- /** the number of faces of the cylinder. This only
- * includes the lateral faces, as the base and top faces (the
- * two discs) are not rendered. */
- int m_faces;
-
- int getVertexCount();
- void buildBuffers();
-
- public:
- Cylinder();
- ~Cylinder() {}
- /** initializes the cylinder with given number of faces. If the
- * cylinder was already initialized, any pre-allocated buffers
- * are freed and then re-allocated */
- void setup( int faces );
- /**
- * draws the cylinder at specified position, with specified
- * radius. the order and shift arguments allow to render
- * multiple cylinders at once. If you only want to render one
- * cylinder, leave order and shift at their default values.
- @param end1 the position of the first end of the cylinder.
- that is, the center of the first disc-shaped face.
- @param end2 the position of the second end of the cylinder.
- that is, the center of the second disc-shaped face.
- @param radius the radius of the cylinder
- @param order to render only one cylinder, leave this set to
- the default value, which is 1. If order>1, then order
- parallel cylinders are drawn around the axis
- (end1 - end2).
- @param order this is only meaningful of order>1, otherwise
- just let this set to the default value. When order>1,
- this is interpreted as the displacement of the axis
- of the drawn cylinders from the axis (end1 - end2).
- */
- void draw( const Eigen::Vector3d &end1, const Eigen::Vector3d &end2,
- double radius, int order = 1, double shift = 0.0 );
+protected:
+ /** Pointer to the buffer storing the vertex array */
+ Eigen::Vector3f *m_vertexBuffer;
+ /** Pointer to the buffer storing the normal array */
+ Eigen::Vector3f *m_normalBuffer;
+ /** The number of vertices, i.e. the size of m_vertexBuffer
+ * or equivalently m_normalBuffer */
+ int m_vertexCount;
+ /** The id of the OpenGL display list (used only if this option
+ * is turned on) */
+ GLuint m_displayList;
+ /** Equals true if the vertex array has been correctly initialized */
+ bool m_isValid;
+
+ /** the number of faces of the cylinder. This only
+ * includes the lateral faces, as the base and top faces (the
+ * two discs) are not rendered. */
+ int m_faces;
+
+ void initialize();
+ void freeBuffers();
+ void do_draw() const;
+
+public:
+ Cylinder();
+ ~Cylinder();
+ /** initializes the cylinder with given number of faces. If the
+ * cylinder was already initialized, any pre-allocated buffers
+ * are freed and then re-allocated */
+ void setup( int faces );
+ /**
+ * draws the cylinder at specified position, with specified
+ * radius. the order and shift arguments allow to render
+ * multiple cylinders at once. If you only want to render one
+ * cylinder, leave order and shift at their default values.
+ @param end1 the position of the first end of the cylinder.
+ that is, the center of the first disc-shaped face.
+ @param end2 the position of the second end of the cylinder.
+ that is, the center of the second disc-shaped face.
+ @param radius the radius of the cylinder
+ @param order to render only one cylinder, leave this set to
+ the default value, which is 1. If order>1, then order
+ parallel cylinders are drawn around the axis
+ (end1 - end2).
+ @param order this is only meaningful of order>1, otherwise
+ just let this set to the default value. When order>1,
+ this is interpreted as the displacement of the axis
+ of the drawn cylinders from the axis (end1 - end2).
+ */
+ void draw( const Eigen::Vector3d &end1, const Eigen::Vector3d &end2,
+ double radius, int order = 1, double shift = 0.0 ) const;
};
/** BEEP BEEP BEEP this will likely be removed as Qt 4.2 has something better
void KalziumGLWidget::drawBond( OBBond *bond )
{
- OBAtom *atom1 = static_cast<OBAtom *>( bond->GetBgn() );
- OBAtom *atom2 = static_cast<OBAtom *>( bond->GetEnd() );
+ OBAtom *atom1 = static_cast<OBAtom *>( bond->GetBeginAtom() );
+ OBAtom *atom2 = static_cast<OBAtom *>( bond->GetEndAtom() );
Vector3d v1 ( atom1->GetVector().AsArray() );
Vector3d v2 ( atom2->GetVector().AsArray() );
// compute rotation matrix to orient the molecule in the (x,y)-plane
Vector3d planeNormalVector( & planeCoeffs(0) ), v, w;
planeNormalVector.normalize();
- createOrthoBasisGivenFirstVector( planeNormalVector, &v, &w );
+ planeNormalVector.makeOrthoVector( &v );
+ w = cross( planeNormalVector, v );
Matrix3d rotation;
rotation.setRow( 0, v );
rotation.setRow( 1, w );