1 /**********************************************************************
2 GLWidget - general OpenGL display
4 Copyright (C) 2006,2007 Geoffrey R. Hutchison
5 Copyright (C) 2006,2007 Donald Ephraim Curtis
6 Copyright (C) 2007 Marcus D. Hanwell
8 This file is part of the Avogadro molecular editor project.
9 For more information, see <http://avogadro.sourceforge.net/>
11 Avogadro is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 Avogadro is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 **********************************************************************/
30 #include <avogadro/global.h>
31 #include <avogadro/engine.h>
32 #include <avogadro/tool.h>
33 #include <avogadro/color.h>
34 #include <avogadro/painter.h>
35 #include <avogadro/camera.h>
50 * @class GLHit glwidget.h <avogadro/glwidget.h>
51 * @brief Class for wrapping hits from GL picking.
52 * @author Donald Ephraim Curtis
54 * Provides an easy to use class to contain OpenGL hits returned from the
55 * process of picking. This class relies on the %Engine subclasses properly
56 * naming the objects that they are rendering. For more information see the
57 * Engine documentation.
70 GLHit(const GLHit
&glHit
);
73 * @param type The type of the OpenGL object that was picked which corresponds
74 * to the Primitive::Type for the object
75 * (ie. type==Primitive::AtomType means an Atom was picked).
76 * @param name The name of the OpenGL object that was picked corresponding
77 * to the primitive index
78 * (ie. name==1 means Atom 1).
80 GLHit(GLuint type
, GLuint name
, GLuint minZ
, GLuint maxZ
);
88 * @param other the other GLHit object to compare to.
89 * @return (this->minZ < other->minZ) ? @c true : @c false
91 bool operator<(const GLHit
&other
) const;
94 * Equivalence operator.
95 * @param other the other GLHit object to test equivalence with.
96 * @return returns true if all elements are equivalent (type, name, minZ, maxZ).
98 bool operator==(const GLHit
&other
) const;
102 * @param other the GLHit object to set this object equal to.
105 GLHit
&operator=(const GLHit
&other
);
108 * @return type of the object that was picked.
113 * @return name of the object that was picked.
118 * @return the minimum z value of this hit corresponding
119 * to the z value of the drawn object closest to the camera.
124 * @return the maximum z value of this hit corresponding
125 * to the z value of the drawn object farthest from the camera.
130 * @param type new object type.
132 void setType(GLuint type
);
134 * @param name new object name.
136 void setName(GLuint name
);
138 * @param minZ minimum z value to set for this object.
140 void setMinZ(GLuint minZ
);
142 * @param maxZ maximum z value to set for this object.
144 void setMaxZ(GLuint maxZ
);
147 GLHitPrivate
* const d
;
151 * @class GLWidget glwidget.h <avogadro/glwidget.h>
152 * @brief GL widget class for rendering molecules.
153 * @author Donald Ephraim Curtis
154 * @author Marcus D. Hanwell
156 * This widget provides a 3D graphical view of a molecule. In terms
157 * of the Model-View architecture we consider
158 * the Molecule the model and GLWidget a view of this model.
159 * The widget relies on various Engine subclasses to handle the
160 * rendering of the 3d objects.
162 * Each engine is allocated a PrimitiveList object. This queue contains
163 * all primitivew which that engine is responsible for rendering for this
164 * GLWidget. Thus, we can have one queue containing only the bonds, and
165 * one queue containing only the atoms which would allow bonds and atoms
166 * to be rendered by two different engines.
169 class GLWidgetPrivate
;
170 class GLPainterDevice
;
171 class A_EXPORT GLWidget
: public QGLWidget
173 friend class GLThread
;
176 Q_PROPERTY(QColor background READ background WRITE setBackground
)
177 // Q_PROPERTY(float scale READ scale WRITE setScale)
182 * @param parent the widget parent.
184 GLWidget(QWidget
*parent
= 0);
188 * @param format the QGLFormat information.
189 * @param parent the widget parent.
191 explicit GLWidget(const QGLFormat
&format
, QWidget
*parent
= 0, const GLWidget
* shareWidget
= 0);
195 * @param molecule the molecule to view.
196 * @param format the QGLFormat information.
197 * @param parent the widget parent.
199 GLWidget(Molecule
*molecule
, const QGLFormat
&format
, QWidget
*parent
= 0, const GLWidget
* shareWidget
= 0);
207 * @return true if the GLWidget is stable as determined
208 * by the tools and extensions.
210 bool isStable() const;
213 * @param stable the new stable value.
215 void setStable(bool stable
);
218 * @return the width of the widget in pixels.
220 int deviceWidth() { return width(); }
223 * @return the height of the widget in pixels.
225 int deviceHeight() { return height(); }
228 * Virtual function setting the size hint for this widget.
230 * @return the preferred size of the widget.
232 QSize
sizeHint() const;
235 * Virtual function setting the minimum size hit for this widget.
237 * @return the minimum size the widget can take without causing
238 * unspecified behaviour.
240 QSize
minimumSizeHint() const;
243 * @return the radius of the primitive object for this glwidget.
245 double radius(const Primitive
*p
) const;
248 * @return the active Tool.
253 * @return the ToolGroup manager.
255 ToolGroup
toolManger() const;
258 * @return the current background color of the rendering area.
260 QColor
background() const;
263 * Set the current global color map for Primitives.
265 void setColorMap(Color
*);
268 * @return the current global color map for Primitives.
270 Color
*colorMap() const;
273 * @param undoStack the new undoStack.
275 void setUndoStack(QUndoStack
*undoStack
);
278 * @return the current GLWidget undoStack.
280 QUndoStack
* undoStack() const;
283 * @return the current Molecule being viewed.
285 const Molecule
* molecule() const;
288 * @return the current Molecule being viewed.
290 Molecule
* molecule();
293 * update the Molecule geometry.
295 void updateGeometry();
298 * @return a pointer to the Camera of this widget.
300 Camera
* camera() const;
303 * @return a list of engines.
305 QList
<Engine
*> engines() const;
308 * @return a list of the engine factories.
310 QList
<EngineFactory
*> engineFactories() const;
313 * Get the hits for a region starting at (x, y) of size (w * h).
315 QList
<GLHit
> hits(int x
, int y
, int w
, int h
);
318 * Take a point and figure out which is the closest Primitive under that point.
319 * @param p the point on the widget that was clicked.
320 * @return the closest Primitive that was clicked or 0 if nothing.
322 Primitive
* computeClickedPrimitive(const QPoint
& p
);
325 * Take a point and figure out which is the closest Atom under that point.
326 * @param p the point on the widget that was clicked.
327 * @return the closest Atom that was clicked or 0 if nothing.
329 Atom
* computeClickedAtom(const QPoint
& p
);
332 * Take a point and figure out which is the closest Bond under that point.
333 * @param p the point on the widget that was clicked.
334 * @return the closest Bond that was clicked or 0 if nothing.
336 Bond
* computeClickedBond(const QPoint
& p
);
339 * @return the point at the center of the Molecule.
341 const Eigen::Vector3d
& center() const;
343 * @return the normalVector for the entire Molecule.
345 const Eigen::Vector3d
& normalVector() const;
347 * @return the radius of the Molecule.
349 const double & radius() const;
351 * @return the Atom farthest away from the camera.
353 const Atom
*farthestAtom() const;
356 * @param quality set the global quality of the widget.
358 void setQuality(int quality
);
360 * @return the global quality of the widget.
365 * Set to render x, y, z axes as an overlay in the bottom left of the widget.
367 void setRenderAxes(bool renderAxes
);
370 * @return true if the x, y, z axes are being rendered.
375 * Set to render the "debug info" (i.e., FPS, number of atoms, etc.)
377 void setRenderDebug(bool renderDebug
);
380 * @return true if the debug panel is being drawn
385 * Set the ToolGroup of the GLWidget.
387 void setToolGroup(ToolGroup
*toolGroup
);
390 * @return the ToolGroup of the GLWidget.
392 ToolGroup
* toolGroup() const;
394 /** Returns the Painter of this widget. For instance, to draw a sphere in this
395 * widget, you could do:
397 painter()->drawSphere(center, radius)
401 Painter
*painter() const;
404 * @return list of primitives for this widget
406 PrimitiveList
primitives() const;
408 /** @name Selection Methods
409 * These methods are used to manipulate user-selected primitives.
410 * Each view tracks a list of selected objects (e.g., atoms)
411 * which can be passed to engines, tools, or used for tasks like
412 * copying selected atoms, etc.
417 * @return the current selected primitives (all Primitive types)
419 PrimitiveList
selectedPrimitives() const;
422 * Toggle the selection for the atoms in the supplied list.
423 * That is, if the primitive is selected, deselect it and vice-versa.
425 * @param primitives the set of objects to update.
427 void toggleSelected(PrimitiveList primitiveList
);
430 * Change the selection status for the atoms in the supplied list.
431 * All objects in the list will have the same selection status.
433 * @param primitives the set of objects to update.
434 * @param select whether to select or deselect the objects.
436 void setSelected(PrimitiveList primitives
, bool select
= true);
439 * Deselect all objects.
441 void clearSelected();
444 * @return true if the Primitive is selected.
446 bool isSelected(const Primitive
*p
) const;
447 /* end selection method grouping */
451 * Set the number of unit cells for a periodic molecule like a crystal
452 * a, b, and c, are the three primitive unit cell axes.
453 * Does nothing if the molecule does not have a unit cell defined.
455 * @param a number of unit cells to display along the a axis.
456 * @param b number of unit cells to display along the b axis.
457 * @param c number of unit cells to display along the c axis.
459 void setUnitCells(int a
, int b
, int c
);
462 * @return the number of unit cells to display along the a axis.
467 * @return the number of unit cells to display along the b axis.
472 * @return the number of unit cells to display along the c axis.
477 * Static pointer to the current GLWidget.
479 static GLWidget
*m_current
;
482 * @return a pointer to the current GLWidget.
484 static GLWidget
*current();
487 * Set this instance of the GLWidget as the current GLWidget instance.
489 static void setCurrent(GLWidget
*current
);
492 * Write the settings of the GLWidget in order to save them to disk.
494 virtual void writeSettings(QSettings
&settings
) const;
497 * Read the settings of the GLWidget and restore them.
499 virtual void readSettings(QSettings
&settings
);
504 * Virtual function called by QGLWidget on initialization of
507 virtual void initializeGL();
510 * Virtual function called by GLWidget before render() to set up the
513 virtual void paintGL();
516 * Virtual function called when the GL area needs repainting.
518 virtual void paintEvent(QPaintEvent
*event
);
521 * Called on resize of the GLWidget to perform resizing of the display.
523 virtual void resizeEvent(QResizeEvent
*event
);
526 * Virtual function called whn the GL area is resized
528 virtual void resizeGL(int, int);
533 virtual bool event(QEvent
*event
);
536 * Virtual function reaction to mouse press in the GL rendering area.
538 virtual void mousePressEvent(QMouseEvent
* event
);
541 * Virtual function reaction to mouse release in the GL rendering area.
543 virtual void mouseReleaseEvent(QMouseEvent
* event
);
546 * Virtual function reaction to mouse being moved in the GL rendering area.
548 virtual void mouseMoveEvent(QMouseEvent
* event
);
551 * Virtual function reaction to mouse while in the GL rendering area.
553 virtual void wheelEvent(QWheelEvent
* event
);
556 * Render the scene. To be used in both modes GL_RENDER and GL_SELECT.
557 * This function calls the render functions of the engines as well as the
558 * paint events of the tools and is where everything drawn onto the widget
561 virtual void render();
564 * Render a full crystal cell
565 * Called by render() automatically
567 * @param displayList the display list of the primitive unit cell
569 virtual void renderCrystal(GLuint displayList
);
572 * Render crystal unit cell axes
573 * called by renderCrystal() automatically
576 virtual void renderCrystalAxes();
579 * Render x, y, z axes as an overlay on the bottom left of the widget.
581 virtual void renderAxesOverlay();
584 * Render a debug overlay with extra debug information on the GLWidget.
586 virtual void renderDebugOverlay();
589 * Helper function to load all engine factories.
591 void loadEngineFactories();
594 * This will return a painting condition that must be met each time
595 * before a GLThread can run.
597 * @return painting condition.
599 // QWaitCondition *paintCondition() const;
603 GLWidgetPrivate
* const d
;
606 * Helper function called by all constructors.
608 void constructor(const GLWidget
*shareWidget
=0);
611 * Compute the average frames per second over the last 200+ ms.
613 inline double computeFramesPerSecond();
618 * Set the active Tool of the GLWidget.
620 void setTool(Tool
*tool
);
623 * Add the primitive to the widget. This slot is called whenever
624 * a new primitive is added to our molecule model. It adds the
625 * primitive to the list in the appropriate group.
627 * @param primitive pointer to a primitive to add to the view
629 void addPrimitive(Primitive
*primitive
);
632 * Update a primitive. This slot is called whenever a primitive of our
633 * molecule model has been changed and we need to check our view.
635 * @note In some cases we are passed the molecule itself meaning that more
636 * than one thing has changed in the molecule.
638 * @param primitive object which changed.
640 void updatePrimitive(Primitive
*primitive
);
642 /** Remove a primitive. This slot is called whenever a primitive of our
643 * molecule model has been removed and we need to take it off our list.
644 * Additionally we need to update other items in our view that are impacted
647 * @param primitive object to remove.
649 void removePrimitive(Primitive
*primitive
);
652 * Set the background color of the rendering area (the default is black).
654 * @param background the new background color.
656 void setBackground(const QColor
&background
);
659 * Set the molecule model for this view.
660 * @param molecule the molecule to view.
662 void setMolecule(Molecule
*molecule
);
665 * @param engine Engine to add to this widget.
667 void addEngine(Engine
*engine
);
670 * @param engine Engine to remove from this widget.
672 void removeEngine(Engine
*engine
);
675 * Reset to default engines (one of each factory).
677 void loadDefaultEngines();
680 * Signal that something changed and the display lists should be invalidated.
682 void invalidateDLs();
686 * Signal for the mouse press event which is passed to the engines and tools.
688 void mousePress(QMouseEvent
* event
);
691 * Signal for the mouse release event which is passed to the engines and tools.
693 void mouseRelease( QMouseEvent
* event
);
696 * Signal for the mouse move event which is passed to the engines and tools.
698 void mouseMove( QMouseEvent
* event
);
701 * Signal for the mouse wheel event which is passed to the engines and tools.
703 void wheel( QWheelEvent
* event
);
706 * Signal that the Molecule has changed.
708 void moleculeChanged(Molecule
*previous
, Molecule
*next
);
711 * Signal that an Engine has been added to the GLWidget.
713 void engineAdded(Engine
*engine
);
716 * Signal that an Engine has been removed from the GLWidget.
718 void engineRemoved(Engine
*engine
);
722 } // end namespace Avogadro