COPASI API  4.16.103
CQGLLayoutPainter.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010 - 2015 by Pedro Mendes, Virginia Tech Intellectual
2 // Properties, Inc., University of Heidelberg, and The University
3 // of Manchester.
4 // All rights reserved.
5 
6 #ifdef __APPLE__
7 // this should make sure g++ on apple does not load
8 // the glext from the 10.4 sdk so that we can load the one provided with COPASI
9 #define GL_GLEXT_LEGACY
10 #endif
11 
12 // SBML includes
13 #include "copasi/model/CModel.h"
15 
16 #include "CQFontRenderer.h"
25 
26 #define GL_GLEXT_PROTOTYPES
27 #include "CQGLLayoutPainter.h"
28 
29 // Qt includes
30 #include <QtGui/QMouseEvent>
31 #include <QtCore/QTimer>
32 #include <QtGui/QCursor>
33 #include <QtGui/QApplication>
34 #include <QtCore/Qt>
35 
36 // global includes
37 #include <limits>
38 #include <functional>
39 #include <algorithm>
40 #ifdef __APPLE__
41 #include <string>
42 #include <stdlib.h>
43 #include <mach-o/dyld.h>
44 #endif // __APPLE__
45 
46 // opengl includes
47 #ifdef _WIN32
48 # define WIN32_LEAN_AND_MEAN 1
49 # include <windows.h>
50 #endif // WIN32
51 
52 #ifdef __APPLE__
53 #include <OpenGL/gl.h>
54 #include <OpenGL/glu.h>
55 #undef GL_GLEXT_LEGACY
56 # include <GL/glext.h>
57 #else
58 #define GLX_GLXEXT_LEGACY
59 #include <GL/gl.h>
60 #include <GL/glu.h>
61 // I am including a new glext with the source code
62 # include <GL/glext.h>
63 #ifndef _WIN32
64 #include <GL/glx.h>
65 #endif // _WIN32
66 // somehow glx defines a macro called CursorShape which clashes with the Qt enum of the same name
67 #undef CursorShape
68 #endif // __APPLE__
69 
70 #include "UI/CQMessageBox.h"
71 
72 // check that the OpenGL extensions we plan to use are at least defined so that we have the necessary enumerations
73 #if !defined(GL_EXT_framebuffer_object) || !defined(GL_EXT_framebuffer_multisample)
74 #error "Error. Your header files do not define the OpenGL macros necessary to compile this program. For further information please see http://www.gamedev.net/community/forums/showfaq.asp?forum_id=25#q5."
75 #endif // GL_EXT_framebuffer_object
76 
77 const int CQGLLayoutPainter::MARGIN = 10;
78 
79 #ifdef _WIN32
80 // windows seems to declare a macro called max which clashes with the STL
81 // function
82 #undef max
83 #endif // _WIN32
84 CQGLLayoutPainter::CQGLLayoutPainter(const QGLFormat& format, QWidget *parent)
85  : QGLWidget(format, parent),
86  mInitialized(false),
87  mMinX(std::numeric_limits<double>::max()),
88  mMinY(std::numeric_limits<double>::max()),
89  mMaxX(-std::numeric_limits<double>::max()),
90  mMaxY(-std::numeric_limits<double>::max()),
91  mCurrentZoom(1.0),
92  mCurrentPositionX(mMinX),
93  mCurrentPositionY(mMinY),
94  mViewportWidth(0),
95  mViewportHeight(0),
96  mpRenderer(NULL),
97  mMousePressPosition(),
98  mMouseCurrentPosition(),
99  mMouseLastPosition(),
100  mMouseButton(Qt::NoButton),
101  mDragTimeout(false),
102  mState(CQGLLayoutPainter::STATE_NORMAL),
103  mpDragPoint(NULL),
104  glCheckFramebufferStatusEXTPtr(NULL),
105  glGenFramebuffersEXTPtr(NULL),
106  glGenRenderbuffersEXTPtr(NULL),
107  glDeleteFramebuffersEXTPtr(NULL),
108  glDeleteRenderbuffersEXTPtr(NULL),
109  glBindFramebufferEXTPtr(NULL),
110  glBindRenderbufferEXTPtr(NULL),
111  glRenderbufferStorageEXTPtr(NULL),
112  glFramebufferRenderbufferEXTPtr(NULL),
113  glRenderbufferStorageMultisampleEXTPtr(NULL),
114  glBlitFramebufferEXTPtr(NULL)
115 
116 {
117  this->setMouseTracking(true);
118 }
119 
121 {
122  if (this->mpRenderer)
123  {
124  delete this->mpRenderer;
125  }
126 }
127 
129 {
130  glEnable(GL_BLEND);
131  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
132  // accoring to the OpenGL documentation the blend function below
133  // should be the one to be used on smoothed polygons, but when I try this,
134  // nothing is displayed at all in the software renderer
135  // Maybe the polygons have to be depth sorted first for this to work
136  //glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
137  glEnable(GL_POLYGON_SMOOTH);
138  //glEnable(GL_LINE_SMOOTH);
139  glShadeModel(GL_SMOOTH);
140  this->mInitialized = true;
141 }
142 
143 void CQGLLayoutPainter::resizeGL(int w, int h)
144 {
145  this->mViewportWidth = w;
146  this->mViewportHeight = h;
147 
148  if (this->mpRenderer && this->mInitialized)
149  {
150  this->mpRenderer->resize(w, h);
151  }
152  else
153  {
154  // setup viewport, projection etc.:
155  glViewport(0, 0, (GLint)w, (GLint)h);
156  glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
157  glLoadIdentity(); // Reset The Projection Matrix
158  gluOrtho2D((GLdouble)mCurrentPositionX,
159  (GLdouble)(mCurrentPositionX + w),
160  (GLdouble)(mCurrentPositionY + h),
161  (GLdouble)mCurrentPositionY); // y: 0.0 is bottom left instead of top left as in SBML
162  glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
163  }
164 }
165 
167 {
168  if (this->isVisible())
169  {
170  if (this->mpRenderer)
171  {
172  this->resizeGL(this->width(), this->height());
173  }
174 
175  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
176  draw();
177  }
178 }
179 
181 {
182  glLoadIdentity();
183 
184  if (mpRenderer)
185  {
188 
189  // display any error messages
190  if (CCopasiMessage::peekLastMessage().getNumber() != MCCopasiMessage + 1)
191  {
192  CQMessageBox::critical(NULL, "Render Error",
194  QMessageBox::Ok | QMessageBox::Default,
195  QMessageBox::NoButton);
197  }
198  }
199 }
200 
202 {
203  if (mpRenderer != NULL && zoom != mpRenderer->getZoomFactor())
204  {
205  this->mpRenderer->setZoomFactor(zoom);
206  this->mCurrentZoom = zoom;
207 
208  if (this->isVisible())
209  {
210  this->resizeGL(this->width(), this->height());
211  this->updateGL();
212  }
213  }
214 }
215 
217 {
218  double zoom = 1.0;
219 
220  if (this->mpRenderer)
221  {
222  zoom = this->mpRenderer->getZoomFactor();
223  }
224 
225  return zoom;
226 }
227 
229 {
230  if (this->mCurrentPositionX != x || this->mCurrentPositionY != y)
231  {
232  this->mCurrentPositionX = x;
233  this->mCurrentPositionY = y;
234 
235  if (this->mpRenderer)
236  {
237  this->mpRenderer->setX(x);
238  this->mpRenderer->setY(y);
239  }
240 
241  this->update();
242  }
243 }
244 
246 {
247  // only update if we have a renderer, otherwise we might call OpenGL
248  // functions before OpenGL has been initialized
249  if (this->mpRenderer && this->isVisible())
250  {
251  this->resizeGL(this->width(), this->height());
252  this->updateGL();
253  }
254 }
255 
257 {
258  if (this->mCurrentPositionX != x)
259  {
260  this->mCurrentPositionX = x;
261 
262  if (this->mpRenderer != NULL)
263  {
264  this->mpRenderer->setX(x);
265  }
266 
267  this->update();
268  }
269 }
270 
272 {
273  if (this->mCurrentPositionY != y)
274  {
275  this->mCurrentPositionY = y;
276 
277  if (this->mpRenderer != NULL)
278  {
279  this->mpRenderer->setY(y);
280  }
281 
282  this->update();
283  }
284 }
285 
287 {
288  return this->mCurrentPositionX;
289 }
290 
292 {
293  return this->mCurrentPositionY;
294 }
295 
297 {
298  this->setZoomFactor(1.0);
299  this->setCurrentPosition(this->minX(), this->minY());
300 }
301 
302 /**
303  * Calculates the ratio that is needed to fit the diagram on the current viewport
304  * and sets this as the zoom factor.
305  * The method returns the new zoom factor.
306  */
308 {
309  double zoom = 1.0;
310  double width = this->mMaxX - this->mMinX;
311  double height = this->mMaxY - this->mMinY;
312  double wRatio = this->mViewportWidth / width;
313  double hRatio = this->mViewportHeight / height;
314 
315  if (wRatio > hRatio)
316  {
317  zoom = hRatio;
318  }
319  else
320  {
321  zoom = wRatio;
322  }
323 
324  this->setZoomFactor(zoom);
325  this->setCurrentPosition(this->mMinX, this->mMinY);
326  return zoom;
327 }
328 
330 {
331  mMinX = x;
332 }
333 
335 {
336  mMinY = y;
337 }
339 {
340  mMaxX = x;
341 }
342 
344 {
345  mMaxY = y;
346 }
347 
348 void CQGLLayoutPainter::setBounds(const QRectF& rect)
349 {
350  setBounds(rect.left(), rect.top(), rect.right(), rect.bottom());
351 }
352 
353 void CQGLLayoutPainter::setBounds(double minX, double minY, double maxX, double maxY)
354 {
355  mMinX = minX;
356  mMinY = minY;
357  mMaxX = maxX;
358  mMaxY = maxY;
359 }
360 
362 {
363  return this->mMinX;
364 }
365 
367 {
368  return this->mMinY;
369 }
370 
372 {
373  return this->mMaxX;
374 }
375 
377 {
378  return this->mMaxY;
379 }
380 
382 {
383  if (pLayout == NULL) return;
384 
385  // update minX, minY, maxX and maxY
386  CLBoundingBox bb = pLayout->calculateBoundingBox();
387  this->mMinX = bb.getPosition().getX();
388  this->mMinY = bb.getPosition().getY();
389 
390  // move into the origin
391  CLPoint differenceToOrigin(
392  -mMinX,
393  -mMinY
394  , -bb.getPosition().getZ()
395  );
396  pLayout->moveBy(differenceToOrigin);
397 
398  if (mMinX > 0)
400 
401  if (mMinY > 0)
403 
404  mMinX = 0;
405  mMinY = 0;
406 
407  if (pLayout->getDimensions().getWidth() > bb.getDimensions().getWidth())
408  {
409  this->mMaxX = pLayout->getDimensions().getWidth() + this->mMinX;
410  }
411  else
412  {
413  this->mMaxX = bb.getDimensions().getWidth() + this->mMinX;
414  }
415 
416  if (pLayout->getDimensions().getHeight() > bb.getDimensions().getHeight())
417  {
418  this->mMaxY = pLayout->getDimensions().getHeight() + this->mMinY;
419  }
420  else
421  {
422  this->mMaxY = bb.getDimensions().getHeight() + this->mMinY;
423  }
424 
425  this->mMinX -= MARGIN;
426  this->mMinY -= MARGIN;
427  this->setCurrentPosition(this->mMinX, this->mMinY);
428 
429  // call resize to set the correct viewport
430  if (this->isVisible())
431  {
432  this->resizeGL(this->width(), this->height());
433  // draw the layout
434  this->updateGL();
435  }
436 }
437 
438 void CQGLLayoutPainter::update(const CCopasiDataModel* pDatamodel, CLayout* pLayout, const CLRenderInformationBase* pRenderInfo, const QString& baseDir)
439 {
440  // delete the current renderer if there is one
441  if (this->mpRenderer)
442  {
443  delete this->mpRenderer;
444  }
445 
446  // create a new renderer with the given options
447  if (dynamic_cast<const CLLocalRenderInformation*>(pRenderInfo))
448  {
449  this->mpRenderer = new CLLayoutRenderer(pLayout, static_cast<const CLLocalRenderInformation*>(pRenderInfo), &pDatamodel->getListOfLayouts()->getListOfGlobalRenderInformationObjects(), pDatamodel->getModel(), baseDir.toLatin1().data());
450  // set the text renderer
451  }
452  else
453  {
454  this->mpRenderer = new CLLayoutRenderer(pLayout, static_cast<const CLGlobalRenderInformation*>(pRenderInfo), &pDatamodel->getListOfLayouts()->getListOfGlobalRenderInformationObjects(), pDatamodel->getModel(), baseDir.toLatin1().data());
455  }
456 
457  if (this->mpRenderer)
458  {
461  }
462 
463  calculateAndAssignBounds(pLayout);
464 }
465 
466 void CQGLLayoutPainter::change_style(const CLRenderInformationBase* pRenderInfo, bool defaultStyle)
467 {
468  const CLLocalRenderInformation* pLRI = dynamic_cast<const CLLocalRenderInformation*>(pRenderInfo);
469 
470  if (pLRI != NULL)
471  {
472  this->mpRenderer->change_style(pLRI);
473  }
474  else
475  {
476  this->mpRenderer->change_style(dynamic_cast<const CLGlobalRenderInformation*>(pRenderInfo), defaultStyle);
477  }
478 
479  if (this->isVisible())
480  {
481  this->updateGL();
482  }
483 }
484 
485 void CQGLLayoutPainter::mousePressEvent(QMouseEvent* pMouseEvent)
486 {
487  if (this->mpRenderer != NULL)
488  {
489  // actually we only store the position of the click here
490  // Selection occurs once the button is released
491  // because a click can also start a drag selection
492  // we need the position within the scene
493  this->mMouseButton = pMouseEvent->button();
494  this->mMousePressPosition = pMouseEvent->pos();
497  this->mDragTimeout = false;
498 
499  // check if the left mouse button has been pressed.
500  if (this->mMouseButton == Qt::LeftButton)
501  {
502 
503  if (this->mMouseButton == Qt::LeftButton)
504  {
505  if (QApplication::keyboardModifiers() != Qt::ShiftModifier &&
506  QApplication::keyboardModifiers() != Qt::ControlModifier)
507  this->mpRenderer->clearSelection();
508 
509  // most often if someone clicks the canvas they want to move something
510  // there is no reason to assume that they want to drag something else
511  // so we are going to first select whatever is under the mouse click
512  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize> hits = this->mpRenderer->getObjectsAtViewportPosition(this->mMouseCurrentPosition.x(), this->mMouseCurrentPosition.y());
513  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>::iterator it = hits.begin(), endit = hits.end();
514 
515  while (it != endit)
516  {
517  if (dynamic_cast<CLTextGlyph*>(*it) == NULL)
518  if (dynamic_cast<CLCompartmentGlyph*>(*it) == NULL)
519  this->mpRenderer->addToSelection(*it);
520 
521  ++it;
522  }
523  }
524 
525  // start a timer that fires after QApplication::startDragTime
526  // if the mouse button is still down when the event fires, we might start a drag operation
527  // depending on how far the mouse pointer has been moved
528  QTimer::singleShot(QApplication::startDragTime(), this, SLOT(timeout()));
529  }
530 
531  this->update_status_and_cursor();
532  }
533 }
534 
535 /**
536  * This slot is called if a timer runs down that is started on a left mouse press
537  */
539 {
540  // if the mouse button has been released already, we don't start a drag operation
541  if (this->mMouseButton != Qt::NoButton)
542  {
543  this->mDragTimeout = true;
544  }
545 }
546 
547 std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize> removeTextGlyphs(std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>& hits)
548 {
549  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize> result;
550  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>::iterator it = hits.begin();
551 
552  while (it != hits.end())
553  {
554  CLTextGlyph* glyph = dynamic_cast<CLTextGlyph*>((*it));
555  CLMetabReferenceGlyph* refGlyph = dynamic_cast<CLMetabReferenceGlyph*>((*it));
556 
557  if (glyph == NULL && refGlyph == NULL)
558  {
559  result.insert(*it);
560  }
561 
562  ++it;
563  }
564 
565  return result;
566 }
567 
568 /**
569  * Gets called when the mouse is released on the scene.
570  */
571 void CQGLLayoutPainter::mouseReleaseEvent(QMouseEvent* pMouseEvent)
572 {
573  this->mMouseCurrentPosition = pMouseEvent->pos();
574 
575  if (pMouseEvent->buttons() == Qt::NoButton)
576  {
577  switch (this->mState)
578  {
580 
581  // the user has been selecting something by a selection rectangle
582  // make the selection;
583  if (this->mpRenderer != NULL)
584  {
585  double minX = this->mMousePressPosition.x() < this->mMouseCurrentPosition.x() ? this->mMousePressPosition.x() : this->mMouseCurrentPosition.x();
586  double minY = this->mMousePressPosition.y() < this->mMouseCurrentPosition.y() ? this->mMousePressPosition.y() : this->mMouseCurrentPosition.y();
587  double maxX = this->mMousePressPosition.x() > this->mMouseCurrentPosition.x() ? this->mMousePressPosition.x() : this->mMouseCurrentPosition.x();
588  double maxY = this->mMousePressPosition.y() > this->mMouseCurrentPosition.y() ? this->mMousePressPosition.y() : this->mMouseCurrentPosition.y();
589  std::pair<double, double> coords1 = this->mpRenderer->convert_to_model_space(minX, minY);
590  std::pair<double, double> coords2 = this->mpRenderer->convert_to_model_space(maxX, maxY);
591  std::vector<CLGraphicalObject*> objects = this->mpRenderer->getObjectsInBoundingBox(coords1.first, coords1.second, coords2.first, coords2.second, false);
592  std::vector<CLGraphicalObject*>::iterator it = objects.begin(), endit = objects.end();
593  Qt::KeyboardModifiers modifiers = pMouseEvent->modifiers();
594 
595  if (modifiers == Qt::NoModifier)
596  {
597  this->mpRenderer->clearSelection();
598 
599  while (it != endit)
600  {
601  this->mpRenderer->addToSelection(*it);
602  ++it;
603  }
604  }
605  else if (modifiers == (Qt::ControlModifier | Qt::ShiftModifier))
606  {
607  // intersection
608  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
609 
610  while (it != endit)
611  {
612  if (selection.find(*it) == selection.end())
613  {
614  this->mpRenderer->removeFromSelection(*it);
615  }
616 
617  ++it;
618  }
619  }
620  else if (modifiers == Qt::ControlModifier)
621  {
622  // subtraction
623  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
624 
625  while (it != endit)
626  {
627  if (selection.find(*it) != selection.end())
628  {
629  this->mpRenderer->removeFromSelection(*it);
630  }
631 
632  ++it;
633  }
634  }
635  else if (modifiers == Qt::ShiftModifier)
636  {
637  // addition
638  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
639 
640  while (it != endit)
641  {
642  if (selection.find(*it) == selection.end())
643  {
644  this->mpRenderer->addToSelection(*it);
645  }
646 
647  ++it;
648  }
649  }
650 
651  this->mpRenderer->setSelectionBox(NULL);
652  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
653 
654  if (selection.size() == 1 &&
655  ((dynamic_cast<const CLMetabReferenceGlyph*>(*selection.begin()) && static_cast<const CLMetabReferenceGlyph*>(*selection.begin())->getCurve().getNumCurveSegments() != 0) ||
656  (dynamic_cast<const CLReactionGlyph*>(*selection.begin()) && static_cast<const CLReactionGlyph*>(*selection.begin())->getCurve().getNumCurveSegments())
657  )
658  )
659  {
660  emit singleCurveSelected(true);
661  }
662  else
663  {
664  emit singleCurveSelected(false);
665  }
666  }
667 
669 
670  if (this->isVisible())
671  {
672  this->updateGL();
673  }
674 
675  break;
676 
678 
679  // the user has been dragging the selected abstract_merge_items
680  // and now we have to see if we have to merge items
681  // move the selected objects
682  if (this->mpRenderer != NULL)
683  {
684  std::pair<double, double> coords1 = this->mpRenderer->convert_to_model_space(this->mMouseCurrentPosition.x(), this->mMouseCurrentPosition.y());
685  std::pair<double, double> coords2 = this->mpRenderer->convert_to_model_space(this->mMouseLastPosition.x(), this->mMouseLastPosition.y());
686  double dx = coords1.first - coords2.first;
687  double dy = coords1.second - coords2.second;
688 
689  // check if we are currently dragging a basepoint
690  if (mpDragPoint != NULL)
691  {
692  // set the dragpoint to NULL
693  this->mpDragPoint->setX(this->mpDragPoint->getX() + dx);
694  this->mpDragPoint->setY(this->mpDragPoint->getY() + dy);
695  this->mpDragPoint = NULL;
696  }
697  else
698  {
699  if (pMouseEvent->modifiers() & Qt::ControlModifier)
700  {
701  this->mpRenderer->move_selection(dx, dy, false);
702  }
703  else
704  {
705  this->mpRenderer->move_selection(dx, dy, true);
706  }
707  }
708 
709  emit documentChanged();
710 
711  if (this->isVisible())
712  {
713  this->updateGL();
714  }
715  }
716 
718  break;
719 
721 
722  // check if there is an item under the mouse
723  if (this->mpRenderer)
724  {
725  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize> hits = this->mpRenderer->getObjectsAtViewportPosition(this->mMouseCurrentPosition.x(), this->mMouseCurrentPosition.y());
726 
727  hits = removeTextGlyphs(hits);
728 
729  if (!hits.empty())
730  {
731  // if there is only one element in hits, we change the selection
732  // depending on the keyboard buttons that were pressed simultaneously
733  if ((pMouseEvent->modifiers() & Qt::ControlModifier) && !(pMouseEvent->modifiers() & Qt::ShiftModifier))
734  {
735  // subtraction mode
736  // TODO enable selection cycling
737  // for now find the first hit object that is not already selected
738  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>::iterator it = hits.begin(), endit = hits.end();
739 
740  while (it != endit)
741  {
742  if (this->mpRenderer->isSelected(*it))
743  {
744  this->mpRenderer->removeFromSelection(*it);
745 
746  if (this->isVisible())
747  {
748  this->updateGL();
749  }
750 
751  break;
752  }
753 
754  ++it;
755  }
756  }
757  else if ((pMouseEvent->modifiers() & Qt::ShiftModifier) && !(pMouseEvent->modifiers() & Qt::ControlModifier))
758  {
759  // addition mode
760  // TODO enable selection cycling
761  //
762  // for now find the first hit object that is not already selected
763  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>::iterator it = hits.begin(), endit = hits.end();
764 
765  while (it != endit)
766  {
767  if (!this->mpRenderer->isSelected(*it))
768  {
769  this->mpRenderer->addToSelection(*it);
770 
771  if (this->isVisible())
772  {
773  this->updateGL();
774  }
775 
776  break;
777  }
778 
779  ++it;
780  }
781  }
782  else
783  {
784  // intersection mode (Ctrl + Shift) is handled the same as if no modifer is pressed.
785  //
786  // treat all others as if no modifier has been pressed
787  // if there are more elements in hits, we see if there is one selected and
788  // if there is, we deselect it and select the one that comes after it.
789  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>::iterator pos;
790  CLGraphicalObject* pObject = NULL;
791 
792  if ((hits.size() > 1) && (this->mpRenderer->getSelection().size() == 1) &&
793  (pos = std::find(hits.begin(), hits.end(), *(this->mpRenderer->getSelection().begin()))) != hits.end())
794  {
795  ++pos;
796 
797  if (pos == hits.end())
798  {
799  pos = hits.begin();
800  }
801 
802  pObject = *pos;
803  }
804  else
805  {
806  pObject = *(hits.begin());
807  }
808 
809  this->mpRenderer->clearSelection();
810  this->mpRenderer->addToSelection(pObject);
811 
812  if (this->isVisible())
813  {
814  this->updateGL();
815  }
816  }
817  }
818  else
819  {
820  if (!this->mpRenderer->getSelection().empty())
821  {
822  this->mpRenderer->clearSelection();
823 
824  if (this->isVisible())
825  {
826  this->updateGL();
827  }
828  }
829  }
830 
831  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
832 
833  if (selection.size() == 1 &&
834  ((dynamic_cast<const CLMetabReferenceGlyph*>(*selection.begin()) && static_cast<const CLMetabReferenceGlyph*>(*selection.begin())->getCurve().getNumCurveSegments() != 0) ||
835  (dynamic_cast<const CLReactionGlyph*>(*selection.begin()) && static_cast<const CLReactionGlyph*>(*selection.begin())->getCurve().getNumCurveSegments() != 0)
836  )
837  )
838  {
839  emit singleCurveSelected(true);
840  }
841  else
842  {
843  emit singleCurveSelected(false);
844  }
845  }
846 
847  break;
848  // didn't add a default statement so that I will get warning when I
849  // miss an enum
850  }
851 
852  this->mMouseButton = Qt::NoButton;
854  this->mDragTimeout = false;
855  // change the cursor
856  this->update_status_and_cursor();
857  }
858 }
859 
860 /**
861  * Gets called when the mouse is moved on the scene.
862  */
863 void CQGLLayoutPainter::mouseMoveEvent(QMouseEvent* pMouseEvent)
864 {
865  // set the current position
867  this->mMouseCurrentPosition = pMouseEvent->pos();
868 
869  switch (this->mState)
870  {
872 
873  // update the selection box
874  if (this->mpRenderer != NULL)
875  {
876  double minX = this->mMousePressPosition.x() < this->mMouseCurrentPosition.x() ? this->mMousePressPosition.x() : this->mMouseCurrentPosition.x();
877  double minY = this->mMousePressPosition.y() < this->mMouseCurrentPosition.y() ? this->mMousePressPosition.y() : this->mMouseCurrentPosition.y();
878  double maxX = this->mMousePressPosition.x() > this->mMouseCurrentPosition.x() ? this->mMousePressPosition.x() : this->mMouseCurrentPosition.x();
879  double maxY = this->mMousePressPosition.y() > this->mMouseCurrentPosition.y() ? this->mMousePressPosition.y() : this->mMouseCurrentPosition.y();
880  std::pair<double, double> coords1 = this->mpRenderer->convert_to_model_space(minX, minY);
881  std::pair<double, double> coords2 = this->mpRenderer->convert_to_model_space(maxX, maxY);
882  CLBoundingBox bb(CLPoint(coords1.first, coords1.second), CLDimensions(coords2.first - coords1.first, coords2.second - coords1.second));
883  this->mpRenderer->setSelectionBox(&bb);
884 
885  if (this->isVisible())
886  {
887  this->updateGL();
888  }
889  }
890 
891  break;
892 
894 
895  if (this->mpRenderer != NULL)
896  {
897  std::pair<double, double> coords1 = this->mpRenderer->convert_to_model_space(this->mMouseCurrentPosition.x(), this->mMouseCurrentPosition.y());
898  std::pair<double, double> coords2 = this->mpRenderer->convert_to_model_space(this->mMouseLastPosition.x(), this->mMouseLastPosition.y());
899  double dx = coords1.first - coords2.first;
900  double dy = coords1.second - coords2.second;
901 
902  // check if we are currently dragging a basepoint
903  if (mpDragPoint != NULL)
904  {
905  // set the dragpoint to NULL
906  this->mpDragPoint->setX(this->mpDragPoint->getX() + dx);
907  this->mpDragPoint->setY(this->mpDragPoint->getY() + dy);
908  }
909  else
910  {
911  if (pMouseEvent->modifiers() & Qt::ControlModifier)
912  {
913  this->mpRenderer->move_selection(dx, dy, false);
914  }
915  else
916  {
917  this->mpRenderer->move_selection(dx, dy, true);
918  }
919  }
920 
921  // there is no need to emit the changed signal here
922  // since the user (normally) releases the mouse button
923  // before anything that can react to the change takes effect
924  if (this->isVisible())
925  {
926  this->updateGL();
927  }
928  }
929 
930  break;
931 
933 
934  // check if a drag timout has occured and the user has moved the
935  // mouse far enough to count as a drag
936  if ((this->mDragTimeout == true) && ((this->mMousePressPosition - this->mMouseCurrentPosition).manhattanLength() >= QApplication::startDragDistance()))
937  {
938  // check if the drag start is on a selected item.
939  // if so, move the selection
940  // else create a new selection based on the rectangle covered by the drag
941  // operation
942  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
943 
944  // we have to check hits on basepoints first since they are the smallest
945  // entities so far that can be dragged.
946  if (selection.size() == 1)
947  {
948  // now we have to check if the click was on a basepoint
949  CLMetabReferenceGlyph* pSRG = dynamic_cast<CLMetabReferenceGlyph*>(*selection.begin());
950  CLCurve* pCurve = NULL;
951 
952  if (pSRG != NULL)
953  {
954  if (pSRG->getCurve().getNumCurveSegments() > 0)
955  {
956  pCurve = &pSRG->getCurve();
957  }
958  }
959  else
960  {
961  CLReactionGlyph* pRG = dynamic_cast<CLReactionGlyph*>(*selection.begin());
962 
963  if (pRG != NULL && pRG->getCurve().getNumCurveSegments() > 0)
964  {
965  pCurve = &pRG->getCurve();
966  }
967  }
968 
969  if (pCurve != NULL)
970  {
971  size_t i, iMax = pCurve->getNumCurveSegments();
972  CLLineSegment* pLS = NULL;
973  std::pair<double, double> coords = this->mpRenderer->convert_to_model_space(this->mMousePressPosition.x(), this->mMousePressPosition.y());
974  CLPoint pressPoint(coords.first, coords.second);
975 
976  for (i = 0; i < iMax ; ++i)
977  {
978  pLS = pCurve->getSegmentAt(i);
979  CLPoint* pP = &pLS->getStart();
980 
981  if (this->mpRenderer->distance(*pP, pressPoint) <= 5.0 / this->mCurrentZoom)
982  {
983  this->mpDragPoint = pP;
985  break;
986  }
987 
988  pP = &pLS->getEnd();
989 
990  if (this->mpRenderer->distance(*pP, pressPoint) <= 5.0 / this->mCurrentZoom)
991  {
992  this->mpDragPoint = pP;
994  break;
995  }
996 
997  pP = &pLS->getBase1();
998 
999  if (this->mpRenderer->distance(*pP, pressPoint) <= 5.0 / this->mCurrentZoom)
1000  {
1001  this->mpDragPoint = pP;
1003  break;
1004  }
1005 
1006  pP = &pLS->getBase2();
1007 
1008  if (this->mpRenderer->distance(*pP, pressPoint) <= 5.0 / this->mCurrentZoom)
1009  {
1010  this->mpDragPoint = pP;
1012  break;
1013  }
1014  }
1015  }
1016  }
1017 
1018  if (this->mpDragPoint == NULL)
1019  {
1020  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize> hits = this->mpRenderer->getObjectsAtViewportPosition(this->mMousePressPosition.x(), this->mMousePressPosition.y());
1021 
1022  if (!hits.empty())
1023  {
1024  // see if the mouse was clicked on a selected item
1025  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>::iterator it = hits.begin(), endit = hits.end();
1026 
1027  while (it != endit)
1028  {
1029  if (selection.find(*it) != selection.end())
1030  {
1032  // TODO it might be a bit smoother if we already move the object here as well
1033  // TODO but this is only sugar coating and not essential
1034  }
1035 
1036  ++it;
1037  }
1038  }
1039  }
1040 
1042  {
1044 
1045  // set the selection frame
1046  if (this->mpRenderer != NULL)
1047  {
1048  double minX = this->mMousePressPosition.x() < this->mMouseCurrentPosition.x() ? this->mMousePressPosition.x() : this->mMouseCurrentPosition.x();
1049  double minY = this->mMousePressPosition.y() < this->mMouseCurrentPosition.y() ? this->mMousePressPosition.y() : this->mMouseCurrentPosition.y();
1050  double maxX = this->mMousePressPosition.x() > this->mMouseCurrentPosition.x() ? this->mMousePressPosition.x() : this->mMouseCurrentPosition.x();
1051  double maxY = this->mMousePressPosition.y() > this->mMouseCurrentPosition.y() ? this->mMousePressPosition.y() : this->mMouseCurrentPosition.y();
1052  std::pair<double, double> coords1 = this->mpRenderer->convert_to_model_space(minX, minY);
1053  std::pair<double, double> coords2 = this->mpRenderer->convert_to_model_space(maxX, maxY);
1054  CLBoundingBox bb(CLPoint(coords1.first, coords1.second), CLDimensions(coords2.first - coords1.first, coords2.second - coords1.second));
1055  this->mpRenderer->setSelectionBox(&bb);
1056 
1057  if (this->isVisible())
1058  {
1059  this->updateGL();
1060  }
1061  }
1062  }
1063  }
1064 
1065  break;
1066  // didn't add a default statement so that I will get a warning when I
1067  // miss an enum
1068  }
1069 
1070  this->update_status_and_cursor();
1071 }
1072 
1073 /**
1074  * This method sets the correct cursor and updates status messages.
1075  */
1077 {
1078  // in order to find out what type of cursor we need to set, we need
1079  // a) the position
1080  // b) which buttons are pressed
1081  // c) which keys are pressed
1082  // d) the state of the layout
1083 
1084  // first we check the state
1085  Qt::CursorShape shape = Qt::ArrowCursor;
1086 
1087  switch (this->mState)
1088  {
1090  shape = Qt::ClosedHandCursor;
1091  emit status_message("Drag item(s) out of their parent to break merge.", 0);
1092  break;
1093 
1095  // make the cursor a crosshair
1096  shape = Qt::CrossCursor;
1097  emit status_message("Drag cursor to make selection.", 0);
1098  break;
1099 
1101  // we check if we are currently over another item
1102  bool selectedHit = false;
1103 
1104  if (this->mpRenderer != NULL)
1105  {
1106  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
1107 
1108  if (!selection.empty())
1109  {
1110  // maybe the user was not on a line, but on the basepoint of a bezier segment
1111  // this would not be covered by the above test and has to be handled separatly
1112  if (selection.size() == 1)
1113  {
1114  const CLMetabReferenceGlyph* pSRG = dynamic_cast<const CLMetabReferenceGlyph*>(*selection.begin());
1115  const CLCurve* pCurve = NULL;
1116 
1117  if (pSRG != NULL && pSRG->getCurve().getNumCurveSegments() != 0)
1118  {
1119  pCurve = &pSRG->getCurve();
1120  }
1121  else
1122  {
1123  const CLReactionGlyph* pRG = dynamic_cast<const CLReactionGlyph*>(*selection.begin());
1124 
1125  if (pRG != NULL && pRG->getCurve().getNumCurveSegments() != 0)
1126  {
1127  pCurve = &pRG->getCurve();
1128  }
1129  }
1130 
1131  if (pCurve != NULL)
1132  {
1133  size_t i, iMax = pCurve->getNumCurveSegments();
1134  std::pair<double, double> coords = this->mpRenderer->convert_to_model_space(this->mMouseCurrentPosition.x(), this->mMouseCurrentPosition.y());
1135  CLPoint currentPoint(coords.first, coords.second);
1136  // we only need to consider the basepoints of cubic beziers since the method
1137  // that checks for a line hit takes care of the other points
1138  const CLPoint* pP = NULL;
1139  const CLLineSegment* pLS = NULL;
1140 
1141  for (i = 0; i < iMax ; ++i)
1142  {
1143  pLS = pCurve->getSegmentAt(i);
1144 
1145  if (pLS->isBezier())
1146  {
1147  pP = &pLS->getBase1();
1148 
1149  if (this->mpRenderer->distance(*pP, currentPoint) <= 5.0 / this->mCurrentZoom)
1150  {
1151  selectedHit = true;
1152  break;
1153  }
1154 
1155  pP = &pLS->getBase2();
1156 
1157  if (this->mpRenderer->distance(*pP, currentPoint) <= 5.0 / this->mCurrentZoom)
1158  {
1159  selectedHit = true;
1160  break;
1161  }
1162  }
1163  }
1164  }
1165  }
1166 
1167  if (!selectedHit)
1168  {
1169  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize> hits = this->mpRenderer->getObjectsAtViewportPosition(this->mMouseCurrentPosition.x(), this->mMouseCurrentPosition.y());
1170 
1171  if (!hits.empty())
1172  {
1173  std::multiset<CLGraphicalObject*, compareGraphicalObjectsBySize>::iterator it = hits.begin(), endit = hits.end(), pos;
1174 
1175  while (it != endit && !selectedHit)
1176  {
1177  selectedHit = (selection.find(*it) != selection.end());
1178  ++it;
1179  }
1180  }
1181  }
1182  }
1183  }
1184 
1185  if (selectedHit)
1186  {
1187  // if we are over a selected item
1188  // the cursor needs to be the open hand
1189  shape = Qt::OpenHandCursor;
1190  emit status_message("Drag item to new destination.", 0);
1191  }
1192  else
1193  {
1194  // if the button is pressed, the user probably wants to start a
1195  // selection
1196  if (this->mMouseButton == Qt::LeftButton)
1197  {
1198  shape = Qt::CrossCursor;
1199  emit status_message("Drag to select an area.", 0);
1200  }
1201  else
1202  {
1203  emit status_message("Click and drag to select an area.", 0);
1204  }
1205  }
1206 
1207  break;
1208  }
1209 
1210  if (this->cursor().shape() != shape)
1211  {
1212  this->setCursor(shape);
1213  }
1214 }
1215 
1216 /**
1217  * Reverts the currently selected curve if there is one.
1218  * If nothing is selected or the single selected item is not a curve,
1219  * nothing is done.
1220  */
1222 {
1223  std::set<CLGraphicalObject*>& selection = this->mpRenderer->getSelection();
1224 
1225  if (selection.size() == 1)
1226  {
1227  if (dynamic_cast<const CLMetabReferenceGlyph*>(*selection.begin()) && static_cast<const CLMetabReferenceGlyph*>(*selection.begin())->getCurve().getNumCurveSegments() != 0)
1228  {
1229  const CLCurve* pCurve = this->mpRenderer->revert_curve(&static_cast<const CLMetabReferenceGlyph*>(*selection.begin())->getCurve());
1230  static_cast<CLMetabReferenceGlyph*>(*selection.begin())->setCurve(*pCurve);
1231  delete pCurve;
1232 
1233  if (this->isVisible())
1234  {
1235  this->updateGL();
1236  }
1237  }
1238  else if (dynamic_cast<const CLReactionGlyph*>(*selection.begin()) && static_cast<const CLReactionGlyph*>(*selection.begin())->getCurve().getNumCurveSegments() != 0)
1239  {
1240  const CLCurve* pCurve = this->mpRenderer->revert_curve(&static_cast<const CLReactionGlyph*>(*selection.begin())->getCurve());
1241  static_cast<CLReactionGlyph*>(*selection.begin())->setCurve(*pCurve);
1242  delete pCurve;
1243 
1244  if (this->isVisible())
1245  {
1246  this->updateGL();
1247  }
1248  }
1249  }
1250 }
1251 
1252 /**
1253  * Returns the width of the current drawing area.
1254  */
1256 {
1257  return this->mViewportWidth;
1258 }
1259 
1260 /**
1261  * Returns the height of the current viewport area.
1262  */
1264 {
1265  return this->mViewportHeight;
1266 }
1267 
1268 /**
1269  * Returns the width of the layout part that is currently displayed.
1270  */
1272 {
1273  return (double)this->mViewportWidth / (double)this->mCurrentZoom;
1274 }
1275 
1276 /**
1277  * Returns the width of the layout part that is currently displayed.
1278  */
1280 {
1281  return (double)this->mViewportHeight / (double)this->mCurrentZoom;
1282 }
1283 
1284 /**
1285  * Returns the currently selected items.
1286  */
1287 std::set<CLGraphicalObject*> CQGLLayoutPainter::getSelection()
1288 {
1289  std::set<CLGraphicalObject*> sel;
1290 
1291  if (this->mpRenderer != NULL)
1292  {
1293  sel = this->mpRenderer->getSelection();
1294  }
1295 
1296  return sel;
1297 }
1298 
1299 /**
1300  * Sets the selection to the items in the given set.
1301  */
1302 void CQGLLayoutPainter::setSelection(const std::set<CLGraphicalObject*>& selection)
1303 {
1304  if (this->mpRenderer == NULL) return;
1305 
1306  this->mpRenderer->getSelection() = selection;
1307 }
1308 
1309 /**
1310  * Sets the aspect for the renderer.
1311  */
1312 void CQGLLayoutPainter::setAspect(double aspect)
1313 {
1314  if (this->mpRenderer != NULL)
1315  {
1316  this->mpRenderer->setAspect(aspect);
1317  }
1318 }
1319 
1320 /**
1321  * Returns the aspect from the renderer.
1322  */
1324 {
1325  double aspect = 0.0;
1326 
1327  if (this->mpRenderer != NULL)
1328  {
1329  aspect = this->mpRenderer->getAspect();
1330  }
1331 
1332  return aspect;
1333 }
1334 
1335 /**
1336  * Exports a bitmap of the given size to
1337  * the file with the given name.
1338  */
1339 GLubyte* CQGLLayoutPainter::export_bitmap(double x, double y, double width, double height, unsigned int imageWidth, unsigned int imageHeight, bool drawSelection)
1340 {
1341  this->makeCurrent();
1342  GLubyte* pImageData = NULL;
1343  const char* extensionsString = (const char*)glGetString(GL_EXTENSIONS);
1344 
1345  // TODO this method of testing if the extension is supported is not very safe, we should check if there is
1346  // a whitespace character or npos after the position
1347  if (std::string(extensionsString).find("GL_EXT_framebuffer_object") == std::string::npos)
1348  {
1349  // give an error message that the image is to large
1350  CQMessageBox::critical(this, tr("Framebuffers not supported"),
1351  tr("This version of OpenGL does not support the framebuffer extension.\nSorry, can't create the bitmap."));
1352  return NULL;
1353  }
1354 
1355  // check if the size of the final image is ok.
1356  double size = imageWidth * imageHeight * 4;
1357 
1358  // TODO: again this arbitrary limit seems odd to me
1359  // I don't think we should write images that are larger than 500MB
1360  if (size >= 5e8)
1361  {
1362  // give an error message that the image is to large
1363  CQMessageBox::critical(this, tr("Image too large"),
1364  tr("Sorry, refusing to create images that are larger than 500MB."));
1365  return NULL;
1366  }
1367 
1368  // set busy cursor
1369  QCursor cursor = this->cursor();
1370  this->setCursor(Qt::BusyCursor);
1371 
1372  // if draw selection is false, we first have to store the selection somewhere
1373  // reset the current selection
1374  std::set<CLGraphicalObject*> selection;
1375 
1376  if (!drawSelection)
1377  {
1378  selection = this->getSelection();
1379  }
1380 
1381  //
1382  size /= 4;
1383  // if the image size is larger than a certain size, we have to subdivide the drawing into smaller bits.
1384  GLint chunk_size = 0;
1385  glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &chunk_size);
1386 
1387  chunk_size /= 8;
1388 
1389  if (chunk_size > 0)
1390  {
1391  // create the framebuffer object, the render buffer objects and bind them
1392  GLuint fboName = 0;
1393  GLuint blitFBOName = 0;
1394  GLuint* rbuffers = NULL;
1395  GLuint* multisampleBuffers = NULL;
1396  bool multisample_supported = false;
1397  GLint samples = 0;
1398 
1399  if (std::string(extensionsString).find("GL_EXT_framebuffer_multisample") != std::string::npos)
1400  {
1401  // enable after the bugs have been fixed
1402  multisample_supported = true;
1403  // check how many samples we can use
1404  glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
1405  // we don't want to do more than 4x AA
1406  samples = (samples > 4) ? 4 : samples;
1407  }
1408 
1409  if (!multisample_supported || samples < 2)
1410  {
1411  CQMessageBox::warning(this, tr("Multisampling unsupported"),
1412  tr("Your implementation does not support multisampling of\nframebuffer objects. The resulting\bitmap might not look very nice."));
1413  }
1414 
1415  // if we are not on an apple, we have to initialize the functions
1416  // for the OpenGL extensions
1418 
1419  if (imageWidth > (unsigned int)chunk_size || imageHeight > (unsigned int)chunk_size)
1420  {
1421  double currentX = x;
1422  double currentY = y;
1423 
1424  // create storage for the complete image
1425  try
1426  {
1427  pImageData = new GLubyte[imageWidth * imageHeight * 4];
1428  }
1429  catch (...)
1430  {
1431  CQMessageBox::critical(this, tr("Error creating image"),
1432  tr("Could not create image. Maybe you ran out of memory."));
1433  // set normal cursor
1434  this->setCursor(cursor);
1435  return NULL;
1436  }
1437 
1438  unsigned int xSteps = imageWidth / chunk_size;
1439  unsigned int ySteps = imageHeight / chunk_size;
1440  unsigned int restX = imageWidth % chunk_size;
1441  unsigned int restY = imageHeight % chunk_size;
1442  unsigned int i = 0, j = 0;
1443  int k;
1444  double xModelStep = chunk_size * width / imageWidth;
1445  double yModelStep = chunk_size * height / imageHeight;
1446  const uchar* pSrc = NULL;
1447  uchar* pDst = NULL;
1448  // For each step we reposition the gl widget, create the pixmap and add the content to the large pixmap
1449  //
1450  GLubyte* pTmpData = NULL;
1451  bool success = true;
1452 
1453  for (i = 0; i < ySteps && success; ++i)
1454  {
1455  currentX = x;
1456 
1457  for (j = 0; j < xSteps && success; ++j)
1458  {
1459  success = this->draw_bitmap(currentX, currentY, xModelStep, yModelStep, chunk_size, chunk_size, fboName, blitFBOName, &rbuffers, &multisampleBuffers, &pTmpData, samples);
1460 
1461  if (success)
1462  {
1463  for (k = 0; k < chunk_size; ++k)
1464  {
1465  // copy the data
1466  pSrc = pTmpData + k * chunk_size * 4;
1467  pDst = pImageData + (i * chunk_size + k) * imageWidth * 4 + j * chunk_size * 4;
1468  memcpy(pDst, pSrc, 4 * chunk_size);
1469  }
1470  }
1471 
1472  currentX += xModelStep;
1473  }
1474 
1475  currentY += yModelStep;
1476  }
1477 
1478  // delete the current render buffer
1479  this->destroy_buffers(fboName, rbuffers, blitFBOName, multisampleBuffers);
1480 
1481  if (rbuffers != NULL)
1482  {
1483  delete[] rbuffers;
1484  rbuffers = NULL;
1485  }
1486 
1487  if (multisampleBuffers != NULL)
1488  {
1489  delete[] multisampleBuffers;
1490  multisampleBuffers = NULL;
1491  }
1492 
1493  // check if there are some pixels left at the right edge
1494  if (success && restX != 0)
1495  {
1496  double tmpWidth = restX * width / imageWidth;
1497  // go back to the top
1498  currentY = y;
1499 
1500  for (i = 0; i < ySteps && success ; ++i)
1501  {
1502  success = this->draw_bitmap(currentX, currentY, tmpWidth, yModelStep, restX, chunk_size, fboName, blitFBOName, &rbuffers, &multisampleBuffers, &pTmpData, samples);
1503 
1504  // if rendering failed, we make sure the buffer for the image
1505  // data is deleted so that it will not be used further down
1506  if (success)
1507  {
1508  for (k = 0; k < chunk_size; ++k)
1509  {
1510  // copy the data
1511  pSrc = pTmpData + k * restX * 4;
1512  pDst = pImageData + (i * chunk_size + k) * imageWidth * 4 + j * chunk_size * 4;
1513  memcpy(pDst, pSrc, 4 * restX);
1514  }
1515  }
1516 
1517  currentY += yModelStep;
1518  }
1519 
1520  // delete the current render buffer
1521  this->destroy_buffers(fboName, rbuffers, blitFBOName, multisampleBuffers);
1522 
1523  if (rbuffers != NULL)
1524  {
1525  delete[] rbuffers;
1526  rbuffers = NULL;
1527  }
1528 
1529  if (multisampleBuffers != NULL)
1530  {
1531  delete[] multisampleBuffers;
1532  multisampleBuffers = NULL;
1533  }
1534  }
1535 
1536  if (success && restY != 0)
1537  {
1538  // go back to the right
1539  double tmpHeight = restY * height / imageHeight;
1540  currentX = x;
1541 
1542  for (j = 0; j < xSteps; ++j)
1543  {
1544  success = this->draw_bitmap(currentX, currentY, xModelStep, tmpHeight, chunk_size, restY, fboName, blitFBOName, &rbuffers, &multisampleBuffers, &pTmpData, samples);
1545 
1546  if (success)
1547  {
1548  for (k = 0; k < (int)restY; ++k)
1549  {
1550  // copy the data
1551  pSrc = pTmpData + k * chunk_size * 4;
1552  pDst = pImageData + (i * chunk_size + k) * imageWidth * 4 + j * chunk_size * 4;
1553  memcpy(pDst, pSrc, 4 * chunk_size);
1554  }
1555  }
1556 
1557  currentX += xModelStep;
1558  }
1559 
1560  // delete the current render buffer
1561  this->destroy_buffers(fboName, rbuffers, blitFBOName, multisampleBuffers);
1562 
1563  if (rbuffers != NULL)
1564  {
1565  delete[] rbuffers;
1566  rbuffers = NULL;
1567  }
1568 
1569  if (multisampleBuffers != NULL)
1570  {
1571  delete[] multisampleBuffers;
1572  multisampleBuffers = NULL;
1573  }
1574 
1575  // check if there are some pixels left
1576  if (success && restX != 0)
1577  {
1578  double tmpWidth = restX * width / imageWidth;
1579  // set the correct viewport size
1580  success = this->draw_bitmap(currentX, currentY, tmpWidth, tmpHeight, restX, restY, fboName, blitFBOName, &rbuffers, &multisampleBuffers, &pTmpData, samples);
1581 
1582  if (success)
1583  {
1584  for (k = 0; k < (int)restY; ++k)
1585  {
1586  // copy the data
1587  pSrc = pTmpData + k * restX * 4;
1588  pDst = pImageData + (i * chunk_size + k) * imageWidth * 4 + j * chunk_size * 4;
1589  memcpy(pDst, pSrc, 4 * restX);
1590  }
1591  }
1592 
1593  // delete the current render buffer
1594  this->destroy_buffers(fboName, rbuffers, blitFBOName, multisampleBuffers);
1595 
1596  if (rbuffers != NULL)
1597  {
1598  delete[] rbuffers;
1599  rbuffers = NULL;
1600  }
1601 
1602  if (multisampleBuffers != NULL)
1603  {
1604  delete[] multisampleBuffers;
1605  multisampleBuffers = NULL;
1606  }
1607  }
1608  }
1609 
1610  // if rendering failed, we make sure the buffer for the image
1611  // data is deleted so that it will not be used further down
1612  if (!success)
1613  {
1614  if (pImageData != NULL) delete[] pImageData;
1615 
1616  pImageData = NULL;
1617  }
1618 
1619  if (pTmpData != NULL) delete[] pTmpData;
1620  }
1621  else
1622  {
1623  // we just draw it in one go
1624  bool success = this->draw_bitmap(x, y, width, height, imageWidth, imageHeight, fboName, blitFBOName, &rbuffers, &multisampleBuffers, &pImageData, samples);
1625 
1626  // if rendering failed, we make sure the buffer for the image
1627  // data is deleted so that it will not be used further down
1628  if (!success && pImageData != NULL)
1629  {
1630  delete[] pImageData;
1631  pImageData = NULL;
1632  }
1633 
1634  // delete the buffers
1635  this->destroy_buffers(fboName, rbuffers, blitFBOName, multisampleBuffers);
1636 
1637  if (rbuffers != NULL) delete[] rbuffers;
1638 
1639  if (multisampleBuffers != NULL) delete[] multisampleBuffers;
1640  }
1641 
1642  // if we are not on an apple, we have to deinitialize the functions
1643  // for the OpenGL extensions again because we can not reuse them
1644  // for the next export sicne they are context dependent and the context might have changed
1645  // This is not absolutly necessary, but it might help finding problems.
1646  this->clear_extension_functions();
1647 
1648  // if the stored selection is not empty, we have to restore the selection
1649  if (!selection.empty())
1650  {
1651  this->setSelection(selection);
1652  }
1653 
1654  // need to convert from RGBA to ARGB
1655  if (pImageData != NULL)
1656  {
1657  unsigned int i, iMax = imageWidth * imageHeight;
1658 
1659  for (i = 0; i < iMax; ++i)
1660  {
1661  // in OpenGL the color values are stored as bytes in
1662  // the order RR GG BB AA
1663  // In Qt the color value has to be an int 0xAARRGGBB
1664  // so the order in memory depends on the endianess of
1665  // the system
1666  ((GLuint*)pImageData)[i] = pImageData[i * 4 + 3] * 16777216 | ((GLuint)pImageData[i * 4]) * 65536 | ((GLuint)pImageData[i * 4 + 1]) * 256 | ((GLuint)pImageData[i * 4 + 2]);
1667  }
1668  }
1669  }
1670 
1671  // set normal cursor
1672  this->setCursor(cursor);
1673 
1674  return pImageData;
1675 }
1676 
1677 /**
1678  * Renders the specified part of the model into a bitmap.
1679  * The bitmap is returned as RGBA data in pImageData.
1680  * If pImageData is pointing to a null pointer, memory is alocated and the caller has to release it.
1681  * If drawing the bitmap is successfull, true is returned, else false is
1682  * returned.
1683  */
1684 bool CQGLLayoutPainter::draw_bitmap(double x, double y, double width, double height, unsigned int imageWidth, unsigned int imageHeight, GLuint& fbo, GLuint& multiFBO, GLuint** rbuffers, GLuint** multiRBuffers, GLubyte** pImageData, GLuint samples)
1685 {
1686  // make sure all the functions that we need are actually initialized
1687  assert(glGenFramebuffersEXTPtr != NULL);
1688  assert(glGenRenderbuffersEXTPtr != NULL);
1689  assert(glBindFramebufferEXTPtr != NULL);
1690  assert(glBindRenderbufferEXTPtr != NULL);
1691  assert(glRenderbufferStorageEXTPtr != NULL);
1692  assert(glFramebufferRenderbufferEXTPtr != NULL);
1693  this->makeCurrent();
1694 
1695  // create the framebuffer object, the render buffer objects and bind them
1696  if (fbo == 0)
1697  {
1698  //std::cout << "Frame buffer object must be created." << std::endl;
1699  // create the framebuffer object
1700  (*glGenFramebuffersEXTPtr)(1, &fbo);
1701  assert(fbo != 0);
1702  (*glBindFramebufferEXTPtr)(GL_FRAMEBUFFER_EXT, fbo);
1703  //std::cout << "Bound framebuffer object: " << fbo << std::endl;
1704  }
1705 
1706  if ((*rbuffers) == NULL)
1707  {
1708  //std::cout << "The render buffers need to be created." << std::endl;
1709  // create the render buffers and create storage for them
1710  (*rbuffers) = new GLuint[2];
1711  (*glGenRenderbuffersEXTPtr)(2, (*rbuffers));
1712  assert((*rbuffers)[0] != 0);
1713  assert((*rbuffers)[1] != 0);
1714  (*glBindRenderbufferEXTPtr)(GL_RENDERBUFFER_EXT, (*rbuffers)[0]);
1715  //std::cout << "render color buffer: " << (*rbuffers)[0] << std::endl;
1716  (*glRenderbufferStorageEXTPtr)(GL_RENDERBUFFER_EXT, GL_RGBA, imageWidth, imageHeight);
1717  (*glBindRenderbufferEXTPtr)(GL_RENDERBUFFER_EXT, (*rbuffers)[1]);
1718  //std::cout << "render depth buffer: " << (*rbuffers)[1] << std::endl;
1719  (*glRenderbufferStorageEXTPtr)(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, imageWidth, imageHeight);
1720  }
1721 
1722  // attach the color buffer
1723  //std::cout << "attaching color buffer: " << (*rbuffers)[0] << std::endl;
1724  (*glFramebufferRenderbufferEXTPtr)(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, (*rbuffers)[0]);
1725  // attach the depth buffer
1726  //std::cout << "attaching depth buffer: " << (*rbuffers)[1] << std::endl;
1727  (*glFramebufferRenderbufferEXTPtr)(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, (*rbuffers)[1]);
1728 
1729  if (samples > 1)
1730  {
1731  //std::cout << "We are doing multismpling." << std::endl;
1732  // make sure all the functions that we need are actually initialized
1734  assert(glBlitFramebufferEXTPtr != NULL);
1735 
1736  // create the framebuffer and render buffers for multisampling
1737  if (multiFBO == 0)
1738  {
1739  // std::cout << "Usinging multisample FBO." << std::endl;
1740  (*glGenFramebuffersEXTPtr)(1, &multiFBO);
1741  assert(multiFBO != 0);
1742  //std::cout << "generated multisample fbo: " << multiFBO << std::endl;
1743  (*glBindFramebufferEXTPtr)(GL_FRAMEBUFFER_EXT, multiFBO);
1744  }
1745 
1746  if ((*multiRBuffers) == NULL)
1747  {
1748  //std::cout << "generating multisample buffers." << std::endl;
1749  // create the render buffers and create storage for them
1750  (*multiRBuffers) = new GLuint[2];
1751  (*glGenRenderbuffersEXTPtr)(2, (*multiRBuffers));
1752  //std::cout << "created multisamplebuffers: " << (*multiRBuffers)[0] << " " << (*multiRBuffers)[1] << std::endl;
1753  assert((*multiRBuffers)[0] != 0);
1754  assert((*multiRBuffers)[1] != 0);
1755  (*glBindRenderbufferEXTPtr)(GL_RENDERBUFFER_EXT, (*multiRBuffers)[0]);
1756  (*glRenderbufferStorageMultisampleEXTPtr)(GL_RENDERBUFFER_EXT, samples, GL_RGBA, imageWidth, imageHeight);
1757  //std::cout << "Bound multisample color buffer: " << (*multiRBuffers)[0] << std::endl;
1758  (*glBindRenderbufferEXTPtr)(GL_RENDERBUFFER_EXT, (*multiRBuffers)[1]);
1759  (*glRenderbufferStorageMultisampleEXTPtr)(GL_RENDERBUFFER_EXT, samples, GL_DEPTH_COMPONENT, imageWidth, imageHeight);
1760  //std::cout << "Bound multisample depth buffer: " << (*multiRBuffers)[1] << std::endl;
1761  }
1762 
1763  // attach the color buffer
1764  //std::cout << "attaching multisample color buffer: " << (*multiRBuffers)[0] << std::endl;
1765  (*glFramebufferRenderbufferEXTPtr)(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, (*multiRBuffers)[0]);
1766  // attach the depth buffer
1767  //std::cout << "attaching multisample depth buffer: " << (*multiRBuffers)[1] << std::endl;
1768  (*glFramebufferRenderbufferEXTPtr)(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, (*multiRBuffers)[1]);
1769  }
1770 
1771  // remember if we have to go on
1772  QString messageHeader, message;
1773  bool fail = !this->check_fbo_status(messageHeader, message);
1774 
1775  if (fail == false && (*pImageData) == NULL)
1776  {
1777  try
1778  {
1779  (*pImageData) = new GLubyte[imageWidth * imageHeight * 4];
1780  }
1781  catch (...)
1782  {
1783  messageHeader = tr("Error creating image");
1784  message = tr("Could not create image. Maybe you ran out of memory.");
1785  fail = true;
1786  (*pImageData) = NULL;
1787  }
1788  }
1789 
1790  // remember the old values
1791  if (fail == false)
1792  {
1793  bool visible = this->isVisible();
1794 
1795  if (visible)
1796  {
1797  this->setVisible(false);
1798  }
1799 
1800  double origX = this->getCurrentPositionX();
1801  double origY = this->getCurrentPositionY();
1802  double origWidth = this->mViewportWidth;
1803  double origHeight = this->mViewportHeight;
1804  double origZoom = this->getZoomFactor();
1805  double origAspect = this->getAspect();
1806  double zoom = (double)imageHeight / height;
1807  double aspect = (double)imageWidth / (width * zoom);
1808  this->setZoomFactor(zoom);
1809  this->setAspect(aspect);
1810  this->setCurrentPosition(x, y);
1811  this->resizeGL(imageWidth, imageHeight);
1812  // now we should be able to actually draw the image
1813  assert(this->mpRenderer != NULL);
1814 
1815  if (this->mpRenderer != NULL)
1816  {
1817  this->mpRenderer->draw_layout();
1818  }
1819 
1820  // now we need to get the pixels back from the render buffer
1821  if (samples > 1)
1822  {
1823  // we need to blit the image from the multisample buffer to the normal buffer
1824  (*glBindFramebufferEXTPtr)(GL_READ_FRAMEBUFFER_EXT, multiFBO);
1825  //std::cout << "Bound buffer for reading: " << multiFBO << std::endl;
1826  (*glBindFramebufferEXTPtr)(GL_DRAW_FRAMEBUFFER_EXT, fbo);
1827  //std::cout << "Bound buffer for drawing: " << fbo << std::endl;
1828  // check the status
1829  fail = !this->check_fbo_status(messageHeader, message);
1830 
1831  if (fail == false)
1832  {
1833  //std::cout << "blitting data from read buffer into draw buffer" << std::endl;
1834  (*glBlitFramebufferEXTPtr)(0, 0, imageWidth, imageHeight, 0, 0, imageWidth, imageHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
1835  // now we need to bind the blit buffer in order to read from it
1836  //std::cout << "Binding framebuffer to read pixels: " << fbo << std::endl;
1837  (*glBindFramebufferEXTPtr)(GL_FRAMEBUFFER_EXT, fbo);
1838  fail = !this->check_fbo_status(messageHeader, message);
1839  }
1840  }
1841 
1842  if (fail == false)
1843  {
1844  //std::cout << "reading pixels from read buffer." << std::endl;
1845  glReadPixels(0, 0, imageWidth, imageHeight, GL_RGBA, GL_UNSIGNED_BYTE, *pImageData);
1846  // the picture is flipped horizontally, so we have to turn it around
1847  GLubyte* pTmpData = new GLubyte[imageWidth * 4];
1848  unsigned int i, iMax = imageHeight / 2;
1849 
1850  for (i = 0; i < iMax; ++i)
1851  {
1852  // save the first line
1853  memcpy(pTmpData, (*pImageData) + i * 4 * imageWidth, imageWidth * 4);
1854  // copy the iMax-1-i the line to the ith line
1855  memcpy((*pImageData) + i * 4 * imageWidth, (*pImageData) + (imageHeight - 1 - i)*imageWidth * 4, imageWidth * 4);
1856  // copy pTmpData into the iMax-1-i th line
1857  memcpy((*pImageData) + (imageHeight - 1 - i) * 4 * imageWidth, pTmpData, imageWidth * 4);
1858  }
1859  }
1860 
1861  // reset the zoom and the aspect
1862  this->setZoomFactor(origZoom);
1863  this->setAspect(origAspect);
1864  this->setCurrentPosition(origX, origY);
1865  this->resizeGL(origWidth, origHeight);
1866 
1867  if (visible)
1868  {
1869  this->setVisible(true);
1870  }
1871  }
1872 
1873  // issue the error message and reset the state
1874  if (fail == true)
1875  {
1876  CQMessageBox::critical(this, messageHeader,
1877  message);
1878  }
1879 
1880  return !fail;
1881 }
1882 
1883 /**
1884  * Destroys the passed in render and framebuffers.
1885  */
1886 void CQGLLayoutPainter::destroy_buffers(GLuint& fbo, GLuint* rbuffers, GLuint& multiFBO, GLuint* multiRBuffers)
1887 {
1888  // make sure all the functions that we need are actually initialized
1889  assert(glDeleteFramebuffersEXTPtr != NULL);
1890  assert(glDeleteRenderbuffersEXTPtr != NULL);
1891 
1892  if (rbuffers != NULL)(*glDeleteRenderbuffersEXTPtr)(2, rbuffers);
1893 
1894  if (multiRBuffers != NULL)(*glDeleteRenderbuffersEXTPtr)(2, multiRBuffers);
1895 
1896  (*glDeleteFramebuffersEXTPtr)(1, &fbo);
1897  (*glDeleteFramebuffersEXTPtr)(1, &multiFBO);
1898  fbo = 0;
1899  multiFBO = 0;
1900 }
1901 
1902 /**
1903  * Checks the state of the currently bound framebuffer.
1904  * If the framebuffer is valid, true is returned, if it is invalid,
1905  * the return value is false and messageHeader and message contain a mesage
1906  * header and a message to display to the user.
1907  */
1908 bool CQGLLayoutPainter::check_fbo_status(QString& messageHeader, QString& message)
1909 {
1910  bool success = false;
1911  messageHeader = tr("Error creating image");
1912  // make sure all the functions that we need are actually initialized
1913  assert(glCheckFramebufferStatusEXTPtr != NULL);
1914  GLenum status = (*glCheckFramebufferStatusEXTPtr)(GL_FRAMEBUFFER_EXT);
1915 
1916  switch (status)
1917  {
1919  // everything is OK
1920  success = true;
1921  break;
1922 
1924  message = tr("Could not create framebuffer object (INCOMPLETE_ATTACHMENT). ");
1925  break;
1926 
1928  message = tr("Could not create framebuffer object (INCOMPLETE_DIMENSIONS). ");
1929  break;
1930 
1932  message = tr("Could not create framebuffer object (INCOMPLETE_MISSING_ATTACHMENT).");
1933  break;
1934 
1936  message = tr("Could not create framebuffer object (INCOMPLETE_UNSUPPORTED). ");
1937  break;
1938 
1939  default:
1940  message = tr("Could not create framebuffer object (UNKNOWN). ");
1941  break;
1942  }
1943 
1944  return success;
1945 }
1946 
1947 /**
1948  * On non apple systems, we need to get the pointers to extension functions.
1949  */
1951 {
1952 #ifdef _WIN32
1953  glCheckFramebufferStatusEXTPtr = (PFNGLCHECKFRAMEBUFFERSTATUSEXT)wglGetProcAddress("glCheckFramebufferStatusEXT");
1954  glGenFramebuffersEXTPtr = (PFNGLGENFRAMEBUFFERSEXT)wglGetProcAddress("glGenFramebuffersEXT");
1955  glGenRenderbuffersEXTPtr = (PFNGLGENRENDERBUFFERSEXT)wglGetProcAddress("glGenRenderbuffersEXT");
1956  glDeleteFramebuffersEXTPtr = (PFNGLDELETEFRAMEBUFFERSEXT)wglGetProcAddress("glDeleteFramebuffersEXT");
1957  glDeleteRenderbuffersEXTPtr = (PFNGLDELETERENDERBUFFERSEXT)wglGetProcAddress("glDeleteRenderbuffersEXT");
1958  glBindFramebufferEXTPtr = (PFNGLBINDFRAMEBUFFEREXT)wglGetProcAddress("glBindFramebufferEXT");
1959  glBindRenderbufferEXTPtr = (PFNGLBINDRENDERBUFFEREXT)wglGetProcAddress("glBindRenderbufferEXT");
1960  glRenderbufferStorageEXTPtr = (PFNGLRENDERBUFFERSTORAGEEXT)wglGetProcAddress("glRenderbufferStorageEXT");
1961  glFramebufferRenderbufferEXTPtr = (PFNGLFRAMEBUFFERRENDERBUFFEREXT)wglGetProcAddress("glFramebufferRenderbufferEXT");
1962  glRenderbufferStorageMultisampleEXTPtr = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXT)wglGetProcAddress("glRenderbufferStorageMultisampleEXT");
1963  glBlitFramebufferEXTPtr = (PFNGLBLITFRAMEBUFFEREXT)wglGetProcAddress("glBlitFramebufferEXT");
1964 #else
1965 #ifndef __APPLE__
1966  glCheckFramebufferStatusEXTPtr = (PFNGLCHECKFRAMEBUFFERSTATUSEXT)glXGetProcAddressARB((const GLubyte*)"glCheckFramebufferStatusEXT");
1967  glGenFramebuffersEXTPtr = (PFNGLGENFRAMEBUFFERSEXT)glXGetProcAddressARB((const GLubyte*)"glGenFramebuffersEXT");
1968  glGenRenderbuffersEXTPtr = (PFNGLGENRENDERBUFFERSEXT)glXGetProcAddressARB((const GLubyte*)"glGenRenderbuffersEXT");
1969  glDeleteFramebuffersEXTPtr = (PFNGLDELETEFRAMEBUFFERSEXT)glXGetProcAddressARB((const GLubyte*)"glDeleteFramebuffersEXT");
1970  glDeleteRenderbuffersEXTPtr = (PFNGLDELETERENDERBUFFERSEXT)glXGetProcAddressARB((const GLubyte*)"glDeleteRenderbuffersEXT");
1971  glBindFramebufferEXTPtr = (PFNGLBINDFRAMEBUFFEREXT)glXGetProcAddressARB((const GLubyte*)"glBindFramebufferEXT");
1972  glBindRenderbufferEXTPtr = (PFNGLBINDRENDERBUFFEREXT)glXGetProcAddressARB((const GLubyte*)"glBindRenderbufferEXT");
1973  glRenderbufferStorageEXTPtr = (PFNGLRENDERBUFFERSTORAGEEXT)glXGetProcAddressARB((const GLubyte*)"glRenderbufferStorageEXT");
1974  glFramebufferRenderbufferEXTPtr = (PFNGLFRAMEBUFFERRENDERBUFFEREXT)glXGetProcAddressARB((const GLubyte*)"glFramebufferRenderbufferEXT");
1975  glRenderbufferStorageMultisampleEXTPtr = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXT)glXGetProcAddressARB((const GLubyte*)"glRenderbufferStorageMultisampleEXT");
1976  glBlitFramebufferEXTPtr = (PFNGLBLITFRAMEBUFFEREXT)glXGetProcAddressARB((const GLubyte*)"glBlitFramebufferEXT");
1977 #else
1978  glCheckFramebufferStatusEXTPtr = (PFNGLCHECKFRAMEBUFFERSTATUSEXT)MyNSGLGetProcAddress("glCheckFramebufferStatusEXT");
1979  glGenFramebuffersEXTPtr = (PFNGLGENFRAMEBUFFERSEXT)MyNSGLGetProcAddress("glGenFramebuffersEXT");
1980  glGenRenderbuffersEXTPtr = (PFNGLGENRENDERBUFFERSEXT)MyNSGLGetProcAddress("glGenRenderbuffersEXT");
1981  glDeleteFramebuffersEXTPtr = (PFNGLDELETEFRAMEBUFFERSEXT)MyNSGLGetProcAddress("glDeleteFramebuffersEXT");
1982  glDeleteRenderbuffersEXTPtr = (PFNGLDELETERENDERBUFFERSEXT)MyNSGLGetProcAddress("glDeleteRenderbuffersEXT");
1983  glBindFramebufferEXTPtr = (PFNGLBINDFRAMEBUFFEREXT)MyNSGLGetProcAddress("glBindFramebufferEXT");
1984  glBindRenderbufferEXTPtr = (PFNGLBINDRENDERBUFFEREXT)MyNSGLGetProcAddress("glBindRenderbufferEXT");
1985  glRenderbufferStorageEXTPtr = (PFNGLRENDERBUFFERSTORAGEEXT)MyNSGLGetProcAddress("glRenderbufferStorageEXT");
1986  glFramebufferRenderbufferEXTPtr = (PFNGLFRAMEBUFFERRENDERBUFFEREXT)MyNSGLGetProcAddress("glFramebufferRenderbufferEXT");
1987  glRenderbufferStorageMultisampleEXTPtr = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXT)MyNSGLGetProcAddress("glRenderbufferStorageMultisampleEXT");
1988  glBlitFramebufferEXTPtr = (PFNGLBLITFRAMEBUFFEREXT)MyNSGLGetProcAddress("glBlitFramebufferEXT");
1989 
1990 #endif // __APPLE__
1991 #endif // _WIN32
1992 }
1993 
1994 /**
1995  * Set all pointer to extension function to NULL.
1996  */
1998 {
2000  glGenFramebuffersEXTPtr = NULL;
2001  glGenRenderbuffersEXTPtr = NULL;
2004  glBindFramebufferEXTPtr = NULL;
2005  glBindRenderbufferEXTPtr = NULL;
2009  glBlitFramebufferEXTPtr = NULL;
2010 }
2011 
2012 #ifdef __APPLE__
2013 #ifndef COPASI_MAC_USE_DEPRECATED_LOOKUP
2014 #include <dlfcn.h>
2015 #endif
2016 void * CQGLLayoutPainter::MyNSGLGetProcAddress(const char *name)
2017 {
2018 #ifndef COPASI_MAC_USE_DEPRECATED_LOOKUP
2019  return dlsym(RTLD_DEFAULT, name);
2020 #else
2021  NSSymbol symbol;
2022  char *symbolName;
2023  symbolName = (char*)malloc(strlen(name) + 2);
2024 
2025  strcpy(symbolName + 1, name);
2026 
2027  symbolName[0] = '_';
2028  symbol = NULL;
2029 
2030  if (NSIsSymbolNameDefined(symbolName))
2031  {
2032  symbol = NSLookupAndBindSymbol(symbolName);
2033  }
2034 
2035  free(symbolName);
2036 
2037  return symbol ? NSAddressOfSymbol(symbol) : NULL;
2038 #endif
2039 }
2040 
2041 #endif // __APPLE__
2042 
2043 // the following methods are used to highlight elements in the diagram
2044 // based on their association to model elements
2045 
2046 /**
2047  * Sets the list of model objects that are to be highlighted in the diagram.
2048  */
2049 void CQGLLayoutPainter::setHighlightedObjects(const std::set<const CLGraphicalObject*>& highlightedObjects)
2050 {
2051  this->mpRenderer->setHighlightedObjects(highlightedObjects);
2052 }
2053 
2054 /**
2055  * Returns a const reference to the set of highlighted model objects.
2056  */
2057 const std::set<const CLGraphicalObject*>& CQGLLayoutPainter::getHighlightedObjects() const
2058 {
2059  return this->mpRenderer->getHighlightedObjects();
2060 }
2061 
2062 /**
2063  * Returns a reference to the set of highlighted model objects.
2064  */
2065 std::set<const CLGraphicalObject*>& CQGLLayoutPainter::getHighlightedObjects()
2066 {
2067  return this->mpRenderer->getHighlightedObjects();
2068 }
2069 
2070 /**
2071  * Sets the highlight color.
2072  */
2074 {
2075  this->mpRenderer->setHighlightColor(c);
2076 }
2077 
2078 /**
2079  * Sets the fog density value.
2080  */
2082 {
2083  this->mpRenderer->setFogDensity(dens);
2084 }
2085 
2086 /**
2087  * Sets the fog density value.
2088  */
2090 {
2091  return this->mpRenderer->getFogDensity();
2092 }
2093 
2094 /**
2095  * Returns a const pointer to the highlight color.
2096  * The array has a size of 4 elements.
2097  */
2099 {
2100  return this->mpRenderer->getHighlightColor();
2101 }
2102 
2103 /**
2104  * Sets the fog color.
2105  */
2106 void CQGLLayoutPainter::setFogColor(const GLfloat c[4])
2107 {
2108  this->mpRenderer->setFogColor(c);
2109 }
2110 
2111 /**
2112  * Returns a const pointer to the fog color.
2113  * The array has a size of 4 elements.
2114  */
2115 const GLfloat* CQGLLayoutPainter::getFogColor() const
2116 {
2117  return this->mpRenderer->getFogColor();
2118 }
2119 
2120 /**
2121  * Toggles the flag that determines if highlighted objects
2122  * are actually highlighted or if the rest is fogged out.
2123  */
2125 {
2127 }
2128 
2129 /**
2130  * Toggles the flag that determines if highlighted objects
2131  * are actually highlighted or if the rest is fogged out.
2132  */
2134 {
2135  this->mpRenderer->setHighlightFlag(flag);
2136 }
2137 
2138 /**
2139  * Returns the highlight flag.
2140  */
2142 {
2143  return this->mpRenderer->getHighlightFlag();
2144 }
unsigned int getViewportHeight() const
void move_selection(double dx, double dy, bool moveAssociated=true)
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXT glRenderbufferStorageMultisampleEXTPtr
double minX() const
static const CCopasiMessage & peekLastMessage()
void setSelection(const std::set< CLGraphicalObject * > &selection)
bool check_fbo_status(QString &messageHeader, QString &message)
double getCurrentHeight() const
const C_FLOAT64 & getZ() const
Definition: CLBase.h:85
void setCurrentPosition(double x, double y)
double getCurrentPositionY() const
const C_FLOAT64 & getWidth() const
Definition: CLBase.h:211
void setBounds(double minX, double minY, double maxX, double maxY)
const GLfloat * getHighlightColor() const
void(* PFNGLBLITFRAMEBUFFEREXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
PFNGLGENRENDERBUFFERSEXT glGenRenderbuffersEXTPtr
void status_message(const QString &message, int timeout)
void(* PFNGLGENRENDERBUFFERSEXT)(GLsizei n, GLuint *renderbuffers)
virtual void initializeGL()
PFNGLGENFRAMEBUFFERSEXT glGenFramebuffersEXTPtr
const GLfloat * getFogColor() const
std::multiset< CLGraphicalObject *, compareGraphicalObjectsBySize > getObjectsAtViewportPosition(unsigned int x, unsigned int y)
void setX(const C_FLOAT64 &x)
Definition: CLBase.h:91
GLfloat getFogDensity() const
virtual void mousePressEvent(QMouseEvent *pMouseEvent)
#define GL_COLOR_ATTACHMENT0_EXT
Definition: glext.h:4203
void(* PFNGLDELETEFRAMEBUFFERSEXT)(GLsizei n, GLuint *framebuffers)
#define GL_FRAMEBUFFER_COMPLETE_EXT
Definition: glext.h:4194
void(* PFNGLFRAMEBUFFERRENDERBUFFEREXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
double maxY() const
const std::set< const CLGraphicalObject * > & getHighlightedObjects() const
static double distance(const CLPoint &p1, const CLPoint &p2)
void setHighlightFlag(bool flag)
static std::string getAllMessageText(const bool &chronological=true)
#define GL_MAX_RENDERBUFFER_SIZE_EXT
Definition: glext.h:4186
void setMinX(double x)
#define GL_DEPTH_ATTACHMENT_EXT
Definition: glext.h:4219
void setHighlightColor(const GLfloat c[4])
PFNGLBLITFRAMEBUFFEREXT glBlitFramebufferEXTPtr
unsigned int mViewportHeight
void setY(const C_FLOAT64 &y)
Definition: CLBase.h:92
void calculateAndAssignBounds(CLayout *pLayout)
void setAspect(double aspect)
const std::set< const CLGraphicalObject * > & getHighlightedObjects() const
double getCurrentPositionX() const
virtual void mouseMoveEvent(QMouseEvent *pMouseEvent)
static const int MARGIN
void setCurrentPositionX(double x)
std::multiset< CLGraphicalObject *, compareGraphicalObjectsBySize > removeTextGlyphs(std::multiset< CLGraphicalObject *, compareGraphicalObjectsBySize > &hits)
CQGLLayoutPainter(const QGLFormat &format, QWidget *parent=0)
#define GL_FRAMEBUFFER_UNSUPPORTED_EXT
Definition: glext.h:4201
PFNGLRENDERBUFFERSTORAGEEXT glRenderbufferStorageEXTPtr
const CLPoint & getBase1() const
Definition: CLCurve.h:82
void resize(GLsizei w, GLsizei h)
void setSelectionBox(const CLBoundingBox *pBox)
void destroy_buffers(GLuint &fbo, GLuint *rbuffers, GLuint &multiFBO, GLuint *multiRBuffers)
static void clearDeque()
bool getHighlightFlag() const
#define MCCopasiMessage
void setCurrentPositionY(double y)
void setFogDensity(GLfloat dens)
#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT
Definition: glext.h:4197
double getZoomFactor() const
double getCurrentWidth() const
const CLDimensions & getDimensions() const
Definition: CLBase.h:266
void setHeight(const C_FLOAT64 &h)
Definition: CLBase.h:220
void setZoomFactor(double zoomFactor)
static StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=Ok, StandardButton defaultButton=NoButton)
const GLfloat * getHighlightColor() const
const CLPoint & getBase2() const
Definition: CLCurve.h:83
void setHighlightColor(const GLfloat c[4])
const CLPoint & getEnd() const
Definition: CLCurve.h:75
void addToSelection(CLGraphicalObject *pObject)
void setMinY(double y)
void setImageTexturizer(CLImageTexturizer *pTexturizer)
PFNGLFRAMEBUFFERRENDERBUFFEREXT glFramebufferRenderbufferEXTPtr
const C_FLOAT64 & getX() const
Definition: CLBase.h:83
Definition: CLBase.h:54
void setHighlightedObjects(const std::set< const CLGraphicalObject * > &highlightedObjects)
const CLPoint & getPosition() const
Definition: CLBase.h:265
void setZoomFactor(double)
void change_style(const CLRenderInformationBase *pRenderInfo, bool defaultStyle=false)
double getAspect() const
void(* PFNGLGENFRAMEBUFFERSEXT)(GLsizei n, GLuint *framebuffers)
bool getHighlightFlag() const
static CLCurve * revert_curve(const CLCurve *pCurve)
void setFogColor(const GLfloat c[4])
CLBoundingBox calculateBoundingBox() const
Definition: CLayout.cpp:684
virtual void resizeGL(int w, int h)
void setFogColor(const GLfloat c[4])
GLubyte * export_bitmap(double x, double y, double width, double height, unsigned int imageWidth, unsigned int imageHeight, bool drawSelection)
CListOfLayouts * getListOfLayouts()
void(* PFNGLBINDFRAMEBUFFEREXT)(GLenum target, GLuint framebuffer)
void removeFromSelection(CLGraphicalObject *pObject)
void setMaxX(double x)
PFNGLCHECKFRAMEBUFFERSTATUSEXT glCheckFramebufferStatusEXTPtr
virtual void paintGL()
PFNGLDELETERENDERBUFFERSEXT glDeleteRenderbuffersEXTPtr
Qt::MouseButton mMouseButton
#define GL_RENDERBUFFER_EXT
Definition: glext.h:4222
long int flag
Definition: f2c.h:52
unsigned int getViewportWidth() const
#define GL_DRAW_FRAMEBUFFER_EXT
Definition: glext.h:4274
std::pair< double, double > convert_to_model_space(double x, double y) const
PFNGLDELETEFRAMEBUFFERSEXT glDeleteFramebuffersEXTPtr
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT
Definition: glext.h:4195
const C_FLOAT64 & getY() const
Definition: CLBase.h:84
#define GL_MAX_SAMPLES_EXT
Definition: glext.h:4282
void change_style(const CLGlobalRenderInformation *pRenderInformation, bool defaultStyle=false)
double maxX() const
const GLfloat * getFogColor() const
bool isBezier() const
Definition: CLCurve.h:90
void setFogDensity(GLfloat dens)
void singleCurveSelected(bool)
static StandardButton critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=Ok, StandardButton defaultButton=NoButton)
double getZoomFactor() const
const C_FLOAT64 & getHeight() const
Definition: CLBase.h:212
std::vector< CLGraphicalObject * > getObjectsInBoundingBox(double lx, double ly, double rx, double ry, bool partial=true)
void(* PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXT)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height)
#define GL_FRAMEBUFFER_EXT
Definition: glext.h:4221
const CLLineSegment * getSegmentAt(size_t i) const
Definition: CLCurve.h:156
bool isSelected(const CLGraphicalObject *) const
virtual void moveBy(const CLPoint &p)
Definition: CLayout.cpp:909
GLfloat getFogDensity() const
PFNGLBINDFRAMEBUFFEREXT glBindFramebufferEXTPtr
void setAspect(double aspect)
virtual void mouseReleaseEvent(QMouseEvent *pMouseEvent)
void setHighlightFlag(bool flag)
PFNGLBINDRENDERBUFFEREXT glBindRenderbufferEXTPtr
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT
Definition: glext.h:4196
GLenum(* PFNGLCHECKFRAMEBUFFERSTATUSEXT)(GLenum target)
std::set< CLGraphicalObject * > & getSelection()
double minY() const
void(* PFNGLRENDERBUFFERSTORAGEEXT)(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
void set_font_renderer(CLFontRendererBase *pFontRenderer)
#define GL_READ_FRAMEBUFFER_EXT
Definition: glext.h:4273
void setMaxY(double y)
std::set< CLGraphicalObject * > getSelection()
void(* PFNGLDELETERENDERBUFFERSEXT)(GLsizei n, GLuint *renderbuffers)
double getAspect() const
bool draw_bitmap(double x, double y, double width, double height, unsigned int imageWidth, unsigned int imageHeight, GLuint &fbo, GLuint &multiFBO, GLuint **rbuffers, GLuint **multiRBuffers, GLubyte **pImageData, GLuint samples=0)
const CLCurve & getCurve() const
size_t getNumCurveSegments() const
Definition: CLCurve.h:168
unsigned int mViewportWidth
const CLDimensions & getDimensions() const
Definition: CLayout.h:76
const CLPoint & getStart() const
Definition: CLCurve.h:74
void setWidth(const C_FLOAT64 &w)
Definition: CLBase.h:219
void setHighlightedObjects(const std::set< const CLGraphicalObject * > &highlightedObjects)
CLLayoutRenderer * mpRenderer
void(* PFNGLBINDRENDERBUFFEREXT)(GLenum target, GLuint renderbuffer)
const CCopasiVector< CLGlobalRenderInformation > & getListOfGlobalRenderInformationObjects() const
#define max(a, b)
Definition: f2c.h:176