/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * GLMoleculeObject.cpp * * This is based on the Qt3D example "teaservice", specifically meshobject.cpp. * * Created on: Aug 17, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "GLMoleculeObject.hpp" #include #include #include #include #include "CodePatterns/MemDebug.hpp" #include "CodePatterns/Assert.hpp" #include "CodePatterns/Log.hpp" #include "Helpers/defs.hpp" #include "Element/element.hpp" #include "Element/periodentafel.hpp" #include "World.hpp" GLMoleculeObject::ElementMaterialMap GLMoleculeObject::ElementNoMaterialMap; #include "CodePatterns/MemDebug.hpp" QGLMaterial *GLMoleculeObject::m_hoverMaterial = NULL; QGLMaterial *GLMoleculeObject::m_selectionMaterial = NULL; QGLMaterial *GLMoleculeObject::m_selectionBoxMaterial = NULL; GLMoleculeObject::GLMoleculeObject(QGLSceneNode *mesh, QObject *parent) : QObject(parent) { //mesh->setParent(this); m_mesh = mesh; m_scale = 1.0f; m_scaleZ = 1.0f; m_rotationAngle = 0.0f; m_effect = 0; m_objectId = -1; m_hovering = false; m_selected = false; m_material = 0; initStaticMaterials(); } GLMoleculeObject::GLMoleculeObject(QGLAbstractScene *scene, QObject *parent) : QObject(parent) { scene->setParent(this); m_mesh = scene->mainNode(); m_scale = 1.0f; m_scaleZ = 1.0f; m_rotationAngle = 0.0f; m_effect = 0; m_objectId = -1; m_hovering = false; m_selected = false; m_material = 0; initStaticMaterials(); } GLMoleculeObject::~GLMoleculeObject() { } void GLMoleculeObject::initialize(QGLView *view, QGLPainter *painter) { Q_UNUSED(painter); if (m_objectId != -1) view->registerObject(m_objectId, this); } /** Draws a box around the mesh. * */ void GLMoleculeObject::drawSelectionBox(QGLPainter *painter) { painter->setFaceMaterial(QGL::AllFaces, m_selectionBoxMaterial); QVector3DArray array; qreal radius = 1.0; array.append(-radius, -radius, -radius); array.append( radius, -radius, -radius); array.append( radius, -radius, -radius); array.append( radius, radius, -radius); array.append( radius, radius, -radius); array.append(-radius, radius, -radius); array.append(-radius, radius, -radius); array.append(-radius, -radius, -radius); array.append(-radius, -radius, radius); array.append( radius, -radius, radius); array.append( radius, -radius, radius); array.append( radius, radius, radius); array.append( radius, radius, radius); array.append(-radius, radius, radius); array.append(-radius, radius, radius); array.append(-radius, -radius, radius); array.append(-radius, -radius, -radius); array.append(-radius, -radius, radius); array.append( radius, -radius, -radius); array.append( radius, -radius, radius); array.append(-radius, radius, -radius); array.append(-radius, radius, radius); array.append( radius, radius, -radius); array.append( radius, radius, radius); painter->clearAttributes(); painter->setVertexAttribute(QGL::Position, array); painter->draw(QGL::Lines, 24); } void GLMoleculeObject::draw(QGLPainter *painter) { // Position the model at its designated position, scale, and orientation. painter->modelViewMatrix().push(); painter->modelViewMatrix().translate(m_position); if (m_scale != 1.0f) painter->modelViewMatrix().scale(m_scale); if (m_rotationAngle != 0.0f) painter->modelViewMatrix().rotate(m_rotationAngle, m_rotationVector); if (m_scaleZ != 1.0f) painter->modelViewMatrix().scale(1.0f, 1.0f, m_scaleZ); // Apply the material and effect to the painter. QGLMaterial *material; if (m_hovering) material = m_hoverMaterial; else if (m_selected) material = m_selectionMaterial; else material = m_material; ASSERT(material, "GLMoleculeObject::draw: chosen material is NULL"); painter->setColor(material->diffuseColor()); painter->setFaceMaterial(QGL::AllFaces, material); if (m_effect) painter->setUserEffect(m_effect); else painter->setStandardEffect(QGL::LitMaterial); // Mark the object for object picking purposes. int prevObjectId = painter->objectPickId(); if (m_objectId != -1) painter->setObjectPickId(m_objectId); // Draw the geometry mesh. m_mesh->draw(painter); // Draw a box around the mesh, if selected. if (m_selected) drawSelectionBox(painter); // Turn off the user effect, if present. if (m_effect) painter->setStandardEffect(QGL::LitMaterial); // Revert to the previous object identifier. painter->setObjectPickId(prevObjectId); // Restore the modelview matrix. painter->modelViewMatrix().pop(); } bool GLMoleculeObject::event(QEvent *e) { // Convert the raw event into a signal representing the user's action. if (e->type() == QEvent::MouseButtonPress) { QMouseEvent *me = (QMouseEvent *)e; if (me->button() == Qt::LeftButton) emit pressed(); } else if (e->type() == QEvent::MouseButtonRelease) { QMouseEvent *me = (QMouseEvent *)e; if (me->button() == Qt::LeftButton) { emit released(); if (me->x() >= 0) // Positive: inside object, Negative: outside. emit clicked(); } } else if (e->type() == QEvent::MouseButtonDblClick) { emit doubleClicked(); } else if (e->type() == QEvent::Enter) { m_hovering = true; emit hoverChanged(this); } else if (e->type() == QEvent::Leave) { m_hovering = false; emit hoverChanged(NULL); } return QObject::event(e); } /** Returns the ref to the Material for element No \a from the map. * * \note We create a new one if the element is missing. * * @param no element no * @return ref to QGLMaterial */ QGLMaterial* GLMoleculeObject::getMaterial(size_t no) { ASSERT( (no > 0) && (no < MAX_ELEMENTS), "GLMoleculeView::getMaterial() - Element no "+toString(no)+" is invalid."); if (ElementNoMaterialMap.find(no) != ElementNoMaterialMap.end()){ // get present one return ElementNoMaterialMap[no]; } else { // create new one LOG(1, "Creating new material for element "+toString(no)+"."); QGLMaterial *newmaterial = new QGLMaterial(NULL); // create material for element periodentafel *periode = World::getInstance().getPeriode(); const element *desiredelement = periode->FindElement(no); ASSERT(desiredelement != NULL, "GLMoleculeView::getMaterial() - desired element "+toString(no)+" not present in periodentafel."); const unsigned char* color = desiredelement->getColor(); LOG(1, "Creating new material with color " << (int)color[0] << "," << (int)color[1] << "," << (int)color[2] << "."); newmaterial->setAmbientColor( QColor((int)color[0], (int)color[1], (int)color[2]) ); newmaterial->setSpecularColor( QColor(60, 60, 60) ); newmaterial->setShininess( 128 ); ElementNoMaterialMap.insert( make_pair(no, newmaterial) ); return newmaterial; } } /** Create the 3 materials shared by all objects. * */ void GLMoleculeObject::initStaticMaterials() { if (!m_hoverMaterial){ m_hoverMaterial = new QGLMaterial(NULL); m_hoverMaterial->setAmbientColor( QColor(0, 128, 128) ); m_hoverMaterial->setSpecularColor( QColor(60, 60, 60) ); m_hoverMaterial->setShininess( 128 ); } if (!m_selectionMaterial){ m_selectionMaterial = new QGLMaterial(NULL); m_selectionMaterial->setAmbientColor( QColor(255, 50, 50) ); m_selectionMaterial->setSpecularColor( QColor(60, 60, 60) ); m_selectionMaterial->setShininess( 128 ); } if (!m_selectionBoxMaterial){ m_selectionBoxMaterial = new QGLMaterial(NULL); m_selectionBoxMaterial->setAmbientColor( QColor(0, 0, 0) ); m_selectionBoxMaterial->setDiffuseColor( QColor(0, 0, 0) ); m_selectionBoxMaterial->setEmittedLight( QColor(155, 50, 50) ); } } /** Static function to be called when Materials have to be removed. * */ void GLMoleculeObject::cleanMaterialMap() { for (ElementMaterialMap::iterator iter = ElementNoMaterialMap.begin(); !ElementNoMaterialMap.empty(); iter = ElementNoMaterialMap.begin()) { delete iter->second; ElementNoMaterialMap.erase(iter); } } void GLMoleculeObject::setSelected(bool value) { if (value != m_selected){ m_selected = value; emit selectionChanged(); } }