some fixes to the cmake files. It still is not working
[kdeedu-porting.git] / kalzium / libavogadro-kalzium / src / sphere.cpp
blobff16f08e45b85d878dca8e463e56117304747561
1 /**********************************************************************
2 Sphere - Class for drawing spheres in OpenGL
4 Copyright (C) 2006,2007 Benoit Jacob
6 This file is part of the Avogadro molecular editor project.
7 For more information, see <http://avogadro.sourceforge.net/>
9 Avogadro is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 Avogadro is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 02110-1301, USA.
23 **********************************************************************/
25 #include "sphere.h"
27 using namespace Eigen;
29 namespace Avogadro {
31 class SpherePrivate
33 public:
34 SpherePrivate() : vertexBuffer(0), indexBuffer(0), displayList(0), isValid(false) {}
36 /** Pointer to the buffer storing the vertex array */
37 Eigen::Vector3f *vertexBuffer;
38 /** Pointer to the buffer storing the indices */
39 unsigned short *indexBuffer;
40 /** The id of the OpenGL display list */
41 GLuint displayList;
42 /** the detail-level of the sphere. Must be at least 0.
43 * If 0, the sphere is an octahedron. If >=1, this number is
44 * interpreted as the number of sub-edges into which
45 * each edge of the icosahedron must be split. So the
46 * number of faces of the sphere is simply:
47 * 20 * detail^2. When detail==1, the sphere is just the
48 * icosahedron */
49 int detail;
51 bool isValid;
54 Sphere::Sphere(int detail) : d(new SpherePrivate)
56 setup(detail);
59 Sphere::~Sphere()
61 freeBuffers();
62 if( d->displayList )
63 glDeleteLists( d->displayList, 1 );
64 delete d;
67 void Sphere::freeBuffers()
69 if( d->indexBuffer )
71 delete [] d->indexBuffer;
72 d->indexBuffer = 0;
74 if( d->vertexBuffer )
76 delete [] d->vertexBuffer;
77 d->vertexBuffer = 0;
81 void Sphere::draw(const Eigen::Vector3d &center, double radius) const
83 glPushMatrix();
84 glTranslated( center.x(), center.y(), center.z() );
85 glScaled( radius, radius, radius );
86 glCallList( d->displayList );
87 glPopMatrix();
90 void Sphere::initialize()
92 if( d->detail < 0 ) return;
94 // deallocate any previously allocated buffer
95 freeBuffers();
96 d->isValid = false;
97 int vertexCount = 0, indexCount = 0;
99 if( d->detail == 0 )
101 if( ! d->displayList ) { d->displayList = glGenLists( 1 ); }
102 if( ! d->displayList ) { return; }
103 float octahedronVertices[6][3] = { { 1, 0, 0 } ,
104 { 0, 1, 0 } ,
105 { 0, 0, 1 } ,
106 { 0, -1, 0 } ,
107 { 0, 0, -1 } ,
108 { -1, 0, 0 } };
109 #define USE_OCTAHEDRON_VERTEX(i) glNormal3fv(octahedronVertices[i]); \
110 glVertex3fv(octahedronVertices[i]);
111 glNewList( d->displayList, GL_COMPILE );
112 glBegin(GL_TRIANGLE_FAN);
113 USE_OCTAHEDRON_VERTEX(0);
114 USE_OCTAHEDRON_VERTEX(1);
115 USE_OCTAHEDRON_VERTEX(2);
116 USE_OCTAHEDRON_VERTEX(3);
117 USE_OCTAHEDRON_VERTEX(4);
118 USE_OCTAHEDRON_VERTEX(1);
119 glEnd();
120 glBegin(GL_TRIANGLE_FAN);
121 USE_OCTAHEDRON_VERTEX(5);
122 USE_OCTAHEDRON_VERTEX(1);
123 USE_OCTAHEDRON_VERTEX(4);
124 USE_OCTAHEDRON_VERTEX(3);
125 USE_OCTAHEDRON_VERTEX(2);
126 USE_OCTAHEDRON_VERTEX(1);
127 glEnd();
128 glEndList();
129 d->isValid = true;
130 return;
133 // compute number of vertices and indices
134 vertexCount = ( 3 * d->detail + 1 ) * ( 5 * d->detail + 1 );
135 indexCount = (2 * ( 2 * d->detail + 1 ) + 2 ) * 5 * d->detail;
137 // allocate memory for buffers
138 d->vertexBuffer = new Vector3f[vertexCount];
139 if( ! d->vertexBuffer ) return;
140 d->indexBuffer = new unsigned short[indexCount];
141 if( ! d->indexBuffer )
143 delete [] d->vertexBuffer;
144 d->vertexBuffer = 0;
145 return;
148 // build vertex buffer
149 for( int strip = 0; strip < 5; strip++ ) {
150 for( int column = 1; column < d->detail; column++ ) {
151 for( int row = column; row <= 2 * d->detail + column; row++ ) {
152 computeVertex( strip, column, row );
157 for( int strip = 1; strip < 5; strip++ ) {
158 for( int row = 0; row <= 3 * d->detail; row++ ) {
159 computeVertex( strip, 0, row );
163 for( int row = 0; row <= 2 * d->detail; row++ )
164 computeVertex( 0, 0, row );
166 for( int row = d->detail; row <= 3 * d->detail; row++ )
167 computeVertex( 4, d->detail, row );
169 // build index buffer
170 unsigned int i = 0;
171 for( int strip = 0; strip < 5; strip++ )
172 for( int column = 0; column < d->detail; column++ )
174 int row = column;
175 d->indexBuffer[i++] = indexOfVertex( strip, column, row );
176 for( ; row <= 2 * d->detail + column; row++ )
178 d->indexBuffer[i++] =
179 indexOfVertex( strip, column, row );
180 d->indexBuffer[i++] =
181 indexOfVertex( strip, column + 1, row + 1 );
183 d->indexBuffer[i++] = indexOfVertex( strip, column + 1,
184 2 * d->detail + column + 1);
187 // compile display list and free buffers
188 if( ! d->displayList ) { d->displayList = glGenLists( 1 ); }
189 if( ! d->displayList ) { return; }
190 glEnableClientState( GL_VERTEX_ARRAY );
191 glEnableClientState( GL_NORMAL_ARRAY );
192 glNewList( d->displayList, GL_COMPILE );
193 glVertexPointer( 3, GL_FLOAT, 0, d->vertexBuffer );
194 glNormalPointer( GL_FLOAT, 0, d->vertexBuffer );
195 glDrawElements( GL_TRIANGLE_STRIP, indexCount,
196 GL_UNSIGNED_SHORT, d->indexBuffer );
197 glEndList();
198 glDisableClientState( GL_VERTEX_ARRAY );
199 glDisableClientState( GL_NORMAL_ARRAY );
200 freeBuffers();
201 d->isValid = true;
204 unsigned short Sphere::indexOfVertex( int strip, int column, int row)
206 return ( row + ( 3 * d->detail + 1 ) * ( column + d->detail * strip ) );
209 void Sphere::computeVertex( int strip, int column, int row)
211 strip %= 5;
212 int next_strip = (strip + 1) % 5;
214 // the index of the vertex we want to store the result in
215 unsigned short index = indexOfVertex( strip, column, row );
217 // reference to the vertex we want to store the result in
218 Vector3f & vertex = d->vertexBuffer[ index ];
220 // the "golden ratio", useful to construct an icosahedron
221 const float phi = ( 1 + sqrtf(5.0f) ) / 2;
223 // the 12 vertices of the icosahedron
224 const Vector3f northPole( 0, 1, phi );
225 const Vector3f northVertices[5] = {
226 Vector3f( 0, -1, phi ),
227 Vector3f( phi, 0, 1 ),
228 Vector3f( 1, phi, 0 ),
229 Vector3f( -1, phi, 0 ),
230 Vector3f( -phi, 0, 1 ) };
231 const Vector3f southVertices[5] = {
232 Vector3f( -1, -phi, 0 ),
233 Vector3f( 1, -phi, 0 ),
234 Vector3f( phi, 0, -1 ),
235 Vector3f( 0, 1, -phi ),
236 Vector3f( -phi, 0, -1 )
238 const Vector3f southPole( 0, -1, -phi );
240 // pointers to the 3 vertices of the face of the icosahedron
241 // in which we are
242 const Vector3f *v0, *v1, *v2;
244 // coordinates of our position inside this face.
245 // range from 0 to d->detail.
246 int c1, c2;
248 // first, normalize the global coords row, column
249 if( row >= 2 * d->detail && column == 0 )
251 strip--;
252 if( strip < 0 ) strip += 5;
253 next_strip--;
254 if( next_strip < 0 ) next_strip += 5;
255 column = d->detail;
258 // next, determine in which face we are, and determine the coords
259 // of our position inside this face
260 if( row <= d->detail )
262 v0 = &northVertices[strip];
263 v1 = &northPole;
264 v2 = &northVertices[next_strip];
265 c1 = d->detail - row;
266 c2 = column;
268 else if( row >= 2 * d->detail )
270 v0 = &southVertices[next_strip];
271 v1 = &southPole;
272 v2 = &southVertices[strip];
273 c1 = row - 2 * d->detail;
274 c2 = d->detail - column;
276 else if( row <= d->detail + column )
278 v0 = &northVertices[next_strip];
279 v1 = &southVertices[next_strip];
280 v2 = &northVertices[strip];
281 c1 = row - d->detail;
282 c2 = d->detail - column;
284 else
286 v0 = &southVertices[strip];
287 v1 = &southVertices[next_strip];
288 v2 = &northVertices[strip];
289 c1 = column;
290 c2 = 2 * d->detail - row;
293 // now, compute the actual coords of the vertex
294 float u1 = static_cast<float>(c1) / d->detail;
295 float u2 = static_cast<float>(c2) / d->detail;
296 vertex = *v0 + u1 * ( *v1 - *v0 ) + u2 * ( *v2 - *v0 );
298 // project the vertex onto the sphere
299 vertex.normalize();
302 void Sphere::setup( int detail )
304 if( d->isValid && detail == d->detail ) return;
305 d->detail = detail;
306 initialize();