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, ¤tGlobalParams);
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 ¶meterSet = 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 ¶ms, 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, ¤tGlobalParams);
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