1 /****************************************************************************
2 * MeshLab                                                           o o     *
3 * An extendible mesh processor                                    o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2005, 2006                                          \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program 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.                                       *
15 *                                                                           *
16 * This program 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 (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 
24 
25 
26 #include "mainwindow.h"
27 #include "plugindialog.h"
28 #include "filterScriptDialog.h"
29 #include "customDialog.h"
30 #include "saveSnapshotDialog.h"
31 #include "ui_aboutDialog.h"
32 #include "savemaskexporter.h"
33 #include "alnParser.h"
34 #include <exception>
35 #include "xmlgeneratorgui.h"
36 #include "filterthread.h"
37 #include "ml_default_decorators.h"
38 
39 #include <QToolBar>
40 #include <QToolTip>
41 #include <QStatusBar>
42 #include <QMenuBar>
43 #include <QProgressBar>
44 #include <QDesktopServices>
45 
46 
47 
48 #include "../common/scriptinterface.h"
49 #include "../common/meshlabdocumentxml.h"
50 #include "../common/meshlabdocumentbundler.h"
51 #include "../common/mlapplication.h"
52 #include "../common/filterscript.h"
53 
54 extern "C" {
55 #include "jhead.h"
56 }
57 
58 
59 using namespace std;
60 using namespace vcg;
61 
updateRecentFileActions()62 void MainWindow::updateRecentFileActions()
63 {
64     bool activeDoc = (bool) !mdiarea->subWindowList().empty() && mdiarea->currentSubWindow();
65 
66     QSettings settings;
67     QStringList files = settings.value("recentFileList").toStringList();
68 
69     int numRecentFiles = qMin(files.size(), (int)MAXRECENTFILES);
70 
71     for (int i = 0; i < numRecentFiles; ++i)
72     {
73         QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).fileName());
74         recentFileActs[i]->setText(text);
75         recentFileActs[i]->setData(files[i]);
76         recentFileActs[i]->setEnabled(activeDoc);
77     }
78     for (int j = numRecentFiles; j < MAXRECENTFILES; ++j)
79         recentFileActs[j]->setVisible(false);
80 }
81 
updateRecentProjActions()82 void MainWindow::updateRecentProjActions()
83 {
84     //bool activeDoc = (bool) !mdiarea->subWindowList().empty() && mdiarea->currentSubWindow();
85 
86     QSettings settings;
87     QStringList projs = settings.value("recentProjList").toStringList();
88 
89     int numRecentProjs = qMin(projs.size(), (int)MAXRECENTFILES);
90     for (int i = 0; i < numRecentProjs; ++i)
91     {
92         QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(projs[i]).fileName());
93         recentProjActs[i]->setText(text);
94         recentProjActs[i]->setData(projs[i]);
95         recentProjActs[i]->setEnabled(true);
96     }
97     for (int j = numRecentProjs; j < MAXRECENTFILES; ++j)
98         recentProjActs[j]->setVisible(false);
99 }
100 
101 // creates the standard plugin window
createStdPluginWnd()102 void MainWindow::createStdPluginWnd()
103 {
104     //checks if a MeshlabStdDialog is already open and closes it
105     if (stddialog!=0)
106     {
107         stddialog->close();
108         delete stddialog;
109     }
110     stddialog = new MeshlabStdDialog(this);
111     stddialog->setAllowedAreas (    Qt::NoDockWidgetArea);
112     //addDockWidget(Qt::RightDockWidgetArea,stddialog);
113 
114     //stddialog->setAttribute(Qt::WA_DeleteOnClose,true);
115     stddialog->setFloating(true);
116     stddialog->hide();
117     connect(GLA(),SIGNAL(glareaClosed()),this,SLOT(updateStdDialog()));
118     connect(GLA(),SIGNAL(glareaClosed()),stddialog,SLOT(closeClick()));
119 }
120 
createXMLStdPluginWnd()121 void MainWindow::createXMLStdPluginWnd()
122 {
123     //checks if a MeshlabStdDialog is already open and closes it
124     if (xmldialog!=nullptr){
125         xmldialog->close();
126         delete xmldialog;
127     }
128     xmldialog = new MeshLabXMLStdDialog(this);
129     //Ask filterParametersEvaluated to add current filter to filterHistory
130     connect(xmldialog,SIGNAL(filterParametersEvaluated(const QString&,const QMap<QString,QString>&)),meshDoc()->filterHistory,SLOT(addExecutedXMLFilter(const QString&,const QMap<QString,QString>& )));
131     //connect(xmldialog,SIGNAL(dialogEvaluateExpression(const Expression&,Value**)),this,SLOT(evaluateExpression(const Expression&,Value**)),Qt::DirectConnection);
132     xmldialog->setAllowedAreas (  Qt::NoDockWidgetArea);
133     //addDockWidget(Qt::RightDockWidgetArea,xmldialog);
134     //stddialog->setAttribute(Qt::WA_DeleteOnClose,true);
135     xmldialog->setFloating(true);
136     xmldialog->hide();
137     connect(GLA(),SIGNAL(glareaClosed()),this,SLOT(updateStdDialog()));
138     connect(GLA(),SIGNAL(glareaClosed()),xmldialog,SLOT(closeClick()));
139     //connect(GLA(),SIGNAL(glareaClosed()),xmldialog,SLOT(close()));
140 }
141 
142 // When we switch the current model (and we change the active window)
143 // we have to close the stddialog.
144 // this one is called when user switch current window.
updateStdDialog()145 void MainWindow::updateStdDialog()
146 {
147     if(stddialog!=0){
148         if(GLA()!=0){
149             if(stddialog->curModel != meshDoc()->mm()){
150                 stddialog->curgla=0; // invalidate the curgla member that is no more valid.
151                 stddialog->close();
152             }
153         }
154     }
155 }
156 
157 // When we switch the current model (and we change the active window)
158 // we have to close the stddialog.
159 // this one is called when user switch current window.
updateXMLStdDialog()160 void MainWindow::updateXMLStdDialog()
161 {
162     if(xmldialog!=0){
163         if(GLA()!=0){
164             if(xmldialog->curModel != meshDoc()->mm()){
165                 xmldialog->resetPointers(); // invalidate the curgla member that is no more valid.
166                 xmldialog->close();
167             }
168         }
169     }
170 }
171 
updateCustomSettings()172 void MainWindow::updateCustomSettings()
173 {
174     mwsettings.updateGlobalParameterSet(currentGlobalParams);
175     emit dispatchCustomSettings(currentGlobalParams);
176 }
177 
updateWindowMenu()178 void MainWindow::updateWindowMenu()
179 {
180     windowsMenu->clear();
181     windowsMenu->addAction(closeAllAct);
182     windowsMenu->addSeparator();
183     windowsMenu->addAction(windowsTileAct);
184     windowsMenu->addAction(windowsCascadeAct);
185     windowsMenu->addAction(windowsNextAct);
186     windowsNextAct->setEnabled(mdiarea-> subWindowList().size()>1);
187 
188     windowsMenu->addSeparator();
189 
190 
191     if((mdiarea-> subWindowList().size()>0)){
192         // Split/Unsplit SUBmenu
193         splitModeMenu = windowsMenu->addMenu(tr("&Split current view"));
194 
195         splitModeMenu->addAction(setSplitHAct);
196         splitModeMenu->addAction(setSplitVAct);
197 
198         windowsMenu->addAction(setUnsplitAct);
199 
200         // Link act
201         windowsMenu->addAction(linkViewersAct);
202 
203         // View From SUBmenu
204         viewFromMenu = windowsMenu->addMenu(tr("&View from"));
205         foreach(QAction *ac, viewFromGroupAct->actions())
206             viewFromMenu->addAction(ac);
207 
208 		// Trackball Step SUBmenu
209 		trackballStepMenu = windowsMenu->addMenu(tr("Trackball step"));
210 		foreach(QAction *ac, trackballStepGroupAct->actions())
211 			trackballStepMenu->addAction(ac);
212 
213         // View From File act
214         windowsMenu->addAction(readViewFromFileAct);
215         windowsMenu->addAction(saveViewToFileAct);
216         windowsMenu->addAction(viewFromMeshAct);
217         windowsMenu->addAction(viewFromRasterAct);
218 
219         // Copy and paste shot acts
220         windowsMenu->addAction(copyShotToClipboardAct);
221         windowsMenu->addAction(pasteShotFromClipboardAct);
222 
223         //Enabling the actions
224         MultiViewer_Container *mvc = currentViewContainer();
225         if(mvc)
226         {
227             setUnsplitAct->setEnabled(mvc->viewerCounter()>1);
228             GLArea* current = mvc->currentView();
229             if(current)
230             {
231                 setSplitHAct->setEnabled(current->size().height()/2 > current->minimumSizeHint().height());
232                 setSplitVAct->setEnabled(current->size().width()/2 > current->minimumSizeHint().width());
233 
234                 linkViewersAct->setEnabled(currentViewContainer()->viewerCounter()>1);
235                 if(currentViewContainer()->viewerCounter()==1)
236                     linkViewersAct->setChecked(false);
237 
238                 windowsMenu->addSeparator();
239             }
240         }
241     }
242 
243     QList<QMdiSubWindow*> windows = mdiarea->subWindowList();
244 
245     if(windows.size() > 0)
246         windowsMenu->addSeparator();
247 
248     int i=0;
249     foreach(QWidget *w,windows)
250     {
251         QString text = tr("&%1. %2").arg(i+1).arg(QFileInfo(w->windowTitle()).fileName());
252         QAction *action  = windowsMenu->addAction(text);
253         action->setCheckable(true);
254         action->setChecked(w == mdiarea->currentSubWindow());
255         // Connect the signal to activate the selected window
256         connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));
257         windowMapper->setMapping(action, w);
258         ++i;
259     }
260 }
261 
enableDocumentSensibleActionsContainer(const bool allowed)262 void MainWindow::enableDocumentSensibleActionsContainer(const bool allowed)
263 {
264     QAction* fileact = fileMenu->menuAction();
265     if (fileact != NULL)
266         fileact->setEnabled(allowed);
267     if (mainToolBar != NULL)
268         mainToolBar->setEnabled(allowed);
269     if (searchToolBar != NULL)
270         searchToolBar->setEnabled(allowed);
271     QAction* filtact = filterMenu->menuAction();
272     if (filtact != NULL)
273         filtact->setEnabled(allowed);
274     if (filterToolBar != NULL)
275         filterToolBar->setEnabled(allowed);
276     QAction* editact = editMenu->menuAction();
277     if (editact != NULL)
278         editact->setEnabled(allowed);
279     if (editToolBar)
280         editToolBar->setEnabled(allowed);
281 }
282 
283 
284 
285 //menu create is not enabled only in case of not valid/existing meshdocument
updateSubFiltersMenu(const bool createmenuenabled,const bool validmeshdoc)286 void MainWindow::updateSubFiltersMenu( const bool createmenuenabled,const bool validmeshdoc )
287 {
288     showFilterScriptAct->setEnabled(validmeshdoc);
289     filterMenuSelect->setEnabled(validmeshdoc);
290     updateMenuItems(filterMenuSelect,validmeshdoc);
291     filterMenuClean->setEnabled(validmeshdoc);
292     updateMenuItems(filterMenuClean,validmeshdoc);
293     filterMenuCreate->setEnabled(createmenuenabled || validmeshdoc);
294     updateMenuItems(filterMenuCreate,createmenuenabled || validmeshdoc);
295     filterMenuRemeshing->setEnabled(validmeshdoc);
296     updateMenuItems(filterMenuRemeshing,validmeshdoc);
297     filterMenuPolygonal->setEnabled(validmeshdoc);
298     updateMenuItems(filterMenuPolygonal,validmeshdoc);
299     filterMenuColorize->setEnabled(validmeshdoc);
300     updateMenuItems(filterMenuColorize,validmeshdoc);
301     filterMenuSmoothing->setEnabled(validmeshdoc);
302     updateMenuItems(filterMenuSmoothing,validmeshdoc);
303     filterMenuQuality->setEnabled(validmeshdoc);
304     updateMenuItems(filterMenuQuality,validmeshdoc);
305     filterMenuNormal->setEnabled(validmeshdoc);
306     updateMenuItems(filterMenuNormal,validmeshdoc);
307     filterMenuMeshLayer->setEnabled(validmeshdoc);
308     updateMenuItems(filterMenuMeshLayer,validmeshdoc);
309     filterMenuRasterLayer->setEnabled(validmeshdoc);
310     updateMenuItems(filterMenuRasterLayer,validmeshdoc);
311     filterMenuRangeMap->setEnabled(validmeshdoc);
312     updateMenuItems(filterMenuRangeMap,validmeshdoc);
313     filterMenuPointSet->setEnabled(validmeshdoc);
314     updateMenuItems(filterMenuPointSet,validmeshdoc);
315     filterMenuSampling->setEnabled(validmeshdoc);
316     updateMenuItems(filterMenuSampling,validmeshdoc);
317     filterMenuTexture->setEnabled(validmeshdoc);
318     updateMenuItems(filterMenuTexture,validmeshdoc);
319     filterMenuCamera->setEnabled(validmeshdoc);
320     updateMenuItems(filterMenuCamera,validmeshdoc);
321 
322 }
323 
updateMenuItems(QMenu * menu,const bool enabled)324 void MainWindow::updateMenuItems(QMenu* menu,const bool enabled)
325 {
326     foreach(QAction* act,menu->actions())
327         act->setEnabled(enabled);
328 }
329 
switchOffDecorator(QAction * decorator)330 void MainWindow::switchOffDecorator(QAction* decorator)
331 {
332     if (GLA() != NULL)
333     {
334         int res = GLA()->iCurPerMeshDecoratorList().removeAll(decorator);
335         if (res == 0)
336             GLA()->iPerDocDecoratorlist.removeAll(decorator);
337         updateMenus();
338 		layerDialog->updateDecoratorParsView();
339         GLA()->update();
340     }
341 }
342 
updateLayerDialog()343 void MainWindow::updateLayerDialog()
344 {
345 	if ((meshDoc() == NULL) || ((layerDialog != NULL) && !(layerDialog->isVisible())))
346 		return;
347     MultiViewer_Container* mvc = currentViewContainer();
348     if (mvc == NULL)
349         return;
350     MLSceneGLSharedDataContext* shared = mvc->sharedDataContext();
351     if (shared == NULL)
352         return;
353     if(GLA())
354     {
355         MLSceneGLSharedDataContext::PerMeshRenderingDataMap dtf;
356         shared->getRenderInfoPerMeshView(GLA()->context(),dtf);
357 		/*Add to the table the info for the per view global rendering of the Project*/
358 		MLRenderingData projdt;
359 		//GLA()->getPerDocGlobalRenderingData(projdt);
360 		dtf[-1] = projdt;
361         layerDialog->updateTable(dtf);
362         layerDialog->updateLog(meshDoc()->Log);
363         layerDialog->updateDecoratorParsView();
364         MLRenderingData dt;
365         if (meshDoc()->mm() != NULL)
366 		{
367 			MLSceneGLSharedDataContext::PerMeshRenderingDataMap::iterator it = dtf.find(meshDoc()->mm()->id());
368 			if (it != dtf.end())
369 				layerDialog->updateRenderingParametersTab(meshDoc()->mm()->id(),*it);
370         }
371 		if (globrendtoolbar != NULL)
372 		{
373 			shared->getRenderInfoPerMeshView(GLA()->context(), dtf);
374 			globrendtoolbar->statusConsistencyCheck(dtf);
375 		}
376     }
377 }
378 
updateMenus()379 void MainWindow::updateMenus()
380 {
381 
382     bool activeDoc = !(mdiarea->subWindowList().empty()) && (mdiarea->currentSubWindow() != NULL);
383     bool notEmptyActiveDoc = activeDoc && (meshDoc() != NULL) && !(meshDoc()->meshList.empty());
384 
385 	//std::cout << "SubWindowsList empty: " << mdiarea->subWindowList().empty() << " Valid Current Sub Windows: " << (mdiarea->currentSubWindow() != NULL) << " MeshList empty: " << meshDoc()->meshList.empty() << "\n";
386 
387     importMeshAct->setEnabled(activeDoc);
388 
389     exportMeshAct->setEnabled(notEmptyActiveDoc);
390     exportMeshAsAct->setEnabled(notEmptyActiveDoc);
391     reloadMeshAct->setEnabled(notEmptyActiveDoc);
392     reloadAllMeshAct->setEnabled(notEmptyActiveDoc);
393     importRasterAct->setEnabled(activeDoc);
394 
395     saveProjectAct->setEnabled(activeDoc);
396     closeProjectAct->setEnabled(activeDoc);
397 
398     saveSnapshotAct->setEnabled(activeDoc);
399 
400     updateRecentFileActions();
401     updateRecentProjActions();
402     filterMenu->setEnabled(!filterMenu->actions().isEmpty());
403     if (!filterMenu->actions().isEmpty())
404         updateSubFiltersMenu(GLA() != NULL,notEmptyActiveDoc);
405     lastFilterAct->setEnabled(false);
406     lastFilterAct->setText(QString("Apply filter"));
407     editMenu->setEnabled(!editMenu->actions().isEmpty());
408     updateMenuItems(editMenu,activeDoc);
409     renderMenu->setEnabled(!renderMenu->actions().isEmpty());
410     updateMenuItems(renderMenu,activeDoc);
411     fullScreenAct->setEnabled(activeDoc);
412     showLayerDlgAct->setEnabled(activeDoc);
413     showTrackBallAct->setEnabled(activeDoc);
414     resetTrackBallAct->setEnabled(activeDoc);
415     showInfoPaneAct->setEnabled(activeDoc);
416     windowsMenu->setEnabled(activeDoc);
417     preferencesMenu->setEnabled(activeDoc);
418 
419     showToolbarStandardAct->setChecked(mainToolBar->isVisible());
420     if(activeDoc && GLA())
421     {
422         if(GLA()->getLastAppliedFilter() != NULL)
423         {
424             lastFilterAct->setText(QString("Apply filter ") + GLA()->getLastAppliedFilter()->text());
425             lastFilterAct->setEnabled(true);
426         }
427 
428         // Management of the editing toolbar
429         // when you enter in a editing mode you can toggle between editing
430         // and camera moving by esc;
431         // you exit from editing mode by pressing again the editing button
432         // When you are in a editing mode all the other editing are disabled.
433 
434         foreach (QAction *a,PM.editActionList)
435         {
436             a->setChecked(false);
437             a->setEnabled( GLA()->getCurrentEditAction() == NULL );
438         }
439 
440         suspendEditModeAct->setChecked(GLA()->suspendedEditor);
441         suspendEditModeAct->setDisabled(GLA()->getCurrentEditAction() == NULL);
442 
443         if(GLA()->getCurrentEditAction())
444         {
445             GLA()->getCurrentEditAction()->setChecked(! GLA()->suspendedEditor);
446             GLA()->getCurrentEditAction()->setEnabled(true);
447         }
448 
449         showInfoPaneAct->setChecked(GLA()->infoAreaVisible);
450         showTrackBallAct->setChecked(GLA()->isTrackBallVisible());
451 
452 //WARNING!!!! It may be useful
453 /* RenderMode rendtmp;
454 if (meshDoc()->meshList.size() > 0)
455 {
456     QMap<int,RenderMode>::iterator it = GLA()->rendermodemap.find(meshDoc()->meshList[0]->id());
457     if (it == GLA()->rendermodemap.end())
458         throw MeshLabException("Something really bad happened. Mesh id has not been found in rendermodemap.");
459     rendtmp = it.value();
460 }
461 bool checktext = (rendtmp.textureMode != GLW::TMNone);
462 int ii = 0;
463 while(ii < meshDoc()->meshList.size())
464 {
465     if (meshDoc()->meshList[ii] == NULL)
466         return;
467     QMap<int,RenderMode>::iterator it = GLA()->rendermodemap.find(meshDoc()->meshList[ii]->id());
468     if (it == GLA()->rendermodemap.end())
469         throw MeshLabException("Something really bad happened. Mesh id has not been found in rendermodemap.");
470     RenderMode& rm = it.value();
471     if (rendtmp.drawMode != rm.drawMode)
472         rendtmp.setDrawMode(vcg::GLW::DMNone);
473 
474     if (rendtmp.colorMode != rm.colorMode)
475         rendtmp.setColorMode(vcg::GLW::CMNone);
476 
477     checktext &= (rm.textureMode != GLW::TMNone);
478 
479     rendtmp.setLighting(rendtmp.lighting && rm.lighting);
480     rendtmp.setFancyLighting(rendtmp.fancyLighting && rm.fancyLighting);
481     rendtmp.setDoubleFaceLighting(rendtmp.doubleSideLighting && rm.doubleSideLighting);
482     rendtmp.setBackFaceCull(rendtmp.backFaceCull || rm.backFaceCull);
483     ++ii;
484 }*/
485 /////////////////////////////
486 
487         // Decorator Menu Checking and unChecking
488         // First uncheck and disable all the decorators
489         foreach (QAction *a, PM.decoratorActionList)
490         {
491             a->setChecked(false);
492             a->setEnabled(true);
493         }
494         // Check the decorator per Document of the current glarea
495         foreach (QAction *a,   GLA()->iPerDocDecoratorlist)
496         { a ->setChecked(true); }
497 
498         // Then check the decorator enabled for the current mesh.
499         if(GLA()->mm())
500             foreach (QAction *a,   GLA()->iCurPerMeshDecoratorList())
501             a ->setChecked(true);
502     } // if active
503     else
504     {
505         foreach (QAction *a,PM.editActionList)
506         {
507             a->setEnabled(false);
508         }
509         foreach (QAction *a,PM.decoratorActionList)
510             a->setEnabled(false);
511 
512     }
513 	GLArea* tmp = GLA();
514     if(tmp != NULL)
515     {
516         showLayerDlgAct->setChecked(layerDialog->isVisible());
517         showRasterAct->setEnabled((meshDoc() != NULL) && (meshDoc()->rm() != 0));
518         showRasterAct->setChecked(tmp->isRaster());
519     }
520     else
521     {
522         foreach (QAction *a,PM.decoratorActionList)
523         {
524             a->setChecked(false);
525             a->setEnabled(false);
526         }
527 
528 
529         layerDialog->setVisible(false);
530     }
531     if (searchMenu != NULL)
532         searchMenu->searchLineWidth() = longestActionWidthInAllMenus();
533     updateWindowMenu();
534 }
535 
setSplit(QAction * qa)536 void MainWindow::setSplit(QAction *qa)
537 {
538     MultiViewer_Container *mvc = currentViewContainer();
539     if(mvc)
540     {
541         GLArea *glwClone=new GLArea(this, mvc, &currentGlobalParams);
542 		//connect(glwClone, SIGNAL(insertRenderingDataForNewlyGeneratedMesh(int)), this, SLOT(addRenderingDataIfNewlyGeneratedMesh(int)));
543         if(qa->text() == tr("&Horizontally"))
544             mvc->addView(glwClone,Qt::Vertical);
545         else if(qa->text() == tr("&Vertically"))
546             mvc->addView(glwClone,Qt::Horizontal);
547 
548         //The loading of the raster must be here
549         if(GLA()->isRaster())
550         {
551             glwClone->setIsRaster(true);
552             if(this->meshDoc()->rm()->id()>=0)
553                 glwClone->loadRaster(this->meshDoc()->rm()->id());
554         }
555 
556         updateMenus();
557 
558         glwClone->resetTrackBall();
559         glwClone->update();
560     }
561 
562 }
563 
setUnsplit()564 void MainWindow::setUnsplit()
565 {
566     MultiViewer_Container *mvc = currentViewContainer();
567     if(mvc)
568     {
569         assert(mvc->viewerCounter() >1);
570 
571         mvc->removeView(mvc->currentView()->getId());
572 
573         updateMenus();
574     }
575 }
576 
577 //set the split/unsplit menu that appears right clicking on a splitter's handle
setHandleMenu(QPoint point,Qt::Orientation orientation,QSplitter * origin)578 void MainWindow::setHandleMenu(QPoint point, Qt::Orientation orientation, QSplitter *origin)
579 {
580     MultiViewer_Container *mvc =  currentViewContainer();
581     int epsilon =10;
582     splitMenu->clear();
583     unSplitMenu->clear();
584     //the viewer to split/unsplit is chosen through picking
585 
586     //Vertical handle allows to split horizontally
587     if(orientation == Qt::Vertical)
588     {
589         splitUpAct->setData(point);
590         splitDownAct->setData(point);
591 
592         //check if the viewer on the top is splittable according to its size
593         int pickingId = mvc->getViewerByPicking(QPoint(point.x(), point.y()-epsilon));
594         if(pickingId>=0)
595             splitUpAct->setEnabled(mvc->getViewer(pickingId)->size().width()/2 > mvc->getViewer(pickingId)->minimumSizeHint().width());
596 
597         //the viewer on top can be closed only if the splitter over the handle that originated the event has one child
598         bool unSplittabilityUp = true;
599         Splitter * upSplitter = qobject_cast<Splitter *>(origin->widget(0));
600         if(upSplitter)
601             unSplittabilityUp = !(upSplitter->count()>1);
602         unsplitUpAct->setEnabled(unSplittabilityUp);
603 
604         //check if the viewer below is splittable according to its size
605         pickingId = mvc->getViewerByPicking(QPoint(point.x(), point.y()+epsilon));
606         if(pickingId>=0)
607             splitDownAct->setEnabled(mvc->getViewer(pickingId)->size().width()/2 > mvc->getViewer(pickingId)->minimumSizeHint().width());
608 
609         //the viewer below can be closed only if the splitter ounder the handle that originated the event has one child
610         bool unSplittabilityDown = true;
611         Splitter * downSplitter = qobject_cast<Splitter *>(origin->widget(1));
612         if(downSplitter)
613             unSplittabilityDown = !(downSplitter->count()>1);
614         unsplitDownAct->setEnabled(unSplittabilityDown);
615 
616         splitMenu->addAction(splitUpAct);
617         splitMenu->addAction(splitDownAct);
618 
619         unsplitUpAct->setData(point);
620         unsplitDownAct->setData(point);
621 
622         unSplitMenu->addAction(unsplitUpAct);
623         unSplitMenu->addAction(unsplitDownAct);
624     }
625     //Horizontal handle allows to split vertically
626     else if (orientation == Qt::Horizontal)
627     {
628         splitRightAct->setData(point);
629         splitLeftAct->setData(point);
630 
631         //check if the viewer on the right is splittable according to its size
632         int pickingId =mvc->getViewerByPicking(QPoint(point.x()+epsilon, point.y()));
633         if(pickingId>=0)
634             splitRightAct->setEnabled(mvc->getViewer(pickingId)->size().height()/2 > mvc->getViewer(pickingId)->minimumSizeHint().height());
635 
636         //the viewer on the right can be closed only if the splitter on the right the handle that originated the event has one child
637         bool unSplittabilityRight = true;
638         Splitter * rightSplitter = qobject_cast<Splitter *>(origin->widget(1));
639         if(rightSplitter)
640             unSplittabilityRight = !(rightSplitter->count()>1);
641         unsplitRightAct->setEnabled(unSplittabilityRight);
642 
643         //check if the viewer on the left is splittable according to its size
644         pickingId =mvc->getViewerByPicking(QPoint(point.x()-epsilon, point.y()));
645         if(pickingId>=0)
646             splitLeftAct->setEnabled(mvc->getViewer(pickingId)->size().height()/2 > mvc->getViewer(pickingId)->minimumSizeHint().height());
647 
648         //the viewer on the left can be closed only if the splitter on the left of the handle that originated the event has one child
649         bool unSplittabilityLeft = true;
650         Splitter * leftSplitter = qobject_cast<Splitter *>(origin->widget(0));
651         if(leftSplitter)
652             unSplittabilityLeft = !(leftSplitter->count()>1);
653         unsplitLeftAct->setEnabled(unSplittabilityLeft);
654 
655         splitMenu->addAction(splitRightAct);
656         splitMenu->addAction(splitLeftAct);
657 
658         unsplitRightAct->setData(point);
659         unsplitLeftAct->setData(point);
660 
661         unSplitMenu->addAction(unsplitRightAct);
662         unSplitMenu->addAction(unsplitLeftAct);
663     }
664     handleMenu->popup(point);
665 }
666 
667 
splitFromHandle(QAction * qa)668 void MainWindow::splitFromHandle(QAction *qa )
669 {
670     MultiViewer_Container *mvc = currentViewContainer();
671     QPoint point = qa->data().toPoint();
672     int epsilon =10;
673 
674     if(qa->text() == tr("&Right"))
675         point.setX(point.x()+ epsilon);
676     else if(qa->text() == tr("&Left"))
677         point.setX(point.x()- epsilon);
678     else if(qa->text() == tr("&Up"))
679         point.setY(point.y()- epsilon);
680     else if(qa->text() == tr("&Down"))
681         point.setY(point.y()+ epsilon);
682 
683     int newCurrent = mvc->getViewerByPicking(point);
684     mvc->updateCurrent(newCurrent);
685 
686     if(qa->text() == tr("&Right") || qa->text() == tr("&Left"))
687         setSplit(new QAction(tr("&Horizontally"), this));
688     else
689         setSplit( new QAction(tr("&Vertically"), this));
690 }
691 
unsplitFromHandle(QAction * qa)692 void MainWindow::unsplitFromHandle(QAction * qa)
693 {
694     MultiViewer_Container *mvc = currentViewContainer();
695 
696     QPoint point = qa->data().toPoint();
697     int epsilon =10;
698 
699     if(qa->text() == tr("&Right"))
700         point.setX(point.x()+ epsilon);
701     else if(qa->text() == tr("&Left"))
702         point.setX(point.x()- epsilon);
703     else if(qa->text() == tr("&Up"))
704         point.setY(point.y()- epsilon);
705     else if(qa->text() == tr("&Down"))
706         point.setY(point.y()+ epsilon);
707 
708     int newCurrent = mvc->getViewerByPicking(point);
709     mvc->updateCurrent(newCurrent);
710 
711     setUnsplit();
712 }
713 
linkViewers()714 void MainWindow::linkViewers()
715 {
716     MultiViewer_Container *mvc = currentViewContainer();
717     mvc->updateTrackballInViewers();
718 }
719 
toggleOrtho()720 void MainWindow::toggleOrtho()
721 {
722 	if (GLA()) GLA()->toggleOrtho();
723 }
724 
viewFrom(QAction * qa)725 void MainWindow::viewFrom(QAction *qa)
726 {
727     if(GLA()) GLA()->createOrthoView(qa->text());
728 }
729 
trackballStep(QAction * qa)730 void MainWindow::trackballStep(QAction *qa)
731 {
732 	if (GLA()) GLA()->trackballStep(qa->text());
733 }
734 
readViewFromFile()735 void MainWindow::readViewFromFile()
736 {
737     if(GLA()) GLA()->readViewFromFile();
738     updateMenus();
739 }
740 
saveViewToFile()741 void MainWindow::saveViewToFile()
742 {
743     if(GLA()) GLA()->saveViewToFile();
744 }
745 
viewFromCurrentMeshShot()746 void MainWindow::viewFromCurrentMeshShot()
747 {
748     if(GLA()) GLA()->viewFromCurrentShot("Mesh");
749     updateMenus();
750 }
751 
viewFromCurrentRasterShot()752 void MainWindow::viewFromCurrentRasterShot()
753 {
754     if(GLA()) GLA()->viewFromCurrentShot("Raster");
755     updateMenus();
756 }
757 
copyViewToClipBoard()758 void MainWindow::copyViewToClipBoard()
759 {
760     if(GLA()) GLA()->viewToClipboard();
761 }
762 
pasteViewFromClipboard()763 void MainWindow::pasteViewFromClipboard()
764 {
765     if(GLA()) GLA()->viewFromClipboard();
766     updateMenus();
767 }
768 
dragEnterEvent(QDragEnterEvent * event)769 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
770 {
771     //qDebug("dragEnterEvent: %s",event->format());
772     event->accept();
773 }
774 
dropEvent(QDropEvent * event)775 void MainWindow::dropEvent ( QDropEvent * event )
776 {
777     //qDebug("dropEvent: %s",event->format());
778     const QMimeData * data = event->mimeData();
779     if (data->hasUrls())
780     {
781         QList< QUrl > url_list = data->urls();
782         bool layervis = false;
783         if (layerDialog != NULL)
784         {
785             layervis = layerDialog->isVisible();
786             showLayerDlg(false);
787         }
788         for (int i=0, size=url_list.size(); i<size; i++)
789         {
790             QString path = url_list.at(i).toLocalFile();
791             if( (event->keyboardModifiers () == Qt::ControlModifier ) || ( QApplication::keyboardModifiers () == Qt::ControlModifier ))
792             {
793                 this->newProject();
794             }
795 
796             if(path.endsWith("mlp",Qt::CaseInsensitive) || path.endsWith("mlb", Qt::CaseInsensitive) || path.endsWith("aln",Qt::CaseInsensitive) || path.endsWith("out",Qt::CaseInsensitive) || path.endsWith("nvm",Qt::CaseInsensitive) )
797                 openProject(path);
798             else
799             {
800                 importMesh(path);
801             }
802         }
803         showLayerDlg(layervis || meshDoc()->meshList.size() > 0);
804     }
805 }
806 
endEdit()807 void MainWindow::endEdit()
808 {
809 	MultiViewer_Container* mvc = currentViewContainer();
810 	if ((meshDoc() == NULL) || (GLA() == NULL) || (mvc == NULL))
811 		return;
812 
813 
814 	for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii)
815 	{
816 		MeshModel* mm = meshDoc()->meshList[ii];
817 		if (mm != NULL)
818 			addRenderingDataIfNewlyGeneratedMesh(mm->id());
819 	}
820 	meshDoc()->meshDocStateData().clear();
821 
822     GLA()->endEdit();
823 	updateLayerDialog();
824 }
825 
applyLastFilter()826 void MainWindow::applyLastFilter()
827 {
828     if(GLA()==nullptr) return;
829     GLA()->getLastAppliedFilter()->activate(QAction::Trigger);
830 }
831 
showFilterScript()832 void MainWindow::showFilterScript()
833 {
834     if (meshDoc()->filterHistory != nullptr)
835     {
836         FilterScriptDialog dialog(this);
837 
838         dialog.setScript(meshDoc()->filterHistory);
839         if (dialog.exec()==QDialog::Accepted)
840         {
841             runFilterScript();
842             return ;
843         }
844     }
845 }
846 
runFilterScript()847 void MainWindow::runFilterScript()
848 {
849     if ((meshDoc() == nullptr) || (meshDoc()->filterHistory == nullptr))
850         return;
851     for(FilterScript::iterator ii= meshDoc()->filterHistory->filtparlist.begin();ii!= meshDoc()->filterHistory->filtparlist.end();++ii)
852     {
853         QString filtnm = (*ii)->filterName();
854         int classes = 0;
855         int postCondMask = 0;
856         if (!(*ii)->isXMLFilter())
857         {
858             QAction *action = PM.actionFilterMap[ filtnm];
859             MeshFilterInterface *iFilter = qobject_cast<MeshFilterInterface *>(action->parent());
860 
861             int req=iFilter->getRequirements(action);
862             if (meshDoc()->mm() != NULL)
863                 meshDoc()->mm()->updateDataMask(req);
864             iFilter->setLog(&meshDoc()->Log);
865             OldFilterNameParameterValuesPair* old = reinterpret_cast<OldFilterNameParameterValuesPair*>(*ii);
866             RichParameterSet &parameterSet = old->pair.second;
867 
868             for(int i = 0; i < parameterSet.paramList.size(); i++)
869             {
870                 //get a modifieable reference
871                 RichParameter* parameter = parameterSet.paramList[i];
872 
873                 //if this is a mesh paramter and the index is valid
874                 if(parameter->val->isMesh())
875                 {
876                     RichMesh* md = reinterpret_cast<RichMesh*>(parameter);
877                     if( md->meshindex < meshDoc()->size() &&
878                         md->meshindex >= 0  )
879                     {
880                         RichMesh* rmesh = new RichMesh(parameter->name,md->meshindex,meshDoc());
881                         parameterSet.paramList.replace(i,rmesh);
882                     } else
883                     {
884                         printf("Meshes loaded: %i, meshes asked for: %i \n", meshDoc()->size(), md->meshindex );
885                         printf("One of the filters in the script needs more meshes than you have loaded.\n");
886                         return;
887                     }
888                     delete parameter;
889                 }
890             }
891             //iFilter->applyFilter( action, *(meshDoc()->mm()), (*ii).second, QCallBack );
892 
893             bool created = false;
894             MLSceneGLSharedDataContext* shar = NULL;
895             if (currentViewContainer() != NULL)
896             {
897                 shar = currentViewContainer()->sharedDataContext();
898                 //GLA() is only the parent
899                 QGLWidget* filterWidget = new QGLWidget(GLA(),shar);
900                 QGLFormat defForm = QGLFormat::defaultFormat();
901                 iFilter->glContext = new MLPluginGLContext(defForm,filterWidget->context()->device(),*shar);
902                 created = iFilter->glContext->create(filterWidget->context());
903                 shar->addView(iFilter->glContext);
904                 MLRenderingData dt;
905                 MLRenderingData::RendAtts atts;
906                 atts[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] = true;
907                 atts[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL] = true;
908 
909 
910                 if (iFilter->filterArity(action) == MeshFilterInterface::SINGLE_MESH)
911                 {
912                     MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(meshDoc()->mm());
913                     if ((pm != MLRenderingData::PR_ARITY) && (meshDoc()->mm() != NULL))
914                     {
915                         dt.set(pm,atts);
916                         shar->setRenderingDataPerMeshView(meshDoc()->mm()->id(),iFilter->glContext,dt);
917                     }
918                 }
919                 else
920                 {
921                     for(int ii = 0;ii < meshDoc()->meshList.size();++ii)
922                     {
923                         MeshModel* mm = meshDoc()->meshList[ii];
924                         MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(mm);
925                         if ((pm != MLRenderingData::PR_ARITY) && (mm != NULL))
926                         {
927                             dt.set(pm,atts);
928                             shar->setRenderingDataPerMeshView(mm->id(),iFilter->glContext,dt);
929                         }
930                     }
931                 }
932 
933             }
934             if ((!created) || (!iFilter->glContext->isValid()))
935                 throw MLException("A valid GLContext is required by the filter to work.\n");
936             meshDoc()->setBusy(true);
937             //WARNING!!!!!!!!!!!!
938             /* to be changed */
939             iFilter->applyFilter( action, *meshDoc(), old->pair.second, QCallBack );
940 			for (MeshModel* mm = meshDoc()->nextMesh(); mm != NULL; mm = meshDoc()->nextMesh(mm))
941 				vcg::tri::Allocator<CMeshO>::CompactEveryVector(mm->cm);
942             meshDoc()->setBusy(false);
943             if (shar != NULL)
944                 shar->removeView(iFilter->glContext);
945             delete iFilter->glContext;
946             classes = int(iFilter->getClass(action));
947 			postCondMask = iFilter->postCondition(action);
948         }
949         else
950         {
951             MeshLabXMLFilterContainer& cont = PM.stringXMLFilterMap[ filtnm];
952             MLXMLPluginInfo* info = cont.xmlInfo;
953             MeshLabFilterInterface* cppfilt = cont.filterInterface;
954             try
955             {
956                 if (cppfilt != NULL)
957                 {
958                     cppfilt->setLog(&meshDoc()->Log);
959 
960                     Env env ;
961 					QMap<QString, QString> persistentparam;
962 					foreach(RichParameter* rp, currentGlobalPars().paramList)
963 					{
964 						if (rp != NULL)
965 							persistentparam[rp->name] = RichParameterAdapter::convertToStringValue(*rp);
966 					}
967 
968 					QScriptValue val = env.loadMLScriptEnv(*meshDoc(), PM, persistentparam);
969                     XMLFilterNameParameterValuesPair* xmlfilt = reinterpret_cast<XMLFilterNameParameterValuesPair*>(*ii);
970                     QMap<QString,QString>& parmap = xmlfilt->pair.second;
971                     for(QMap<QString,QString>::const_iterator it = parmap.constBegin();it != parmap.constEnd();++it)
972                         env.insertExpressionBinding(it.key(),it.value());
973 
974                     EnvWrap envwrap(env);
975                     MLXMLPluginInfo::XMLMapList params = info->filterParameters(filtnm);
976                     for(int i = 0; i < params.size(); ++i)
977                     {
978                         MLXMLPluginInfo::XMLMap& parinfo = params[i];
979 
980                         //if this is a mesh parameter and the index is valid
981                         if(parinfo[MLXMLElNames::paramType]  == MLXMLElNames::meshType)
982                         {
983                             QString& parnm = parinfo[MLXMLElNames::paramName];
984                             MeshModel* meshmdl = envwrap.evalMesh(parnm);
985                             if( meshmdl == NULL)
986                             {
987                                 //parnm is associated with ,
988                                 printf("Meshes loaded: %i, meshes asked for: %i \n", meshDoc()->size(), envwrap.evalInt(parnm) );
989                                 printf("One of the filters in the script needs more meshes than you have loaded.\n");
990                                 return;
991                             }
992                         }
993                     }
994                     disconnect(meshDoc(),SIGNAL(documentUpdated()),GLA(),SLOT(completeUpdateRequested()));
995                     MLSceneGLSharedDataContext* shar = NULL;
996                     bool created = false;
997                     if (currentViewContainer() != NULL)
998                     {
999                         shar = currentViewContainer()->sharedDataContext();
1000                         //GLA() is only the parent
1001                         QGLWidget* filterWidget = new QGLWidget(GLA(),shar);
1002                         QGLFormat defForm = QGLFormat::defaultFormat();
1003                         cppfilt->glContext = new MLPluginGLContext(defForm,filterWidget->context()->device(),*shar);
1004                         created = cppfilt->glContext->create(filterWidget->context());
1005 
1006                         MLRenderingData dt;
1007                         MLRenderingData::RendAtts atts;
1008                         atts[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] = true;
1009                         atts[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL] = true;
1010 
1011 
1012                         if (info->filterAttribute(filtnm,MLXMLElNames::filterArity) == MLXMLElNames::singleMeshArity)
1013                         {
1014                             MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(meshDoc()->mm());
1015                             if ((pm != MLRenderingData::PR_ARITY) && (meshDoc()->mm() != NULL))
1016                             {
1017                                 dt.set(pm,atts);
1018                                 shar->setRenderingDataPerMeshView(meshDoc()->mm()->id(),cppfilt->glContext,dt);
1019                             }
1020                         }
1021                         else
1022                         {
1023                             for(int ii = 0;ii < meshDoc()->meshList.size();++ii)
1024                             {
1025                                 MeshModel* mm = meshDoc()->meshList[ii];
1026                                 MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(mm);
1027                                 if ((pm != MLRenderingData::PR_ARITY) && (mm != NULL))
1028                                 {
1029                                     dt.set(pm,atts);
1030                                     shar->setRenderingDataPerMeshView(mm->id(),cppfilt->glContext,dt);
1031                                 }
1032                             }
1033                         }
1034                     }
1035                     if ((!created) || (!cppfilt->glContext->isValid()))
1036                         throw MLException("A valid GLContext is required by the filter to work.\n");
1037 
1038 
1039                     //WARNING!!!!!!!!!!!!
1040                     /* IT SHOULD INVOKE executeFilter function. Unfortunately this function create a different thread for each invoked filter, and the MeshLab synchronization mechanisms are quite naive. Better to invoke the filters list in the same thread*/
1041                     meshDoc()->setBusy(true);
1042                     cppfilt->applyFilter( filtnm, *meshDoc(), envwrap, QCallBack );
1043 					for (MeshModel* mm = meshDoc()->nextMesh(); mm != NULL; mm = meshDoc()->nextMesh(mm))
1044 						vcg::tri::Allocator<CMeshO>::CompactEveryVector(mm->cm);
1045                     meshDoc()->setBusy(false);
1046                     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1047                     if ((currentViewContainer() != NULL) && (currentViewContainer()->sharedDataContext() != NULL))
1048                         currentViewContainer()->sharedDataContext()->removeView(cppfilt->glContext);
1049                     delete cppfilt->glContext;
1050                     GLA()->completeUpdateRequested();
1051                     connect(meshDoc(),SIGNAL(documentUpdated()),GLA(),SLOT(completeUpdateRequested()));
1052                     QStringList filterClassesList = cont.xmlInfo->filterAttribute(filtnm,MLXMLElNames::filterClass).split(QRegExp("\\W+"), QString::SkipEmptyParts);
1053                     classes = MeshLabFilterInterface::convertStringListToCategoryEnum(filterClassesList);
1054 					QString postCond = cont.xmlInfo->filterAttribute(filtnm, MLXMLElNames::filterPostCond);
1055 					QStringList postCondList = postCond.split(QRegExp("\\W+"), QString::SkipEmptyParts);
1056 					postCondMask = MeshLabFilterInterface::convertStringListToMeshElementEnum(postCondList);
1057                 }
1058                 else
1059                     throw MLException("WARNING! The MeshLab Script System is able to manage just the C++ XML filters.");
1060             }
1061             catch (MLException& e)
1062             {
1063                 meshDoc()->Log.Log(GLLogStream::WARNING,e.what());
1064             }
1065         }
1066         if (meshDoc()->mm() != NULL)
1067         {
1068             if(classes & MeshFilterInterface::FaceColoring )
1069             {
1070                 meshDoc()->mm()->updateDataMask(MeshModel::MM_FACECOLOR);
1071             }
1072             if(classes & MeshFilterInterface::VertexColoring )
1073 			{
1074                 meshDoc()->mm()->updateDataMask(MeshModel::MM_VERTCOLOR);
1075             }
1076             if(classes & MeshModel::MM_COLOR)
1077             {
1078                 meshDoc()->mm()->updateDataMask(MeshModel::MM_COLOR);
1079             }
1080             if(classes & MeshModel::MM_CAMERA)
1081                 meshDoc()->mm()->updateDataMask(MeshModel::MM_CAMERA);
1082         }
1083 
1084 		bool newmeshcreated = false;
1085 		if (classes & MeshFilterInterface::MeshCreation)
1086 			newmeshcreated = true;
1087 		updateSharedContextDataAfterFilterExecution(postCondMask, classes, newmeshcreated);
1088 		meshDoc()->meshDocStateData().clear();
1089 
1090         if(classes & MeshFilterInterface::MeshCreation)
1091             GLA()->resetTrackBall();
1092         /* to be changed */
1093 
1094         qb->reset();
1095         GLA()->update();
1096         GLA()->Logf(GLLogStream::SYSTEM,"Re-Applied filter %s",qUtf8Printable((*ii)->filterName()));
1097 		if (_currviewcontainer != NULL)
1098 			_currviewcontainer->updateAllDecoratorsForAllViewers();
1099     }
1100 }
1101 
1102 // Receives the action that wants to show a tooltip and display it
1103 // on screen at the current mouse position.
1104 // TODO: have the tooltip always display with fixed width at the right
1105 //       hand side of the menu entry (not invasive)
showTooltip(QAction * q)1106 void MainWindow::showTooltip(QAction* q)
1107 {
1108     QString tip = q->toolTip();
1109     QToolTip::showText(QCursor::pos(), tip);
1110 }
1111 
1112 // /////////////////////////////////////////////////
1113 // The Very Important Procedure of applying a filter
1114 // /////////////////////////////////////////////////
1115 // It is split in two part
1116 // - startFilter that setup the dialogs and asks for parameters
1117 // - executeFilter callback invoked when the params have been set up.
1118 
1119 
startFilter()1120 void MainWindow::startFilter()
1121 {
1122     if(currentViewContainer() == NULL) return;
1123     if(GLA() == NULL) return;
1124 
1125     // In order to avoid that a filter changes something assumed by the current editing tool,
1126     // before actually starting the filter we close the current editing tool (if any).
1127     if (GLA()->getCurrentEditAction() != NULL)
1128         endEdit();
1129     updateMenus();
1130 
1131     QStringList missingPreconditions;
1132     QAction *action = qobject_cast<QAction *>(sender());
1133     if (action == NULL)
1134         throw MLException("Invalid filter action value.");
1135     MeshFilterInterface *iFilter = qobject_cast<MeshFilterInterface *>(action->parent());
1136     if (meshDoc() == NULL)
1137         return;
1138     //OLD FILTER PHILOSOPHY
1139     if (iFilter != NULL)
1140     {
1141         //if(iFilter->getClass(action) == MeshFilterInterface::MeshCreation)
1142         //{
1143         //	qDebug("MeshCreation");
1144         //	GLA()->meshDoc->addNewMesh("",iFilter->filterName(action) );
1145         //}
1146         //else
1147         if (!iFilter->isFilterApplicable(action,(*meshDoc()->mm()),missingPreconditions))
1148         {
1149             QString enstr = missingPreconditions.join(",");
1150             QMessageBox::warning(this, tr("PreConditions' Failure"), QString("Warning the filter <font color=red>'" + iFilter->filterName(action) + "'</font> has not been applied.<br>"
1151                 "Current mesh does not have <i>" + enstr + "</i>."));
1152             return;
1153         }
1154 
1155         if(currentViewContainer())
1156         {
1157             iFilter->setLog(currentViewContainer()->LogPtr());
1158             currentViewContainer()->LogPtr()->SetBookmark();
1159         }
1160         // just to be sure...
1161         createStdPluginWnd();
1162 
1163         if (xmldialog != nullptr)
1164         {
1165             xmldialog->close();
1166             delete xmldialog;
1167             xmldialog = nullptr;
1168         }
1169 
1170         // (2) Ask for filter parameters and eventually directly invoke the filter
1171         // showAutoDialog return true if a dialog have been created (and therefore the execution is demanded to the apply event)
1172         // if no dialog is created the filter must be executed immediately
1173         if(! stddialog->showAutoDialog(iFilter, meshDoc()->mm(), (meshDoc()), action, this, GLA()) )
1174         {
1175             RichParameterSet dummyParSet;
1176             executeFilter(action, dummyParSet, false);
1177 
1178             //Insert the filter to filterHistory
1179             OldFilterNameParameterValuesPair* tmp = new OldFilterNameParameterValuesPair();
1180             tmp->pair = qMakePair(action->text(), dummyParSet);
1181             meshDoc()->filterHistory->filtparlist.append(tmp);
1182         }
1183     }
1184     else // NEW XML PHILOSOPHY
1185     {
1186         try
1187         {
1188             MeshLabFilterInterface *iXMLFilter = qobject_cast<MeshLabFilterInterface *>(action->parent());
1189             QString fname = action->text();
1190             fname.replace("&","");
1191             MeshLabXMLFilterContainer& filt  = PM.stringXMLFilterMap[fname];
1192 
1193             if ((iXMLFilter == NULL) || (filt.xmlInfo == NULL) || (filt.act == NULL))
1194                 throw MLException("An invalid MLXMLPluginInfo handle has been detected in startFilter function.");
1195             QString filterClasses = filt.xmlInfo->filterAttribute(fname,MLXMLElNames::filterClass);
1196             QStringList filterClassesList = filterClasses.split(QRegExp("\\W+"), QString::SkipEmptyParts);
1197             if(filterClassesList.contains("MeshCreation"))
1198             {
1199                 qDebug("MeshCreation");
1200                 meshDoc()->addNewMesh("","untitled.ply");
1201             }
1202             else
1203             {
1204                 QString preCond = filt.xmlInfo->filterAttribute(fname,MLXMLElNames::filterPreCond);
1205                 QStringList preCondList = preCond.split(QRegExp("\\W+"), QString::SkipEmptyParts);
1206                 int preCondMask = MeshLabFilterInterface::convertStringListToMeshElementEnum(preCondList);
1207                 if (!MeshLabFilterInterface::arePreCondsValid(preCondMask,(*meshDoc()->mm()),missingPreconditions))
1208                 {
1209                     QString enstr = missingPreconditions.join(",");
1210                     QMessageBox::warning(this, tr("PreConditions' Failure"), QString("Warning the filter <font color=red>'" + fname + "'</font> has not been applied.<br>"
1211                         "Current mesh does not have <i>" + enstr + "</i>."));
1212                     return;
1213                 }
1214             }
1215             //INIT PARAMETERS WITH EXPRESSION : Both are defined inside the XML file
1216 
1217             //Inside the MapList there are QMap<QString,QString> containing info about parameters. In particular:
1218             // "type" - "Boolean","Real" etc
1219             // "name" - "parameter name"
1220             // "defaultExpression" - "defExpression"
1221             // "help" - "parameter help"
1222             // "typeGui" - "ABSPERC_GUI" "CHECKBOX_GUI" etc
1223             // "label" - "gui label"
1224             // Depending to the typeGui could be inside the map other info:
1225             // for example for ABSPERC_GUI there are also
1226             // "minExpr" - "minExpr"
1227             // "maxExpr" - "maxExpr"
1228 
1229             MLXMLPluginInfo::XMLMapList params = filt.xmlInfo->filterParametersExtendedInfo(fname);
1230 
1231 
1232             /*****IMPORTANT NOTE******/
1233             //the popContext will be called:
1234             //- or in the executeFilter if the filter will be executed
1235             //- or in the close Event of stdDialog window if the filter will NOT be executed
1236             //- or in the catch exception if something went wrong during parsing/scanning
1237 
1238             try
1239             {
1240 
1241                 if(currentViewContainer())
1242                 {
1243                     if (iXMLFilter)
1244                         iXMLFilter->setLog(currentViewContainer()->LogPtr());
1245                     currentViewContainer()->LogPtr()->SetBookmark();
1246                 }
1247                 // just to be sure...
1248                 createXMLStdPluginWnd();
1249                 if (stddialog != nullptr)
1250                 {
1251                     stddialog->close();
1252                     delete stddialog;
1253                     stddialog = nullptr;
1254                 }
1255                 // (2) Ask for filter parameters and eventually directly invoke the filter
1256                 // showAutoDialog return true if a dialog have been created (and therefore the execution is demanded to the apply event)
1257                 // if no dialog is created the filter must be executed immediatel
1258                 if(!xmldialog->showAutoDialog(filt,PM,meshDoc(),  this, GLA()))
1259                 {
1260                     /*Mock Parameters (there are no ones in the filter indeed) for the filter history.The filters with parameters are inserted by the applyClick of the XMLStdParDialog.
1261                     That is the only place where I can easily evaluate the parameter values without writing a long, boring and horrible if on the filter type for the correct evaluation of the expressions contained inside the XMLWidgets*/
1262                     QMap<QString,QString> mock;
1263                     meshDoc()->filterHistory->addExecutedXMLFilter(fname,mock);
1264 
1265                     executeFilter(&filt, mock, false);
1266                     meshDoc()->Log.Log(GLLogStream::SYSTEM,"OUT OF SCOPE\n");
1267                 }
1268                 //delete env;
1269             }
1270             catch (MLException& e)
1271             {
1272                 meshDoc()->Log.Log(GLLogStream::SYSTEM,e.what());
1273             }
1274         }
1275         catch(ParsingException e)
1276         {
1277             meshDoc()->Log.Log(GLLogStream::SYSTEM,e.what());
1278         }
1279     }//else
1280 
1281 }//void MainWindow::startFilter()
1282 
1283 
updateSharedContextDataAfterFilterExecution(int postcondmask,int fclasses,bool & newmeshcreated)1284 void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,int fclasses,bool& newmeshcreated)
1285 {
1286     MultiViewer_Container* mvc = currentViewContainer();
1287     if ((meshDoc() != NULL) && (mvc != NULL))
1288     {
1289         if (GLA() == NULL)
1290             return;
1291         MLSceneGLSharedDataContext* shared = mvc->sharedDataContext();
1292         if (shared != NULL)
1293         {
1294             for(MeshModel* mm = meshDoc()->nextMesh();mm != NULL;mm = meshDoc()->nextMesh(mm))
1295             {
1296                 if (mm == NULL)
1297                     continue;
1298                 //Just to be sure that the filter author didn't forget to add changing tags to the postCondition field
1299                 if ((mm->hasDataMask(MeshModel::MM_FACECOLOR)) && (fclasses & MeshFilterInterface::FaceColoring ))
1300                     postcondmask = postcondmask | MeshModel::MM_FACECOLOR;
1301 
1302                 if ((mm->hasDataMask(MeshModel::MM_VERTCOLOR)) && (fclasses & MeshFilterInterface::VertexColoring ))
1303                     postcondmask = postcondmask | MeshModel::MM_VERTCOLOR;
1304 
1305                 if ((mm->hasDataMask(MeshModel::MM_COLOR)) && (fclasses & MeshFilterInterface::MeshColoring ))
1306                     postcondmask = postcondmask | MeshModel::MM_COLOR;
1307 
1308                 if ((mm->hasDataMask(MeshModel::MM_FACEQUALITY)) && (fclasses & MeshFilterInterface::Quality ))
1309                     postcondmask = postcondmask | MeshModel::MM_FACEQUALITY;
1310 
1311                 if ((mm->hasDataMask(MeshModel::MM_VERTQUALITY)) && (fclasses & MeshFilterInterface::Quality ))
1312                     postcondmask = postcondmask | MeshModel::MM_VERTQUALITY;
1313 
1314                 MLRenderingData dttoberendered;
1315                 QMap<int,MeshModelStateData>::Iterator existit = meshDoc()->meshDocStateData().find(mm->id());
1316 				if (existit != meshDoc()->meshDocStateData().end())
1317                 {
1318 
1319                     shared->getRenderInfoPerMeshView(mm->id(),GLA()->context(),dttoberendered);
1320                     int updatemask = MeshModel::MM_NONE;
1321 					bool connectivitychanged = false;
1322                     if (((unsigned int)mm->cm.VN() != existit->_nvert) || ((unsigned int)mm->cm.FN() != existit->_nface) ||
1323                         bool(postcondmask & MeshModel::MM_UNKNOWN) || bool(postcondmask & MeshModel::MM_VERTNUMBER) ||
1324                         bool(postcondmask & MeshModel::MM_FACENUMBER) || bool(postcondmask & MeshModel::MM_FACEVERT) ||
1325                         bool(postcondmask & MeshModel::MM_VERTFACETOPO) || bool(postcondmask & MeshModel::MM_FACEFACETOPO))
1326                     {
1327 						updatemask = MeshModel::MM_ALL;
1328                         connectivitychanged = true;
1329                     }
1330                     else
1331                     {
1332                         //masks differences bitwise operator (^) -> remove the attributes that didn't apparently change + the ones that for sure changed according to the postCondition function
1333                         //this operation has been introduced in order to minimize problems with filters that didn't declared properly the postCondition mask
1334                         updatemask = (existit->_mask ^ mm->dataMask()) | postcondmask;
1335                         connectivitychanged = false;
1336                     }
1337 
1338                     MLRenderingData::RendAtts dttoupdate;
1339                     //1) we convert the meshmodel updating mask to a RendAtts structure
1340                     MLPoliciesStandAloneFunctions::fromMeshModelMaskToMLRenderingAtts(updatemask,dttoupdate);
1341                     //2) The correspondent bos to the updated rendering attributes are set to invalid
1342                     shared->meshAttributesUpdated(mm->id(),connectivitychanged,dttoupdate);
1343 
1344                     //3) we took the current rendering modality for the mesh in the active gla
1345                     MLRenderingData curr;
1346                     shared->getRenderInfoPerMeshView(mm->id(),GLA()->context(),curr);
1347 
1348                     //4) we add to the current rendering modality in the current GLArea just the minimum attributes having been updated
1349                     //   WARNING!!!! There are priority policies
1350                     //               ex1) suppose that the current rendering modality is PR_POINTS and ATT_VERTPOSITION, ATT_VERTNORMAL,ATT_VERTCOLOR
1351                     //               if i updated, for instance, just the ATT_FACECOLOR, we switch off in the active GLArea the per ATT_VERTCOLOR attribute
1352                     //               and turn on the ATT_FACECOLOR
1353                     //               ex2) suppose that the current rendering modality is PR_POINTS and ATT_VERTPOSITION, ATT_VERTNORMAL,ATT_VERTCOLOR
1354                     //               if i updated, for instance, both the ATT_FACECOLOR and the ATT_VERTCOLOR, we continue to render the updated value of the ATT_VERTCOLOR
1355                     //               ex3) suppose that in all the GLAreas the current rendering modality is PR_POINTS and we run a surface reconstruction filter
1356                     //               in the current GLA() we switch from the PR_POINTS to PR_SOLID primitive rendering modality. In the other GLArea we maintain the per points visualization
1357                     for(MLRenderingData::PRIMITIVE_MODALITY pm = MLRenderingData::PRIMITIVE_MODALITY(0);pm < MLRenderingData::PR_ARITY;pm = MLRenderingData::next(pm))
1358                     {
1359                         bool wasprimitivemodalitymeaningful = MLPoliciesStandAloneFunctions::isPrimitiveModalityCompatibleWithMeshInfo((existit->_nvert > 0),(existit->_nface > 0),(existit->_nedge > 0),existit->_mask,pm);
1360                         bool isprimitivemodalitymeaningful = MLPoliciesStandAloneFunctions::isPrimitiveModalityCompatibleWithMesh(mm,pm);
1361                         bool isworthtobevisualized = MLPoliciesStandAloneFunctions::isPrimitiveModalityWorthToBeActivated(pm,curr.isPrimitiveActive(pm),wasprimitivemodalitymeaningful,isprimitivemodalitymeaningful);
1362 
1363 
1364                         MLRenderingData::RendAtts rd;
1365 						curr.get(pm, rd);
1366 						MLPoliciesStandAloneFunctions::updatedRendAttsAccordingToPriorities(pm, dttoupdate, rd, rd);
1367 						rd[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] = isworthtobevisualized;
1368                         MLPoliciesStandAloneFunctions::filterUselessUdpateAccordingToMeshMask(mm,rd);
1369                         curr.set(pm,rd);
1370                     }
1371 					MLPerViewGLOptions opts;
1372 					curr.get(opts);
1373 					if (fclasses & MeshFilterInterface::MeshColoring)
1374 					{
1375 						bool hasmeshcolor = mm->hasDataMask(MeshModel::MM_COLOR);
1376 						opts._perpoint_mesh_color_enabled = hasmeshcolor;
1377 						opts._perwire_mesh_color_enabled = hasmeshcolor;
1378 						opts._persolid_mesh_color_enabled = hasmeshcolor;
1379 
1380 						for (MLRenderingData::PRIMITIVE_MODALITY pm = MLRenderingData::PRIMITIVE_MODALITY(0); pm < MLRenderingData::PR_ARITY; pm = MLRenderingData::next(pm))
1381 						{
1382 							MLRenderingData::RendAtts atts;
1383 							curr.get(pm, atts);
1384 							atts[MLRenderingData::ATT_NAMES::ATT_VERTCOLOR] = false;
1385 							atts[MLRenderingData::ATT_NAMES::ATT_FACECOLOR] = false;
1386 							curr.set(pm, atts);
1387 						}
1388 						curr.set(opts);
1389 					}
1390 					MLPoliciesStandAloneFunctions::setPerViewGLOptionsAccordindToWireModality(mm, curr);
1391                     MLPoliciesStandAloneFunctions::setPerViewGLOptionsPriorities(curr);
1392 
1393 					if (mm == meshDoc()->mm())
1394 					{
1395 						/*HORRIBLE TRICK IN ORDER TO HAVE VALID ACTIONS ASSOCIATED WITH THE CURRENT WIRE RENDERING MODALITY*/
1396 						MLRenderingFauxEdgeWireAction* fauxaction = new MLRenderingFauxEdgeWireAction(meshDoc()->mm()->id(), NULL);
1397 						fauxaction->setChecked(curr.isPrimitiveActive(MLRenderingData::PR_WIREFRAME_EDGES));
1398 						layerDialog->_tabw->switchWireModality(fauxaction);
1399 						delete fauxaction;
1400 						/****************************************************************************************************/
1401 					}
1402 
1403 
1404                     shared->setRenderingDataPerMeshView(mm->id(),GLA()->context(),curr);
1405                 }
1406                 else
1407                 {
1408                     //A new mesh has been created by the filter. I have to add it in the shared context data structure
1409                     newmeshcreated = true;
1410                     MLPoliciesStandAloneFunctions::suggestedDefaultPerViewRenderingData(mm,dttoberendered,mwsettings.minpolygonpersmoothrendering);
1411 					if (mm == meshDoc()->mm())
1412 					{
1413 						/*HORRIBLE TRICK IN ORDER TO HAVE VALID ACTIONS ASSOCIATED WITH THE CURRENT WIRE RENDERING MODALITY*/
1414 						MLRenderingFauxEdgeWireAction* fauxaction = new MLRenderingFauxEdgeWireAction(meshDoc()->mm()->id(), NULL);
1415 						fauxaction->setChecked(dttoberendered.isPrimitiveActive(MLRenderingData::PR_WIREFRAME_EDGES));
1416 						layerDialog->_tabw->switchWireModality(fauxaction);
1417 						delete fauxaction;
1418 						/****************************************************************************************************/
1419 					}
1420 					foreach(GLArea* gla,mvc->viewerList)
1421                     {
1422                         if (gla != NULL)
1423                             shared->setRenderingDataPerMeshView(mm->id(),gla->context(),dttoberendered);
1424                     }
1425 				}
1426 				shared->manageBuffers(mm->id());
1427             }
1428 			updateLayerDialog();
1429         }
1430     }
1431 }
1432 
1433 /*
1434 callback function that actually start the chosen filter.
1435 it is called once the parameters have been filled.
1436 It can be called
1437 from the automatic dialog
1438 from the user defined dialog
1439 */
1440 
1441 
executeFilter(QAction * action,RichParameterSet & params,bool isPreview)1442 void MainWindow::executeFilter(QAction *action, RichParameterSet &params, bool isPreview)
1443 {
1444      MeshFilterInterface *iFilter = qobject_cast<MeshFilterInterface *>(action->parent());
1445     qb->show();
1446     iFilter->setLog(&meshDoc()->Log);
1447 
1448     // Ask for filter requirements (eg a filter can need topology, border flags etc)
1449     // and satisfy them
1450     qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
1451     MainWindow::globalStatusBar()->showMessage("Starting Filter...",5000);
1452     int req=iFilter->getRequirements(action);
1453     if (!meshDoc()->meshList.isEmpty())
1454         meshDoc()->mm()->updateDataMask(req);
1455     qApp->restoreOverrideCursor();
1456 
1457     // (3) save the current filter and its parameters in the history
1458     if(!isPreview)
1459         meshDoc()->Log.ClearBookmark();
1460     else
1461         meshDoc()->Log.BackToBookmark();
1462     // (4) Apply the Filter
1463     bool ret;
1464     qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
1465     QElapsedTimer tt; tt.start();
1466     meshDoc()->setBusy(true);
1467     RichParameterSet mergedenvironment(params);
1468     mergedenvironment.join(currentGlobalParams);
1469 
1470     MLSceneGLSharedDataContext* shar = NULL;
1471     QGLWidget* filterWidget = NULL;
1472     if (currentViewContainer() != NULL)
1473     {
1474         shar = currentViewContainer()->sharedDataContext();
1475         //GLA() is only the parent
1476         filterWidget = new QGLWidget(NULL,shar);
1477         QGLFormat defForm = QGLFormat::defaultFormat();
1478         iFilter->glContext = new MLPluginGLContext(defForm,filterWidget->context()->device(),*shar);
1479         iFilter->glContext->create(filterWidget->context());
1480 
1481         MLRenderingData dt;
1482         MLRenderingData::RendAtts atts;
1483         atts[MLRenderingData::ATT_NAMES::ATT_VERTPOSITION] = true;
1484         atts[MLRenderingData::ATT_NAMES::ATT_VERTNORMAL] = true;
1485 
1486         if (iFilter->filterArity(action) == MeshFilterInterface::SINGLE_MESH)
1487         {
1488             MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(meshDoc()->mm());
1489             if ((pm != MLRenderingData::PR_ARITY) && (meshDoc()->mm() != NULL))
1490             {
1491                 dt.set(pm,atts);
1492                 iFilter->glContext->initPerViewRenderingData(meshDoc()->mm()->id(),dt);
1493             }
1494         }
1495         else
1496         {
1497             for(int ii = 0;ii < meshDoc()->meshList.size();++ii)
1498             {
1499                 MeshModel* mm = meshDoc()->meshList[ii];
1500                 MLRenderingData::PRIMITIVE_MODALITY pm = MLPoliciesStandAloneFunctions::bestPrimitiveModalityAccordingToMesh(mm);
1501                 if ((pm != MLRenderingData::PR_ARITY) && (mm != NULL))
1502                 {
1503                     dt.set(pm,atts);
1504                     iFilter->glContext->initPerViewRenderingData(mm->id(),dt);
1505                 }
1506             }
1507         }
1508     }
1509     bool newmeshcreated = false;
1510     try
1511     {
1512         meshDoc()->meshDocStateData().clear();
1513 		meshDoc()->meshDocStateData().create(*meshDoc());
1514         ret=iFilter->applyFilter(action, *(meshDoc()), mergedenvironment, QCallBack);
1515 		for (MeshModel* mm = meshDoc()->nextMesh(); mm != NULL; mm = meshDoc()->nextMesh(mm))
1516 			vcg::tri::Allocator<CMeshO>::CompactEveryVector(mm->cm);
1517 
1518 		if (shar != NULL)
1519 		{
1520 			shar->removeView(iFilter->glContext);
1521 			delete filterWidget;
1522 		}
1523 
1524         meshDoc()->setBusy(false);
1525 
1526         qApp->restoreOverrideCursor();
1527 
1528         // (5) Apply post filter actions (e.g. recompute non updated stuff if needed)
1529 
1530         if(ret)
1531         {
1532             meshDoc()->Log.Logf(GLLogStream::SYSTEM,"Applied filter %s in %i msec",qUtf8Printable(action->text()),tt.elapsed());
1533             if (meshDoc()->mm() != NULL)
1534                 meshDoc()->mm()->meshModified() = true;
1535             MainWindow::globalStatusBar()->showMessage("Filter successfully completed...",2000);
1536             if(GLA())
1537             {
1538                 GLA()->setLastAppliedFilter(action);
1539             }
1540             lastFilterAct->setText(QString("Apply filter ") + action->text());
1541             lastFilterAct->setEnabled(true);
1542         }
1543         else // filter has failed. show the message error.
1544         {
1545             QMessageBox::warning(this, tr("Filter Failure"), QString("Failure of filter <font color=red>: '%1'</font><br><br>").arg(action->text())+iFilter->errorMsg()); // text
1546             meshDoc()->Log.Logf(GLLogStream::SYSTEM,"Filter failed: %s",qUtf8Printable(iFilter->errorMsg()));
1547             MainWindow::globalStatusBar()->showMessage("Filter failed...",2000);
1548         }
1549 
1550 
1551         MeshFilterInterface::FILTER_ARITY arity = iFilter->filterArity(action);
1552         QList<MeshModel*> tmp;
1553         switch(arity)
1554         {
1555         case (MeshFilterInterface::SINGLE_MESH):
1556             {
1557                 tmp.push_back(meshDoc()->mm());
1558                 break;
1559             }
1560         case (MeshFilterInterface::FIXED):
1561             {
1562                 for(int ii = 0;ii < mergedenvironment.paramList.size();++ii)
1563                 {
1564                     if (mergedenvironment.paramList[ii]->val->isMesh())
1565                     {
1566                         MeshModel* mm = mergedenvironment.paramList[ii]->val->getMesh();
1567                         if (mm != NULL)
1568                             tmp.push_back(mm);
1569                     }
1570                 }
1571                 break;
1572             }
1573         case (MeshFilterInterface::VARIABLE):
1574             {
1575                 for(MeshModel* mm = meshDoc()->nextMesh();mm != NULL;mm=meshDoc()->nextMesh(mm))
1576                 {
1577                     if (mm->isVisible())
1578                         tmp.push_back(mm);
1579                 }
1580                 break;
1581             }
1582         default:
1583             break;
1584         }
1585 
1586         if(iFilter->getClass(action) & MeshFilterInterface::MeshCreation )
1587             GLA()->resetTrackBall();
1588 
1589         for(int jj = 0;jj < tmp.size();++jj)
1590         {
1591             MeshModel* mm = tmp[jj];
1592             if (mm != NULL)
1593             {
1594                 // at the end for filters that change the color, or selection set the appropriate rendering mode
1595                 if(iFilter->getClass(action) & MeshFilterInterface::FaceColoring )
1596                     mm->updateDataMask(MeshModel::MM_FACECOLOR);
1597 
1598                 if(iFilter->getClass(action) & MeshFilterInterface::VertexColoring )
1599                     mm->updateDataMask(MeshModel::MM_VERTCOLOR);
1600 
1601                 if(iFilter->getClass(action) & MeshFilterInterface::MeshColoring )
1602                     mm->updateDataMask(MeshModel::MM_COLOR);
1603 
1604                 if(iFilter->postCondition(action) & MeshModel::MM_CAMERA)
1605                     mm->updateDataMask(MeshModel::MM_CAMERA);
1606 
1607                 if(iFilter->getClass(action) & MeshFilterInterface::Texture )
1608                     updateTexture(mm->id());
1609             }
1610         }
1611 
1612         int fclasses =	iFilter->getClass(action);
1613         //MLSceneGLSharedDataContext* sharedcont = GLA()->getSceneGLSharedContext();
1614         int postCondMask = iFilter->postCondition(action);
1615         updateSharedContextDataAfterFilterExecution(postCondMask,fclasses,newmeshcreated);
1616         meshDoc()->meshDocStateData().clear();
1617     }
1618     catch (std::bad_alloc& bdall)
1619     {
1620         meshDoc()->setBusy(false);
1621         qApp->restoreOverrideCursor();
1622         QMessageBox::warning(this, tr("Filter Failure"),
1623                              QString("Operating system was not able to allocate the requested memory.<br><b>"
1624                                      "Failure of filter <font color=red>: '%1'</font><br>").arg(action->text())+bdall.what()); // text
1625         MainWindow::globalStatusBar()->showMessage("Filter failed...",2000);
1626     }
1627     qb->reset();
1628     layerDialog->setVisible(layerDialog->isVisible() || ((newmeshcreated) && (meshDoc()->size() > 0)));
1629     updateLayerDialog();
1630     updateMenus();
1631     MultiViewer_Container* mvc = currentViewContainer();
1632 	if (mvc)
1633 	{
1634 		mvc->updateAllDecoratorsForAllViewers();
1635 		mvc->updateAllViewers();
1636 	}
1637 }
1638 
initDocumentMeshRenderState(MeshLabXMLFilterContainer *)1639 void MainWindow::initDocumentMeshRenderState(MeshLabXMLFilterContainer* /*mfc*/)
1640 {
1641     /* if (env.isNull())
1642     throw MeshLabException("Critical error in initDocumentMeshRenderState: Env object inside the QSharedPointer is NULL");*/
1643     //if (meshDoc() == NULL)
1644     //    return;
1645 
1646     //QString fname = mfc->act->text();
1647     //QString ar = mfc->xmlInfo->filterAttribute(fname,MLXMLElNames::filterArity);
1648 
1649     //if ((ar == MLXMLElNames::singleMeshArity)&& (meshDoc()->mm() != NULL))
1650     //{
1651 
1652     //    QTime tt;
1653     //    tt.start();
1654     //    meshDoc()->renderState().add(meshDoc()->mm()->id(),meshDoc()->mm()->cm);
1655     //    GLA()->Logf(0,"Elapsed time %d\n",tt.elapsed());
1656     //    return;
1657     //}
1658 
1659     //if (ar == MLXMLElNames::fixedArity)
1660     //{
1661     //    Env env;
1662     //    QScriptValue val = env.loadMLScriptEnv(*meshDoc(),PM);
1663     //    EnvWrap envwrap(env);
1664     //    //I have to check which are the meshes requested as parameters by the filter. It's disgusting but there is not other way.
1665     //    MLXMLPluginInfo::XMLMapList params = mfc->xmlInfo->filterParameters(fname);
1666     //    for(int ii = 0;ii < params.size();++ii)
1667     //    {
1668     //        if (params[ii][MLXMLElNames::paramType] == MLXMLElNames::meshType)
1669     //        {
1670     //            try
1671     //            {
1672     //                MeshModel* tmp = envwrap.evalMesh(params[ii][MLXMLElNames::paramName]);
1673     //                if (tmp != NULL)
1674     //                    meshDoc()->renderState().add(tmp->id(),tmp->cm);
1675     //            }
1676     //            catch (ExpressionHasNotThisTypeException&)
1677     //            {
1678     //                QString st = "parameter " + params[ii][MLXMLElNames::paramName] + "declared of type mesh contains a not mesh value.\n";
1679     //                meshDoc()->Log.Logf(GLLogStream::FILTER, qUtf8Printable(st));
1680     //            }
1681     //        }
1682     //    }
1683     //    return;
1684     //}
1685 
1686     ////In this case I can only copy all the meshes in the document!
1687     //if (ar == MLXMLElNames::variableArity)
1688     //{
1689     //    for(int ii = 0;ii<meshDoc()->meshList.size();++ii)
1690     //        meshDoc()->renderState().add(meshDoc()->meshList[ii]->id(),meshDoc()->meshList[ii]->cm);
1691     //    return;
1692     //}
1693 }
1694 
initDocumentRasterRenderState(MeshLabXMLFilterContainer *)1695 void MainWindow::initDocumentRasterRenderState(MeshLabXMLFilterContainer* /*mfc*/)
1696 {
1697     //if (meshDoc() == NULL)
1698     //    return;
1699     //QString fname = mfc->act->text();
1700     //QString ar = mfc->xmlInfo->filterAttribute(fname,MLXMLElNames::filterRasterArity);
1701 
1702     //if ((ar == MLXMLElNames::singleRasterArity)&& (meshDoc()->rm() != NULL))
1703     //{
1704     //    meshDoc()->renderState().add(meshDoc()->rm()->id(),*meshDoc()->rm());
1705     //    return;
1706     //}
1707 
1708     //if (ar == MLXMLElNames::fixedRasterArity)
1709     //{
1710     //    // TO DO!!!!!! I have to add RasterType in order to understand which are the parameters working on Raster!!!
1711 
1712     //    //	//I have to check which are the meshes requested as parameters by the filter. It's disgusting but there is not other way.
1713     //    //	MLXMLPluginInfo::XMLMapList params = mfc->xmlInfo->filterParameters(fname);
1714     //    //	for(int ii = 0;ii < params.size();++ii)
1715     //    //	{
1716     //    //		if (params[ii][MLXMLElNames::paramType] == MLXMLElNames::meshType)
1717     //    //		{
1718     //    //			try
1719     //    //			{
1720     //    //				MeshModel* tmp = env.evalMesh(params[ii][MLXMLElNames::paramName]);
1721     //    //				if (tmp != NULL)
1722     //    //					meshDoc()->renderState().add(tmp->id(),tmp->cm);
1723     //    //			}
1724     //    //			catch (ExpressionHasNotThisTypeException& e)
1725     //    //			{
1726     //    //				QString st = "parameter " + params[ii][MLXMLElNames::paramName] + "declared of type mesh contains a not mesh value.\n";
1727     //    //				meshDoc()->Log.Logf(GLLogStream::FILTER, qUtf8Printable(st));
1728     //    //			}
1729     //    //		}
1730     //    //	}
1731     //    return;
1732     //}
1733 
1734     ////In this case I can only copy all the meshes in the document!
1735     //if (ar == MLXMLElNames::variableRasterArity)
1736     //{
1737     //    for(int ii = 0;meshDoc()->rasterList.size();++ii)
1738     //        if (meshDoc()->rasterList[ii] != NULL)
1739     //            meshDoc()->renderState().add(meshDoc()->rasterList[ii]->id(),*meshDoc()->rasterList[ii]);
1740     //    return;
1741     //}
1742 }
1743 
executeFilter(MeshLabXMLFilterContainer * mfc,const QMap<QString,QString> & parexpval,bool ispreview)1744 void MainWindow::executeFilter(MeshLabXMLFilterContainer* mfc,const QMap<QString,QString>& parexpval , bool  ispreview)
1745 {
1746     if (mfc == NULL)
1747         return;
1748     MeshLabFilterInterface         *iFilter    = mfc->filterInterface;
1749     bool jscode = (mfc->xmlInfo->filterScriptCode(mfc->act->text()) != "");
1750     bool filtercpp = (iFilter != NULL) && (!jscode);
1751 
1752     if ((!filtercpp) && (!jscode))
1753         throw MLException("A not-C++ and not-JaveScript filter has been invoked.There is something really wrong in MeshLab.");
1754 
1755     QString fname = mfc->act->text();
1756     fname.replace("&","");
1757     QString postCond = mfc->xmlInfo->filterAttribute(fname,MLXMLElNames::filterPostCond);
1758     QStringList postCondList = postCond.split(QRegExp("\\W+"), QString::SkipEmptyParts);
1759     int postCondMask = MeshLabFilterInterface::convertStringListToMeshElementEnum(postCondList);
1760     /*if (postCondMask != MeshModel::MM_NONE)
1761     initDocumentMeshRenderState(mfc);
1762 
1763     initDocumentRasterRenderState(mfc);
1764     */
1765     if(!ispreview)
1766         meshDoc()->Log.ClearBookmark();
1767     else
1768         meshDoc()->Log.BackToBookmark();
1769 
1770     qb->show();
1771     if (filtercpp)
1772         iFilter->setLog(&meshDoc()->Log);
1773 
1774     //// Ask for filter requirements (eg a filter can need topology, border flags etc)
1775     //// and satisfy them
1776     qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
1777     MainWindow::globalStatusBar()->showMessage("Starting Filter...",5000);
1778     //int req=iFilter->getRequirements(action);
1779     meshDoc()->mm()->updateDataMask(postCondMask);
1780     qApp->restoreOverrideCursor();
1781 
1782     //// (3) save the current filter and its parameters in the history
1783     //if(!isPreview)
1784     //{
1785     //	meshDoc()->filterHistory.actionList.append(qMakePair(action->text(),params));
1786     //	meshDoc()->Log.ClearBookmark();
1787     //}
1788     //else
1789     //	meshDoc()->Log.BackToBookmark();
1790     //// (4) Apply the Filter
1791 
1792 
1793 
1794     qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
1795     bool isinter = (mfc->xmlInfo->filterAttribute(fname,MLXMLElNames::filterIsInterruptible) == "true");
1796 
1797     if(!isinter) meshDoc()->setBusy(true);
1798 
1799     //RichParameterSet MergedEnvironment(params);
1800     //MergedEnvironment.join(currentGlobalParams);
1801 
1802     ////GLA() is only the parent
1803     xmlfiltertimer.restart();
1804 
1805     /*if (filtercpp)
1806     {
1807     QGLWidget* filterWidget = new QGLWidget(GLA());
1808     QGLFormat defForm = QGLFormat::defaultFormat();
1809     iFilter->glContext = new QGLContext(defForm,filterWidget->context()->device());
1810     iFilter->glContext->create(filterWidget->context());
1811     }*/
1812     try
1813     {
1814         MLXMLPluginInfo::XMLMapList ml = mfc->xmlInfo->filterParametersExtendedInfo(fname);
1815 		QString funcall = MLXMLUtilityFunctions::completeFilterProgrammingName(MLXMLUtilityFunctions::pluginsNameSpace(), mfc->xmlInfo->pluginAttribute(MLXMLElNames::pluginScriptName), mfc->xmlInfo->filterAttribute(fname, MLXMLElNames::filterScriptFunctName)) + "(";
1816         if (mfc->xmlInfo->filterAttribute(fname,MLXMLElNames::filterArity) == MLXMLElNames::singleMeshArity && !jscode)
1817         {
1818             funcall = funcall + QString::number(meshDoc()->mm()->id());
1819             if (ml.size() != 0)
1820                 funcall = funcall + ",";
1821         }
1822         for(int ii = 0;ii < ml.size();++ii)
1823         {
1824             funcall = funcall + parexpval[ml[ii][MLXMLElNames::paramName]];
1825             if (ii != ml.size() - 1)
1826                 funcall = funcall + ",";
1827         }
1828         funcall = funcall + ");";
1829 
1830         meshDoc()->xmlhistory << funcall;
1831 		meshDoc()->meshDocStateData().clear();
1832 		meshDoc()->meshDocStateData().create(*meshDoc());
1833 
1834         if (filtercpp)
1835         {
1836             enableDocumentSensibleActionsContainer(false);
1837             FilterThread* ft = new FilterThread(fname,parexpval,PM,*(meshDoc()),this);
1838 
1839             connect(ft,SIGNAL(finished()),this,SLOT(postFilterExecution()));
1840             connect(ft,SIGNAL(threadCB(const int, const QString&)),this,SLOT(updateProgressBar(const int,const QString&)));
1841             connect(xmldialog,SIGNAL(filterInterrupt(const bool)),PM.stringXMLFilterMap[fname].filterInterface,SLOT(setInterrupt(const bool)));
1842 
1843             /*if ((_mw != NULL) && (_mw->currentViewContainer() != NULL))
1844             {
1845                 QGLWidget* tmpglwid = new QGLWidget(NULL,currentViewContainer()->sharedDataContext());
1846                 filtercpp->glContext = new MLPluginGLContext(QGLFormat::defaultFormat(),tmpglwid->context()->device(),(*currentViewContainer()->sharedDataContext()));
1847                 bool res = it->filterInterface->glContext->create(tmpglwid->context());
1848             }*/
1849             ft->start();
1850         }
1851         else
1852         {
1853             QElapsedTimer t;
1854             t.start();
1855             Env env;
1856 			QMap<QString, QString> persistentparam;
1857 			foreach(RichParameter* rp, currentGlobalPars().paramList)
1858 			{
1859 				if (rp != NULL)
1860 					persistentparam[rp->name] = RichParameterAdapter::convertToStringValue(*rp);
1861 			}
1862 
1863 			env.loadMLScriptEnv(*meshDoc(), PM, persistentparam);
1864             QScriptValue result = env.evaluate(funcall);
1865             scriptCodeExecuted(result,t.elapsed(),"");
1866             postFilterExecution();
1867 
1868         }
1869     }
1870     catch(MLException& e)
1871     {
1872         meshDoc()->Log.Log(GLLogStream::SYSTEM,e.what());
1873     }
1874 
1875 }
1876 
postFilterExecution()1877 void MainWindow::postFilterExecution()
1878 {
1879     emit filterExecuted();
1880     //meshDoc()->renderState().clearState();
1881     qApp->restoreOverrideCursor();
1882     qb->reset();
1883     //foreach(QAction* act,filterMenu->actions())
1884     //    act->setEnabled(true);
1885     enableDocumentSensibleActionsContainer(true);
1886 
1887     FilterThread* obj = qobject_cast<FilterThread*>(QObject::sender());
1888     if (obj == NULL)
1889         return;
1890     QMap<QString,MeshLabXMLFilterContainer>::const_iterator mfc = PM.stringXMLFilterMap.find(obj->filterName());
1891     if (mfc == PM.stringXMLFilterMap.constEnd())
1892         return;
1893     QString fname = mfc->act->text();
1894     fname.replace("&","");
1895     // at the end for filters that change the color, or selection set the appropriate rendering mode
1896     QString filterClasses = mfc->xmlInfo->filterAttribute(fname,MLXMLElNames::filterClass);
1897     QStringList filterClassesList = filterClasses.split(QRegExp("\\W+"), QString::SkipEmptyParts);
1898     int fclasses =	MeshLabFilterInterface::convertStringListToCategoryEnum(filterClassesList);
1899     bool newmeshcreated = false;
1900     if (mfc->filterInterface != NULL)
1901     {
1902         mfc->filterInterface->setInterrupt(false);
1903         QString postCond = mfc->xmlInfo->filterAttribute(fname,MLXMLElNames::filterPostCond);
1904         QStringList postCondList = postCond.split(QRegExp("\\W+"), QString::SkipEmptyParts);
1905         int postCondMask = MeshLabFilterInterface::convertStringListToMeshElementEnum(postCondList);
1906         updateSharedContextDataAfterFilterExecution(postCondMask,fclasses,newmeshcreated);
1907         MultiViewer_Container* mvc = currentViewContainer();
1908         if(mvc)
1909             mvc->updateAllViewers();
1910     }
1911     meshDoc()->meshDocStateData().clear();
1912     meshDoc()->setBusy(false);
1913 
1914 
1915 
1916     //// (5) Apply post filter actions (e.g. recompute non updated stuff if needed)
1917 
1918     if(obj->succeed())
1919     {
1920         meshDoc()->Log.Logf(GLLogStream::SYSTEM,"Applied filter %s in %i msec\n",qUtf8Printable(fname),xmlfiltertimer.elapsed());
1921         MainWindow::globalStatusBar()->showMessage("Filter successfully completed...",2000);
1922         if(GLA())
1923         {
1924             GLA()->setLastAppliedFilter(mfc->act);
1925         }
1926         lastFilterAct->setText(QString("Apply filter ") + fname);
1927         lastFilterAct->setEnabled(true);
1928     }
1929     else // filter has failed. show the message error.
1930     {
1931         MeshLabFilterInterface         *iFilter = mfc->filterInterface;
1932         QMessageBox::warning(this, tr("Filter Failure"), QString("Failure of filter: '%1'<br><br>").arg(fname)+iFilter->errorMsg()); // text
1933         meshDoc()->Log.Logf(GLLogStream::SYSTEM,"Filter failed: %s",qUtf8Printable(iFilter->errorMsg()));
1934         MainWindow::globalStatusBar()->showMessage("Filter failed...",2000);
1935     }
1936 
1937     if(fclasses & MeshFilterInterface::FaceColoring ) {
1938         meshDoc()->mm()->updateDataMask(MeshModel::MM_FACECOLOR);
1939     }
1940     if(fclasses & MeshFilterInterface::VertexColoring ){
1941         meshDoc()->mm()->updateDataMask(MeshModel::MM_VERTCOLOR);
1942     }
1943     if(fclasses & MeshModel::MM_COLOR)
1944     {
1945         meshDoc()->mm()->updateDataMask(MeshModel::MM_COLOR);
1946     }
1947 
1948 
1949     //if(iFilter->postCondition(action) & MeshModel::MM_CAMERA)
1950     //	meshDoc()->mm()->updateDataMask(MeshModel::MM_CAMERA);
1951 
1952     if(fclasses & MeshFilterInterface::MeshCreation )
1953         GLA()->resetTrackBall();
1954 
1955     if(fclasses & MeshFilterInterface::Texture )
1956     {
1957 //WARNING!!!!! This should be replaced in some way
1958 //WARNING!!!!! HERE IT SHOULD BE A CHECK IF THE FILTER IS FOR MESH OR FOR DOCUMENT (IN THIS CASE I SHOULD ACTIVATE ALL THE TEXTURE MODE FOR EVERYONE...)
1959 //NOW WE HAVE JUST TEXTURE FILTERS WORKING ON SINGLE MESH
1960 //QMap<int,RenderMode>::iterator it = GLA()->rendermodemap.find(meshDoc()->mm()->id());
1961 //if (it != GLA()->rendermodemap.end())
1962 //    it.value().setTextureMode(GLW::TMPerWedgeMulti);
1963 //////////////////////////////////////////////////////////////////////////////
1964 
1965         updateTexture(meshDoc()->mm()->id());
1966     }
1967     /* QMap<QThread*,Env*>::iterator it = envtobedeleted.find(obj);
1968     if (it == envtobedeleted.end())
1969     {
1970     QString err;
1971     err.sprintf("FilterThread with address: %08p already does not exist.",obj);
1972     throw MeshLabException(err);
1973     }
1974     else
1975     {
1976     Env* tmpenv = it.value();
1977     envtobedeleted.erase(it);
1978     delete tmpenv;
1979     }*/
1980 
1981     layerDialog->setVisible((layerDialog->isVisible() || ((newmeshcreated) && (meshDoc()->size() > 0))));
1982     updateLayerDialog();
1983     updateMenus();
1984 	MultiViewer_Container* mvc = currentViewContainer();
1985 	if (mvc)
1986 	{
1987 		mvc->updateAllDecoratorsForAllViewers();
1988 		mvc->updateAllViewers();
1989 	}
1990     delete obj;
1991 }
1992 
scriptCodeExecuted(const QScriptValue & val,const int time,const QString & output)1993 void MainWindow::scriptCodeExecuted( const QScriptValue& val,const int time,const QString& output )
1994 {
1995     if (val.isError())
1996     {
1997         meshDoc()->Log.Logf(GLLogStream::SYSTEM,"Interpreter Error: line %i: %s",val.property("lineNumber").toInt32(),qUtf8Printable(val.toString()));
1998         layerDialog->updateLog(meshDoc()->Log);
1999     }
2000     else
2001     {
2002         meshDoc()->Log.Logf(GLLogStream::SYSTEM,"Code executed in %d millisecs.\nOutput:\n%s",time,qUtf8Printable(output));
2003 		//bool res;
2004 		//updateSharedContextDataAfterFilterExecution((int)MeshModel::MM_ALL, (int)MeshFilterInterface::Generic, res);
2005         GLA()->update();
2006     }
2007 }
2008 
2009 // Edit Mode Management
2010 // At any point there can be a single editing plugin active.
2011 // When a plugin is active it intercept the mouse actions.
2012 // Each active editing tools
2013 //
2014 //
2015 
2016 
suspendEditMode()2017 void MainWindow::suspendEditMode()
2018 {
2019     // return if no window is open
2020     if(!GLA()) return;
2021 
2022     // return if no editing action is currently ongoing
2023     if(!GLA()->getCurrentEditAction()) return;
2024 
2025     GLA()->suspendEditToggle();
2026     updateMenus();
2027     GLA()->update();
2028 }
applyEditMode()2029 void MainWindow::applyEditMode()
2030 {
2031     if(!GLA()) { //prevents crash without mesh
2032         QAction *action = qobject_cast<QAction *>(sender());
2033         action->setChecked(false);
2034         return;
2035     }
2036 
2037     QAction *action = qobject_cast<QAction *>(sender());
2038 
2039     if(GLA()->getCurrentEditAction()) //prevents multiple buttons pushed
2040     {
2041         if(action==GLA()->getCurrentEditAction()) // We have double pressed the same action and that means disable that actioon
2042         {
2043             if(GLA()->suspendedEditor)
2044             {
2045                 suspendEditMode();
2046                 return;
2047             }
2048 			endEdit();
2049             updateMenus();
2050             return;
2051         }
2052         assert(0); // it should be impossible to start an action without having ended the previous one.
2053         return;
2054     }
2055 
2056     //if this GLArea does not have an instance of this action's MeshEdit tool then give it one
2057     if(!GLA()->editorExistsForAction(action))
2058     {
2059         MeshEditInterfaceFactory *iEditFactory = qobject_cast<MeshEditInterfaceFactory *>(action->parent());
2060         MeshEditInterface *iEdit = iEditFactory->getMeshEditInterface(action);
2061         GLA()->addMeshEditor(action, iEdit);
2062     }
2063 	meshDoc()->meshDocStateData().create(*meshDoc());
2064     GLA()->setCurrentEditAction(action);
2065     updateMenus();
2066     GLA()->update();
2067 }
2068 
applyRenderMode()2069 void MainWindow::applyRenderMode()
2070 {
2071     QAction *action = qobject_cast<QAction *>(sender());		// find the action which has sent the signal
2072     if ((GLA()!= NULL) && (GLA()->getRenderer() != NULL))
2073     {
2074         GLA()->getRenderer()->Finalize(GLA()->getCurrentShaderAction(),meshDoc(),GLA());
2075         GLA()->setRenderer(NULL,NULL);
2076     }
2077     // Make the call to the plugin core
2078     MeshRenderInterface *iRenderTemp = qobject_cast<MeshRenderInterface *>(action->parent());
2079     bool initsupport = false;
2080 
2081 	if (currentViewContainer() == NULL)
2082 		return;
2083 
2084 	MLSceneGLSharedDataContext* shared = currentViewContainer()->sharedDataContext();
2085 
2086     if ((shared != NULL) && (iRenderTemp != NULL))
2087     {
2088 		MLSceneGLSharedDataContext::PerMeshRenderingDataMap rdmap;
2089 		shared->getRenderInfoPerMeshView(GLA()->context(), rdmap);
2090         iRenderTemp->Init(action,*(meshDoc()),rdmap, GLA());
2091         initsupport = iRenderTemp->isSupported();
2092         if (initsupport)
2093             GLA()->setRenderer(iRenderTemp,action);
2094         else
2095         {
2096             if (!initsupport)
2097             {
2098                 QString msg = "The selected shader is not supported by your graphic hardware!";
2099                 GLA()->Log(GLLogStream::SYSTEM,qUtf8Printable(msg));
2100             }
2101             iRenderTemp->Finalize(action,meshDoc(),GLA());
2102         }
2103     }
2104 
2105     /*I clicked None in renderMenu */
2106     if ((action->parent() == this) || (!initsupport))
2107     {
2108         QString msg("No Shader.");
2109         GLA()->Log(GLLogStream::SYSTEM,qUtf8Printable(msg));
2110         GLA()->setRenderer(0,0); //default opengl pipeline or vertex and fragment programs not supported
2111     }
2112     GLA()->update();
2113 }
2114 
2115 
applyDecorateMode()2116 void MainWindow::applyDecorateMode()
2117 {
2118     if(GLA()->mm() == 0) return;
2119     QAction *action = qobject_cast<QAction *>(sender());		// find the action which has sent the signal
2120 
2121     MeshDecorateInterface *iDecorateTemp = qobject_cast<MeshDecorateInterface *>(action->parent());
2122 
2123     GLA()->toggleDecorator(iDecorateTemp->decorationName(action));
2124 
2125 	updateMenus();
2126     layerDialog->updateDecoratorParsView();
2127     layerDialog->updateLog(meshDoc()->Log);
2128     layerDialog->update();
2129     GLA()->update();
2130 }
2131 
2132 
2133 /*
2134 Save project. It saves the info of all the layers and the layer themselves. So
2135 */
saveProject()2136 void MainWindow::saveProject()
2137 {
2138     if (meshDoc() == NULL)
2139         return;
2140     //if a mesh has been created by a create filter we must before to save it. Otherwise the project will refer to a mesh without file name path.
2141     foreach(MeshModel * mp, meshDoc()->meshList)
2142     {
2143         if ((mp != NULL) && (mp->fullName().isEmpty()))
2144         {
2145             bool saved = exportMesh(tr(""),mp,false);
2146             if (!saved)
2147             {
2148                 QString msg = "Mesh layer " + mp->label() + " cannot be saved on a file.\nProject \"" + meshDoc()->docLabel() + "\" saving has been aborted.";
2149                 QMessageBox::warning(this,tr("Project Saving Aborted"),msg);
2150                 return;
2151             }
2152         }
2153     }
2154     QFileDialog* saveDiag = new QFileDialog(this,tr("Save Project File"),lastUsedDirectory.path().append(""), tr("MeshLab Project (*.mlp);;MeshLab Binary Project (*.mlb);;Align Project (*.aln)"));
2155 #if defined(Q_OS_WIN)
2156     saveDiag->setOption(QFileDialog::DontUseNativeDialog);
2157 #endif
2158     QCheckBox* saveAllFile = new QCheckBox(QString("Save All Files"),saveDiag);
2159     saveAllFile->setCheckState(Qt::Unchecked);
2160     QCheckBox* onlyVisibleLayers = new QCheckBox(QString("Only Visible Layers"),saveDiag);
2161     onlyVisibleLayers->setCheckState(Qt::Unchecked);
2162 	QCheckBox* saveViewState = new QCheckBox(QString("Save View State"), saveDiag);
2163 	saveViewState->setCheckState(Qt::Checked);
2164     QGridLayout* layout = qobject_cast<QGridLayout*>(saveDiag->layout());
2165     if (layout != NULL)
2166     {
2167 		layout->addWidget(onlyVisibleLayers, 4, 0);
2168 		layout->addWidget(saveViewState, 4, 1);
2169 		layout->addWidget(saveAllFile, 4, 2);
2170     }
2171     saveDiag->setAcceptMode(QFileDialog::AcceptSave);
2172     saveDiag->exec();
2173     QStringList files = saveDiag->selectedFiles();
2174     if (files.size() != 1)
2175         return;
2176     QString fileName = files[0];
2177     // this change of dir is needed for subsequent textures/materials loading
2178     QFileInfo fi(fileName);
2179     if (fi.isDir())
2180         return;
2181     if (fi.suffix().isEmpty())
2182     {
2183         QRegExp reg("\\.\\w+");
2184         saveDiag->selectedNameFilter().indexOf(reg);
2185         QString ext = reg.cap();
2186         fileName.append(ext);
2187         fi.setFile(fileName);
2188     }
2189     QDir::setCurrent(fi.absoluteDir().absolutePath());
2190 
2191     /*********WARNING!!!!!! CHANGE IT!!! ALSO IN THE OPENPROJECT FUNCTION********/
2192     meshDoc()->setDocLabel(fileName);
2193     QMdiSubWindow* sub = mdiarea->currentSubWindow();
2194     if (sub != NULL)
2195     {
2196         sub->setWindowTitle(meshDoc()->docLabel());
2197         layerDialog->setWindowTitle(meshDoc()->docLabel());
2198     }
2199     /****************************************************************************/
2200 
2201 
2202     bool ret;
2203 	qDebug("Saving aln file %s\n", qUtf8Printable(fileName));
2204     if (fileName.isEmpty()) return;
2205     else
2206     {
2207         //save path away so we can use it again
2208         QString path = fileName;
2209         path.truncate(path.lastIndexOf("/"));
2210         lastUsedDirectory.setPath(path);
2211     }
2212     if (QString(fi.suffix()).toLower() == "aln")
2213     {
2214         vector<string> meshNameVector;
2215         vector<Matrix44m> transfVector;
2216 
2217         foreach(MeshModel * mp, meshDoc()->meshList)
2218         {
2219             if((!onlyVisibleLayers->isChecked()) || (mp->visible))
2220             {
2221 				meshNameVector.push_back(qUtf8Printable(mp->relativePathName()));
2222                 transfVector.push_back(mp->cm.Tr);
2223             }
2224         }
2225 		ret = ALNParser::SaveALN(qUtf8Printable(fileName), meshNameVector, transfVector);
2226     }
2227     else
2228     {
2229       std::map<int, MLRenderingData> rendOpt;
2230 	  foreach(MeshModel * mp, meshDoc()->meshList)
2231 	  {
2232 		MLRenderingData ml;
2233 		getRenderingData(mp->id(), ml);
2234 		rendOpt.insert(std::pair<int, MLRenderingData>(mp->id(), ml));
2235 	  }
2236 	  ret = MeshDocumentToXMLFile(*meshDoc(), fileName, onlyVisibleLayers->isChecked(), saveViewState->isChecked(), QString(fi.suffix()).toLower() == "mlb", rendOpt);
2237     }
2238 
2239     if (saveAllFile->isChecked())
2240     {
2241         for(int ii = 0; ii < meshDoc()->meshList.size();++ii)
2242         {
2243             MeshModel* mp = meshDoc()->meshList[ii];
2244             if((!onlyVisibleLayers->isChecked()) || (mp->visible))
2245             {
2246                 ret |= exportMesh(mp->fullName(),mp,true);
2247             }
2248         }
2249     }
2250     if(!ret)
2251         QMessageBox::critical(this, tr("Meshlab Saving Error"), QString("Unable to save project file %1\n").arg(fileName));
2252 }
2253 
openProject(QString fileName)2254 bool MainWindow::openProject(QString fileName)
2255 {
2256     bool visiblelayer = layerDialog->isVisible();
2257     showLayerDlg(false);
2258 	globrendtoolbar->setEnabled(false);
2259     if (fileName.isEmpty())
2260         fileName = QFileDialog::getOpenFileName(this,tr("Open Project File"), lastUsedDirectory.path(), tr("All Project Files (*.mlp *.mlb *.aln *.out *.nvm);;MeshLab Project (*.mlp);;MeshLab Binary Project (*.mlb);;Align Project (*.aln);;Bundler Output (*.out);;VisualSFM Output (*.nvm)"));
2261 
2262     if (fileName.isEmpty()) return false;
2263 
2264     QFileInfo fi(fileName);
2265     lastUsedDirectory = fi.absoluteDir();
2266     if((fi.suffix().toLower()!="aln") && (fi.suffix().toLower()!="mlp")  && (fi.suffix().toLower() != "mlb") && (fi.suffix().toLower()!="out") && (fi.suffix().toLower()!="nvm"))
2267     {
2268         QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unknown project file extension");
2269         return false;
2270     }
2271 
2272     // Common Part: init a Doc if necessary, and
2273     bool activeDoc = (bool) !mdiarea->subWindowList().empty() && mdiarea->currentSubWindow();
2274     bool activeEmpty = activeDoc && meshDoc()->meshList.empty();
2275 
2276     if (!activeEmpty)  newProject(fileName);
2277 
2278     meshDoc()->setFileName(fileName);
2279     mdiarea->currentSubWindow()->setWindowTitle(fileName);
2280     meshDoc()->setDocLabel(fileName);
2281 
2282     meshDoc()->setBusy(true);
2283 
2284     // this change of dir is needed for subsequent textures/materials loading
2285     QDir::setCurrent(fi.absoluteDir().absolutePath());
2286     qb->show();
2287 
2288     if (QString(fi.suffix()).toLower() == "aln")
2289     {
2290         vector<RangeMap> rmv;
2291 		int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(fileName));
2292         if(retVal != ALNParser::NoError)
2293         {
2294             QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open ALN file");
2295             return false;
2296         }
2297 
2298         bool openRes=true;
2299         vector<RangeMap>::iterator ir;
2300         for(ir=rmv.begin();ir!=rmv.end() && openRes;++ir)
2301         {
2302             QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str();
2303             meshDoc()->addNewMesh(relativeToProj,relativeToProj);
2304             openRes = loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),ir->trasformation);
2305             if(!openRes)
2306                 meshDoc()->delMesh(meshDoc()->mm());
2307         }
2308     }
2309 
2310     if (QString(fi.suffix()).toLower() == "mlp" || QString(fi.suffix()).toLower() == "mlb")
2311     {
2312         std::map<int, MLRenderingData> rendOpt;
2313         if (!MeshDocumentFromXML(*meshDoc(), fileName, (QString(fi.suffix()).toLower() == "mlb"), rendOpt))
2314         {
2315           QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open MeshLab Project file");
2316           return false;
2317         }
2318 		GLA()->updateMeshSetVisibilities();
2319         for (int i=0; i<meshDoc()->meshList.size(); i++)
2320         {
2321             QString fullPath = meshDoc()->meshList[i]->fullName();
2322             //meshDoc()->setBusy(true);
2323             Matrix44m trm = this->meshDoc()->meshList[i]->cm.Tr; // save the matrix, because loadMeshClear it...
2324             MLRenderingData* ptr = NULL;
2325             if (rendOpt.find(meshDoc()->meshList[i]->id()) != rendOpt.end())
2326               ptr = &rendOpt[meshDoc()->meshList[i]->id()];
2327             if (!loadMeshWithStandardParams(fullPath, this->meshDoc()->meshList[i], trm, false, ptr))
2328                 meshDoc()->delMesh(meshDoc()->meshList[i]);
2329         }
2330     }
2331 
2332     ////// BUNDLER
2333     if (QString(fi.suffix()).toLower() == "out"){
2334 
2335         QString cameras_filename = fileName;
2336         QString image_list_filename;
2337         QString model_filename;
2338 
2339         image_list_filename = QFileDialog::getOpenFileName(
2340             this  ,  tr("Open image list file"),
2341             QFileInfo(fileName).absolutePath(),
2342             tr("Bundler images list file (*.txt)")
2343             );
2344         if(image_list_filename.isEmpty())
2345             return false;
2346 
2347         if(!MeshDocumentFromBundler(*meshDoc(),cameras_filename,image_list_filename,model_filename)){
2348             QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open OUTs file");
2349             return false;
2350         }
2351 
2352 
2353 //WARNING!!!!! i suppose it's not useful anymore but.......
2354 /*GLA()->setColorMode(GLW::CMPerVert);
2355 GLA()->setDrawMode(GLW::DMPoints);*/
2356 /////////////////////////////////////////////////////////
2357     }
2358 
2359     //////NVM
2360     if (QString(fi.suffix()).toLower() == "nvm"){
2361 
2362         QString cameras_filename = fileName;
2363         QString model_filename;
2364 
2365         if(!MeshDocumentFromNvm(*meshDoc(),cameras_filename,model_filename)){
2366             QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open NVMs file");
2367             return false;
2368         }
2369 //WARNING!!!!! i suppose it's not useful anymore but.......
2370 /*GLA()->setColorMode(GLW::CMPerVert);
2371 GLA()->setDrawMode(GLW::DMPoints);*/
2372 /////////////////////////////////////////////////////////
2373     }
2374 
2375     meshDoc()->setBusy(false);
2376     if(this->GLA() == 0)  return false;
2377 
2378     MultiViewer_Container* mvc = currentViewContainer();
2379 	if (mvc != NULL)
2380 	{
2381 		mvc->resetAllTrackBall();
2382 		mvc->updateAllDecoratorsForAllViewers();
2383 	}
2384 
2385 	setCurrentMeshBestTab();
2386     qb->reset();
2387     saveRecentProjectList(fileName);
2388 	globrendtoolbar->setEnabled(true);
2389     showLayerDlg(visiblelayer || (meshDoc()->meshList.size() > 0));
2390 
2391     return true;
2392 }
2393 
appendProject(QString fileName)2394 bool MainWindow::appendProject(QString fileName)
2395 {
2396     QStringList fileNameList;
2397 	globrendtoolbar->setEnabled(false);
2398   if (fileName.isEmpty())
2399     fileNameList = QFileDialog::getOpenFileNames(this, tr("Append Project File"), lastUsedDirectory.path(), "All Project Files (*.mlp *.mlb *.aln *.out *.nvm);;MeshLab Project (*.mlp);;MeshLab Binary Project (*.mlb);;Align Project (*.aln);;Bundler Output (*.out);;VisualSFM Output (*.nvm)");
2400     else
2401         fileNameList.append(fileName);
2402 
2403     if (fileNameList.isEmpty()) return false;
2404 
2405     // Ccheck if we have a doc and if it is empty
2406     bool activeDoc = (bool) !mdiarea->subWindowList().empty() && mdiarea->currentSubWindow();
2407 	if (!activeDoc || meshDoc()->meshList.empty())  // it is wrong to try appending to an empty project, even if it is possible
2408     {
2409         QMessageBox::critical(this, tr("Meshlab Opening Error"), "Current project is empty, cannot append");
2410         return false;
2411     }
2412 
2413     meshDoc()->setBusy(true);
2414 
2415     // load all projects
2416     foreach(fileName,fileNameList)
2417     {
2418         QFileInfo fi(fileName);
2419         lastUsedDirectory = fi.absoluteDir();
2420 
2421         if((fi.suffix().toLower()!="aln") && (fi.suffix().toLower()!="mlp") && (fi.suffix().toLower() != "mlb") && (fi.suffix().toLower() != "out") && (fi.suffix().toLower() != "nvm"))
2422         {
2423             QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unknown project file extension");
2424             return false;
2425         }
2426 
2427         // this change of dir is needed for subsequent textures/materials loading
2428         QDir::setCurrent(fi.absoluteDir().absolutePath());
2429         qb->show();
2430 
2431         if (QString(fi.suffix()).toLower() == "aln")
2432         {
2433             vector<RangeMap> rmv;
2434 			int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(fileName));
2435             if(retVal != ALNParser::NoError)
2436             {
2437                 QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open ALN file");
2438                 return false;
2439             }
2440 
2441             for(vector<RangeMap>::iterator ir=rmv.begin();ir!=rmv.end();++ir)
2442             {
2443                 QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str();
2444                 meshDoc()->addNewMesh(relativeToProj,relativeToProj);
2445                 if(!loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),(*ir).trasformation))
2446                     meshDoc()->delMesh(meshDoc()->mm());
2447             }
2448         }
2449 
2450         if (QString(fi.suffix()).toLower() == "mlp" || QString(fi.suffix()).toLower() == "mlb")
2451         {
2452 			int alreadyLoadedNum = meshDoc()->meshList.size();
2453             std::map<int, MLRenderingData> rendOpt;
2454             if (!MeshDocumentFromXML(*meshDoc(),fileName, QString(fi.suffix()).toLower() == "mlb", rendOpt))
2455             {
2456                 QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open MeshLab Project file");
2457                 return false;
2458             }
2459 			GLA()->updateMeshSetVisibilities();
2460 			for (int i = alreadyLoadedNum; i<meshDoc()->meshList.size(); i++)
2461             {
2462                 QString fullPath = meshDoc()->meshList[i]->fullName();
2463                 meshDoc()->setBusy(true);
2464                 Matrix44m trm = this->meshDoc()->meshList[i]->cm.Tr; // save the matrix, because loadMeshClear it...
2465                 MLRenderingData* ptr = NULL;
2466                 if (rendOpt.find(meshDoc()->meshList[i]->id()) != rendOpt.end())
2467                   ptr = &rendOpt[meshDoc()->meshList[i]->id()];
2468                 if(!loadMeshWithStandardParams(fullPath,this->meshDoc()->meshList[i],trm, false, ptr))
2469                     meshDoc()->delMesh(meshDoc()->meshList[i]);
2470             }
2471         }
2472 
2473         if (QString(fi.suffix()).toLower() == "out") {
2474 
2475           QString cameras_filename = fileName;
2476           QString image_list_filename;
2477           QString model_filename;
2478 
2479           image_list_filename = QFileDialog::getOpenFileName(
2480             this, tr("Open image list file"),
2481             QFileInfo(fileName).absolutePath(),
2482             tr("Bundler images list file (*.txt)")
2483           );
2484           if (image_list_filename.isEmpty())
2485             return false;
2486 
2487           if (!MeshDocumentFromBundler(*meshDoc(), cameras_filename, image_list_filename, model_filename)) {
2488             QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open OUTs file");
2489             return false;
2490           }
2491         }
2492 
2493        if (QString(fi.suffix()).toLower() == "nvm") {
2494 
2495           QString cameras_filename = fileName;
2496           QString model_filename;
2497 
2498           if (!MeshDocumentFromNvm(*meshDoc(), cameras_filename, model_filename)) {
2499             QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open NVMs file");
2500             return false;
2501           }
2502         }
2503     }
2504 
2505 	globrendtoolbar->setEnabled(true);
2506     meshDoc()->setBusy(false);
2507     if(this->GLA() == 0)  return false;
2508 	MultiViewer_Container* mvc = currentViewContainer();
2509 	if (mvc != NULL)
2510 	{
2511 		mvc->updateAllDecoratorsForAllViewers();
2512 		mvc->resetAllTrackBall();
2513 	}
2514 
2515 	setCurrentMeshBestTab();
2516     qb->reset();
2517     saveRecentProjectList(fileName);
2518     return true;
2519 }
2520 
setCurrentMeshBestTab()2521 void MainWindow::setCurrentMeshBestTab()
2522 {
2523 	if (layerDialog == NULL)
2524 		return;
2525 
2526 	MultiViewer_Container* mvc = currentViewContainer();
2527 	if (mvc != NULL)
2528 	{
2529 		MLSceneGLSharedDataContext* cont = mvc->sharedDataContext();
2530 		if ((GLA() != NULL) && (meshDoc() != NULL) && (meshDoc()->mm() != NULL))
2531 		{
2532 			MLRenderingData dt;
2533 			cont->getRenderInfoPerMeshView(meshDoc()->mm()->id(), GLA()->context(), dt);
2534 			layerDialog->setCurrentTab(dt);
2535 		}
2536 	}
2537 }
2538 
newProject(const QString & projName)2539 void MainWindow::newProject(const QString& projName)
2540 {
2541     if (gpumeminfo == NULL)
2542         return;
2543     MultiViewer_Container *mvcont = new MultiViewer_Container(*gpumeminfo,mwsettings.highprecision,mwsettings.perbatchprimitives,mwsettings.minpolygonpersmoothrendering,mdiarea);
2544     connect(&mvcont->meshDoc,SIGNAL(meshAdded(int)),this,SLOT(meshAdded(int)));
2545     connect(&mvcont->meshDoc,SIGNAL(meshRemoved(int)),this,SLOT(meshRemoved(int)));
2546 	connect(&mvcont->meshDoc, SIGNAL(documentUpdated()), this, SLOT(documentUpdateRequested()));
2547 	connect(mvcont, SIGNAL(closingMultiViewerContainer()), this, SLOT(closeCurrentDocument()));
2548     mdiarea->addSubWindow(mvcont);
2549     connect(mvcont,SIGNAL(updateMainWindowMenus()),this,SLOT(updateMenus()));
2550     connect(mvcont,SIGNAL(updateDocumentViewer()),this,SLOT(updateLayerDialog()));
2551 	connect(&mvcont->meshDoc.Log, SIGNAL(logUpdated()), this, SLOT(updateLog()));
2552     filterMenu->setEnabled(!filterMenu->actions().isEmpty());
2553     if (!filterMenu->actions().isEmpty())
2554         updateSubFiltersMenu(true,false);
2555     GLArea *gla=new GLArea(this, mvcont, &currentGlobalParams);
2556 	//connect(gla, SIGNAL(insertRenderingDataForNewlyGeneratedMesh(int)), this, SLOT(addRenderingDataIfNewlyGeneratedMesh(int)));
2557     mvcont->addView(gla, Qt::Horizontal);
2558 
2559     if (projName.isEmpty())
2560     {
2561         static int docCounter = 1;
2562         mvcont->meshDoc.setDocLabel(QString("Project_") + QString::number(docCounter));
2563         ++docCounter;
2564     }
2565     else
2566         mvcont->meshDoc.setDocLabel(projName);
2567     mvcont->setWindowTitle(mvcont->meshDoc.docLabel());
2568 	if (layerDialog != NULL)
2569 		layerDialog->reset();
2570 	//if(mdiarea->isVisible())
2571     updateLayerDialog();
2572     mvcont->showMaximized();
2573     connect(mvcont->sharedDataContext(),SIGNAL(currentAllocatedGPUMem(int,int,int,int)),this,SLOT(updateGPUMemBar(int,int,int,int)));
2574 }
2575 
documentUpdateRequested()2576 void MainWindow::documentUpdateRequested()
2577 {
2578 	if (meshDoc() == NULL)
2579 		return;
2580 	for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii)
2581 	{
2582 		MeshModel* mm = meshDoc()->meshList[ii];
2583 		if (mm != NULL)
2584 		{
2585 			addRenderingDataIfNewlyGeneratedMesh(mm->id());
2586 			updateLayerDialog();
2587 			if (currentViewContainer() != NULL)
2588 			{
2589 				currentViewContainer()->resetAllTrackBall();
2590 				currentViewContainer()->updateAllViewers();
2591 			}
2592 		}
2593 	}
2594 }
2595 
updateGPUMemBar(int nv_allmem,int nv_currentallocated,int ati_free_tex,int ati_free_vbo)2596 void MainWindow::updateGPUMemBar(int nv_allmem, int nv_currentallocated, int ati_free_tex, int ati_free_vbo)
2597 {
2598 #ifdef Q_OS_WIN
2599     if (nvgpumeminfo != NULL)
2600     {
2601 		if (nv_allmem + nv_currentallocated > 0)
2602 		{
2603 			nvgpumeminfo->setFormat("Mem %p% %v/%m MB");
2604 			int allmb = nv_allmem / 1024;
2605 			nvgpumeminfo->setRange(0, allmb);
2606 			int remainingmb = (nv_allmem - nv_currentallocated) / 1024;
2607 			nvgpumeminfo->setValue(remainingmb);
2608 			nvgpumeminfo->setFixedWidth(300);
2609 		}
2610 		else if (ati_free_tex + ati_free_vbo > 0)
2611 		{
2612 			int texmb = ati_free_tex / 1024;
2613 			int vbomb = ati_free_vbo / 1024;
2614 			nvgpumeminfo->setFormat(QString("Free: " + QString::number(vbomb) + "MB vbo - " + QString::number(texmb) + "MB tex"));
2615 			nvgpumeminfo->setRange(0, 100);
2616 			nvgpumeminfo->setValue(100);
2617 			nvgpumeminfo->setFixedWidth(300);
2618 		}
2619 		else
2620 		{
2621 			nvgpumeminfo->setFormat("UNRECOGNIZED CARD");
2622 			nvgpumeminfo->setRange(0, 100);
2623 			nvgpumeminfo->setValue(0);
2624 			nvgpumeminfo->setFixedWidth(300);
2625 		}
2626     }
2627 #else
2628     //avoid unused parameter warning
2629     (void) nv_allmem;
2630     (void) nv_currentallocated;
2631     (void) ati_free_tex;
2632     (void) ati_free_vbo;
2633     nvgpumeminfo->hide();
2634 #endif
2635 }
2636 //WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2637 //Temporary disgusting inequality between open (slot) - importMesh (function)
2638 //and importRaster (slot). It's not also difficult to remove the problem because
2639 //addNewRaster add a raster on a document and open the file, instead addNewMesh add a new mesh layer
2640 //without loading the model.
2641 
importRaster(const QString & fileImg)2642 bool MainWindow::importRaster(const QString& fileImg)
2643 {
2644 	if (!GLA())
2645 	{
2646 		this->newProject();
2647 		if (!GLA())
2648 			return false;
2649 	}
2650 
2651     QStringList filters;
2652     filters.push_back("Images (*.jpg *.png *.xpm)");
2653     filters.push_back("*.jpg");
2654     filters.push_back("*.png");
2655     filters.push_back("*.xpm");
2656 
2657     QStringList fileNameList;
2658     if (fileImg.isEmpty())
2659         fileNameList = QFileDialog::getOpenFileNames(this,tr("Open File"), lastUsedDirectory.path(), filters.join(";;"));
2660     else
2661         fileNameList.push_back(fileImg);
2662 
2663     foreach(QString fileName,fileNameList)
2664     {
2665         QFileInfo fi(fileName);
2666         if( fi.suffix().toLower()=="png" || fi.suffix().toLower()=="xpm" || fi.suffix().toLower()=="jpg")
2667         {
2668             qb->show();
2669 
2670             if(!fi.exists()) 	{
2671                 QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 does not exist.";
2672                 QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
2673                 return false;
2674             }
2675             if(!fi.isReadable()) 	{
2676                 QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable.";
2677                 QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
2678                 return false;
2679             }
2680 
2681             this->meshDoc()->setBusy(true);
2682             RasterModel *rm= meshDoc()->addNewRaster();
2683             rm->setLabel(fileImg);
2684             rm->addPlane(new Plane(fileName,Plane::RGBA));
2685             meshDoc()->setBusy(false);
2686             showLayerDlg(true);
2687 
2688 			/// Intrinsics extraction from EXIF
2689             ///	If no CCD Width value is provided, the intrinsics are extracted using the Equivalent 35mm focal
2690             /// If no or invalid EXIF info is found, the Intrinsics are initialized as a "plausible" 35mm sensor, with 50mm focal
2691 
2692             ::ResetJpgfile();
2693 			FILE * pFile = fopen(qUtf8Printable(fileName), "rb");
2694 
2695             int ret = ::ReadJpegSections (pFile, READ_METADATA);
2696             fclose(pFile);
2697             if (!ret || (ImageInfo.CCDWidth==0.0f && ImageInfo.FocalLength35mmEquiv==0.0f))
2698             {
2699                 rm->shot.Intrinsics.ViewportPx = vcg::Point2i(rm->currentPlane->image.width(), rm->currentPlane->image.height());
2700                 rm->shot.Intrinsics.CenterPx   = Point2m(float(rm->currentPlane->image.width()/2.0), float(rm->currentPlane->image.width()/2.0));
2701                 rm->shot.Intrinsics.PixelSizeMm[0]=36.0f/(float)rm->currentPlane->image.width();
2702                 rm->shot.Intrinsics.PixelSizeMm[1]=rm->shot.Intrinsics.PixelSizeMm[0];
2703                 rm->shot.Intrinsics.FocalMm = 50.0f;
2704             }
2705             else if (ImageInfo.CCDWidth!=0)
2706             {
2707                 rm->shot.Intrinsics.ViewportPx = vcg::Point2i(ImageInfo.Width, ImageInfo.Height);
2708                 rm->shot.Intrinsics.CenterPx   = Point2m(float(ImageInfo.Width/2.0), float(ImageInfo.Height/2.0));
2709                 float ratio;
2710                 if (ImageInfo.Width>ImageInfo.Height)
2711                     ratio=(float)ImageInfo.Width/(float)ImageInfo.Height;
2712                 else
2713                     ratio=(float)ImageInfo.Height/(float)ImageInfo.Width;
2714                 rm->shot.Intrinsics.PixelSizeMm[0]=ImageInfo.CCDWidth/(float)ImageInfo.Width;
2715                 rm->shot.Intrinsics.PixelSizeMm[1]=ImageInfo.CCDWidth/((float)ImageInfo.Height*ratio);
2716                 rm->shot.Intrinsics.FocalMm = ImageInfo.FocalLength;
2717             }
2718             else
2719             {
2720                 rm->shot.Intrinsics.ViewportPx = vcg::Point2i(ImageInfo.Width, ImageInfo.Height);
2721                 rm->shot.Intrinsics.CenterPx   = Point2m(float(ImageInfo.Width/2.0), float(ImageInfo.Height/2.0));
2722                 float ratioFocal=ImageInfo.FocalLength/ImageInfo.FocalLength35mmEquiv;
2723                 rm->shot.Intrinsics.PixelSizeMm[0]=(36.0f*ratioFocal)/(float)ImageInfo.Width;
2724                 rm->shot.Intrinsics.PixelSizeMm[1]=(24.0f*ratioFocal)/(float)ImageInfo.Height;
2725                 rm->shot.Intrinsics.FocalMm = ImageInfo.FocalLength;
2726             }
2727 
2728 			// End of EXIF reading
2729 
2730 			//// Since no extrinsic are available, the current trackball is reset (except for the FOV) and assigned to the raster
2731 			GLA()->resetTrackBall();
2732 			GLA()->fov = rm->shot.GetFovFromFocal();
2733 			rm->shot = GLA()->shotFromTrackball().first;
2734 			GLA()->resetTrackBall(); // and then we reset the trackball again, to have the standard view
2735 
2736 			if (_currviewcontainer != NULL)
2737 				_currviewcontainer->updateAllDecoratorsForAllViewers();
2738 
2739             //			if(mdiarea->isVisible()) GLA()->mvc->showMaximized();
2740             updateMenus();
2741             updateLayerDialog();
2742 
2743         }
2744         else
2745             return false;
2746     }
2747     return true;
2748 }
2749 
loadMesh(const QString & fileName,MeshIOInterface * pCurrentIOPlugin,MeshModel * mm,int & mask,RichParameterSet * prePar,const Matrix44m & mtr,bool isareload,MLRenderingData * rendOpt)2750 bool MainWindow::loadMesh(const QString& fileName, MeshIOInterface *pCurrentIOPlugin, MeshModel* mm, int& mask,RichParameterSet* prePar, const Matrix44m &mtr, bool isareload, MLRenderingData* rendOpt)
2751 {
2752     if ((GLA() == NULL) || (mm == NULL))
2753         return false;
2754 
2755     QFileInfo fi(fileName);
2756     QString extension = fi.suffix();
2757     if(!fi.exists())
2758     {
2759         QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 does not exist.";
2760         QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
2761         return false;
2762     }
2763     if(!fi.isReadable())
2764     {
2765         QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable.";
2766         QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
2767         return false;
2768     }
2769 
2770     // the original directory path before we switch it
2771     QString origDir = QDir::current().path();
2772 
2773     // this change of dir is needed for subsequent textures/materials loading
2774     QDir::setCurrent(fi.absoluteDir().absolutePath());
2775 
2776     // Adjust the file name after changing the directory
2777     QString fileNameSansDir = fi.fileName();
2778 
2779     // retrieving corresponding IO plugin
2780     if (pCurrentIOPlugin == 0)
2781     {
2782         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension does not correspond to any supported format.";
2783         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(fileName, extension));
2784         QDir::setCurrent(origDir); // undo the change of directory before leaving
2785         return false;
2786     }
2787     meshDoc()->setBusy(true);
2788     pCurrentIOPlugin->setLog(&meshDoc()->Log);
2789 
2790     if (!pCurrentIOPlugin->open(extension, fileNameSansDir, *mm ,mask,*prePar,QCallBack,this /*gla*/))
2791     {
2792         QMessageBox::warning(this, tr("Opening Failure"), QString("While opening: '%1'\n\n").arg(fileName)+pCurrentIOPlugin->errorMsg()); // text+
2793         pCurrentIOPlugin->clearErrorString();
2794         meshDoc()->setBusy(false);
2795         QDir::setCurrent(origDir); // undo the change of directory before leaving
2796         return false;
2797     }
2798 
2799 
2800 	//std::cout << "Opened mesh: in " << tm.elapsed() << " secs\n";
2801 	// After opening the mesh lets ask to the io plugin if this format
2802     // requires some optional, or userdriven post-opening processing.
2803     // and in that case ask for the required parameters and then
2804     // ask to the plugin to perform that processing
2805     //RichParameterSet par;
2806     //pCurrentIOPlugin->initOpenParameter(extension, *mm, par);
2807     //pCurrentIOPlugin->applyOpenParameter(extension, *mm, par);
2808 
2809     QString err = pCurrentIOPlugin->errorMsg();
2810     if (!err.isEmpty())
2811     {
2812         QMessageBox::warning(this, tr("Opening Problems"), QString("While opening: '%1'\n\n").arg(fileName)+pCurrentIOPlugin->errorMsg());
2813         pCurrentIOPlugin->clearErrorString();
2814     }
2815 
2816     saveRecentFileList(fileName);
2817 
2818     if (!(mm->cm.textures.empty()))
2819         updateTexture(mm->id());
2820 
2821     // In case of polygonal meshes the normal should be updated accordingly
2822     if( mask & vcg::tri::io::Mask::IOM_BITPOLYGONAL)
2823     {
2824         mm->updateDataMask(MeshModel::MM_POLYGONAL); // just to be sure. Hopefully it should be done in the plugin...
2825         int degNum = tri::Clean<CMeshO>::RemoveDegenerateFace(mm->cm);
2826         if(degNum)
2827             GLA()->Logf(0,"Warning model contains %i degenerate faces. Removed them.",degNum);
2828         mm->updateDataMask(MeshModel::MM_FACEFACETOPO);
2829         vcg::tri::UpdateNormal<CMeshO>::PerBitQuadFaceNormalized(mm->cm);
2830         vcg::tri::UpdateNormal<CMeshO>::PerVertexFromCurrentFaceNormal(mm->cm);
2831     } // standard case
2832     else
2833     {
2834         vcg::tri::UpdateNormal<CMeshO>::PerFaceNormalized(mm->cm);
2835         if(!( mask & vcg::tri::io::Mask::IOM_VERTNORMAL) )
2836             vcg::tri::UpdateNormal<CMeshO>::PerVertexAngleWeighted(mm->cm);
2837     }
2838 
2839     vcg::tri::UpdateBounding<CMeshO>::Box(mm->cm);					// updates bounding box
2840     if(mm->cm.fn==0 && mm->cm.en==0)
2841     {
2842         if(mask & vcg::tri::io::Mask::IOM_VERTNORMAL)
2843             mm->updateDataMask(MeshModel::MM_VERTNORMAL);
2844     }
2845 
2846     if(mm->cm.fn==0 && mm->cm.en>0)
2847     {
2848         if (mask & vcg::tri::io::Mask::IOM_VERTNORMAL)
2849             mm->updateDataMask(MeshModel::MM_VERTNORMAL);
2850     }
2851 
2852     updateMenus();
2853     int delVertNum = vcg::tri::Clean<CMeshO>::RemoveDegenerateVertex(mm->cm);
2854     int delFaceNum = vcg::tri::Clean<CMeshO>::RemoveDegenerateFace(mm->cm);
2855     tri::Allocator<CMeshO>::CompactEveryVector(mm->cm);
2856     if(delVertNum>0 || delFaceNum>0 )
2857         QMessageBox::warning(this, "MeshLab Warning", QString("Warning mesh contains %1 vertices with NAN coords and %2 degenerated faces.\nCorrected.").arg(delVertNum).arg(delFaceNum) );
2858     mm->cm.Tr = mtr;
2859 
2860 	computeRenderingDataOnLoading(mm,isareload, rendOpt);
2861 	updateLayerDialog();
2862 
2863 
2864     meshDoc()->setBusy(false);
2865 
2866     QDir::setCurrent(origDir); // undo the change of directory before leaving
2867 
2868     return true;
2869 }
2870 
computeRenderingDataOnLoading(MeshModel * mm,bool isareload,MLRenderingData * rendOpt)2871 void MainWindow::computeRenderingDataOnLoading(MeshModel* mm,bool isareload, MLRenderingData* rendOpt)
2872 {
2873 	MultiViewer_Container* mv = currentViewContainer();
2874 	if (mv != NULL)
2875 	{
2876 		MLSceneGLSharedDataContext* shared = mv->sharedDataContext();
2877 		if ((shared != NULL) && (mm != NULL))
2878 		{
2879 			MLRenderingData defdt;
2880 		  MLPoliciesStandAloneFunctions::suggestedDefaultPerViewRenderingData(mm, defdt,mwsettings.minpolygonpersmoothrendering);
2881       if (rendOpt != NULL)
2882         defdt = *rendOpt;
2883 			for (int glarid = 0; glarid < mv->viewerCounter(); ++glarid)
2884 			{
2885 				GLArea* ar = mv->getViewer(glarid);
2886 				if (ar != NULL)
2887 				{
2888 
2889 					if (isareload)
2890 					{
2891 						MLRenderingData currentdt;
2892 						shared->getRenderInfoPerMeshView(mm->id(), ar->context(), currentdt);
2893 						MLRenderingData newdt;
2894 						MLPoliciesStandAloneFunctions::computeRequestedRenderingDataCompatibleWithMeshSameGLOpts(mm, currentdt, newdt);
2895 						MLPoliciesStandAloneFunctions::setPerViewGLOptionsAccordindToWireModality(mm,newdt);
2896 						MLPoliciesStandAloneFunctions::setBestWireModality(mm, newdt);
2897 						shared->setRenderingDataPerMeshView(mm->id(), ar->context(), newdt);
2898 						shared->meshAttributesUpdated(mm->id(), true, MLRenderingData::RendAtts(true));
2899 					}
2900 					else
2901 						shared->setRenderingDataPerMeshView(mm->id(), ar->context(), defdt);
2902 				}
2903 			}
2904 			shared->manageBuffers(mm->id());
2905 		}
2906 	}
2907 }
2908 
importMeshWithLayerManagement(QString fileName)2909 bool MainWindow::importMeshWithLayerManagement(QString fileName)
2910 {
2911     bool layervisible = false;
2912     if (layerDialog != NULL)
2913     {
2914         layervisible = layerDialog->isVisible();
2915         showLayerDlg(false);
2916     }
2917 	globrendtoolbar->setEnabled(false);
2918     bool res = importMesh(fileName,false);
2919 	globrendtoolbar->setEnabled(true);
2920 	if (layerDialog != NULL)
2921 		showLayerDlg(layervisible || meshDoc()->meshList.size());
2922 	setCurrentMeshBestTab();
2923     return res;
2924 }
2925 
2926 // Opening files in a transparent form (IO plugins contribution is hidden to user)
importMesh(QString fileName,bool isareload)2927 bool MainWindow::importMesh(QString fileName,bool isareload)
2928 {
2929     if (!GLA())
2930     {
2931         this->newProject();
2932         if(!GLA())
2933             return false;
2934     }
2935 
2936 
2937     //QStringList suffixList;
2938     // HashTable storing all supported formats together with
2939     // the (1-based) index  of first plugin which is able to open it
2940     //QHash<QString, MeshIOInterface*> allKnownFormats;
2941     //PM.LoadFormats(suffixList, allKnownFormats,PluginManager::IMPORT);
2942     QStringList fileNameList;
2943     if (fileName.isEmpty())
2944         fileNameList = QFileDialog::getOpenFileNames(this,tr("Import Mesh"), lastUsedDirectory.path(), PM.inpFilters.join(";;"));
2945     else
2946         fileNameList.push_back(fileName);
2947 
2948     if (fileNameList.isEmpty())	return false;
2949     else
2950     {
2951         //save path away so we can use it again
2952         QString path = fileNameList.first();
2953         path.truncate(path.lastIndexOf("/"));
2954         lastUsedDirectory.setPath(path);
2955     }
2956 
2957     QElapsedTimer allFileTime;
2958     allFileTime.start();
2959     foreach(fileName,fileNameList)
2960     {
2961         QFileInfo fi(fileName);
2962         QString extension = fi.suffix();
2963         MeshIOInterface *pCurrentIOPlugin = PM.allKnowInputFormats[extension.toLower()];
2964         //pCurrentIOPlugin->setLog(gla->log);
2965         if (pCurrentIOPlugin == NULL)
2966         {
2967             QString errorMsgFormat("Unable to open file:\n\"%1\"\n\nError details: file format " + extension + " not supported.");
2968             QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
2969             return false;
2970         }
2971 
2972         RichParameterSet prePar;
2973         pCurrentIOPlugin->initPreOpenParameter(extension, fileName,prePar);
2974         if(!prePar.isEmpty())
2975         {
2976             GenericParamDialog preOpenDialog(this, &prePar, tr("Pre-Open Options"));
2977             preOpenDialog.setFocus();
2978             preOpenDialog.exec();
2979         }
2980 		prePar.join(currentGlobalParams);
2981         int mask = 0;
2982         //MeshModel *mm= new MeshModel(gla->meshDoc);
2983         QFileInfo info(fileName);
2984 		MeshModel *mm = meshDoc()->addNewMesh(fileName, info.fileName());
2985         qb->show();
2986         QElapsedTimer t;
2987 		t.start();
2988 		Matrix44m mtr;
2989 		mtr.SetIdentity();
2990         bool open = loadMesh(fileName,pCurrentIOPlugin,mm,mask,&prePar,mtr,isareload);
2991         if(open)
2992         {
2993 			GLA()->Logf(0, "Opened mesh %s in %i msec", qUtf8Printable(fileName), t.elapsed());
2994             RichParameterSet par;
2995             pCurrentIOPlugin->initOpenParameter(extension, *mm, par);
2996             if(!par.isEmpty())
2997             {
2998                 GenericParamDialog postOpenDialog(this, &par, tr("Post-Open Processing"));
2999                 postOpenDialog.setFocus();
3000                 postOpenDialog.exec();
3001                 pCurrentIOPlugin->applyOpenParameter(extension, *mm, par);
3002             }
3003             /*MultiViewer_Container* mv = GLA()->mvc();
3004             if (mv != NULL)
3005             {
3006             for(int glarid = 0;glarid < mv->viewerCounter();++glarid)
3007             {
3008             GLArea* ar = mv->getViewer(glarid);
3009             if (ar != NULL)
3010             MLSceneRenderModeAdapter::setupRequestedAttributesAccordingToRenderMode(mm->id(),*ar);
3011             }
3012             }*/
3013         }
3014         else
3015         {
3016             meshDoc()->delMesh(mm);
3017 			GLA()->Logf(0, "Warning: Mesh %s has not been opened", qUtf8Printable(fileName));
3018         }
3019     }// end foreach file of the input list
3020     GLA()->Logf(0,"All files opened in %i msec",allFileTime.elapsed());
3021 
3022 	if (_currviewcontainer != NULL)
3023 	{
3024 		_currviewcontainer->resetAllTrackBall();
3025 		_currviewcontainer->updateAllDecoratorsForAllViewers();
3026 	}
3027 	qb->reset();
3028     return true;
3029 }
3030 
openRecentMesh()3031 void MainWindow::openRecentMesh()
3032 {
3033     if(!GLA()) return;
3034     if(meshDoc()->isBusy()) return;
3035     QAction *action = qobject_cast<QAction *>(sender());
3036     if (action)	importMeshWithLayerManagement(action->data().toString());
3037 }
3038 
openRecentProj()3039 void MainWindow::openRecentProj()
3040 {
3041     QAction *action = qobject_cast<QAction *>(sender());
3042     if (action)	openProject(action->data().toString());
3043 }
3044 
loadMeshWithStandardParams(QString & fullPath,MeshModel * mm,const Matrix44m & mtr,bool isreload,MLRenderingData * rendOpt)3045 bool MainWindow::loadMeshWithStandardParams(QString& fullPath, MeshModel* mm, const Matrix44m &mtr, bool isreload, MLRenderingData* rendOpt)
3046 {
3047     if ((meshDoc() == NULL) || (mm == NULL))
3048         return false;
3049     bool ret = false;
3050     if (!mm->isVisible())
3051     {
3052       mm->Clear();
3053       mm->visible = false;
3054     }
3055     else
3056       mm->Clear();
3057     QFileInfo fi(fullPath);
3058     QString extension = fi.suffix();
3059     MeshIOInterface *pCurrentIOPlugin = PM.allKnowInputFormats[extension.toLower()];
3060 
3061     if(pCurrentIOPlugin != NULL)
3062     {
3063         RichParameterSet prePar;
3064         pCurrentIOPlugin->initPreOpenParameter(extension, fullPath,prePar);
3065 		prePar = prePar.join(currentGlobalParams);
3066         int mask = 0;
3067         QElapsedTimer t;t.start();
3068         bool open = loadMesh(fullPath,pCurrentIOPlugin,mm,mask,&prePar,mtr,isreload, rendOpt);
3069         if(open)
3070         {
3071 			GLA()->Logf(0, "Opened mesh %s in %i msec", qUtf8Printable(fullPath), t.elapsed());
3072             RichParameterSet par;
3073             pCurrentIOPlugin->initOpenParameter(extension, *mm, par);
3074             pCurrentIOPlugin->applyOpenParameter(extension,*mm,par);
3075             ret = true;
3076         }
3077         else
3078 			GLA()->Logf(0, "Warning: Mesh %s has not been opened", qUtf8Printable(fullPath));
3079     }
3080     else
3081 		GLA()->Logf(0, "Warning: Mesh %s cannot be opened. Your MeshLab version has not plugin to read %s file format", qUtf8Printable(fullPath), qUtf8Printable(extension));
3082     return ret;
3083 }
3084 
reloadAllMesh()3085 void MainWindow::reloadAllMesh()
3086 {
3087     // Discards changes and reloads current file
3088     // save current file name
3089     qb->show();
3090     foreach(MeshModel *mmm,meshDoc()->meshList)
3091     {
3092         QString fileName = mmm->fullName();
3093 		Matrix44m mat;
3094 		mat.SetIdentity();
3095         loadMeshWithStandardParams(fileName,mmm,mat,true);
3096     }
3097     qb->reset();
3098 
3099 	if (_currviewcontainer != NULL)
3100 	{
3101 		_currviewcontainer->updateAllDecoratorsForAllViewers();
3102 		_currviewcontainer->updateAllViewers();
3103 	}
3104 }
3105 
reload()3106 void MainWindow::reload()
3107 {
3108     if ((meshDoc() == NULL) || (meshDoc()->mm() == NULL))
3109         return;
3110     // Discards changes and reloads current file
3111     // save current file name
3112     qb->show();
3113     QString fileName = meshDoc()->mm()->fullName();
3114 	if (fileName.isEmpty())
3115 	{
3116 		QMessageBox::critical(this, "Reload Error", "Impossible to reload an unsaved mesh model!!");
3117 		return;
3118 	}
3119 	Matrix44m mat;
3120 	mat.SetIdentity();
3121     loadMeshWithStandardParams(fileName,meshDoc()->mm(),mat,true);
3122     qb->reset();
3123 	if (_currviewcontainer != NULL)
3124 	{
3125 		_currviewcontainer->updateAllDecoratorsForAllViewers();
3126 		_currviewcontainer->updateAllViewers();
3127 	}
3128 }
3129 
exportMesh(QString fileName,MeshModel * mod,const bool saveAllPossibleAttributes)3130 bool MainWindow::exportMesh(QString fileName,MeshModel* mod,const bool saveAllPossibleAttributes)
3131 {
3132     QStringList& suffixList = PM.outFilters;
3133 
3134     //QHash<QString, MeshIOInterface*> allKnownFormats;
3135     QFileInfo fi(fileName);
3136     //PM.LoadFormats( suffixList, allKnownFormats,PluginManager::EXPORT);
3137     //QString defaultExt = "*." + mod->suffixName().toLower();
3138     QString defaultExt = "*." + fi.suffix().toLower();
3139     if(defaultExt == "*.")
3140         defaultExt = "*.ply";
3141     if (mod == NULL)
3142         return false;
3143     mod->meshModified() = false;
3144     QString laylabel = "Save \"" + mod->label() + "\" Layer";
3145     QString ss = fi.absoluteFilePath();
3146     QFileDialog* saveDialog = new QFileDialog(this,laylabel, fi.absolutePath());
3147 #if defined(Q_OS_WIN)
3148     saveDialog->setOption(QFileDialog::DontUseNativeDialog);
3149 #endif
3150     saveDialog->setNameFilters(suffixList);
3151     saveDialog->setAcceptMode(QFileDialog::AcceptSave);
3152     saveDialog->setFileMode(QFileDialog::AnyFile);
3153     saveDialog->selectFile(fileName);
3154     QStringList matchingExtensions=suffixList.filter(defaultExt);
3155     if(!matchingExtensions.isEmpty())
3156         saveDialog->selectNameFilter(matchingExtensions.last());
3157     connect(saveDialog,SIGNAL(filterSelected(const QString&)),this,SLOT(changeFileExtension(const QString&)));
3158 
3159     if (fileName.isEmpty()){
3160         saveDialog->selectFile(meshDoc()->mm()->fullName());
3161         int dialogRet = saveDialog->exec();
3162         if(dialogRet==QDialog::Rejected	)
3163             return false;
3164         fileName=saveDialog->selectedFiles ().first();
3165         QFileInfo fni(fileName);
3166         if(fni.suffix().isEmpty())
3167         {
3168             QString ext = saveDialog->selectedNameFilter();
3169             ext.chop(1); ext = ext.right(4);
3170             fileName = fileName + ext;
3171 			qDebug("File without extension adding it by hand '%s'", qUtf8Printable(fileName));
3172         }
3173     }
3174 
3175 
3176     bool ret = false;
3177 
3178     QStringList fs = fileName.split(".");
3179 
3180     if(!fileName.isEmpty() && fs.size() < 2)
3181     {
3182         QMessageBox::warning(this,"Save Error","You must specify file extension!!");
3183         return ret;
3184     }
3185 
3186     if (!fileName.isEmpty())
3187     {
3188         //save path away so we can use it again
3189         QString path = fileName;
3190         path.truncate(path.lastIndexOf("/"));
3191         lastUsedDirectory.setPath(path);
3192 
3193         QString extension = fileName;
3194         extension.remove(0, fileName.lastIndexOf('.')+1);
3195 
3196         QStringListIterator itFilter(suffixList);
3197 
3198         MeshIOInterface *pCurrentIOPlugin = PM.allKnowOutputFormats[extension.toLower()];
3199         if (pCurrentIOPlugin == 0)
3200         {
3201             QMessageBox::warning(this, "Unknown type", "File extension not supported!");
3202             return false;
3203         }
3204         //MeshIOInterface* pCurrentIOPlugin = meshIOPlugins[idx-1];
3205         pCurrentIOPlugin->setLog(&meshDoc()->Log);
3206 
3207         int capability=0,defaultBits=0;
3208         pCurrentIOPlugin->GetExportMaskCapability(extension,capability,defaultBits);
3209 
3210         // optional saving parameters (like ascii/binary encoding)
3211         RichParameterSet savePar;
3212 
3213         pCurrentIOPlugin->initSaveParameter(extension,*(mod),savePar);
3214 
3215         SaveMaskExporterDialog maskDialog(new QWidget(),mod,capability,defaultBits,&savePar,this->GLA());
3216         if (!saveAllPossibleAttributes)
3217             maskDialog.exec();
3218         else
3219         {
3220             maskDialog.SlotSelectionAllButton();
3221             maskDialog.updateMask();
3222         }
3223         int mask = maskDialog.GetNewMask();
3224         if (!saveAllPossibleAttributes)
3225         {
3226             maskDialog.close();
3227             if(maskDialog.result() == QDialog::Rejected)
3228                 return false;
3229         }
3230         if(mask == -1)
3231             return false;
3232 
3233         qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
3234         qb->show();
3235         QElapsedTimer tt; tt.start();
3236         ret = pCurrentIOPlugin->save(extension, fileName, *mod ,mask,savePar,QCallBack,this);
3237         qb->reset();
3238 		if (ret)
3239 		{
3240 			GLA()->Logf(GLLogStream::SYSTEM, "Saved Mesh %s in %i msec", qUtf8Printable(fileName), tt.elapsed());
3241 			mod->setFileName(fileName);
3242 			QSettings settings;
3243 			int savedMeshCounter = settings.value("savedMeshCounter", 0).toInt();
3244 			settings.setValue("savedMeshCounter", savedMeshCounter + 1);
3245 		}
3246 		else
3247 		{
3248 			GLA()->Logf(GLLogStream::SYSTEM, "Error Saving Mesh %s", qUtf8Printable(fileName));
3249 			QMessageBox::critical(this, tr("Meshlab Saving Error"),  pCurrentIOPlugin->errorMessage);
3250 		}
3251         qApp->restoreOverrideCursor();
3252 		updateLayerDialog();
3253 
3254 		if (ret)
3255 			QDir::setCurrent(fi.absoluteDir().absolutePath()); //set current dir
3256     }
3257     return ret;
3258 }
3259 
changeFileExtension(const QString & st)3260 void MainWindow::changeFileExtension(const QString& st)
3261 {
3262     QFileDialog* fd = qobject_cast<QFileDialog*>(sender());
3263     if (fd == NULL)
3264         return;
3265     QRegExp extlist("\\*.\\w+");
3266     int start = st.indexOf(extlist);
3267     (void)start;
3268     QString ext = extlist.cap().remove("*");
3269     QStringList stlst = fd->selectedFiles();
3270     if (!stlst.isEmpty())
3271     {
3272         QFileInfo fi(stlst[0]);
3273         fd->selectFile(fi.baseName() + ext);
3274     }
3275 }
3276 
save(const bool saveAllPossibleAttributes)3277 bool MainWindow::save(const bool saveAllPossibleAttributes)
3278 {
3279     return exportMesh(meshDoc()->mm()->fullName(),meshDoc()->mm(),saveAllPossibleAttributes);
3280 }
3281 
saveAs(QString fileName,const bool saveAllPossibleAttributes)3282 bool MainWindow::saveAs(QString fileName,const bool saveAllPossibleAttributes)
3283 {
3284     return exportMesh(fileName,meshDoc()->mm(),saveAllPossibleAttributes);
3285 }
3286 
readViewFromFile(QString const & filename)3287 void MainWindow::readViewFromFile(QString const& filename){
3288       if(GLA() != 0)
3289           GLA()->readViewFromFile(filename);
3290 }
3291 
saveSnapshot()3292 bool MainWindow::saveSnapshot()
3293 {
3294 	if (!GLA()) return false;
3295 	if (meshDoc()->isBusy()) return false;
3296 
3297     SaveSnapshotDialog dialog(this);
3298     dialog.setValues(GLA()->ss);
3299 
3300     if (dialog.exec()==QDialog::Accepted)
3301     {
3302         GLA()->ss=dialog.getValues();
3303         GLA()->saveSnapshot();
3304         return true;
3305     }
3306 
3307     return false;
3308 }
about()3309 void MainWindow::about()
3310 {
3311     QDialog *about_dialog = new QDialog();
3312     Ui::aboutDialog temp;
3313     temp.setupUi(about_dialog);
3314     temp.labelMLName->setText(MeshLabApplication::completeName(MeshLabApplication::HW_ARCHITECTURE(QSysInfo::WordSize))+"   (built on "+__DATE__+")");
3315     //about_dialog->setFixedSize(566,580);
3316     about_dialog->show();
3317 }
3318 
aboutPlugins()3319 void MainWindow::aboutPlugins()
3320 {
3321     qDebug( "aboutPlugins(): Current Plugins Dir: %s ",qUtf8Printable(pluginManager().getDefaultPluginDirPath()));
3322     PluginDialog dialog(pluginManager().getDefaultPluginDirPath(), pluginManager().pluginsLoaded, this);
3323     dialog.exec();
3324 }
3325 
helpOnscreen()3326 void MainWindow::helpOnscreen()
3327 {
3328     if(GLA()) GLA()->toggleHelpVisible();
3329 }
3330 
helpOnline()3331 void MainWindow::helpOnline()
3332 {
3333     checkForUpdates(false);
3334     QDesktopServices::openUrl(QUrl("http://www.meshlab.net/#support"));
3335 }
3336 
showToolbarFile()3337 void MainWindow::showToolbarFile(){
3338     mainToolBar->setVisible(!mainToolBar->isVisible());
3339 }
3340 
showInfoPane()3341 void MainWindow::showInfoPane()  {if(GLA() != 0)	GLA()->infoAreaVisible =!GLA()->infoAreaVisible;}
showTrackBall()3342 void MainWindow::showTrackBall() {if(GLA() != 0) 	GLA()->showTrackBall(!GLA()->isTrackBallVisible());}
resetTrackBall()3343 void MainWindow::resetTrackBall(){if(GLA() != 0)	GLA()->resetTrackBall();}
showRaster()3344 void MainWindow::showRaster()    {if(GLA() != 0)	GLA()->showRaster((QApplication::keyboardModifiers () & Qt::ShiftModifier));}
showLayerDlg(bool visible)3345 void MainWindow::showLayerDlg(bool visible)
3346 {
3347     if ((GLA() != 0) && (layerDialog != NULL))
3348     {
3349         layerDialog->setVisible( visible);
3350         showLayerDlgAct->setChecked(visible);
3351     }
3352 }
showXMLPluginEditorGui()3353 void MainWindow::showXMLPluginEditorGui()
3354 {
3355     if(GLA() != 0)
3356         plugingui->setVisible( !plugingui->isVisible() );
3357 }
3358 
3359 
setCustomize()3360 void MainWindow::setCustomize()
3361 {
3362     CustomDialog dialog(currentGlobalParams,defaultGlobalParams, this);
3363     connect(&dialog,SIGNAL(applyCustomSetting()),this,SLOT(updateCustomSettings()));
3364     dialog.exec();
3365 }
3366 
fullScreen()3367 void MainWindow::fullScreen(){
3368     if(!isFullScreen())
3369     {
3370         toolbarState = saveState();
3371         menuBar()->hide();
3372         mainToolBar->hide();
3373         globalStatusBar()->hide();
3374         setWindowState(windowState()^Qt::WindowFullScreen);
3375         bool found=true;
3376         //Caso di piu' finestre aperte in tile:
3377         if((mdiarea->subWindowList()).size()>1){
3378             foreach(QWidget *w,mdiarea->subWindowList()){if(w->isMaximized()) found=false;}
3379             if (found)mdiarea->tileSubWindows();
3380         }
3381     }
3382     else
3383     {
3384         menuBar()->show();
3385         restoreState(toolbarState);
3386         globalStatusBar()->show();
3387 
3388         setWindowState(windowState()^ Qt::WindowFullScreen);
3389         bool found=true;
3390         //Caso di piu' finestre aperte in tile:
3391         if((mdiarea->subWindowList()).size()>1){
3392             foreach(QWidget *w,mdiarea->subWindowList()){if(w->isMaximized()) found=false;}
3393             if (found){mdiarea->tileSubWindows();}
3394         }
3395         fullScreenAct->setChecked(false);
3396     }
3397 }
3398 
keyPressEvent(QKeyEvent * e)3399 void MainWindow::keyPressEvent(QKeyEvent *e)
3400 {
3401     if(e->key()==Qt::Key_Return && e->modifiers()==Qt::AltModifier)
3402     {
3403         fullScreen();
3404         e->accept();
3405     }
3406     else e->ignore();
3407 }
3408 
3409 /**
3410  * @brief static function that updates the progress bar
3411  * @param pos: an int value between 0 and 100
3412  * @param str
3413  * @return
3414  */
QCallBack(const int pos,const char * str)3415 bool MainWindow::QCallBack(const int pos, const char * str)
3416 {
3417 	int static lastPos = -1;
3418 	if (pos == lastPos) return true;
3419 	lastPos = pos;
3420 
3421 	static QElapsedTimer currTime;
3422 	if (currTime.isValid() && currTime.elapsed() < 100)
3423 		return true;
3424 	currTime.start();
3425 	MainWindow::globalStatusBar()->showMessage(str, 5000);
3426 	qb->show();
3427 	qb->setEnabled(true);
3428 	qb->setValue(pos);
3429 	MainWindow::globalStatusBar()->update();
3430 	qApp->processEvents();
3431     return true;
3432 }
3433 
updateTexture(int meshid)3434 void MainWindow::updateTexture(int meshid)
3435 {
3436     MultiViewer_Container* mvc = currentViewContainer();
3437     if ((mvc == NULL) || (meshDoc() == NULL))
3438         return;
3439 
3440     MLSceneGLSharedDataContext* shared = mvc->sharedDataContext();
3441     if (shared == NULL)
3442         return;
3443 
3444     MeshModel* mymesh = meshDoc()->getMesh(meshid);
3445     if (mymesh  == NULL)
3446         return;
3447 
3448     shared->deAllocateTexturesPerMesh(mymesh->id());
3449 
3450     int textmemMB = int(mwsettings.maxTextureMemory / ((float) 1024 * 1024));
3451 
3452     size_t totalTextureNum = 0;
3453     foreach (MeshModel *mp, meshDoc()->meshList)
3454         totalTextureNum+=mp->cm.textures.size();
3455 
3456     int singleMaxTextureSizeMpx = int(textmemMB/((totalTextureNum != 0)? totalTextureNum : 1));
3457     bool sometextfailed = false;
3458     QString unexistingtext = "In mesh file <i>" + mymesh->fullName() + "</i> : Failure loading textures:<br>";
3459     for(size_t i =0; i< mymesh->cm.textures.size();++i)
3460     {
3461         QImage img;
3462         QFileInfo fi(mymesh->cm.textures[i].c_str());
3463         QString filename = fi.absoluteFilePath();
3464         bool res = img.load(filename);
3465         sometextfailed = sometextfailed || !res;
3466         if(!res)
3467         {
3468             res = img.load(filename);
3469             if(!res)
3470             {
3471                 QString errmsg = QString("Failure of loading texture %1").arg(fi.fileName());
3472                 meshDoc()->Log.Log(GLLogStream::WARNING,qUtf8Printable(errmsg));
3473                 unexistingtext += "<font color=red>" + filename + "</font><br>";
3474             }
3475         }
3476 
3477 /*PLEASE EXPLAIN ME!*********************************************************************************************************************************************************************************/
3478         //if(!res && filename.endsWith("dds",Qt::CaseInsensitive))
3479         //{
3480         //    qDebug("DDS binding!");
3481         //    int newTexId = shared->bindTexture(filename);
3482         //    shared->txtcont.push_back(newTexId);
3483         //}
3484 /*PLEASE EXPLAIN ME!*********************************************************************************************************************************************************************************/
3485 
3486         if (!res)
3487             res = img.load(":/images/dummy.png");
3488         GLuint textid = shared->allocateTexturePerMesh(meshid,img,singleMaxTextureSizeMpx);
3489 
3490         if (sometextfailed)
3491             QMessageBox::warning(this,"Texture file has not been correctly loaded",unexistingtext);
3492 
3493         for(int tt = 0;tt < mvc->viewerCounter();++tt)
3494         {
3495             GLArea* ar = mvc->getViewer(tt);
3496             if (ar != NULL)
3497                 ar->setupTextureEnv(textid);
3498         }
3499     }
3500     if (sometextfailed)
3501         QMessageBox::warning(this,"Texture file has not been correctly loaded",unexistingtext);
3502 }
3503 
updateProgressBar(const int pos,const QString & text)3504 void MainWindow::updateProgressBar( const int pos,const QString& text )
3505 {
3506     this->QCallBack(pos,qUtf8Printable(text));
3507 }
3508 
3509 //void MainWindow::evaluateExpression(const Expression& exp,Value** res )
3510 //{
3511 //	try
3512 //	{
3513 //		PM.env.pushContext();
3514 //		*res = exp.eval(&PM.env);
3515 //		PM.env.popContext();
3516 //	}
3517 //	catch (ParsingException& e)
3518 //	{
3519 //		GLA()->Logf(GLLogStream::WARNING,e.what());
3520 //	}
3521 //}
updateDocumentScriptBindings()3522 void MainWindow::updateDocumentScriptBindings()
3523 {
3524     if(currentViewContainer())
3525     {
3526         plugingui->setDocument(meshDoc());
3527         //PM.updateDocumentScriptBindings(*meshDoc());
3528     }
3529 }
3530 
loadAndInsertXMLPlugin(const QString & xmlpath,const QString & scriptname)3531 void MainWindow::loadAndInsertXMLPlugin(const QString& xmlpath,const QString& scriptname)
3532 {
3533     if ((xmldialog != NULL) && (xmldialog->isVisible()))
3534         this->xmldialog->close();
3535     PM.deleteXMLPlugin(scriptname);
3536     try
3537     {
3538         PM.loadXMLPlugin(xmlpath);
3539     }
3540     catch (MeshLabXMLParsingException& e)
3541     {
3542         qDebug() << e.what();
3543     }
3544     fillFilterMenu();
3545     initSearchEngine();
3546 }
3547 
sendHistory()3548 void MainWindow::sendHistory()
3549 {
3550     plugingui->getHistory(meshDoc()->xmlhistory);
3551 }
3552 
3553 //WARNING!!!! Probably it's useless
3554 //void MainWindow::updateRenderMode( )
3555 //{
3556 //    if ((GLA() == NULL) || (meshDoc() == NULL))
3557 //        return;
3558 //    QMap<int,RenderMode>& rmode = GLA()->rendermodemap;
3559 //
3560 //    RenderModeAction* act = qobject_cast<RenderModeAction*>(sender());
3561 //    RenderModeTexturePerWedgeAction* textact = qobject_cast<RenderModeTexturePerWedgeAction*>(act);
3562 //
3563 //    //act->data contains the meshid to which the action is referred.
3564 //    //if the meshid is -1 the action is intended to be per-document and not per mesh
3565 //    bool isvalidid = true;
3566 //    int meshid = act->data().toInt(&isvalidid);
3567 //    if (!isvalidid)
3568 //        throw MeshLabException("A RenderModeAction contains a non-integer data id.");
3569 //
3570 //    if (meshid == -1)
3571 //    {
3572 //        for(QMap<int,RenderMode>::iterator it =	rmode.begin();it != rmode.end();++it)
3573 //        {
3574 //            RenderMode& rm = it.value();
3575 //            RenderMode old = rm;
3576 //
3577 //            act->updateRenderMode(rm);
3578 //            //horrible trick caused by MeshLab GUI. In MeshLab exists just a button turning on/off the texture visualization.
3579 //            //Unfortunately the RenderMode::textureMode member field is not just a boolean value but and enum one.
3580 //            //The enum-value depends from the enabled attributes of input mesh.
3581 //            if (textact != NULL)
3582 //                setBestTextureModePerMesh(textact,it.key(),rm);
3583 //
3584 //            MeshModel* mmod = meshDoc()->getMesh(it.key());
3585 //            if (mmod != NULL)
3586 //            {
3587 //                throw MeshLabException("A RenderModeAction referred to a non-existent mesh.");
3588 //                act->updateRenderMode(rm);
3589 //                if (textact != NULL)
3590 //                    setBestTextureModePerMesh(textact,it.key(),rm);
3591 //
3592 ////                deallocateReqAttsConsideringAllOtherGLArea(GLA(),it.key(),old,rm;)
3593 //
3594 //                GLA()->setupRequestedAttributesPerMesh(it.key());
3595 //            }
3596 //            else throw MeshLabException("A RenderModeAction referred to a non-existent mesh.");
3597 //
3598 //			GLA()->setupRequestedAttributesPerMesh(it.key());
3599 //        }
3600 //    }
3601 //    else
3602 //    {
3603 //        QMap<int,RenderMode>::iterator it = rmode.find(meshid);
3604 //        RenderMode& rm = it.value();
3605 //        RenderMode old = rm;
3606 //        if (it == rmode.end())
3607 //            throw MeshLabException("A RenderModeAction contains a non-valid data meshid.");
3608 //        MeshModel* mmod = meshDoc()->getMesh(it.key());
3609 //        if (mmod == NULL)
3610 //            throw MeshLabException("A RenderModeAction referred to a non-existent mesh.");
3611 //        act->updateRenderMode(rm);
3612 //        updateMenus();
3613 //        //horrible trick caused by MeshLab GUI. In MeshLab exists just a button turning on/off the texture visualization.
3614 //        //Unfortunately the RenderMode::textureMode member field is not just a boolean value but and enum one.
3615 //        //The enum-value depends from the enabled attributes of input mesh.
3616 //        if (textact != NULL)
3617 ///*setBestTextureModePerMesh(textact,meshid,rm)*/;
3618 //
3619 ////        deallocateReqAttsConsideringAllOtherGLArea(GLA(),it.key(),old,rm);
3620 //        GLA()->setupRequestedAttributesPerMesh(it.key());
3621 //    }
3622 //    GLA()->update();
3623 //}
3624 
3625 //WARNING!!!!!! I suppose it should not be useful anymore, but....
3626 //void MainWindow::setBestTextureModePerMesh(RenderModeAction* textact,const int meshid, RenderMode& rm)
3627 //{
3628 //    MeshModel* mesh = NULL;
3629 //    if ((meshDoc() == NULL) || ((mesh  = meshDoc()->getMesh(meshid)) == NULL))
3630 //    {
3631 //        bool clicked = (textact != NULL) && (textact->isChecked());
3632 //        MLPoliciesStandAloneFunctions::computeRequestedRenderingAttributesCompatibleWithMesh(mesh,rm.pmmask,rm.atts,rm.pmmask,rm.atts);
3633 //        rm.atts[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE] = rm.atts[MLRenderingData::ATT_NAMES::ATT_VERTTEXTURE] && clicked;
3634 //        rm.atts[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE] = rm.atts[MLRenderingData::ATT_NAMES::ATT_WEDGETEXTURE] && clicked;
3635 //    }
3636 //}
3637 
3638 
showEvent(QShowEvent * event)3639 void MainWindow::showEvent(QShowEvent * event)
3640 {
3641 	QWidget::showEvent(event);
3642 	QSettings settings;
3643     QSettings::setDefaultFormat(QSettings::NativeFormat);
3644 	const QString versioncheckeddatestring("lastTimeMeshLabVersionCheckedOnStart");
3645 	QDate today = QDate::currentDate();
3646     QString todayStr = today.toString();
3647 	if (settings.contains(versioncheckeddatestring))
3648 	{
3649 		QDate lasttimechecked = QDate::fromString(settings.value(versioncheckeddatestring).toString());
3650 		if (lasttimechecked < today)
3651 		{
3652 			checkForUpdates(false);
3653 			settings.setValue(versioncheckeddatestring, todayStr);
3654 		}
3655 	}
3656 	else
3657 	{
3658 		checkForUpdates(false);
3659 		settings.setValue(versioncheckeddatestring, todayStr);
3660 	}
3661 	sendUsAMail();
3662 }
3663 
meshAdded(int mid)3664 void MainWindow::meshAdded(int mid)
3665 {
3666     MultiViewer_Container* mvc = currentViewContainer();
3667     if (mvc != NULL)
3668     {
3669         MLSceneGLSharedDataContext* shared = mvc->sharedDataContext();
3670         if (shared != NULL)
3671         {
3672             shared->meshInserted(mid);
3673             QList<QGLContext*> contlist;
3674             for(int glarid = 0;glarid < mvc->viewerCounter();++glarid)
3675             {
3676                 GLArea* ar = mvc->getViewer(glarid);
3677                 if (ar != NULL)
3678                     contlist.push_back(ar->context());
3679             }
3680             MLRenderingData defdt;
3681             if (meshDoc() != NULL)
3682             {
3683                 MeshModel* mm = meshDoc()->getMesh(mid);
3684                 if (mm != NULL)
3685                 {
3686                     for(int glarid = 0;glarid < mvc->viewerCounter();++glarid)
3687                     {
3688                         GLArea* ar = mvc->getViewer(glarid);
3689                         if (ar != NULL)
3690                             shared->setRenderingDataPerMeshView(mid,ar->context(),defdt);
3691                     }
3692                     shared->manageBuffers(mid);
3693                 }
3694 				//layerDialog->setVisible(meshDoc()->meshList.size() > 0);
3695 				updateLayerDialog();
3696             }
3697         }
3698 
3699     }
3700 }
3701 
meshRemoved(int mid)3702 void MainWindow::meshRemoved(int mid)
3703 {
3704     MultiViewer_Container* mvc = currentViewContainer();
3705     if (mvc != NULL)
3706     {
3707         MLSceneGLSharedDataContext* shared = mvc->sharedDataContext();
3708         if (shared != NULL)
3709             shared->meshRemoved(mid);
3710     }
3711     updateLayerDialog();
3712 }
3713 
getRenderingData(int mid,MLRenderingData & dt) const3714 void MainWindow::getRenderingData( int mid,MLRenderingData& dt) const
3715 {
3716 	if (mid == -1)
3717 	{
3718 		//if (GLA() != NULL)
3719 			//GLA()->getPerDocGlobalRenderingData(dt);
3720 	}
3721 	else
3722 	{
3723 		MultiViewer_Container* cont = currentViewContainer();
3724 		if (cont != NULL)
3725 		{
3726 			MLSceneGLSharedDataContext* share = cont->sharedDataContext();
3727 			if ((share != NULL) && (GLA() != NULL))
3728 				share->getRenderInfoPerMeshView(mid, GLA()->context(), dt);
3729 		}
3730 	}
3731 }
3732 
setRenderingData(int mid,const MLRenderingData & dt)3733 void MainWindow::setRenderingData(int mid,const MLRenderingData& dt)
3734 {
3735 	if (mid == -1)
3736 	{
3737 		/*if (GLA() != NULL)
3738 			GLA()->setPerDocGlobalRenderingData(dt);*/
3739 	}
3740 	else
3741 	{
3742 		MultiViewer_Container* cont = currentViewContainer();
3743 		if (cont != NULL)
3744 		{
3745 			MLSceneGLSharedDataContext* share = cont->sharedDataContext();
3746 			if ((share != NULL) && (GLA() != NULL))
3747 			{
3748 				share->setRenderingDataPerMeshView(mid, GLA()->context(), dt);
3749 				share->manageBuffers(mid);
3750 				//addRenderingSystemLogInfo(mid);
3751 				if (globrendtoolbar != NULL)
3752 				{
3753 					MLSceneGLSharedDataContext::PerMeshRenderingDataMap mp;
3754 					share->getRenderInfoPerMeshView(GLA()->context(), mp);
3755 					globrendtoolbar->statusConsistencyCheck(mp);
3756 				}
3757 			}
3758 		}
3759 	}
3760 }
3761 
3762 
addRenderingSystemLogInfo(unsigned mmid)3763 void MainWindow::addRenderingSystemLogInfo(unsigned mmid)
3764 {
3765     MultiViewer_Container* cont = currentViewContainer();
3766     if (cont != NULL)
3767     {
3768         MLRenderingData::DebugInfo deb;
3769         MLSceneGLSharedDataContext* share = cont->sharedDataContext();
3770         if ((share != NULL) && (GLA() != NULL))
3771         {
3772             share->getLog(mmid,deb);
3773             MeshModel* mm = meshDoc()->getMesh(mmid);
3774             if (mm != NULL)
3775             {
3776                 QString data = QString(deb._currentlyallocated.c_str()) + "\n" + QString(deb._tobedeallocated.c_str()) + "\n" + QString(deb._tobeallocated.c_str()) + "\n" + QString(deb._tobeupdated.c_str()) + "\n";
3777                 for(std::vector<std::string>::iterator it = deb._perviewdata.begin();it != deb._perviewdata.end();++it)
3778                     data += QString((*it).c_str()) + "<br>";
3779                 meshDoc()->Log.Log(GLLogStream::SYSTEM, data);
3780             }
3781         }
3782     }
3783 }
3784 
updateRenderingDataAccordingToActionsCommonCode(int meshid,const QList<MLRenderingAction * > & acts)3785 void MainWindow::updateRenderingDataAccordingToActionsCommonCode(int meshid, const QList<MLRenderingAction*>& acts)
3786 {
3787 	if (meshDoc() == NULL)
3788 		return;
3789 
3790 	MLRenderingData olddt;
3791 	getRenderingData(meshid, olddt);
3792 	MLRenderingData dt(olddt);
3793 	foreach(MLRenderingAction* act, acts)
3794 	{
3795 		if (act != NULL)
3796 			act->updateRenderingData(dt);
3797 	}
3798 	MeshModel* mm = meshDoc()->getMesh(meshid);
3799 	if (mm != NULL)
3800 	{
3801 		MLPoliciesStandAloneFunctions::setBestWireModality(mm, dt);
3802 		MLPoliciesStandAloneFunctions::computeRequestedRenderingDataCompatibleWithMeshSameGLOpts(mm, dt, dt);
3803 	}
3804 	setRenderingData(meshid, dt);
3805 
3806 	/*if (meshid == -1)
3807 	{
3808 		foreach(MeshModel* mm, meshDoc()->meshList)
3809 		{
3810 			if (mm != NULL)
3811 			{
3812 				MLDefaultMeshDecorators dec(this);
3813 				dec.updateMeshDecorationData(*mm, olddt, dt);
3814 			}
3815 		}
3816 	}
3817 	else
3818 	{*/
3819 		if (mm != NULL)
3820 		{
3821 			MLDefaultMeshDecorators dec(this);
3822 			dec.updateMeshDecorationData(*mm, olddt, dt);
3823 		}
3824 	/*}*/
3825 
3826 }
3827 
3828 
updateRenderingDataAccordingToActions(int meshid,const QList<MLRenderingAction * > & acts)3829 void MainWindow::updateRenderingDataAccordingToActions(int meshid,const QList<MLRenderingAction*>& acts)
3830 {
3831 	updateRenderingDataAccordingToActionsCommonCode(meshid, acts);
3832 	if (GLA() != NULL)
3833 		GLA()->update();
3834 }
3835 
updateRenderingDataAccordingToActionsToAllVisibleLayers(const QList<MLRenderingAction * > & acts)3836 void MainWindow::updateRenderingDataAccordingToActionsToAllVisibleLayers(const QList<MLRenderingAction*>& acts)
3837 {
3838 	if (meshDoc() == NULL)
3839 		return;
3840 	for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii)
3841 	{
3842 		MeshModel* mm = meshDoc()->meshList[ii];
3843 		if ((mm != NULL) && (mm->isVisible()))
3844 		{
3845 			updateRenderingDataAccordingToActionsCommonCode(mm->id(), acts);
3846 		}
3847 	}
3848 	//updateLayerDialog();
3849 	if (GLA() != NULL)
3850 		GLA()->update();
3851 }
3852 
updateRenderingDataAccordingToActions(int,MLRenderingAction * act,QList<MLRenderingAction * > & acts)3853 void MainWindow::updateRenderingDataAccordingToActions(int /*meshid*/, MLRenderingAction* act, QList<MLRenderingAction*>& acts)
3854 {
3855 	if ((meshDoc() == NULL) || (act == NULL))
3856 		return;
3857 
3858 	QList<MLRenderingAction*> tmpacts;
3859 	for (int ii = 0; ii < acts.size(); ++ii)
3860 	{
3861 		if (acts[ii] != NULL)
3862 		{
3863 			MLRenderingAction* sisteract = NULL;
3864 			acts[ii]->createSisterAction(sisteract, NULL);
3865 			sisteract->setChecked(acts[ii] == act);
3866 			tmpacts.push_back(sisteract);
3867 		}
3868 	}
3869 
3870 	for (int hh = 0; hh < meshDoc()->meshList.size(); ++hh)
3871 	{
3872 		if (meshDoc()->meshList[hh] != NULL)
3873 			updateRenderingDataAccordingToActionsCommonCode(meshDoc()->meshList[hh]->id(), tmpacts);
3874 	}
3875 
3876 	for (int ii = 0; ii < tmpacts.size(); ++ii)
3877 		delete tmpacts[ii];
3878 	tmpacts.clear();
3879 
3880 	if (GLA() != NULL)
3881 		GLA()->update();
3882 
3883 	updateLayerDialog();
3884 }
3885 
3886 
updateRenderingDataAccordingToActionCommonCode(int meshid,MLRenderingAction * act)3887 void MainWindow::updateRenderingDataAccordingToActionCommonCode(int meshid, MLRenderingAction* act)
3888 {
3889 	if ((meshDoc() == NULL) || (act == NULL))
3890 		return;
3891 
3892 	if (meshid != -1)
3893 	{
3894 		MLRenderingData olddt;
3895 		getRenderingData(meshid, olddt);
3896 		MLRenderingData dt(olddt);
3897 		act->updateRenderingData(dt);
3898 		MeshModel* mm = meshDoc()->getMesh(meshid);
3899 		if (mm != NULL)
3900 		{
3901 			MLPoliciesStandAloneFunctions::setBestWireModality(mm, dt);
3902 			MLPoliciesStandAloneFunctions::computeRequestedRenderingDataCompatibleWithMeshSameGLOpts(mm, dt, dt);
3903 		}
3904 		setRenderingData(meshid, dt);
3905 		if (mm != NULL)
3906 		{
3907 			MLDefaultMeshDecorators dec(this);
3908 			dec.updateMeshDecorationData(*mm, olddt, dt);
3909 		}
3910 	}
3911 }
3912 
updateRenderingDataAccordingToAction(int meshid,MLRenderingAction * act)3913 void MainWindow::updateRenderingDataAccordingToAction( int meshid,MLRenderingAction* act)
3914 {
3915 	updateRenderingDataAccordingToActionCommonCode(meshid, act);
3916 	if (GLA() != NULL)
3917 		GLA()->update();
3918 }
3919 
updateRenderingDataAccordingToActionToAllVisibleLayers(MLRenderingAction * act)3920 void MainWindow::updateRenderingDataAccordingToActionToAllVisibleLayers(MLRenderingAction* act)
3921 {
3922 	if (meshDoc() == NULL)
3923 		return;
3924 
3925 	for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii)
3926 	{
3927 		MeshModel* mm = meshDoc()->meshList[ii];
3928 		if ((mm != NULL) && (mm->isVisible()))
3929 		{
3930 			updateRenderingDataAccordingToActionCommonCode(mm->id(), act);
3931 		}
3932 	}
3933 	updateLayerDialog();
3934 	if (GLA() != NULL)
3935 		GLA()->update();
3936 }
3937 
updateRenderingDataAccordingToActions(QList<MLRenderingGlobalAction * > actlist)3938 void  MainWindow::updateRenderingDataAccordingToActions(QList<MLRenderingGlobalAction*> actlist)
3939 {
3940 	if (meshDoc() == NULL)
3941 		return;
3942 
3943 	for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii)
3944 	{
3945 		MeshModel* mm = meshDoc()->meshList[ii];
3946 		if (mm != NULL)
3947 		{
3948 			foreach(MLRenderingGlobalAction* act, actlist)
3949 			{
3950 				foreach(MLRenderingAction* ract, act->mainActions())
3951 					updateRenderingDataAccordingToActionCommonCode(mm->id(), ract);
3952 
3953 				foreach(MLRenderingAction* ract, act->relatedActions())
3954 					updateRenderingDataAccordingToActionCommonCode(mm->id(), ract);
3955 			}
3956 		}
3957 	}
3958 	updateLayerDialog();
3959 	if (GLA() != NULL)
3960 		GLA()->update();
3961 }
3962 
updateRenderingDataAccordingToAction(int,MLRenderingAction * act,bool check)3963 void MainWindow::updateRenderingDataAccordingToAction(int /*meshid*/, MLRenderingAction* act, bool check)
3964 {
3965 	MLRenderingAction* sisteract = NULL;
3966 	act->createSisterAction(sisteract, NULL);
3967 	sisteract->setChecked(check);
3968 	foreach(MeshModel* mm, meshDoc()->meshList)
3969 	{
3970 		if (mm != NULL)
3971 			updateRenderingDataAccordingToActionCommonCode(mm->id(), sisteract);
3972 	}
3973 	delete sisteract;
3974 	if (GLA() != NULL)
3975 		GLA()->update();
3976 	updateLayerDialog();
3977 }
3978 
addRenderingDataIfNewlyGeneratedMesh(int meshid)3979 bool MainWindow::addRenderingDataIfNewlyGeneratedMesh(int meshid)
3980 {
3981 	MultiViewer_Container* mvc = currentViewContainer();
3982 	if (mvc == NULL)
3983 		return false;
3984 	MLSceneGLSharedDataContext* shared = mvc->sharedDataContext();
3985 	if (shared != NULL)
3986 	{
3987 		MeshModel* mm = meshDoc()->getMesh(meshid);
3988 		if ((meshDoc()->meshDocStateData().find(meshid) == meshDoc()->meshDocStateData().end()) && (mm != NULL))
3989 		{
3990 			MLRenderingData dttoberendered;
3991 			MLPoliciesStandAloneFunctions::suggestedDefaultPerViewRenderingData(mm, dttoberendered,mwsettings.minpolygonpersmoothrendering);
3992 			foreach(GLArea* gla, mvc->viewerList)
3993 			{
3994 				if (gla != NULL)
3995 					shared->setRenderingDataPerMeshView(meshid, gla->context(), dttoberendered);
3996 			}
3997 			shared->manageBuffers(meshid);
3998 			return true;
3999 		}
4000 	}
4001 	return false;
4002 }
4003 
viewsRequiringRenderingActions(int meshid,MLRenderingAction * act)4004 unsigned int MainWindow::viewsRequiringRenderingActions(int meshid, MLRenderingAction* act)
4005 {
4006 	unsigned int res = 0;
4007 	MultiViewer_Container* cont = currentViewContainer();
4008 	if (cont != NULL)
4009 	{
4010 		MLSceneGLSharedDataContext* share = cont->sharedDataContext();
4011 		if (share != NULL)
4012 		{
4013 			foreach(GLArea* area,cont->viewerList)
4014 			{
4015 				MLRenderingData dt;
4016 				share->getRenderInfoPerMeshView(meshid, area->context(), dt);
4017 				if (act->isRenderingDataEnabled(dt))
4018 					++res;
4019 			}
4020 		}
4021 	}
4022 	return res;
4023 }
4024 
updateLog()4025 void MainWindow::updateLog()
4026 {
4027 	GLLogStream* senderlog = qobject_cast<GLLogStream*>(sender());
4028 	if ((senderlog != NULL) && (layerDialog != NULL))
4029 		layerDialog->updateLog(*senderlog);
4030 }
4031 
switchCurrentContainer(QMdiSubWindow * subwin)4032 void MainWindow::switchCurrentContainer(QMdiSubWindow * subwin)
4033 {
4034 	if (subwin == NULL)
4035 	{
4036 		if (globrendtoolbar != NULL)
4037 			globrendtoolbar->reset();
4038 		return;
4039 	}
4040 	if (mdiarea->currentSubWindow() != 0)
4041 	{
4042 		MultiViewer_Container* split = qobject_cast<MultiViewer_Container*>(mdiarea->currentSubWindow()->widget());
4043 		if (split != NULL)
4044 			_currviewcontainer = split;
4045 	}
4046 	if (_currviewcontainer != NULL)
4047 	{
4048 		updateLayerDialog();
4049 		updateMenus();
4050 		updateStdDialog();
4051 		updateXMLStdDialog();
4052 		updateDocumentScriptBindings();
4053 	}
4054 }
4055 
closeCurrentDocument()4056 void MainWindow::closeCurrentDocument()
4057 {
4058 	_currviewcontainer = NULL;
4059 	layerDialog->setVisible(false);
4060 	if (mdiarea != NULL)
4061 		mdiarea->closeActiveSubWindow();
4062 	updateMenus();
4063 }
4064