1 /**
2  * UGENE - Integrated Bioinformatics Tools.
3  * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4  * http://ugene.net
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21 
22 #include <math.h>
23 #include <time.h>
24 
25 #include <QColorDialog>
26 #include <QImageWriter>
27 #include <QMessageBox>
28 #include <QMouseEvent>
29 #include <QOffscreenSurface>
30 #include <QOpenGLContext>
31 #include <QOpenGLShaderProgram>
32 #include <QTime>
33 
34 #include <U2Algorithm/MolecularSurfaceFactoryRegistry.h>
35 #include <U2Algorithm/StructuralAlignmentAlgorithm.h>
36 
37 #include <U2Core/AnnotationSelection.h>
38 #include <U2Core/AnnotationSettings.h>
39 #include <U2Core/AnnotationTableObject.h>
40 #include <U2Core/AppContext.h>
41 #include <U2Core/BioStruct3D.h>
42 #include <U2Core/BioStruct3DObject.h>
43 #include <U2Core/Counter.h>
44 #include <U2Core/DNASequenceObject.h>
45 #include <U2Core/DNASequenceSelection.h>
46 #include <U2Core/DocumentModel.h>
47 #include <U2Core/GObjectRelationRoles.h>
48 #include <U2Core/GUrlUtils.h>
49 #include <U2Core/Log.h>
50 #include <U2Core/ProjectModel.h>
51 #include <U2Core/QObjectScopedPointer.h>
52 #include <U2Core/TaskSignalMapper.h>
53 #include <U2Core/U2SafePoints.h>
54 
55 #include <U2Gui/ExportImageDialog.h>
56 
57 #include <U2View/ADVSequenceObjectContext.h>
58 #include <U2View/AnnotatedDNAView.h>
59 
60 #include "BioStruct3DColorScheme.h"
61 #include "BioStruct3DGLImageExportTask.h"
62 #include "BioStruct3DGLRender.h"
63 #include "BioStruct3DGLWidget.h"
64 #include "GLFrameManager.h"
65 #include "SelectModelsDialog.h"
66 #include "SettingsDialog.h"
67 #include "StructuralAlignmentDialog.h"
68 #include "gl2ps/gl2ps.h"
69 
70 // disable "unsafe functions" deprecation warnings on MS VS
71 #ifdef Q_OS_WIN
72 #    pragma warning(disable : 4996)
73 #endif
74 
75 namespace U2 {
76 
77 int BioStruct3DGLWidget::widgetCount = 0;
78 
checkShaderPrograms()79 bool BioStruct3DGLWidget::checkShaderPrograms() {
80     QOffscreenSurface surf;
81     surf.create();
82 
83     QOpenGLContext ctx;
84     ctx.create();
85     ctx.makeCurrent(&surf);
86 
87     bool opgl = QOpenGLShaderProgram::hasOpenGLShaderPrograms(&ctx);
88     if (!opgl) {
89         coreLog.error(tr("The \"3D Structure Viewer\" was disabled, because shader programs written in the OpenGL Shading Language (GLSL) are not supported on this system. "
90                          "Please try to update drivers and reset the UGENE settings to default in the \"Application Settings\" dialog."));
91     }
92 
93     return opgl;
94 }
95 
tryGL()96 void BioStruct3DGLWidget::tryGL() {
97     volatile QOpenGLWidget wgt;
98     Q_UNUSED(wgt);
99 }
100 
101 const double BioStruct3DGLWidget::MINIMUM_ACCEPTABLE_VERSION = 2.0f;
102 
103 static QColor DEFAULT_BACKGROUND_COLOR = Qt::black;
104 static QColor DEFAULT_SELECTION_COLOR = Qt::yellow;
105 
106 static float DEFAULT_RENDER_DETAIL_LEVEL = 1.0;
107 static int DEFAULT_SHADING_LEVEL = 50;
108 
109 const QString BioStruct3DGLWidget::BACKGROUND_COLOR_NAME("BackgroundColor");
110 const QString BioStruct3DGLWidget::PRODUCT_NAME("Unipro Ugene");
111 const QString BioStruct3DGLWidget::PLUGIN_NAME("BioStruct3D Viewer Plugin");
112 const QString BioStruct3DGLWidget::COLOR_SCHEME_NAME("ColorScheme");
113 const QString BioStruct3DGLWidget::RENDERER_NAME("GLRenderer");
114 const QString BioStruct3DGLWidget::OBJECT_ID_NAME("OBJECT_ID");
115 
116 const QString BioStruct3DGLWidget::SELECTION_COLOR_NAME("SelectionColor");
117 const QString BioStruct3DGLWidget::SHADING_LEVEL_NAME("Shading Unselected Regions Level");
118 const QString BioStruct3DGLWidget::RENDER_DETAIL_LEVEL_NAME("RenderDetailLevel");
119 const QString BioStruct3DGLWidget::ANAGLYPH_STATUS_NAME("AnaglyphStatus");
120 
BioStruct3DGLWidget(BioStruct3DObject * obj,const AnnotatedDNAView * _dnaView,GLFrameManager * manager,QWidget * parent)121 BioStruct3DGLWidget::BioStruct3DGLWidget(BioStruct3DObject *obj, const AnnotatedDNAView *_dnaView, GLFrameManager *manager, QWidget *parent /* = 0*/)
122     : QOpenGLWidget(parent),
123       dnaView(_dnaView), contexts(),
124       rendererSettings(DEFAULT_RENDER_DETAIL_LEVEL),
125       frameManager(manager), glFrame(new GLFrame(this)),
126       molSurface(0), surfaceRenderer(), surfaceCalcTask(0),
127       anaglyphStatus(DISABLED),
128       anaglyph(new AnaglyphRenderer(this, AnaglyphSettings::defaultSettings())),
129 
130       defaultsSettings(), currentColorSchemeName(), currentGLRendererName(),
131       rotAngle(0), spinAngle(0), rotAxis(), lastPos(),
132       backgroundColor(DEFAULT_BACKGROUND_COLOR),
133       selectionColor(DEFAULT_SELECTION_COLOR), animationTimer(0),
134       unselectedShadingLevel(DEFAULT_SHADING_LEVEL), imageRenderingMode(false),
135 
136       spinAction(0), settingsAction(0), closeAction(0), exportImageAction(0), selectModelsAction(0), alignWithAction(0),
137       resetAlignmentAction(0), colorSchemeActions(0), rendererActions(0), molSurfaceRenderActions(0),
138       molSurfaceTypeActions(0), selectColorSchemeMenu(0), selectRendererMenu(0), displayMenu(0), lblGlError(nullptr) {
139     lightPosition[0] = lightPosition[1] = lightPosition[2] = lightPosition[3] = 0;
140     GCOUNTER(cvar, "BioStruct3DGLWidget");
141 
142     QString currentModelID = obj->getBioStruct3D().pdbId;
143     setObjectName(QString("%1-%2").arg(++widgetCount).arg(currentModelID));
144 
145     setWindowIcon(GObjectTypes::getTypeInfo(GObjectTypes::BIOSTRUCTURE_3D).icon);
146 
147     connectExternalSignals();
148 
149     currentColorSchemeName = BioStruct3DColorSchemeRegistry::defaultFactoryName();
150     currentGLRendererName = BioStruct3DGLRendererRegistry::defaultFactoryName();
151 
152     QList<QString> availableRenders = BioStruct3DGLRendererRegistry::getRenderersAvailableFor(obj->getBioStruct3D());
153     if (!availableRenders.contains(currentGLRendererName)) {
154         currentGLRendererName = availableRenders.first();
155     }
156 
157     addBiostruct(obj);
158 
159     checkRenderingAndCreateLblError();
160 
161     createActions();
162     createMenus();
163 
164     loadColorSchemes();
165     loadGLRenderers(availableRenders);
166 
167     frameManager->addGLFrame(glFrame.data());
168     saveDefaultSettings();
169 }
170 
~BioStruct3DGLWidget()171 BioStruct3DGLWidget::~BioStruct3DGLWidget() {
172     uiLog.trace("Biostruct3DGLWdiget " + objectName() + " deleted");
173 }
174 
setupFrame()175 void BioStruct3DGLWidget::setupFrame() {
176     const float scaleFactor = 2.5;
177     float radius = getSceneRadius();
178     float camZ = scaleFactor * radius;
179 
180     float cameraClipNear = (camZ - radius) * 0.66f;
181     float cameraClipFar = (camZ + radius) * 1.2f;
182 
183     glFrame->setCameraClip(cameraClipNear, cameraClipFar);
184 
185     Vector3D pos = glFrame->getCameraPosition();
186     pos.z = camZ;
187     glFrame->setCameraPosition(pos);
188 }
189 
getSceneRadius() const190 float BioStruct3DGLWidget::getSceneRadius() const {
191     // good idea: ask renderer for radius instead of asking biostruct
192     float maxRadius = 0;
193     const Vector3D sceneCenter = getSceneCenter();
194 
195     foreach (const BioStruct3DRendererContext &ctx, contexts) {
196         Vector3D center = ctx.biostruct->getCenter();
197         float radius = (center - sceneCenter).length() + ctx.biostruct->getRadius();
198         if (maxRadius < radius) {
199             maxRadius = radius;
200         }
201     }
202 
203     return maxRadius;
204 }
205 
getSceneCenter() const206 Vector3D BioStruct3DGLWidget::getSceneCenter() const {
207     // good idea: ask renderer for center instead of asking biostruct
208     Vector3D c;
209     foreach (const BioStruct3DRendererContext &ctx, contexts) {
210         // TODO: transform should be applied in BioStruct
211         Vector3D tmp = ctx.biostruct->getCenter();
212         c += tmp.dot(ctx.biostruct->getTransform());
213     }
214 
215     return c / float(contexts.length());
216 }
217 
getBioStruct3D() const218 const BioStruct3D &BioStruct3DGLWidget::getBioStruct3D() const {
219     return *(contexts.first().biostruct);
220 }
221 
getPDBId() const222 const QString BioStruct3DGLWidget::getPDBId() const {
223     return contexts.first().biostruct->pdbId;
224 }
225 
getBioStruct3DObjectName() const226 const QString BioStruct3DGLWidget::getBioStruct3DObjectName() const {
227     return contexts.first().obj->getGObjectName();
228 }
229 
setImageRenderingMode(bool status)230 void BioStruct3DGLWidget::setImageRenderingMode(bool status) {
231     imageRenderingMode = status;
232 }
233 
getGLFrame()234 GLFrame *BioStruct3DGLWidget::getGLFrame() {
235     return glFrame.data();
236 }
237 
initializeGL()238 void BioStruct3DGLWidget::initializeGL() {
239     setLightPosition(Vector3D(0, 0.0, 1.0));
240     GLfloat light_diffuse[] = {0.8f, 0.8f, 0.8f, 1.0};
241     GLfloat light_specular[] = {0.6f, 0.6f, 0.6f, 1.0};
242     GLfloat mat_specular[] = {0.6f, 0.6f, 0.6f, 1.0};
243     GLfloat mat_shininess[] = {90.0};
244 
245     glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), backgroundColor.alphaF());
246     glShadeModel(GL_SMOOTH);
247     glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
248     glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
249     glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
250     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
251     glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
252     glEnable(GL_BLEND);  // Enable Blending
253     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
254 
255     updateAllRenderers();
256 
257     QString videoAdapterString(QLatin1String(reinterpret_cast<const char *>(glGetString(GL_VENDOR))));
258     if (videoAdapterString.contains("intel", Qt::CaseInsensitive)) {
259         anaglyphStatus = NOT_AVAILABLE;
260     } else if (!imageRenderingMode) {
261         anaglyph->init();
262         if (!anaglyph->isAvailable()) {
263             anaglyphStatus = NOT_AVAILABLE;
264         }
265     }
266 }
267 
resizeGL(int width,int height)268 void BioStruct3DGLWidget::resizeGL(int width, int height) {
269     glFrame->updateViewPort(width, height);
270     if (lblGlError != nullptr) {
271         lblGlError->resize(size());
272     }
273     if (anaglyphStatus == ENABLED) {
274         anaglyph->resize(width, height);
275     }
276 }
277 
paintGL()278 void BioStruct3DGLWidget::paintGL() {
279     if (!isVisible()) {
280         return;
281     }
282 
283     clock_t frameStart = clock();
284 
285     // Clear buffers, setup modelview matrix
286     // Scene render unable to do this since it used by anaglyph renderer
287     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
288 
289     glMatrixMode(GL_MODELVIEW);
290     glLoadIdentity();
291 
292     gluLookAt(0.0, 0.0, glFrame->getCameraPosition().z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
293 
294     if (anaglyphStatus == ENABLED && !imageRenderingMode) {
295         // draw using anaglyph renderer
296         anaglyph->draw();
297     } else {
298         // draw using default scene renderer (this)
299         draw();
300     }
301 
302     clock_t frameEnd = clock();
303     double frameTime = (frameEnd - frameStart) / (double)CLOCKS_PER_SEC;
304     perfLog.trace(QString("BioStruct3DView frame rendering time %1 s").arg(frameTime));
305 }
306 
draw()307 void BioStruct3DGLWidget::draw() {
308     glEnable(GL_DEPTH_TEST);
309     glEnable(GL_LIGHTING);
310     glEnable(GL_LIGHT0);
311 
312     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
313 
314     Vector3D rotCenter = getSceneCenter();
315 
316     glTranslatef(glFrame->getCameraPosition().x, glFrame->getCameraPosition().y, 0);
317 
318     glMultMatrixf(glFrame->getRotationMatrix());
319     glTranslatef(-rotCenter.x, -rotCenter.y, -rotCenter.z);
320 
321     foreach (const BioStruct3DRendererContext &ctx, contexts) {
322         glPushMatrix();
323 
324         Matrix44 colmt = ctx.biostruct->getTransform();
325         colmt.transpose();
326         glMultMatrixf(colmt.data());
327 
328         ctx.renderer->drawBioStruct3D();
329         glPopMatrix();
330     }
331 
332     if (!molSurface.isNull()) {
333         glEnable(GL_CULL_FACE);
334 
335         glCullFace(GL_FRONT);
336         surfaceRenderer->drawSurface(*molSurface);
337 
338         glCullFace(GL_BACK);
339         surfaceRenderer->drawSurface(*molSurface);
340 
341         glDisable(GL_CULL_FACE);
342         CHECK_GL_ERROR;
343     }
344 
345     glDisable(GL_LIGHTING);
346     glDisable(GL_LIGHT0);
347     glDisable(GL_DEPTH_TEST);
348 }
349 
getTrackballMapping(int x,int y)350 Vector3D BioStruct3DGLWidget::getTrackballMapping(int x, int y) {
351     Vector3D pos;
352     /* project x,y onto a hemisphere centered within width, height */
353     pos.x = (2.0f * x - width()) / width();
354     pos.y = (height() - 2.0f * y) / height();
355     pos.z = 0;
356     float d = pos.length();
357     d = (d < 1.0) ? d : 1.0;
358     pos.z = sqrtf(1.0f - d * d);
359     pos.normalize();
360 
361     return pos;
362 }
363 
contextMenuEvent(QContextMenuEvent * event)364 void BioStruct3DGLWidget::contextMenuEvent(QContextMenuEvent *event) {
365     QMenu menu;
366     foreach (QAction *action, getDisplayMenu()->actions()) {
367         menu.addAction(action);
368     }
369 
370     menu.addAction(closeAction);
371 
372     menu.exec(event->globalPos());
373 }
374 
setLightPosition(const Vector3D & pos)375 void BioStruct3DGLWidget::setLightPosition(const Vector3D &pos) {
376     lightPosition[0] = pos.x;
377     lightPosition[1] = pos.y;
378     lightPosition[2] = pos.z;
379     lightPosition[3] = 1.0;
380 }
381 
getSequenceChainId(const U2SequenceObject * seqObj)382 static int getSequenceChainId(const U2SequenceObject *seqObj) {
383     bool isFound = false;
384     qint64 result = seqObj->getSequenceInfo().value(DNAInfo::CHAIN_ID).toInt(&isFound);
385     SAFE_POINT(isFound, "Sequence does not have the CHAIN_ID attribute", -1);
386     return (int)result;
387 }
388 
sl_onSequenceSelectionChanged(LRegionsSelection * s,const QVector<U2Region> & added,const QVector<U2Region> & removed)389 void BioStruct3DGLWidget::sl_onSequenceSelectionChanged(LRegionsSelection *s, const QVector<U2Region> &added, const QVector<U2Region> &removed) {
390     if (!isVisible())
391         return;
392 
393     DNASequenceSelection *selection = qobject_cast<DNASequenceSelection *>(s);
394     const U2SequenceObject *seqObj = selection->getSequenceObject();
395     assert(seqObj);
396 
397     const BioStruct3DRendererContext &ctx = contexts.first();
398 
399     // check that biostruct and sequence objects are from the same document
400     // appropriate relation check must be here
401     if (seqObj->getDocument() == ctx.obj->getDocument()) {
402         int chainId = getSequenceChainId(seqObj);
403         assert(ctx.biostruct->moleculeMap.contains(chainId));
404 
405         ctx.colorScheme->updateSelectionRegion(chainId, added, removed);
406 
407         updateAllColorSchemes();
408         update();
409     }
410 }
411 
getState()412 QVariantMap BioStruct3DGLWidget::getState() {
413     QVariantMap state;
414     glFrame->writeStateToMap(state);
415     anaglyph->getSettings().toMap(state);
416 
417     state[ANAGLYPH_STATUS_NAME] = qVariantFromValue((int)anaglyphStatus);
418 
419     state[COLOR_SCHEME_NAME] = QVariant::fromValue(currentColorSchemeName);
420     state[RENDERER_NAME] = QVariant::fromValue(currentGLRendererName);
421     state[OBJECT_ID_NAME] = QVariant::fromValue(getBioStruct3DObjectName());
422 
423     state[BACKGROUND_COLOR_NAME] = QVariant::fromValue(backgroundColor);
424     state[SELECTION_COLOR_NAME] = QVariant::fromValue(selectionColor);
425 
426     state[RENDER_DETAIL_LEVEL_NAME] = QVariant::fromValue(rendererSettings.detailLevel);
427     state[SHADING_LEVEL_NAME] = QVariant::fromValue(unselectedShadingLevel);
428 
429     return state;
430 }
431 
setState(const QVariantMap & state)432 void BioStruct3DGLWidget::setState(const QVariantMap &state) {
433     // bug-2859: correct save/restore current selection.
434     if (state.isEmpty()) {
435         return;
436     }
437     glFrame->makeCurrent();
438     glFrame->setState(state);
439 
440     anaglyphStatus = (AnaglyphStatus)state.value(ANAGLYPH_STATUS_NAME).value<int>();
441     anaglyph->setSettings(AnaglyphSettings::fromMap(state));
442 
443     backgroundColor = state.value(BACKGROUND_COLOR_NAME, DEFAULT_BACKGROUND_COLOR).value<QColor>();
444     setBackgroundColor(backgroundColor);
445 
446     selectionColor = state.value(SELECTION_COLOR_NAME, DEFAULT_SELECTION_COLOR).value<QColor>();
447 
448     rendererSettings.detailLevel = state.value(RENDER_DETAIL_LEVEL_NAME, DEFAULT_RENDER_DETAIL_LEVEL).value<float>();
449 
450     QString previousColorSchemeName = currentColorSchemeName;
451     QString previousGLRendererName = currentGLRendererName;
452 
453     currentColorSchemeName = state.value(COLOR_SCHEME_NAME, BioStruct3DColorSchemeRegistry::defaultFactoryName()).value<QString>();
454     currentGLRendererName = state.value(RENDERER_NAME, BioStruct3DGLRendererRegistry::defaultFactoryName()).value<QString>();
455 
456     if (previousColorSchemeName != currentColorSchemeName) {
457         setupColorScheme(currentColorSchemeName);
458     }
459 
460     unselectedShadingLevel = state.value(SHADING_LEVEL_NAME, DEFAULT_SHADING_LEVEL).value<int>();
461     setUnselectedShadingLevel(unselectedShadingLevel);
462 
463     if (previousGLRendererName != currentGLRendererName) {
464         setupRenderer(currentGLRendererName);
465     }
466 
467     resizeGL(width(), height());
468     update();
469 }
470 
setupColorScheme(const QString & name)471 void BioStruct3DGLWidget::setupColorScheme(const QString &name) {
472     QList<BioStruct3DRendererContext>::iterator i = contexts.begin();
473     for (; i != contexts.end(); ++i) {
474         BioStruct3DRendererContext &ctx = *(i);
475 
476         // TODO: this situation may be potentialy dangerous
477         // if renderer starts draw right now, maybe SharedPointer will be good solution
478         BioStruct3DColorScheme *scheme = BioStruct3DColorSchemeRegistry::createColorScheme(name, ctx.obj);
479         assert(scheme);
480 
481         scheme->setSelectionColor(selectionColor);
482         scheme->setUnselectedShadingLevel((double)unselectedShadingLevel / 100.0);
483 
484         ctx.colorScheme = QSharedPointer<BioStruct3DColorScheme>(scheme);
485         ctx.renderer->setColorScheme(scheme);
486     }
487 }
488 
setupRenderer(const QString & name)489 void BioStruct3DGLWidget::setupRenderer(const QString &name) {
490     QList<BioStruct3DRendererContext>::iterator i = contexts.begin();
491     for (; i != contexts.end(); ++i) {
492         BioStruct3DRendererContext &ctx = *(i);
493 
494         // TODO: this situation may be potentialy dangerous
495         // if renderer starts draw right now, maybe SharedPointer will be good solution
496         const QList<int> &shownModelsIndexes = ctx.renderer->getShownModelsIndexes();
497         BioStruct3DGLRenderer *rend = BioStruct3DGLRendererRegistry::createRenderer(name, *ctx.biostruct, ctx.colorScheme.data(), shownModelsIndexes, &rendererSettings);
498         assert(rend);
499         ctx.renderer = QSharedPointer<BioStruct3DGLRenderer>(rend);
500     }
501 }
502 
updateAllColorSchemes()503 void BioStruct3DGLWidget::updateAllColorSchemes() {
504     foreach (const BioStruct3DRendererContext &ctx, contexts) {
505         ctx.renderer->updateColorScheme();
506     }
507 }
508 
updateAllRenderers()509 void BioStruct3DGLWidget::updateAllRenderers() {
510     foreach (const BioStruct3DRendererContext &ctx, contexts) {
511         ctx.renderer->update();
512     }
513 }
514 
setBackgroundColor(QColor backgroundColor)515 void BioStruct3DGLWidget::setBackgroundColor(QColor backgroundColor) {
516     this->backgroundColor = backgroundColor;
517     glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), backgroundColor.alphaF());
518 }
519 
zoom(float delta)520 void BioStruct3DGLWidget::zoom(float delta) {
521     bool syncLock = isSyncModeOn();
522     QList<GLFrame *> frames = frameManager->getActiveGLFrameList(glFrame.data(), syncLock);
523     foreach (GLFrame *frame, frames) {
524         frame->makeCurrent();
525         frame->performZoom(delta);
526         frame->updateViewPort();
527         frame->updateGL();
528     }
529 }
530 
shift(float deltaX,float deltaY)531 void BioStruct3DGLWidget::shift(float deltaX, float deltaY) {
532     bool syncLock = isSyncModeOn();
533     QList<GLFrame *> frames = frameManager->getActiveGLFrameList(glFrame.data(), syncLock);
534     foreach (GLFrame *frame, frames) {
535         frame->makeCurrent();
536         frame->performShift(deltaX, deltaY);
537         frame->updateViewPort();
538         frame->updateGL();
539     }
540 }
541 
saveDefaultSettings()542 void BioStruct3DGLWidget::saveDefaultSettings() {
543     glFrame->writeStateToMap(defaultsSettings);
544     defaultsSettings[COLOR_SCHEME_NAME] = QVariant::fromValue(currentColorSchemeName);
545     defaultsSettings[RENDERER_NAME] = QVariant::fromValue(currentGLRendererName);
546 }
547 
restoreDefaultSettigns()548 void BioStruct3DGLWidget::restoreDefaultSettigns() {
549     assert(!defaultsSettings.isEmpty());
550     bool syncLock = isSyncModeOn();
551     QList<GLFrame *> frames = frameManager->getActiveGLFrameList(glFrame.data(), syncLock);
552     foreach (GLFrame *frame, frames) {
553         frame->makeCurrent();
554         frame->setState(defaultsSettings);
555         frame->updateViewPort();
556         frame->updateGL();
557     }
558 }
559 
showModel(int modelId,bool show)560 void BioStruct3DGLWidget::showModel(int modelId, bool show) {
561     BioStruct3DRendererContext &ctx = contexts.first();
562 
563     // this function uses modelId - key from BioStruct3D::modelMap
564     int idx = ctx.biostruct->modelMap.keys().indexOf(modelId);
565     assert(idx != -1);
566 
567     QList<int> shownModelsIndexes = ctx.renderer->getShownModelsIndexes();
568 
569     if (show && !shownModelsIndexes.contains(idx)) {
570         shownModelsIndexes.append(idx);
571     } else if (!show) {
572         shownModelsIndexes.removeAll(idx);
573     }
574     ctx.renderer->setShownModelsIndexes(shownModelsIndexes);
575 }
576 
showAllModels(bool show)577 void BioStruct3DGLWidget::showAllModels(bool show) {
578     BioStruct3DRendererContext &ctx = contexts.first();
579 
580     QList<int> shownModelsIndexes;
581     if (show) {
582         int numModels = ctx.biostruct->modelMap.size();
583         for (int i = 0; i < numModels; ++i) {
584             shownModelsIndexes.append(i);
585         }
586     }
587     ctx.renderer->setShownModelsIndexes(shownModelsIndexes);
588 }
589 
sl_selectModels()590 void BioStruct3DGLWidget::sl_selectModels() {
591     BioStruct3DRendererContext &ctx = contexts.first();
592     QObjectScopedPointer<SelectModelsDialog> dlg = new SelectModelsDialog(ctx.biostruct->getModelsNames(), ctx.renderer->getShownModelsIndexes(), this);
593     dlg->exec();
594     CHECK(!dlg.isNull(), );
595 
596     if (dlg->result() == QDialog::Accepted) {
597         ctx.renderer->setShownModelsIndexes(dlg->getSelectedModelsIndexes());
598 
599         contexts.first().renderer->updateShownModels();
600         update();
601     }
602 }
603 
writeImage2DToFile(int format,int options,int nbcol,const char * fileName)604 void BioStruct3DGLWidget::writeImage2DToFile(int format, int options, int nbcol, const char *fileName) {
605     FILE *fp = nullptr;
606     const char *FOPEN_ARGS = "wb";
607     const QByteArray title(fileName);
608     int state = GL2PS_OVERFLOW, buffsize = 0;
609     GLint viewport[4];
610     int sort = GL2PS_SIMPLE_SORT;
611 
612     fp = fopen(fileName, FOPEN_ARGS);
613 
614     if (!fp) {
615         QMessageBox::warning(this, tr("Error"), tr("Unable to open file %1 for writing").arg(fileName));
616         return;
617     }
618 
619     glGetIntegerv(GL_VIEWPORT, viewport);
620 
621     if (format == GL2PS_EPS) {
622         // hack -> make widget aspect ratio 1:1
623         if (width() > height()) {
624             int size = height();
625             resize(size, size);
626         }
627     }
628 
629     while (state == GL2PS_OVERFLOW) {
630         buffsize += 2048 * 2048;
631         gl2psBeginPage(title.constData(), "Unipro UGENE BioStruct3D Viewer plugin", viewport, format, sort, options, GL_RGBA, 0, nullptr, nbcol, nbcol, nbcol, buffsize, fp, fileName);
632         paintGL();
633         state = gl2psEndPage();
634     }
635 
636     fclose(fp);
637 
638     if (format == GL2PS_EPS) {
639         // restore sizes
640         updateGeometry();
641     }
642 }
643 
loadColorSchemes()644 void BioStruct3DGLWidget::loadColorSchemes() {
645     currentColorSchemeName = BioStruct3DColorSchemeRegistry::defaultFactoryName();
646 
647     // highlight default color scheme in menu
648     QList<QAction *>::iterator iter;
649     QList<QAction *> schemeActions = colorSchemeActions->actions();
650     for (iter = schemeActions.begin(); iter != schemeActions.end(); ++iter) {
651         if ((*iter)->text() == currentColorSchemeName) {
652             (*iter)->setChecked(true);
653             break;
654         }
655     }
656     assert(iter != schemeActions.end());
657 }
658 
loadGLRenderers(const QList<QString> & availableRenderers)659 void BioStruct3DGLWidget::loadGLRenderers(const QList<QString> &availableRenderers) {
660     // highlight current renderer in menu
661 
662     foreach (QAction *ac, rendererActions->actions()) {
663         // disable all unavailable renderers in menu
664         if (!availableRenderers.contains(ac->text())) {
665             ac->setDisabled(true);
666         }
667 
668         if (ac->text() == currentGLRendererName) {
669             ac->setChecked(true);
670         }
671     }
672 
673     QString surfaceRendererName = ConvexMapRenderer::ID;
674     surfaceRenderer.reset(MolecularSurfaceRendererRegistry::createMSRenderer(surfaceRendererName));
675 }
676 
isSyncModeOn()677 bool BioStruct3DGLWidget::isSyncModeOn() {
678     Qt::KeyboardModifiers km = QApplication::keyboardModifiers();
679     bool synchronizationMode = km.testFlag(Qt::ShiftModifier) || frameManager->getSyncLock();
680     synchronizationMode &= frameManager->getGLFrames().count() > 1;
681     return synchronizationMode;
682 }
683 
checkRenderingAndCreateLblError()684 void BioStruct3DGLWidget::checkRenderingAndCreateLblError() {
685     QOffscreenSurface surf;
686     QOpenGLContext ctx;
687     surf.create();
688     ctx.create();
689     ctx.makeCurrent(&surf);
690 
691     GLenum error = glGetError();
692     bool canRender = error == GL_NO_ERROR;
693     if (!canRender) {
694         coreLog.info(tr("The \"3D Structure Viewer\" was disabled, because OpenGL has error ") +
695                      QString("(%1): %2").arg(error).arg(reinterpret_cast<const char *>(gluErrorString(error))));
696         lblGlError = new QLabel("Failed to initialize OpenGL", this);
697         lblGlError->setAlignment(Qt::AlignCenter | Qt::AlignHCenter);
698         lblGlError->setStyleSheet("QLabel { background-color : black; color : white; }");
699     }
700 }
701 
setUnselectedShadingLevel(int shading)702 void BioStruct3DGLWidget::setUnselectedShadingLevel(int shading) {
703     foreach (const BioStruct3DRendererContext &ctx, contexts) {
704         ctx.colorScheme->setUnselectedShadingLevel((double)shading / 100.0);
705     }
706     updateAllColorSchemes();
707 }
708 
getDisplayMenu()709 QMenu *BioStruct3DGLWidget::getDisplayMenu() {
710     assert(displayMenu != nullptr);
711     return displayMenu;
712 }
713 
mousePressEvent(QMouseEvent * event)714 void BioStruct3DGLWidget::mousePressEvent(QMouseEvent *event) {
715     lastPos = getTrackballMapping(event->x(), event->y());
716 }
717 
mouseMoveEvent(QMouseEvent * event)718 void BioStruct3DGLWidget::mouseMoveEvent(QMouseEvent *event) {
719     if (event->buttons() & Qt::LeftButton) {
720         Vector3D curPos = getTrackballMapping(event->x(), event->y());
721         Vector3D delta = curPos - lastPos;
722 
723         if (delta.x || delta.y || delta.z) {
724             rotAngle = 90.0f * delta.length();
725             rotAxis = vector_cross(lastPos, curPos);
726 
727             bool syncLock = isSyncModeOn();
728             QList<GLFrame *> frames = frameManager->getActiveGLFrameList(glFrame.data(), syncLock);
729             foreach (GLFrame *frame, frames) {
730                 frame->makeCurrent();
731 
732                 if (event->modifiers() & Qt::CTRL)
733                     frame->performShift(delta.x, delta.y);
734                 else
735                     frame->rotateCamera(rotAxis, rotAngle);
736 
737                 frame->updateGL();
738             }
739         }
740 
741         lastPos = curPos;
742     }
743 }
744 
wheelEvent(QWheelEvent * event)745 void BioStruct3DGLWidget::wheelEvent(QWheelEvent *event) {
746     float numDegrees = event->delta() / 8;
747     zoom(numDegrees / 10);
748 }
749 
createActions()750 void BioStruct3DGLWidget::createActions() {
751     QAction *action = nullptr;
752 
753     animationTimer = new QTimer(this);
754     animationTimer->setInterval(20);  // fixed interval
755     connect(animationTimer, SIGNAL(timeout()), this, SLOT(sl_updateAnnimation()));
756 
757     rendererActions = new QActionGroup(this);
758     connect(rendererActions, SIGNAL(triggered(QAction *)), this, SLOT(sl_selectGLRenderer(QAction *)));
759 
760     foreach (const QString &key, BioStruct3DGLRendererRegistry::factoriesNames()) {
761         action = new QAction(key, rendererActions);
762         action->setCheckable(true);
763         action->setObjectName(action->text());
764     }
765 
766     colorSchemeActions = new QActionGroup(this);
767     connect(colorSchemeActions, SIGNAL(triggered(QAction *)), this, SLOT(sl_selectColorScheme(QAction *)));
768     foreach (const QString &key, BioStruct3DColorSchemeRegistry::factoriesNames()) {
769         action = new QAction(key, colorSchemeActions);
770         action->setCheckable(true);
771         action->setObjectName(key);
772     }
773 
774     molSurfaceRenderActions = new QActionGroup(this);
775     connect(molSurfaceRenderActions, SIGNAL(triggered(QAction *)), this, SLOT(sl_selectSurfaceRenderer(QAction *)));
776     foreach (const QString &key, MolecularSurfaceRendererRegistry::factoriesNames()) {
777         action = new QAction(key, molSurfaceRenderActions);
778         action->setCheckable(true);
779         if (key == ConvexMapRenderer::ID) {
780             action->setChecked(true);
781         }
782     }
783 
784     molSurfaceTypeActions = new QActionGroup(this);
785     foreach (QString key, AppContext::getMolecularSurfaceFactoryRegistry()->getSurfNameList()) {
786         action = new QAction(key, molSurfaceTypeActions);
787         action->setObjectName(key);
788         connect(action, SIGNAL(triggered()), this, SLOT(sl_showSurface()));
789         action->setCheckable(true);
790         bool hasConstraints = AppContext::getMolecularSurfaceFactoryRegistry()->getSurfaceFactory(key)->hasConstraints(*contexts.first().biostruct);
791         action->setEnabled(!hasConstraints);
792     }
793     action = new QAction(tr("Off"), molSurfaceTypeActions);
794     connect(action, SIGNAL(triggered()), this, SLOT(sl_hideSurface()));
795     action->setCheckable(true);
796     action->setChecked(true);
797 
798     selectModelsAction = 0;
799     if (!contexts.isEmpty() && contexts.first().biostruct->getModelsNames().size() > 1) {
800         selectModelsAction = new QAction(tr("Models.."), this);
801         connect(selectModelsAction, SIGNAL(triggered()), this, SLOT(sl_selectModels()));
802     }
803 
804     spinAction = new QAction(tr("Spin"), this);
805     spinAction->setCheckable(true);
806     connect(spinAction, SIGNAL(triggered()), this, SLOT(sl_acitvateSpin()));
807 
808     settingsAction = new QAction(tr("Settings..."), this);
809     connect(settingsAction, SIGNAL(triggered()), this, SLOT(sl_settings()));
810 
811     closeAction = new QAction(tr("Close"), this);
812     connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
813 
814     exportImageAction = new QAction(tr("Export Image..."), this);
815     connect(exportImageAction, SIGNAL(triggered()), this, SLOT(sl_exportImage()));
816 
817     createStrucluralAlignmentActions();
818 
819     connect(AppContext::getTaskScheduler(), SIGNAL(si_stateChanged(Task *)), SLOT(sl_onTaskFinished(Task *)));
820 }
821 
createStrucluralAlignmentActions()822 void BioStruct3DGLWidget::createStrucluralAlignmentActions() {
823     alignWithAction = new QAction(tr("Align With..."), this);
824     alignWithAction->setObjectName("align_with");
825     connect(alignWithAction, SIGNAL(triggered()), this, SLOT(sl_alignWith()));
826 
827     resetAlignmentAction = new QAction(tr("Reset"), this);
828     connect(resetAlignmentAction, SIGNAL(triggered()), this, SLOT(sl_resetAlignment()));
829 }
830 
createMenus()831 void BioStruct3DGLWidget::createMenus() {
832     // Renderer selection
833     selectRendererMenu = new QMenu(tr("Render Style"));
834     selectRendererMenu->addActions(rendererActions->actions());
835     selectRendererMenu->menuAction()->setObjectName("Render Style");
836 
837     // Color scheme selection
838     selectColorSchemeMenu = new QMenu(tr("Coloring Scheme"));
839     selectColorSchemeMenu->addActions(colorSchemeActions->actions());
840     selectColorSchemeMenu->menuAction()->setObjectName("Coloring Scheme");
841 
842     // Molecular surface
843     QMenu *surfaceMenu = new QMenu(tr("Molecular Surface Render Style"));
844     surfaceMenu->addActions(molSurfaceRenderActions->actions());
845     surfaceMenu->menuAction()->setObjectName("Molecular Surface Render Style");
846 
847     QMenu *surfaceTypeMenu = new QMenu(tr("Molecular Surface"));
848     surfaceTypeMenu->addActions(molSurfaceTypeActions->actions());
849     surfaceTypeMenu->menuAction()->setObjectName("Molecular Surface");
850 
851     // Display (context) menu
852     displayMenu = new QMenu(this);
853     displayMenu->addMenu(selectRendererMenu);
854     displayMenu->addMenu(selectColorSchemeMenu);
855 
856     displayMenu->addMenu(surfaceMenu);
857     displayMenu->addMenu(surfaceTypeMenu);
858 
859     if (selectModelsAction) {
860         displayMenu->addAction(selectModelsAction);
861     }
862 
863     displayMenu->addAction(spinAction);
864     displayMenu->addAction(settingsAction);
865     displayMenu->addAction(exportImageAction);
866 
867     QMenu *saMenu = createStructuralAlignmentMenu();
868     displayMenu->addMenu(saMenu);
869 }
870 
createStructuralAlignmentMenu()871 QMenu *BioStruct3DGLWidget::createStructuralAlignmentMenu() {
872     QMenu *saMenu = new QMenu(tr("Structural Alignment"));
873     saMenu->menuAction()->setObjectName("Structural Alignment");
874 
875     saMenu->addAction(alignWithAction);
876     saMenu->addAction(resetAlignmentAction);
877 
878     return saMenu;
879 }
880 
connectExternalSignals()881 void BioStruct3DGLWidget::connectExternalSignals() {
882     AnnotationSettingsRegistry *asr = AppContext::getAnnotationsSettingsRegistry();
883     connect(asr, SIGNAL(si_annotationSettingsChanged(const QStringList &)), this, SLOT(sl_updateRenderSettings(const QStringList &)));
884 
885     const QList<ADVSequenceObjectContext *> seqContexts = dnaView->getSequenceContexts();
886 
887     foreach (ADVSequenceObjectContext *ctx, seqContexts) {
888         connect(ctx->getSequenceSelection(),
889                 SIGNAL(si_selectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)),
890                 SLOT(sl_onSequenceSelectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)));
891     }
892 
893     connect(dnaView,
894             SIGNAL(si_sequenceAdded(ADVSequenceObjectContext *)),
895             SLOT(sl_onSequenceAddedToADV(ADVSequenceObjectContext *)));
896 
897     connect(dnaView,
898             SIGNAL(si_sequenceRemoved(ADVSequenceObjectContext *)),
899             SLOT(sl_onSequenceRemovedFromADV(ADVSequenceObjectContext *)));
900 }
901 
sl_onSequenceAddedToADV(ADVSequenceObjectContext * ctx)902 void BioStruct3DGLWidget::sl_onSequenceAddedToADV(ADVSequenceObjectContext *ctx) {
903     connect(ctx->getSequenceSelection(),
904             SIGNAL(si_selectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)),
905             SLOT(sl_onSequenceSelectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)));
906 }
907 
sl_onSequenceRemovedFromADV(ADVSequenceObjectContext * ctx)908 void BioStruct3DGLWidget::sl_onSequenceRemovedFromADV(ADVSequenceObjectContext *ctx) {
909     disconnect(ctx->getSequenceSelection(), SIGNAL(si_selectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)), this, SLOT(sl_onSequenceSelectionChanged(LRegionsSelection *, const QVector<U2Region> &, const QVector<U2Region> &)));
910 }
911 
sl_selectColorScheme(QAction * action)912 void BioStruct3DGLWidget::sl_selectColorScheme(QAction *action) {
913     QString schemeName = action->text();
914 
915     currentColorSchemeName = schemeName;
916     setupColorScheme(schemeName);
917 
918     GLFrame *frame = frameManager->getGLWidgetFrame(this);
919     frame->makeCurrent();
920     frame->updateGL();
921 }
922 
sl_updateRenderSettings(const QStringList & list)923 void BioStruct3DGLWidget::sl_updateRenderSettings(const QStringList &list) {
924     Q_UNUSED(list);
925     sl_selectColorScheme(colorSchemeActions->checkedAction());
926 }
927 
sl_acitvateSpin()928 void BioStruct3DGLWidget::sl_acitvateSpin() {
929     if (spinAction->isChecked()) {
930         animationTimer->start();
931     } else {
932         animationTimer->stop();
933     }
934 
935     update();
936 }
937 
sl_updateAnnimation()938 void BioStruct3DGLWidget::sl_updateAnnimation() {
939     static float velocity = 0.05f;
940     spinAngle = velocity * animationTimer->interval();
941     Vector3D rotAxis(0, 1, 0);
942     bool syncLock = isSyncModeOn();
943     QList<GLFrame *> frames = frameManager->getActiveGLFrameList(glFrame.data(), syncLock);
944 
945     foreach (GLFrame *frame, frames) {
946         frame->makeCurrent();
947         frame->rotateCamera(rotAxis, spinAngle);
948         frame->updateGL();
949     }
950     update();
951 }
952 
sl_selectGLRenderer(QAction * action)953 void BioStruct3DGLWidget::sl_selectGLRenderer(QAction *action) {
954     QString rendererName = action->text();
955     currentGLRendererName = rendererName;
956     setupRenderer(currentGLRendererName);
957 
958     GLFrame *frame = frameManager->getGLWidgetFrame(this);
959     frame->makeCurrent();
960     frame->updateGL();
961 }
962 
sl_settings()963 void BioStruct3DGLWidget::sl_settings() {
964     QObjectScopedPointer<BioStruct3DSettingsDialog> dialog = new BioStruct3DSettingsDialog();
965 
966     dialog->setWidget(this);
967 
968     dialog->setBackgroundColor(backgroundColor);
969     dialog->setSelectionColor(selectionColor);
970     dialog->setRenderDetailLevel(rendererSettings.detailLevel);
971     dialog->setShadingLevel(unselectedShadingLevel);
972 
973     dialog->setAnaglyphStatus(anaglyphStatus);
974     dialog->setAnaglyphSettings(anaglyph->getSettings());
975 
976     QVariantMap previousState = getState();
977 
978     dialog->exec();
979     CHECK(!dialog.isNull(), );
980 
981     if (QDialog::Accepted == dialog->result()) {
982         backgroundColor = dialog->getBackgroundColor();
983         selectionColor = dialog->getSelectionColor();
984         unselectedShadingLevel = dialog->getShadingLevel();
985 
986         foreach (const BioStruct3DRendererContext &ctx, contexts) {
987             ctx.colorScheme->setSelectionColor(selectionColor);
988         }
989         setUnselectedShadingLevel(unselectedShadingLevel);
990 
991         rendererSettings.detailLevel = dialog->getRenderDetailLevel();
992 
993         anaglyphStatus = dialog->getAnaglyphStatus();
994         anaglyph->setSettings(dialog->getAnaglyphSettings());
995 
996         this->makeCurrent();
997         setBackgroundColor(backgroundColor);
998 
999         update();
1000     } else {
1001         setState(previousState);
1002     }
1003 }
1004 
sl_exportImage()1005 void BioStruct3DGLWidget::sl_exportImage() {
1006     BioStruct3DImageExportController factory(this);
1007     QString fileName = GUrlUtils::fixFileName(getBioStruct3DObjectName());
1008     QObjectScopedPointer<ExportImageDialog> dialog = new ExportImageDialog(&factory, ExportImageDialog::MolView, fileName, ExportImageDialog::SupportScaling, this);
1009     dialog->exec();
1010 }
1011 
sl_showSurface()1012 void BioStruct3DGLWidget::sl_showSurface() {
1013     QList<SharedAtom> atoms;
1014     BioStruct3DRendererContext ctx = contexts.first();
1015     atoms = ctx.biostruct->getAllAtoms();
1016 
1017     QString surfaceType = qobject_cast<QAction *>(sender())->text();
1018     surfaceCalcTask = new MolecularSurfaceCalcTask(surfaceType, atoms);
1019     AppContext::getTaskScheduler()->registerTopLevelTask(surfaceCalcTask);
1020 }
1021 
sl_hideSurface()1022 void BioStruct3DGLWidget::sl_hideSurface() {
1023     molSurface.reset();
1024 
1025     makeCurrent();
1026     update();
1027 }
1028 
sl_selectSurfaceRenderer(QAction * action)1029 void BioStruct3DGLWidget::sl_selectSurfaceRenderer(QAction *action) {
1030     QString msRendererName = action->text();
1031     surfaceRenderer.reset(MolecularSurfaceRendererRegistry::createMSRenderer(msRendererName));
1032 
1033     makeCurrent();
1034     update();
1035 }
1036 
sl_onTaskFinished(Task * task)1037 void BioStruct3DGLWidget::sl_onTaskFinished(Task *task) {
1038     if (surfaceCalcTask != task || surfaceCalcTask->getState() != Task::State_Finished) {
1039         return;
1040     }
1041 
1042     molSurface.reset(surfaceCalcTask->getCalculatedSurface());
1043 
1044     makeCurrent();
1045     update();
1046 }
1047 
1048 /** Convert modelId's list to modelIndexes list */
modelIdsToModelIdx(const BioStruct3D & bs,const QList<int> & modelsIds)1049 static QList<int> modelIdsToModelIdx(const BioStruct3D &bs, const QList<int> &modelsIds) {
1050     QList<int> modelsIdx;
1051     foreach (int modelId, modelsIds) {
1052         int idx = bs.getModelsNames().indexOf(modelId);
1053         assert(idx != -1 && "No such modelId in biostruct");
1054         modelsIdx << idx;
1055     }
1056 
1057     return modelsIdx;
1058 }
1059 
addBiostruct(const BioStruct3DObject * obj,const QList<int> & shownModels)1060 void BioStruct3DGLWidget::addBiostruct(const BioStruct3DObject *obj, const QList<int> &shownModels /* = QList<int>()*/) {
1061     assert(contexts.size() < 2 && "Multiple models in one view is unsupported now");
1062     BioStruct3DRendererContext ctx(obj);
1063 
1064     QList<int> shownModelsIdx = modelIdsToModelIdx(*ctx.biostruct, shownModels);
1065 
1066     // show only first model if model list is empty
1067     if (shownModelsIdx.isEmpty()) {
1068         shownModelsIdx << 0;
1069     }
1070 
1071     BioStruct3DColorScheme *colorScheme = BioStruct3DColorSchemeRegistry::createColorScheme(currentColorSchemeName, ctx.obj);
1072     assert(colorScheme);
1073     ctx.colorScheme = QSharedPointer<BioStruct3DColorScheme>(colorScheme);
1074     ctx.colorScheme->setSelectionColor(selectionColor);
1075     ctx.colorScheme->setUnselectedShadingLevel((double)unselectedShadingLevel / 100.0);
1076 
1077     BioStruct3DGLRenderer *renderer = BioStruct3DGLRendererRegistry::createRenderer(currentGLRendererName, *ctx.biostruct, ctx.colorScheme.data(), shownModelsIdx, &rendererSettings);
1078     assert(renderer);
1079     ctx.renderer = QSharedPointer<BioStruct3DGLRenderer>(renderer);
1080 
1081     contexts.append(ctx);
1082     setupRenderer(currentGLRendererName);
1083 
1084     setupFrame();
1085 }
1086 
sl_alignWith()1087 void BioStruct3DGLWidget::sl_alignWith() {
1088     const BioStruct3DRendererContext &ctx = contexts.first();
1089     int currentModelId = ctx.biostruct->getModelsNames().at(ctx.renderer->getShownModelsIndexes().first());
1090 
1091     QObjectScopedPointer<StructuralAlignmentDialog> dlg = new StructuralAlignmentDialog(contexts.first().obj, currentModelId);
1092     const int dialogResult = dlg->execIfAlgorithmAvailable();
1093     CHECK(!dlg.isNull(), );
1094 
1095     if (QDialog::Accepted == dialogResult) {
1096         sl_resetAlignment();
1097 
1098         Task *task = dlg->getTask();
1099         assert(task && "If dialog accepded it must return valid task");
1100 
1101         TaskSignalMapper *taskMapper = new TaskSignalMapper(task);
1102         connect(taskMapper, SIGNAL(si_taskFinished(Task *)), this, SLOT(sl_onAlignmentDone(Task *)));
1103 
1104         AppContext::getTaskScheduler()->registerTopLevelTask(task);
1105     }
1106 }
1107 
sl_resetAlignment()1108 void BioStruct3DGLWidget::sl_resetAlignment() {
1109     assert(contexts.size() < 3 && "Multiple models in one view is unsupported now");
1110     if (contexts.size() == 2) {
1111         contexts.removeLast();
1112         setupFrame();
1113 
1114         glFrame->makeCurrent();
1115         update();
1116     }
1117 }
1118 
sl_onAlignmentDone(Task * task)1119 void BioStruct3DGLWidget::sl_onAlignmentDone(Task *task) {
1120     if (!task->hasError()) {
1121         StructuralAlignmentTask *saTask = qobject_cast<StructuralAlignmentTask *>(task);
1122         assert(saTask && "Task should have type StructuralAlignmentTask");
1123 
1124         StructuralAlignment result = saTask->getResult();
1125         StructuralAlignmentTaskSettings settings = saTask->getSettings();
1126 
1127         const Matrix44 &mt = result.transform;
1128         const_cast<BioStruct3D *>(&settings.alt.obj->getBioStruct3D())->setTransform(mt);
1129 
1130         addBiostruct(settings.alt.obj, QList<int>() << settings.alt.modelId);
1131 
1132         glFrame->makeCurrent();
1133         update();
1134     }
1135 }
1136 
1137 }  // namespace U2
1138