/********************************************************************** SphereEngine - Engine for "spheres" display Copyright (C) 2007-2008 Marcus D. Hanwell Copyright (C) 2006-2007 Geoffrey R. Hutchison Copyright (C) 2007 Benoit Jacob This file is part of the Avogadro molecular editor project. For more information, see Avogadro 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. Avogadro 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **********************************************************************/ #include "sphereengine.h" #include #include #include #include #include #include #include #include #include #include using namespace Eigen; namespace Avogadro { SphereEngine::SphereEngine(QObject *parent) : Engine(parent), m_settingsWidget(0), m_alpha(1.0) { } SphereEngine::~SphereEngine() { // Delete the settings widget if it exists if(m_settingsWidget) m_settingsWidget->deleteLater(); } Engine* SphereEngine::clone() const { SphereEngine* engine = new SphereEngine(parent()); engine->setAlias(alias()); engine->m_alpha = m_alpha; engine->setEnabled(isEnabled()); return engine; } bool SphereEngine::renderOpaque(PainterDevice *pd) { // Render the opaque spheres if m_alpha is 1 if (m_alpha >= 0.999) { // Render the atoms as VdW spheres glDisable(GL_NORMALIZE); glEnable(GL_RESCALE_NORMAL); foreach(Atom *a, atoms()) render(pd, a); glDisable(GL_RESCALE_NORMAL); glEnable(GL_NORMALIZE); } return true; } bool SphereEngine::renderTransparent(PainterDevice *pd) { // If m_alpha is between 0 and 1 then render our transparent spheres if (m_alpha > 0.001 && m_alpha < 0.999) { // First pass using a colour mask - nothing is actually drawn glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDisable(GL_LIGHTING); glDisable(GL_BLEND); // This is a little hackish but I am not sure there is a better way, // OpenGL requires this to cull the internal surfaces but it breaks POV-Ray // renders. So I set the color to black and totally transparent, render // with a slightly smaller radius than the actual VdW spheres. Works but // not pretty... pd->painter()->setColor(0.0, 0.0, 0.0, 1.0); foreach(Atom *a, atoms()) { pd->painter()->drawSphere(a->pos(), radius(a)*0.9999); } glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_BLEND); glEnable(GL_LIGHTING); // Render the atoms as VdW spheres glDisable(GL_NORMALIZE); glEnable(GL_RESCALE_NORMAL); foreach(Atom *a, atoms()) render(pd, a); glDisable(GL_RESCALE_NORMAL); glEnable(GL_NORMALIZE); } // Render the selection sphere if required Color *map = colorMap(); // possible custom color map if (!map) map = pd->colorMap(); // fall back to global color map foreach(Atom *a, atoms()) { if (pd->isSelected(a)) { map->setToSelectionColor(); pd->painter()->setColor(map); pd->painter()->setName(a); pd->painter()->drawSphere(a->pos(), SEL_ATOM_EXTRA_RADIUS + radius(a)); } } return true; } bool SphereEngine::renderQuick(PainterDevice *pd) { // Render the atoms as VdW spheres glDisable(GL_NORMALIZE); glEnable(GL_RESCALE_NORMAL); Color *map = colorMap(); if (!map) map = pd->colorMap(); foreach(Atom *a, atoms()) { map->set(a); pd->painter()->setColor(map); pd->painter()->setName(a); pd->painter()->drawSphere(a->pos(), radius(a)); } glDisable(GL_RESCALE_NORMAL); glEnable(GL_NORMALIZE); return true; } bool SphereEngine::render(PainterDevice *pd, const Atom *a) { // Render the atoms as Van der Waals spheres Color *map = colorMap(); // possible custom color map if (!map) map = pd->colorMap(); // fall back to global color map map->set(a); map->setAlpha(m_alpha); pd->painter()->setColor(map); pd->painter()->setName(a); pd->painter()->drawSphere(a->pos(), radius(a)); return true; } inline double SphereEngine::radius(const Atom *a) const { return OpenBabel::etab.GetVdwRad(a->atomicNumber()); } double SphereEngine::radius(const PainterDevice *pd, const Primitive *p) const { // Atom radius if (p->type() == Primitive::AtomType) { if(primitives().contains(p)) { if (pd && pd->isSelected(p)) { return radius(static_cast(p)) + SEL_ATOM_EXTRA_RADIUS; } return radius(static_cast(p)); } } // Something else return 0.; } double SphereEngine::transparencyDepth() const { return 1.0; } Engine::Layers SphereEngine::layers() const { return Engine::Opaque | Engine::Transparent; } Engine::PrimitiveTypes SphereEngine::primitiveTypes() const { return Engine::Atoms; } void SphereEngine::setOpacity(int value) { m_alpha = 0.05 * value; emit changed(); } QWidget* SphereEngine::settingsWidget() { if(!m_settingsWidget) { m_settingsWidget = new SphereSettingsWidget(); connect(m_settingsWidget->opacitySlider, SIGNAL(valueChanged(int)), this, SLOT(setOpacity(int))); connect(m_settingsWidget, SIGNAL(destroyed()), this, SLOT(settingsWidgetDestroyed())); m_settingsWidget->opacitySlider->setValue(20*m_alpha); } return m_settingsWidget; } void SphereEngine::settingsWidgetDestroyed() { qDebug() << "Destroyed Settings Widget"; m_settingsWidget = 0; } void SphereEngine::writeSettings(QSettings &settings) const { Engine::writeSettings(settings); settings.setValue("opacity", 20*m_alpha); } void SphereEngine::readSettings(QSettings &settings) { Engine::readSettings(settings); setOpacity(settings.value("opacity", 20).toInt()); if (m_settingsWidget) { m_settingsWidget->opacitySlider->setValue(20*m_alpha); } } } #include "sphereengine.moc" Q_EXPORT_PLUGIN2(sphereengine, Avogadro::SphereEngineFactory)