some fixes to the cmake files. It still is not working
[kdeedu-porting.git] / kalzium / libavogadro-kalzium / src / painterengine.cpp
blob6ca85b0493c9a7ee27f2594df134800d0f1deb8b
1 /**********************************************************************
2 painterengine - Class Description
4 Copyright (C) 2007 <>
6 This file is part of the Software Architecture Description Language
7 (SADL) project. For more information, see <http://milkbox.net/sadl/>
9 SADL is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2 of the License, or (at your
12 option) any later version.
14 SADL is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 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 "painterengine.h"
26 #include <avogadro/sphere.h>
27 #include <avogadro/cylinder.h>
28 #include <avogadro/textrenderer.h>
29 #include <avogadro/glwidget.h>
31 #include <QDebug>
33 namespace Avogadro
36 const int PAINTER_GLOBAL_QUALITY_SETTINGS = 5;
37 const int DEFAULT_GLOBAL_QUALITY_SETTING = PAINTER_GLOBAL_QUALITY_SETTINGS - 3;
38 const int PAINTER_DETAIL_LEVELS = 10;
39 // Sphere detail level array. Each row is a detail level.
40 // The first column is the sphere detail level at the furthest
41 // point and the last column is the detail level at the closest
42 // point.
43 const int PAINTER_SPHERES_LEVELS_ARRAY[5][10]
45 { {0, 0, 1, 1, 2, 2, 3, 3, 4, 4},
46 {0, 1, 2, 3, 4, 4, 5, 5, 6, 6},
47 {1, 2, 3, 4, 5, 6, 7, 8, 9, 9},
48 {1, 2, 3, 4, 6, 7, 8, 9, 11, 12},
49 {2, 3, 4, 5, 7, 9, 12, 15, 18, 22}
51 const double PAINTER_SPHERES_LIMIT_MIN_LEVEL = 0.005;
52 const double PAINTER_SPHERES_LIMIT_MAX_LEVEL = 0.15;
54 // Cylinder detail level array. Each row is a detail level.
55 // The first column is the cylinder detail level at the furthest
56 // point and the last column is the detail level at the closest
57 // point.
58 const int PAINTER_CYLINDERS_LEVELS_ARRAY[5][10]
60 { {0, 3, 5, 5, 8, 8, 12, 12, 16, 16},
61 {0, 4, 6, 9, 12, 12, 16, 16, 20, 20},
62 {0, 4, 6, 10, 14, 18, 22, 26, 32, 40},
63 {0, 4, 6, 12, 16, 20, 24, 28, 34, 42},
64 {0, 5, 10, 15, 20, 25, 30, 35, 40, 45}
66 const double PAINTER_CYLINDERS_LIMIT_MIN_LEVEL = 0.001;
67 const double PAINTER_CYLINDERS_LIMIT_MAX_LEVEL = 0.03;
68 const int PAINTER_MAX_DETAIL_LEVEL = PAINTER_DETAIL_LEVELS - 1;
69 const double PAINTER_SPHERES_SQRT_LIMIT_MIN_LEVEL
70 = sqrt ( PAINTER_SPHERES_LIMIT_MIN_LEVEL );
71 const double PAINTER_SPHERES_SQRT_LIMIT_MAX_LEVEL
72 = sqrt ( PAINTER_SPHERES_LIMIT_MAX_LEVEL );
73 const double PAINTER_SPHERES_DETAIL_COEFF
74 = static_cast<double> ( PAINTER_MAX_DETAIL_LEVEL - 1 )
75 / ( PAINTER_SPHERES_SQRT_LIMIT_MAX_LEVEL - PAINTER_SPHERES_SQRT_LIMIT_MIN_LEVEL );
76 const double PAINTER_CYLINDERS_SQRT_LIMIT_MIN_LEVEL
77 = sqrt ( PAINTER_CYLINDERS_LIMIT_MIN_LEVEL );
78 const double PAINTER_CYLINDERS_SQRT_LIMIT_MAX_LEVEL
79 = sqrt ( PAINTER_CYLINDERS_LIMIT_MAX_LEVEL );
80 const double PAINTER_CYLINDERS_DETAIL_COEFF
81 = static_cast<double> ( PAINTER_MAX_DETAIL_LEVEL - 1 )
82 / ( PAINTER_CYLINDERS_SQRT_LIMIT_MAX_LEVEL - PAINTER_CYLINDERS_SQRT_LIMIT_MIN_LEVEL );
83 const double PAINTER_FRUSTUM_CULL_TRESHOLD = -0.8;
85 class PainterEnginePrivate
87 public:
88 PainterEnginePrivate() : widget ( 0 ), quality ( 0 ), spheres ( 0 ), cylinders ( 0 ),
89 textRenderer ( new TextRenderer ), initialized ( false ), qualityChanged ( false ), sharing ( 0 ) {};
90 ~PainterEnginePrivate()
92 deleteObjects();
93 delete textRenderer;
96 GLWidget *widget;
98 int newQuality;
99 int quality;
101 /** array of pointers to Spheres. You might ask, why not have
102 * a plain array of Spheres. The idea is that more than one global detail level
103 * may use a given sphere detail level. It is therefore interesting to be able
104 * to share that sphere, instead of having redundant spheres in memory.
106 Sphere **spheres;
107 /** array of pointers to Cylinders. You might ask, why not have
108 * a plain array of Cylinders. The idea is that more than one global detail level
109 * may use a given cylinder detail level. It is therefore interesting to be able
110 * to share that cylinder, instead of having redundant cylinder in memory.
112 Cylinder **cylinders;
114 TextRenderer *textRenderer;
116 bool initialized;
117 bool qualityChanged;
119 void updateObjects();
120 void deleteObjects();
121 void createObjects();
124 * PainterEngines can be shared, we must keep track of this.
126 int sharing;
130 void PainterEnginePrivate::deleteObjects()
132 int level, lastLevel, n;
133 // delete the spheres. One has to be wary that more than one sphere
134 // pointer may have the same value. One wants to avoid deleting twice the same sphere.
135 if ( spheres )
137 lastLevel = -1;
138 for ( n = 0; n < PAINTER_DETAIL_LEVELS; n++ )
140 level = PAINTER_SPHERES_LEVELS_ARRAY[quality][n];
141 if ( level != lastLevel )
143 lastLevel = level;
144 if ( spheres[n] )
146 delete spheres[n];
147 spheres[n] = 0;
151 delete[] spheres;
152 spheres = 0;
155 // delete the cylinders. One has to be wary that more than one cylinder
156 // pointer may have the same value. One wants to avoid deleting twice the same cylinder.
157 if ( cylinders )
159 lastLevel = -1;
160 for ( n = 0; n < PAINTER_DETAIL_LEVELS; n++ )
162 level = PAINTER_CYLINDERS_LEVELS_ARRAY[quality][n];
163 if ( level != lastLevel )
165 lastLevel = level;
166 if ( cylinders[n] )
168 delete cylinders[n];
169 cylinders[n] = 0;
173 delete[] cylinders;
174 cylinders = 0;
178 void PainterEnginePrivate::createObjects()
180 // create the spheres. More than one sphere detail level may have the same value.
181 // in that case we want to reuse the corresponding sphere by just copying the pointer,
182 // instead of creating redundant spheres.
183 if ( spheres == 0 )
185 spheres = new Sphere*[PAINTER_DETAIL_LEVELS];
186 int level, lastLevel;
187 lastLevel = PAINTER_SPHERES_LEVELS_ARRAY[quality][0];
188 spheres[0] = new Sphere ( lastLevel );
189 for ( int n = 1; n < PAINTER_DETAIL_LEVELS; n++ )
191 level = PAINTER_SPHERES_LEVELS_ARRAY[quality][n];
192 if ( level == lastLevel )
194 spheres[n] = spheres[n-1];
196 else
198 lastLevel = level;
199 spheres[n] = new Sphere ( level );
204 // create the cylinders. More than one cylinder detail level may have the same value.
205 // in that case we want to reuse the corresponding cylinder by just copying the pointer,
206 // instead of creating redundant cylinders.
207 if ( cylinders == 0 )
209 cylinders = new Cylinder*[PAINTER_DETAIL_LEVELS];
210 int level, lastLevel;
211 lastLevel = PAINTER_SPHERES_LEVELS_ARRAY[quality][0];
212 cylinders[0] = new Cylinder ( lastLevel );
213 for ( int n = 1; n < PAINTER_DETAIL_LEVELS; n++ )
215 level = PAINTER_CYLINDERS_LEVELS_ARRAY[quality][n];
216 if ( level == lastLevel )
218 cylinders[n] = cylinders[n-1];
220 else
222 lastLevel = level;
223 cylinders[n] = new Cylinder ( level );
229 void PainterEnginePrivate::updateObjects()
231 if(newQuality != quality)
233 deleteObjects();
234 quality = newQuality;
235 createObjects();
239 PainterEngine::PainterEngine( int quality ) : d ( new PainterEnginePrivate )
241 if ( quality < 0 || quality >= PAINTER_MAX_DETAIL_LEVEL )
243 quality = DEFAULT_GLOBAL_QUALITY_SETTING;
245 d->quality = quality;
248 PainterEngine::~PainterEngine()
250 delete d;
253 // void PainterEngine::setGLWidget( GLWidget * widget )
254 // {
255 // d->widget = widget;
256 // d->textRenderer->setGLWidget(d->widget);
257 // }
259 void PainterEngine::setQuality ( int quality )
261 assert ( quality >= 0 && quality < PAINTER_GLOBAL_QUALITY_SETTINGS );
262 d->deleteObjects();
263 d->quality = quality;
264 d->qualityChanged = true;
267 int PainterEngine::quality() const
269 return d->quality;
272 // void PainterEngine::initialize( GLWidget * widget, int quality )
273 // {
274 // if(quality == -1) {
275 // quality = DEFAULT_GLOBAL_QUALITY_SETTING;
276 // }
277 // else {
278 // assert( quality >= 0 && quality < PAINTER_GLOBAL_QUALITY_SETTINGS );
279 // }
280 // d->initialized = true;
281 // setGLWidget(widget);
282 // setQuality(quality);
283 // }
285 void PainterEngine::drawSphere ( const Eigen::Vector3d & center, double radius, int detailLevel ) const
287 if ( d->textRenderer->isActive() )
289 d->textRenderer->end();
291 assert ( d->widget );
292 assert ( detailLevel >= 0 && detailLevel <= PAINTER_MAX_DETAIL_LEVEL );
293 d->spheres[detailLevel]->draw ( center, radius );
296 void PainterEngine::drawSphere ( const Eigen::Vector3d & center, double radius ) const
298 if ( d->textRenderer->isActive() )
300 d->textRenderer->end();
302 assert ( d->widget );
303 Eigen::Vector3d transformedCenter = d->widget->camera()->modelview() * center;
304 double distance = transformedCenter.norm();
306 // perform a rough form of frustum culling
307 double dot = transformedCenter.z() / distance;
308 if ( dot > PAINTER_FRUSTUM_CULL_TRESHOLD ) return;
310 double apparentRadius = radius / distance;
312 int detailLevel = 1 + static_cast<int> ( floor (
313 PAINTER_SPHERES_DETAIL_COEFF * ( sqrt ( apparentRadius ) - PAINTER_SPHERES_SQRT_LIMIT_MIN_LEVEL )
314 ) );
315 if ( detailLevel < 0 )
317 detailLevel = 0;
319 if ( detailLevel > PAINTER_MAX_DETAIL_LEVEL )
321 detailLevel = PAINTER_MAX_DETAIL_LEVEL;
323 d->spheres[detailLevel]->draw ( center, radius );
326 void PainterEngine::drawCylinder ( const Eigen::Vector3d &end1, const Eigen::Vector3d &end2,
327 double radius, int detailLevel ) const
329 if ( d->textRenderer->isActive() )
331 d->textRenderer->end();
333 assert ( d->widget );
334 assert ( detailLevel >= 0 && detailLevel <= PAINTER_MAX_DETAIL_LEVEL );
335 d->cylinders[detailLevel]->draw ( end1, end2, radius );
338 void PainterEngine::drawCylinder ( const Eigen::Vector3d &end1, const Eigen::Vector3d &end2,
339 double radius ) const
341 if ( d->textRenderer->isActive() )
343 d->textRenderer->end();
345 assert ( d->widget );
346 Eigen::Vector3d transformedEnd1 = d->widget->camera()->modelview() * end1;
347 double distance = transformedEnd1.norm();
349 // perform a rough form of frustum culling
350 double dot = transformedEnd1.z() / distance;
351 if ( dot > PAINTER_FRUSTUM_CULL_TRESHOLD ) return;
353 double apparentRadius = radius / distance;
354 int detailLevel = 1 + static_cast<int> ( floor (
355 PAINTER_CYLINDERS_DETAIL_COEFF
356 * ( sqrt ( apparentRadius ) - PAINTER_CYLINDERS_SQRT_LIMIT_MIN_LEVEL )
357 ) );
358 if ( detailLevel < 0 )
360 detailLevel = 0;
362 if ( detailLevel > PAINTER_MAX_DETAIL_LEVEL )
364 detailLevel = PAINTER_MAX_DETAIL_LEVEL;
366 d->cylinders[detailLevel]->draw ( end1, end2, radius );
369 void PainterEngine::drawMultiCylinder ( const Eigen::Vector3d &end1, const Eigen::Vector3d &end2,
370 double radius, int order, double shift, int detailLevel ) const
372 if ( d->textRenderer->isActive() )
374 d->textRenderer->end();
376 assert ( d->widget );
377 assert ( detailLevel >= 0 && detailLevel <= PAINTER_MAX_DETAIL_LEVEL );
378 d->cylinders[detailLevel]->drawMulti ( end1, end2, radius, order,
379 shift, d->widget->normalVector() );
382 void PainterEngine::drawMultiCylinder ( const Eigen::Vector3d &end1, const Eigen::Vector3d &end2,
383 double radius, int order, double shift ) const
385 if ( d->textRenderer->isActive() )
387 d->textRenderer->end();
389 assert ( d->widget );
390 Eigen::Vector3d transformedEnd1 = d->widget->camera()->modelview() * end1;
391 double distance = transformedEnd1.norm();
393 // perform a rough form of frustum culling
394 double dot = transformedEnd1.z() / distance;
395 if ( dot > PAINTER_FRUSTUM_CULL_TRESHOLD ) return;
397 double apparentRadius = radius / distance;
398 int detailLevel = 1 + static_cast<int> ( floor (
399 PAINTER_CYLINDERS_DETAIL_COEFF
400 * ( sqrt ( apparentRadius ) - PAINTER_CYLINDERS_SQRT_LIMIT_MIN_LEVEL )
401 ) );
402 if ( detailLevel < 0 )
404 detailLevel = 0;
406 if ( detailLevel > PAINTER_MAX_DETAIL_LEVEL )
408 detailLevel = PAINTER_MAX_DETAIL_LEVEL;
410 d->cylinders[detailLevel]->drawMulti ( end1, end2, radius, order,
411 shift, d->widget->normalVector() );
414 int PainterEngine::drawText ( int x, int y, const QString &string ) const
416 if ( !d->textRenderer->isActive() )
418 d->textRenderer->begin ( d->widget );
420 return d->textRenderer->draw ( x, y, string );
423 int PainterEngine::drawText ( const QPoint& pos, const QString &string ) const
425 if ( !d->textRenderer->isActive() )
427 d->textRenderer->begin( d->widget );
429 return d->textRenderer->draw ( pos.x(), pos.y(), string );
432 int PainterEngine::drawText ( const Eigen::Vector3d &pos, const QString &string ) const
434 if ( !d->textRenderer->isActive() )
436 d->textRenderer->begin ( d->widget );
438 Eigen::Vector3d transformedPos = d->widget->camera()->modelview() * pos;
440 // perform a rough form of frustum culling
441 double dot = transformedPos.z() / transformedPos.norm();
442 if ( dot > PAINTER_FRUSTUM_CULL_TRESHOLD ) return 0;
444 return d->textRenderer->draw ( pos, string );
447 void PainterEngine::begin ( GLWidget *widget )
449 if(!d->initialized)
451 qDebug() << "createObjects()";
452 d->createObjects();
453 d->initialized = true;
455 else if (d->qualityChanged)
457 qDebug() << "updateObjects()";
458 d->updateObjects();
459 d->qualityChanged = false;
462 d->widget = widget;
465 void PainterEngine::end()
467 if ( d->textRenderer->isActive() )
469 d->textRenderer->end();
471 d->widget = 0;
474 int PainterEngine::defaultQuality()
476 return DEFAULT_GLOBAL_QUALITY_SETTING;
479 int PainterEngine::maxQuality()
481 return PAINTER_GLOBAL_QUALITY_SETTINGS-1;
484 bool PainterEngine::isShared()
486 return d->sharing-1;
489 void PainterEngine::incrementShare()
491 d->sharing++;
494 void PainterEngine::decrementShare()
496 d->sharing--;
498 } // end namespace Avogadro