/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Copyright (C) 2013 Frederik Heber. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * MoleCuilder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * GLWorldView.cpp * * Created on: Aug 1, 2010 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "GLWorldView.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include "GLWorldScene.hpp" #include "CodePatterns/MemDebug.hpp" #include "Atom/AtomObserver.hpp" #include "Atom/atom_observable.hpp" #include "Box.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Observer/Notification.hpp" #include "CodePatterns/Observer/ObserverLog.hpp" #include "Descriptors/MoleculeIdDescriptor.hpp" #include "molecule.hpp" #include "Shapes/ShapeRegistry.hpp" #include "World.hpp" #include "WorldTime.hpp" GLWorldView::GLWorldView(QWidget *parent) : QGLView(parent), Observer("GLWorldView"), worldscene(NULL), changesPresent(false), needsRedraw(false) { worldscene = new GLWorldScene(this); setOption(QGLView::ObjectPicking, true); setOption(QGLView::CameraNavigation, false); setFocusPolicy(Qt::StrongFocus); setCameraControlMode(Rotate); defaultEyeSeparation = 4.0; createDomainBox(); createDreiBein(); //changeMaterials(false); qRegisterMetaType("atomId_t"); qRegisterMetaType("moleculeId_t"); connect(this, SIGNAL(ShapeAdded(const std::string &)), worldscene, SLOT(addShape(const std::string &))); connect(this, SIGNAL(ShapeRemoved(const std::string &)), worldscene, SLOT(removeShape(const std::string &))); // connect(this, SIGNAL(TimeChanged()), worldscene, SIGNAL(updated())); connect(worldscene, SIGNAL(changeOccured()), this, SLOT(changeSignalled())); connect(worldscene, SIGNAL(changed()), this, SIGNAL(changed())); connect(worldscene, SIGNAL(hoverChanged(const atomId_t)), this, SLOT(sceneHoverSignalled(const atomId_t))); connect(worldscene, SIGNAL(hoverChanged(const moleculeId_t, int)), this, SLOT(sceneHoverSignalled(const moleculeId_t, int))); connect(this, SIGNAL(atomRemoved(const moleculeId_t, const atomId_t)), worldscene, SLOT(atomRemoved(const moleculeId_t, const atomId_t)), Qt::DirectConnection); connect(this, SIGNAL(atomInserted(const moleculeId_t, const atomId_t)), worldscene, SLOT(atomInserted(const moleculeId_t, const atomId_t)), Qt::DirectConnection); connect(this, SIGNAL(moleculeInserted(const moleculeId_t)), worldscene, SLOT(moleculePrepareInserted(const moleculeId_t)), Qt::DirectConnection); connect(this, SIGNAL(moleculeRemoved(const moleculeId_t)), worldscene, SLOT(moleculePrepareRemoved(const moleculeId_t)), Qt::DirectConnection); //connect(this, SIGNAL(changed()), this, SLOT(updateGL())); connect(this, SIGNAL(changed()), this, SLOT(sceneChangeSignalled())); connect(this, SIGNAL(moleculesVisibilityChanged(const moleculeId_t,bool)), worldscene, SLOT(moleculesVisibilityChanged(const moleculeId_t,bool))); // sign on to changes in the world World::getInstance().signOn(this); World::getInstance().signOn(this, World::MoleculeInserted); World::getInstance().signOn(this, World::SelectionChanged); // WorldTime::getInstance().signOn(this, WorldTime::TimeChanged); AtomObserver::getInstance().signOn(this, AtomObservable::PositionChanged); ShapeRegistry::getInstance().signOn(this); ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeInserted); ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeRemoved); ShapeRegistry::getInstance().signOn(this, ShapeRegistry::SelectionChanged); redrawTimer = new QTimer(this); } GLWorldView::~GLWorldView() { // remove me from all observed molecules for (ObservedMolecules_t::iterator iter = ObservedMolecules.begin(); !ObservedMolecules.empty(); iter = ObservedMolecules.begin()) signOffFromMolecule(*iter); QSettings settings; settings.beginGroup("WorldView"); settings.setValue("domainBoxEnabled", (meshDomainBox->options() & QGLSceneNode::HideNode) == 0); settings.setValue("dreiBeinEnabled", (meshDreiBein->options() & QGLSceneNode::HideNode) == 0); settings.endGroup(); World::getInstance().signOff(this); World::getInstance().signOff(this, World::MoleculeInserted); World::getInstance().signOff(this, World::SelectionChanged); // WorldTime::getInstance().signOff(this, WorldTime::TimeChanged); AtomObserver::getInstance().signOff(this, AtomObservable::PositionChanged); ShapeRegistry::getInstance().signOff(this); ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeInserted); ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeRemoved); ShapeRegistry::getInstance().signOff(this, ShapeRegistry::SelectionChanged); delete worldscene; delete(domainBoxMaterial); for (int i=0;i<3;i++) delete(dreiBeinMaterial[i]); } /** * Add some widget specific actions to the toolbar: * - camera rotation/translation mode * - camera fit to domain */ void GLWorldView::addToolBarActions(QToolBar *toolbar) { // camera control mode toolbar->addSeparator(); QAction *transAction = new QAction(QIcon::fromTheme("forward"), tr("camera translation mode"), this); connect(transAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeTranslation())); toolbar->addAction(transAction); QAction *rotAction = new QAction(QIcon::fromTheme("object-rotate-left"), tr("camera rotation mode"), this); connect(rotAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeRotation())); toolbar->addAction(rotAction); QAction *fitAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("camera fit to domain"), this); connect(fitAction, SIGNAL(triggered()), this, SLOT(fitCameraToDomain())); toolbar->addAction(fitAction); // stereo mode QToolButton *stereoButton = new QToolButton(toolbar); QMenu *stereoMenu = new QMenu(); QAction *stereoDisableAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("disable"), this); connect(stereoDisableAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeDisable())); stereoMenu->addAction(stereoDisableAction); QAction *stereoHardwareAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("hardware"), this); connect(stereoHardwareAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeHardware())); stereoMenu->addAction(stereoHardwareAction); QAction *stereoLeftRightAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("left right"), this); connect(stereoLeftRightAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeLeftRight())); stereoMenu->addAction(stereoLeftRightAction); QAction *stereoRightLeftAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("right left"), this); connect(stereoRightLeftAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeRightLeft())); stereoMenu->addAction(stereoRightLeftAction); QAction *stereoTopBottomAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("top bottom"), this); connect(stereoTopBottomAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeTopBottom())); stereoMenu->addAction(stereoTopBottomAction); QAction *stereoBottomTopAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("bottom top"), this); connect(stereoBottomTopAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeBottomTop())); stereoMenu->addAction(stereoBottomTopAction); QAction *stereoAnaglyphAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("anaglyph"), this); connect(stereoAnaglyphAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeAnaglyph())); stereoMenu->addAction(stereoAnaglyphAction); stereoButton->setMenu(stereoMenu); stereoButton->setIcon(QIcon(QPixmap(":/icon_view_stereo.png"))); stereoButton->setPopupMode(QToolButton::InstantPopup); toolbar->addWidget(stereoButton); // selection mode toolbar->addSeparator(); QAction *selAtomAction = new QAction(QIcon(QPixmap(":/icon_select_atom.png")), tr("select atom by clicking"), this); connect(selAtomAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeAtom())); toolbar->addAction(selAtomAction); QAction *selMolAction = new QAction(QIcon(QPixmap(":/icon_select_molecule.png")), tr("select molecule by clicking"), this); connect(selMolAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeMolecule())); toolbar->addAction(selMolAction); // dreiBein/domain enabler toolbar->addSeparator(); QAction *seldreiBein = new QAction(QIcon(QPixmap(":/icon_dreiBein.png")), tr("enable/disable dreiBein"), this); connect(seldreiBein, SIGNAL(triggered()), this, SLOT(changeDreiBein())); toolbar->addAction(seldreiBein); QAction *seldomain = new QAction(QIcon(QPixmap(":/icon_domain.png")), tr("enable/disable domain box"), this); connect(seldomain, SIGNAL(triggered()), this, SLOT(changeDomain())); toolbar->addAction(seldomain); } void GLWorldView::createDomainBox() { QSettings settings; settings.beginGroup("WorldView"); QColor colorFrame = settings.value("domainBoxColorFrame", QColor(150,160,200,255)).value(); QColor colorAmbient = settings.value("domainBoxColorAmbient", QColor(50,60,100,255)).value(); QColor colorDiffuse = settings.value("domainBoxColorDiffuse", QColor(150,160,200,180)).value(); settings.setValue("domainBoxColorFrame", colorFrame); settings.setValue("domainBoxColorAmbient", colorAmbient); settings.setValue("domainBoxColorDiffuse", colorDiffuse); const bool status = settings.value("domainBoxEnabled").toBool(); settings.endGroup(); domainBoxMaterial = new QGLMaterial; domainBoxMaterial->setAmbientColor(QColor(0,0,0,255)); domainBoxMaterial->setDiffuseColor(QColor(0,0,0,255)); domainBoxMaterial->setEmittedLight(colorFrame); QGLMaterial *material = new QGLMaterial; material->setAmbientColor(colorAmbient); material->setDiffuseColor(colorDiffuse); QGLBuilder builder; builder << QGL::Faceted; builder << QGLCube(-1.0); // "inverted" => inside faces are used as front. meshDomainBox = builder.finalizedSceneNode(); QMatrix4x4 mat; mat.translate(0.5f, 0.5f, 0.5f); meshDomainBox->setLocalTransform(mat); meshDomainBox->setMaterial(material); setDomainStatus( status ); } void GLWorldView::createDreiBein() { QSettings settings; settings.beginGroup("WorldView"); QColor colorX = settings.value("dreiBeinColorX", QColor(255,50,50,255)).value(); QColor colorY = settings.value("dreiBeinColorY", QColor(50,255,50,255)).value(); QColor colorZ = settings.value("dreiBeinColorZ", QColor(50,50,255,255)).value(); settings.setValue("dreiBeinColorX", colorX); settings.setValue("dreiBeinColorY", colorY); settings.setValue("dreiBeinColorZ", colorZ); const bool status = settings.value("dreiBeinEnabled").toBool(); settings.endGroup(); // Create 3 color for the 3 axes. dreiBeinMaterial[0] = new QGLMaterial; dreiBeinMaterial[0]->setColor(colorX); dreiBeinMaterial[1] = new QGLMaterial; dreiBeinMaterial[1]->setColor(colorY); dreiBeinMaterial[2] = new QGLMaterial; dreiBeinMaterial[2]->setColor(colorZ); // Create the basic meshes (cylinder and cone). QGLBuilder builderCyl; builderCyl << QGLCylinder(.15,.15,1.6,16); QGLSceneNode *cyl = builderCyl.finalizedSceneNode(); QGLBuilder builderCone; builderCone << QGLCylinder(0,.4,0.4,16); QGLSceneNode *cone = builderCone.finalizedSceneNode(); { QMatrix4x4 mat; mat.translate(0.0f, 0.0f, 1.0f); cone->setLocalTransform(mat); } // Create a scene node from the 3 axes. meshDreiBein = new QGLSceneNode(this); // X-direction QGLSceneNode *node = new QGLSceneNode(meshDreiBein); node->setMaterial(dreiBeinMaterial[0]); node->addNode(cyl); node->setPosition(QVector3D(.8f, 0.f, 0.f)); node->addNode(cone); { QMatrix4x4 mat; mat.rotate(90, 0.0f, 1.0f, 0.0f); node->setLocalTransform(mat); } // Y-direction node = new QGLSceneNode(meshDreiBein); node->setMaterial(dreiBeinMaterial[1]); node->addNode(cyl); node->addNode(cone); { QMatrix4x4 mat; mat.rotate(-90, 1.0f, 0.0f, 0.0f); node->setLocalTransform(mat); } node->setPosition(QVector3D(0.f, .8f, 0.f)); // Z-direction node = new QGLSceneNode(meshDreiBein); node->setMaterial(dreiBeinMaterial[2]); node->addNode(cyl); node->addNode(cone); node->setPosition(QVector3D(0.f, 0.f, .8f)); setdreiBeinStatus( status ); } void GLWorldView::setSelectionChangedAgent(QtSelectionChangedAgent *agent) { worldscene->setSelectionChangedAgent(agent); } /** * Update operation which can be invoked by the observable (which should be the * change tracker here). */ void GLWorldView::update(Observable *publisher) { // emit changed(); } void GLWorldView::signOnToMolecule(const molecule *_mol) { ASSERT( _mol != NULL, "GLWorldView::signOnToMolecule() - molecule ref is NULL."); _mol->signOn(this, molecule::AtomInserted); _mol->signOn(this, molecule::AtomRemoved); ObservedMolecules.insert(const_cast(_mol)); } void GLWorldView::signOffFromMolecule(const molecule *_mol) { ObservedMolecules_t::const_iterator iter = ObservedMolecules.find( const_cast(_mol)); ASSERT( iter != ObservedMolecules.end(), "GLWorldView::signOffFromMolecule() - molecule "+toString(_mol) +" gave subjectKilled we are not signed on."); // LOG(1, "INFO: Erasing " << mol << " from ObservedMolecules."); ObservedMolecules.erase(iter); ASSERT( _mol != NULL, "GLWorldView::signOffFromMolecule() - molecule ref is NULL."); _mol->signOff(this, molecule::AtomInserted); _mol->signOff(this, molecule::AtomRemoved); } /** * The observable can tell when it dies. */ void GLWorldView::subjectKilled(Observable *publisher) { molecule * mol = static_cast(publisher); // std::copy(ObservedMolecules.begin(), ObservedMolecules.end(), // std::ostream_iterator(std::cout, "\n")); if (mol != NULL) { // sign off signOffFromMolecule(mol); // emit removed signal const moleculeId_t _id = mol->getId(); emit moleculeRemoved(_id); } } /** Listen to specific changes to the world. * * @param publisher ref to observable. * @param notification type of notification */ void GLWorldView::recieveNotification(Observable *publisher, Notification_ptr notification) { if (static_cast(publisher) == World::getPointer()) { switch (notification->getChannelNo()) { case World::SelectionChanged: { #ifdef LOG_OBSERVER observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that selection has changed."; #endif emit worldSelectionChanged(); break; } case World::MoleculeInserted: { const moleculeId_t _id = const_cast(World::getInstance()).lastChangedMolId(); #ifdef LOG_OBSERVER observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that molecule "+toString(_id)+" has been inserted."; #endif const molecule * const _molecule = const_cast(World::getInstance()). getMolecule(MoleculeById(_id)); if (_molecule != NULL) { signOnToMolecule(_molecule); emit moleculeInserted(_id); } break; } default: ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for World."); break; } } else if (static_cast(publisher) == WorldTime::getPointer()) { switch (notification->getChannelNo()) { case WorldTime::TimeChanged: { #ifdef LOG_OBSERVER observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that WorldTime's time has changed."; #endif emit changed(); emit TimeChanged(); break; } default: ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for WorldTime."); break; } } else if (dynamic_cast(publisher) != NULL) { const molecule * mol = const_cast(dynamic_cast(publisher)); const moleculeId_t molid = mol->getId(); const atomId_t atomid = mol->lastChangedAtomId(); switch (notification->getChannelNo()) { case molecule::AtomInserted: { #ifdef LOG_OBSERVER observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that atom "+toString(atomid)+" has been inserted into molecule "+toString(molid)+"."; #endif emit atomInserted(molid, atomid); break; } case World::AtomRemoved: { #ifdef LOG_OBSERVER observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that atom "+toString(atomid)+" has been removed from molecule "+toString(molid)+"."; #endif emit atomRemoved(molid, atomid); break; } default: ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for molecule."); break; } } else if (dynamic_cast(publisher) != NULL) { switch (notification->getChannelNo()) { case AtomObservable::PositionChanged: { #ifdef LOG_OBSERVER const atom *_atom = dynamic_cast(publisher); observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that atom "+toString(_atom->getId())+" has changed its position."; #endif emit changed(); break; } default: ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for AtomObservable."); break; } } else if (static_cast(publisher) == ShapeRegistry::getPointer()) { switch (notification->getChannelNo()) { case ShapeRegistry::ShapeInserted: { emit ShapeAdded(ShapeRegistry::getInstance().lastChanged()->getName()); break; } case ShapeRegistry::ShapeRemoved: { emit ShapeRemoved(ShapeRegistry::getInstance().lastChanged()->getName()); break; } case ShapeRegistry::SelectionChanged: { worldscene->updateSelectedShapes(); break; } default: ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for ShapeRegistry."); break; } } } void GLWorldView::checkChanges() { updateGL(); needsRedraw = false; } void GLWorldView::changeDreiBein() { // invert to new status const bool status = ((meshDreiBein->options() & QGLSceneNode::HideNode) == 0); setdreiBeinStatus(!status); // realize updateGL(); needsRedraw = true; } void GLWorldView::setdreiBeinStatus(const bool status) { if (status) meshDreiBein->setOptions( meshDreiBein->options() & (255-QGLSceneNode::HideNode) ); else meshDreiBein->setOptions( meshDreiBein->options() | QGLSceneNode::HideNode ); } void GLWorldView::changeDomain() { // invert to new status const bool status = ((meshDomainBox->options() & QGLSceneNode::HideNode) == 0); setDomainStatus(!status); // realize updateGL(); needsRedraw = true; } void GLWorldView::setDomainStatus(const bool status) { if (status) meshDomainBox->setOptions( meshDomainBox->options() & (255-QGLSceneNode::HideNode) ); else meshDomainBox->setOptions( meshDomainBox->options() | QGLSceneNode::HideNode ); } void GLWorldView::sceneChangeSignalled() { if (!needsRedraw){ redrawTimer->singleShot(0, this, SLOT(checkChanges())); needsRedraw = true; redrawTimer->start(); } } void GLWorldView::initializeGL(QGLPainter *painter) { worldscene->initialize(this, painter); changesPresent = false; } void GLWorldView::paintGL(QGLPainter *painter) { if (changesPresent) { initializeGL(painter); changesPresent = false; } QVector3D cameraDir = camera()->center() - camera()->eye(); cameraDir.normalize(); QVector4D cameraPlane(cameraDir, QVector3D::dotProduct(cameraDir, camera()->eye())); worldscene->draw(painter, cameraPlane); drawDreiBein(painter); // Domain box has to be last because of its transparency. drawDomainBox(painter); } void GLWorldView::keyPressEvent(QKeyEvent *e) { // Find the distance between the eye and focus point. QVector3D d = camera()->eye() - camera()->center(); // LOG(1, "Distance vector eye and center is " // << d.x() << "," << d.y() << "," << d.z()); // scale the move unit by the eye <-> domain center distance const double key_move_unit = 0.04*(d.length()/50.); if (e->key() == Qt::Key_Tab) { // The Tab key turns the ShowPicking option on and off, // which helps show what the pick buffer looks like. setOption(QGLView::ShowPicking, ((options() & QGLView::ShowPicking) == 0)); updateGL(); } else if ((e->key() == Qt::Key_Minus) || (e->key() == Qt::Key_Plus)) { // Scale the distance. if (e->key() == Qt::Key_Minus) d *= 1.2; else if (e->key() == Qt::Key_Plus) d /= 1.2; // Set new eye position. camera()->setEye(camera()->center() + d); } else if ((e->key() == Qt::Key_Left) || (e->key() == Qt::Key_Right)) { // Translate the camera. const double d = (e->key() == Qt::Key_Left) ? -key_move_unit : key_move_unit; camera()->translateCenter( d, 0., 0); camera()->translateEye( d, 0., 0); } else if ((e->key() == Qt::Key_Up) || (e->key() == Qt::Key_Down)) { // Translate the camera. const double d = (e->key() == Qt::Key_Up) ? -key_move_unit : key_move_unit; camera()->translateCenter( 0., d, 0); camera()->translateEye( 0., d, 0); } else if ((e->key() == Qt::Key_PageUp) || (e->key() == Qt::Key_PageDown)) { // Translate the camera. const double d = (e->key() == Qt::Key_PageUp) ? -key_move_unit : key_move_unit; camera()->translateCenter( 0., 0., d); camera()->translateEye( 0., 0., d); } QGLView::keyPressEvent(e); } void GLWorldView::changeSignalled() { changesPresent = true; } /** * Set the current camera control mode. */ void GLWorldView::setCameraControlMode(GLWorldView::CameraControlModeType mode) { cameraControlMode = mode; } void GLWorldView::setCameraControlModeRotation() { setCameraControlMode(Rotate); } void GLWorldView::setCameraControlModeTranslation() { setCameraControlMode(Translate); } /** * Returns the current camera control mode. * This needs to be invertable (rotation - translation), if the shift key is pressed. */ GLWorldView::CameraControlModeType GLWorldView::getCameraControlMode(bool inverted) { if (inverted){ if (cameraControlMode == Rotate) return Translate; if (cameraControlMode == Translate) return Rotate; return Rotate; }else return cameraControlMode; } /** * Set the camera so it can oversee the whole domain. */ void GLWorldView::fitCameraToDomain() { // Move the camera focus point to the center of the domain box. Vector v = World::getInstance().getDomain().translateIn(Vector(0.5, 0.5, 0.5)); camera()->setCenter(QVector3D(v[0], v[1], v[2])); // Guess some eye distance. double dist = v.Norm() * 3; camera()->setEye(QVector3D(v[0], v[1], v[2] + dist)); camera()->setUpVector(QVector3D(0, 1, 0)); } void GLWorldView::setCameraStereoModeDisable() { setStereoType(QGLView::Hardware); camera()->setEyeSeparation(0.0); updateGL(); } void GLWorldView::setCameraStereoModeHardware() { setStereoType(QGLView::Hardware); camera()->setEyeSeparation(defaultEyeSeparation); updateGL(); } void GLWorldView::setCameraStereoModeLeftRight() { setStereoType(QGLView::LeftRight); camera()->setEyeSeparation(defaultEyeSeparation); updateGL(); } void GLWorldView::setCameraStereoModeRightLeft() { setStereoType(QGLView::RightLeft); camera()->setEyeSeparation(defaultEyeSeparation); updateGL(); } void GLWorldView::setCameraStereoModeTopBottom() { setStereoType(QGLView::TopBottom); camera()->setEyeSeparation(defaultEyeSeparation); updateGL(); } void GLWorldView::setCameraStereoModeBottomTop() { setStereoType(QGLView::BottomTop); camera()->setEyeSeparation(defaultEyeSeparation); updateGL(); } void GLWorldView::setCameraStereoModeAnaglyph() { setStereoType(QGLView::RedCyanAnaglyph); camera()->setEyeSeparation(defaultEyeSeparation); updateGL(); } void GLWorldView::mousePressEvent(QMouseEvent *event) { QGLView::mousePressEvent(event); // Reset the saved mouse position. lastMousePos = event->posF(); } /** * Handle a mouse move event. * This is used to control the camera (rotation and translation) when the left button is being pressed. */ void GLWorldView::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton){ // Find the mouse distance since the last event. QPointF d = event->posF() - lastMousePos; lastMousePos = event->posF(); // Rotate or translate? (inverted by shift key) CameraControlModeType mode = getCameraControlMode(event->modifiers() & Qt::ShiftModifier); if (mode == Rotate){ // Rotate the camera. d *= 0.3; camera()->tiltPanRollCenter(- d.y(), - d.x(), 0); }else if (mode == Translate){ // Translate the camera. d *= 0.02; camera()->translateCenter(- d.x(), d.y(), 0); camera()->translateEye(- d.x(), d.y(), 0); } }else{ // Without this Qt would not test for hover events (i.e. mouse over an atom). QGLView::mouseMoveEvent(event); } } /** * When the mouse wheel is used, zoom in or out. */ void GLWorldView::wheelEvent(QWheelEvent *event) { // Find the distance between the eye and focus point. QVector3D d = camera()->eye() - camera()->center(); // Scale the distance. if (event->delta() < 0) d *= 1.2; else if (event->delta() > 0) d /= 1.2; // Set new eye position. camera()->setEye(camera()->center() + d); } /** * Draw a transparent cube representing the domain. */ void GLWorldView::drawDomainBox(QGLPainter *painter) const { // Apply the domain matrix. RealSpaceMatrix m = World::getInstance().getDomain().getM(); painter->modelViewMatrix().push(); painter->modelViewMatrix() *= QMatrix4x4(m.at(0,0), m.at(0,1), m.at(0,2), 0.0, m.at(1,0), m.at(1,1), m.at(1,2), 0.0, m.at(2,0), m.at(2,1), m.at(2,2), 0.0, 0.0, 0.0, 0.0, 1.0); // Draw the transparent cube. painter->setStandardEffect(QGL::LitMaterial); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glEnable(GL_BLEND); glDepthMask(0); //glDisable(GL_DEPTH_TEST); meshDomainBox->draw(painter); //glEnable(GL_DEPTH_TEST); glDepthMask(1); glDisable(GL_BLEND); glDisable(GL_CULL_FACE); // Draw the outlines (if we have drawn the box itself) if ((meshDomainBox->options() & QGLSceneNode::HideNode) == 0) { painter->setFaceMaterial(QGL::AllFaces, domainBoxMaterial); //glEnable(GL_LINE_SMOOTH); QVector3DArray array; array.append(0, 0, 0); array.append(1, 0, 0); array.append(1, 0, 0); array.append(1, 1, 0); array.append(1, 1, 0); array.append(0, 1, 0); array.append(0, 1, 0); array.append(0, 0, 0); array.append(0, 0, 1); array.append(1, 0, 1); array.append(1, 0, 1); array.append(1, 1, 1); array.append(1, 1, 1); array.append(0, 1, 1); array.append(0, 1, 1); array.append(0, 0, 1); array.append(0, 0, 0); array.append(0, 0, 1); array.append(1, 0, 0); array.append(1, 0, 1); array.append(0, 1, 0); array.append(0, 1, 1); array.append(1, 1, 0); array.append(1, 1, 1); painter->clearAttributes(); painter->setVertexAttribute(QGL::Position, array); painter->draw(QGL::Lines, 24); } painter->modelViewMatrix().pop(); } void GLWorldView::drawDreiBein(QGLPainter *painter) { painter->modelViewMatrix().push(); painter->modelViewMatrix().translate(camera()->center()); painter->setStandardEffect(QGL::LitMaterial); painter->setFaceMaterial(QGL::FrontFaces, NULL); meshDreiBein->draw(painter); painter->modelViewMatrix().pop(); } void GLWorldView::sceneHoverSignalled(const atomId_t _id) { emit hoverChanged(_id); } void GLWorldView::sceneHoverSignalled(const moleculeId_t _id, int _i) { emit hoverChanged(_id, _i); }