diff --git a/sample/furniture.3ds b/sample/furniture.3ds new file mode 100644 index 000000000..ea39757e0 Binary files /dev/null and b/sample/furniture.3ds differ diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b8251cdb3..b1f377488 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -42,22 +42,6 @@ else() endif() set(HEADERS - globals.h - plugins/containers/generic_container_iterator.h - plugins/containers/decorate_plugin_container.h - plugins/containers/edit_plugin_container.h - plugins/containers/filter_plugin_container.h - plugins/containers/io_plugin_container.h - plugins/containers/render_plugin_container.h - plugins/interfaces/meshlab_plugin.h - plugins/interfaces/meshlab_plugin_logger.h - plugins/interfaces/decorate_plugin.h - plugins/interfaces/edit_plugin.h - plugins/interfaces/filter_plugin.h - plugins/interfaces/io_plugin.h - plugins/interfaces/render_plugin.h - plugins/meshlab_plugin_type.h - plugins/plugin_manager.h ml_document/helpers/mesh_document_state_data.h ml_document/helpers/mesh_model_state_data.h ml_document/base_types.h @@ -73,11 +57,28 @@ set(HEADERS parameters/rich_parameter.h parameters/rich_parameter_list.h parameters/value.h + plugins/containers/generic_container_iterator.h + plugins/containers/decorate_plugin_container.h + plugins/containers/edit_plugin_container.h + plugins/containers/filter_plugin_container.h + plugins/containers/io_plugin_container.h + plugins/containers/render_plugin_container.h + plugins/interfaces/meshlab_plugin.h + plugins/interfaces/meshlab_plugin_logger.h + plugins/interfaces/decorate_plugin.h + plugins/interfaces/edit_plugin.h + plugins/interfaces/filter_plugin.h + plugins/interfaces/io_plugin.h + plugins/interfaces/render_plugin.h + plugins/meshlab_plugin_type.h + plugins/plugin_manager.h python/function.h python/function_parameter.h python/function_set.h python/python_utils.h utilities/file_format.h + utilities/load_save.h + globals.h GLExtensionsManager.h GLLogStream.h filterscript.h @@ -91,18 +92,6 @@ set(HEADERS searcher.h) set(SOURCES - globals.cpp - plugins/containers/decorate_plugin_container.cpp - plugins/containers/edit_plugin_container.cpp - plugins/containers/filter_plugin_container.cpp - plugins/containers/io_plugin_container.cpp - plugins/containers/render_plugin_container.cpp - plugins/interfaces/meshlab_plugin_logger.cpp - plugins/interfaces/decorate_plugin.cpp - plugins/interfaces/filter_plugin.cpp - plugins/interfaces/io_plugin.cpp - plugins/meshlab_plugin_type.cpp - plugins/plugin_manager.cpp ml_document/helpers/mesh_document_state_data.cpp ml_document/cmesh.cpp ml_document/mesh_document.cpp @@ -116,10 +105,23 @@ set(SOURCES parameters/rich_parameter.cpp parameters/rich_parameter_list.cpp parameters/value.cpp + plugins/containers/decorate_plugin_container.cpp + plugins/containers/edit_plugin_container.cpp + plugins/containers/filter_plugin_container.cpp + plugins/containers/io_plugin_container.cpp + plugins/containers/render_plugin_container.cpp + plugins/interfaces/meshlab_plugin_logger.cpp + plugins/interfaces/decorate_plugin.cpp + plugins/interfaces/filter_plugin.cpp + plugins/interfaces/io_plugin.cpp + plugins/meshlab_plugin_type.cpp + plugins/plugin_manager.cpp python/function.cpp python/function_parameter.cpp python/function_set.cpp python/python_utils.cpp + utilities/load_save.cpp + globals.cpp GLExtensionsManager.cpp GLLogStream.cpp filterscript.cpp diff --git a/src/common/common.pro b/src/common/common.pro index 5f57e013d..2a8346c3a 100644 --- a/src/common/common.pro +++ b/src/common/common.pro @@ -71,6 +71,7 @@ HEADERS += \ python/function_set.h \ python/python_utils.h \ utilities/file_format.h \ + utilities/load_save.h \ GLExtensionsManager.h \ filterscript.h \ GLLogStream.h \ @@ -111,6 +112,7 @@ SOURCES += \ python/function_parameter.cpp \ python/function_set.cpp \ python/python_utils.cpp \ + utilities/load_save.cpp \ GLExtensionsManager.cpp \ filterscript.cpp \ GLLogStream.cpp \ diff --git a/src/common/ml_document/mesh_document.cpp b/src/common/ml_document/mesh_document.cpp index 6714242d2..a923b49b9 100644 --- a/src/common/ml_document/mesh_document.cpp +++ b/src/common/ml_document/mesh_document.cpp @@ -338,6 +338,27 @@ MeshModel * MeshDocument::addOrGetMesh(QString fullPath, const QString& label, b return addNewMesh(std::move(fullPath),label,setAsCurrent); } +/** + * Returns the ordered list of the meshes loaded from the same + * file in which has been loaded the model mm. + */ +std::list MeshDocument::getMeshesLoadedFromSameFile(MeshModel* mm) +{ + std::list ml; + if (mm->idInFile() == -1){ + ml.push_back(mm); + } + else { + if (!mm->fullName().isEmpty()){ + for (MeshModel* m : meshList){ + if (m->fullName() == mm->fullName()) + ml.push_back(m); + } + } + } + return ml; +} + bool MeshDocument::delMesh(MeshModel *mmToDel) { if(!meshList.removeOne(mmToDel)) diff --git a/src/common/ml_document/mesh_document.h b/src/common/ml_document/mesh_document.h index 3775bb758..f27511009 100644 --- a/src/common/ml_document/mesh_document.h +++ b/src/common/ml_document/mesh_document.h @@ -90,7 +90,7 @@ public: MeshModel* addNewMesh(const CMeshO& mesh, QString Label, bool setAsCurrent=true); MeshModel *addNewMesh(QString fullPath, QString Label, bool setAsCurrent=true); MeshModel *addOrGetMesh(QString fullPath, const QString& Label, bool setAsCurrent=true); - + std::list getMeshesLoadedFromSameFile(MeshModel* mm); ///remove the mesh from the list and delete it from memory bool delMesh(MeshModel *mmToDel); diff --git a/src/common/plugins/interfaces/io_plugin.cpp b/src/common/plugins/interfaces/io_plugin.cpp index 66584a40d..6782b0baf 100644 --- a/src/common/plugins/interfaces/io_plugin.cpp +++ b/src/common/plugins/interfaces/io_plugin.cpp @@ -39,16 +39,18 @@ void IOPlugin::open( void IOPlugin::reportWarning(const QString& warningMessage) const { - MeshLabPluginLogger::log(GLLogStream::WARNING, warningMessage.toStdString()); - warnString += "\n" + warningMessage; + if (!warningMessage.isEmpty()){ + MeshLabPluginLogger::log(GLLogStream::WARNING, warningMessage.toStdString()); + warnString += "\n" + warningMessage; + } } -void IOPlugin::wrongOpenFormat(const QString& format) +void IOPlugin::wrongOpenFormat(const QString& format) const { throw MLException("Internal error: unknown open format " + format + " to " + pluginName() + " plugin."); } -void IOPlugin::wrongSaveFormat(const QString& format) +void IOPlugin::wrongSaveFormat(const QString& format) const { throw MLException("Internal error: unknown save format " + format + " to " + pluginName() + " plugin."); } diff --git a/src/common/plugins/interfaces/io_plugin.h b/src/common/plugins/interfaces/io_plugin.h index cf406c937..974582ccf 100644 --- a/src/common/plugins/interfaces/io_plugin.h +++ b/src/common/plugins/interfaces/io_plugin.h @@ -276,14 +276,14 @@ public: * (initPreOpenParameters, load...) whenever you receive as parameter a * format that is not supported by your plugin */ - void wrongOpenFormat(const QString& format); + void wrongOpenFormat(const QString& format) const; /** * @brief call this function in any of the export functions * (exportMaskCapability, save...) whenever you receive as parameter a * format that is not supported by your plugin */ - void wrongSaveFormat(const QString& format); + void wrongSaveFormat(const QString& format) const; /** * @brief The warningMessageString is invoked by the framework after the diff --git a/src/common/utilities/load_save.cpp b/src/common/utilities/load_save.cpp new file mode 100644 index 000000000..ef238215b --- /dev/null +++ b/src/common/utilities/load_save.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2020 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#include "load_save.h" + +#include +#include + +#include "../globals.h" +#include "../plugins/plugin_manager.h" + +namespace meshlab { + +void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterList& prePar, const std::list& meshList, std::list& maskList, vcg::CallBackPos *cb) +{ + QFileInfo fi(fileName); + QString extension = fi.suffix(); + + // the original directory path before we switch it + QString origDir = QDir::current().path(); + + // this change of dir is needed for subsequent textures/materials loading + QDir::setCurrent(fi.absoluteDir().absolutePath()); + + // Adjust the file name after changing the directory + QString fileNameSansDir = fi.fileName(); + + try { + ioPlugin->open(extension, fileNameSansDir, meshList ,maskList, prePar, cb); + } + catch(const MLException& e) { + QDir::setCurrent(origDir); // undo the change of directory before leaving + throw e; + } + + auto itmesh = meshList.begin(); + auto itmask = maskList.begin(); + for (unsigned int i = 0; i < meshList.size(); ++i){ + MeshModel* mm = *itmesh; + int mask = *itmask; + + // In case of polygonal meshes the normal should be updated accordingly + if( mask & vcg::tri::io::Mask::IOM_BITPOLYGONAL) { + mm->updateDataMask(MeshModel::MM_POLYGONAL); // just to be sure. Hopefully it should be done in the plugin... + int degNum = vcg::tri::Clean::RemoveDegenerateFace(mm->cm); + if(degNum) + ioPlugin->log("Warning model contains " + std::to_string(degNum) +" degenerate faces. Removed them."); + mm->updateDataMask(MeshModel::MM_FACEFACETOPO); + vcg::tri::UpdateNormal::PerBitQuadFaceNormalized(mm->cm); + vcg::tri::UpdateNormal::PerVertexFromCurrentFaceNormal(mm->cm); + } // standard case + else { + vcg::tri::UpdateNormal::PerFaceNormalized(mm->cm); + if(!( mask & vcg::tri::io::Mask::IOM_VERTNORMAL) ) + vcg::tri::UpdateNormal::PerVertexAngleWeighted(mm->cm); + } + + vcg::tri::UpdateBounding::Box(mm->cm); + if(mm->cm.fn==0 && mm->cm.en==0) { + if(mask & vcg::tri::io::Mask::IOM_VERTNORMAL) + mm->updateDataMask(MeshModel::MM_VERTNORMAL); + } + + if(mm->cm.fn==0 && mm->cm.en>0) { + if (mask & vcg::tri::io::Mask::IOM_VERTNORMAL) + mm->updateDataMask(MeshModel::MM_VERTNORMAL); + } + + //updateMenus(); + int delVertNum = vcg::tri::Clean::RemoveDegenerateVertex(mm->cm); + int delFaceNum = vcg::tri::Clean::RemoveDegenerateFace(mm->cm); + vcg::tri::Allocator::CompactEveryVector(mm->cm); + if(delVertNum>0 || delFaceNum>0 ) + ioPlugin->reportWarning(QString("Warning mesh contains %1 vertices with NAN coords and %2 degenerated faces.\nCorrected.").arg(delVertNum).arg(delFaceNum)); + + //computeRenderingDataOnLoading(mm,isareload, rendOpt); + ++itmesh; + ++itmask; + } + QDir::setCurrent(origDir); // undo the change of directory before leaving +} + + +void loadMeshWithStandardParameters(const QString& filename, MeshDocument& md, vcg::CallBackPos *cb) +{ + QFileInfo fi(filename); + QString extension = fi.suffix(); + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin *ioPlugin = pm.inputMeshPlugin(extension); + + if (ioPlugin == nullptr) + throw MLException( + "Mesh " + filename + " cannot be opened. Your MeshLab version " + "has not plugin to read " + extension + " file format"); + + + RichParameterList prePar; + ioPlugin->initPreOpenParameter(extension, prePar); + prePar.join(meshlab::defaultGlobalParameterList()); + + + unsigned int nMeshes = ioPlugin->numberMeshesContainedInFile(extension, filename); + std::list meshList; + for (unsigned int i = 0; i < nMeshes; i++) { + MeshModel *mm = md.addNewMesh(filename, fi.fileName()); + if (nMeshes != 1) { + // if the file contains more than one mesh, this id will be + // != -1 + mm->setIdInFile(i); + } + meshList.push_back(mm); + } + + std::list masks; + + try{ + loadMesh(fi.fileName(), ioPlugin, prePar, meshList, masks, cb); + RichParameterList par; + ioPlugin->initOpenParameter(extension, meshList, par); + ioPlugin->applyOpenParameter(extension, meshList, par); + } + catch(const MLException& e){ + for (MeshModel* mm : meshList) + md.delMesh(mm); + throw e; + } +} + + +void reloadMesh( + const QString& filename, + const std::list& meshList, + vcg::CallBackPos* cb) +{ + + QFileInfo fi(filename); + QString extension = fi.suffix(); + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin *ioPlugin = pm.inputMeshPlugin(extension); + + if (ioPlugin == nullptr) { + throw MLException( + "Mesh " + filename + " cannot be opened. Your MeshLab " + "version has not plugin to read " + extension + + " file format"); + } + + RichParameterList prePar; + ioPlugin->initPreOpenParameter(extension, prePar); + prePar.join(meshlab::defaultGlobalParameterList()); + + unsigned int nMeshes = ioPlugin->numberMeshesContainedInFile(extension, filename); + + if (meshList.size() != nMeshes){ + throw MLException( + "Cannot reload " + filename + ": expected number layers is " + "different from the number of meshes contained in th file."); + } + + std::list masks; + for (MeshModel* mm : meshList){ + mm->Clear(); + } + loadMesh(filename, ioPlugin, prePar, meshList, masks, cb); + RichParameterList par; + ioPlugin->initOpenParameter(extension, meshList, par); + ioPlugin->applyOpenParameter(extension, meshList, par); +} + +void loadRaster(const QString& filename, MeshDocument& md, vcg::CallBackPos* cb) +{ + QFileInfo fi(filename); + QString extension = fi.suffix(); + PluginManager& pm = meshlab::pluginManagerInstance(); + IOPlugin *ioPlugin = pm.inputRasterPlugin(extension); + + if (ioPlugin == nullptr) + throw MLException( + "Raster " + filename + " cannot be opened. Your MeshLab version " + "has not plugin to read " + extension + " file format."); + + RasterModel *rm = md.addNewRaster(); + try { + ioPlugin->openRaster(extension, filename, *rm, cb); + } + catch(const MLException& e){ + md.delRaster(rm); + throw e; + } + +} + +} diff --git a/src/common/utilities/load_save.h b/src/common/utilities/load_save.h new file mode 100644 index 000000000..61e96cebb --- /dev/null +++ b/src/common/utilities/load_save.h @@ -0,0 +1,61 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2020 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef MESHLAB_LOAD_SAVE_H +#define MESHLAB_LOAD_SAVE_H + +#include "../ml_shared_data_context/ml_shared_data_context.h" +#include "../plugins/interfaces/io_plugin.h" + +/** + * Utility functions to load/save meshes using plugins loaded in the plugin + * manager. + */ + +namespace meshlab { + +void loadMesh( + const QString& fileName, + IOPlugin* ioPlugin, + const RichParameterList& prePar, + const std::list& meshList, + std::list& maskList, + vcg::CallBackPos *cb); + +void loadMeshWithStandardParameters( + const QString& filename, + MeshDocument& md, + vcg::CallBackPos *cb); + +void reloadMesh( + const QString& filename, + const std::list& meshList, + vcg::CallBackPos* cb); + +void loadRaster( + const QString& filename, + MeshDocument& md, + vcg::CallBackPos *cb); +} + +#endif // MESHLAB_LOAD_SAVE_H diff --git a/src/meshlab/mainwindow_RunTime.cpp b/src/meshlab/mainwindow_RunTime.cpp index aa0693b3a..5242e8919 100644 --- a/src/meshlab/mainwindow_RunTime.cpp +++ b/src/meshlab/mainwindow_RunTime.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include "rich_parameter_gui/richparameterlistdialog.h" @@ -1739,21 +1740,23 @@ bool MainWindow::openProject(QString fileName) { vector rmv; int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(fileName)); - if(retVal != ALNParser::NoError) - { + if(retVal != ALNParser::NoError) { QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open ALN file"); return false; } - bool openRes=true; - vector::iterator ir; - for(ir=rmv.begin();ir!=rmv.end() && openRes;++ir) - { - QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str(); - meshDoc()->addNewMesh(relativeToProj,relativeToProj); - openRes = loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),ir->transformation); - if(!openRes) - meshDoc()->delMesh(meshDoc()->mm()); + for(const RangeMap& rm : rmv) { + QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + rm.filename.c_str(); + try { + meshlab::loadMeshWithStandardParameters(relativeToProj, *meshDoc(), QCallBack); + meshDoc()->mm()->cm.Tr.Import(rm.transformation); + computeRenderingDataOnLoading(meshDoc()->mm(), false, nullptr); + if (!(meshDoc()->mm()->cm.textures.empty())) + updateTexture(meshDoc()->mm()->id()); + } + catch (const MLException& e){ + QMessageBox::critical(this, "Meshlab Opening Error", e.what()); + } } } @@ -1882,18 +1885,23 @@ bool MainWindow::appendProject(QString fileName) { vector rmv; int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(fileName)); - if(retVal != ALNParser::NoError) - { + if(retVal != ALNParser::NoError) { QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open ALN file"); return false; } - for(vector::iterator ir=rmv.begin();ir!=rmv.end();++ir) - { - QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str(); - meshDoc()->addNewMesh(relativeToProj,relativeToProj); - if(!loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),(*ir).transformation)) - meshDoc()->delMesh(meshDoc()->mm()); + for(const RangeMap& rm : rmv) { + QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + rm.filename.c_str(); + try { + meshlab::loadMeshWithStandardParameters(relativeToProj, *meshDoc(), QCallBack); + meshDoc()->mm()->cm.Tr.Import(rm.transformation); + computeRenderingDataOnLoading(meshDoc()->mm(), false, nullptr); + if (!(meshDoc()->mm()->cm.textures.empty())) + updateTexture(meshDoc()->mm()->id()); + } + catch (const MLException& e){ + QMessageBox::critical(this, "Meshlab Opening Error", e.what()); + } } } @@ -2132,43 +2140,29 @@ bool MainWindow::importRaster(const QString& fileImg) allFileTime.start(); for(const QString& fileName : fileNameList) { - QFileInfo fi(fileName); - QString extension = fi.suffix(); - IOPlugin *pCurrentIOPlugin = PM.inputRasterPlugin(extension); - //pCurrentIOPlugin->setLog(gla->log); - if (pCurrentIOPlugin == NULL) - { - QString errorMsgFormat("Unable to open file:\n\"%1\"\n\nError details: file format " + extension + " not supported."); - QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName)); - return false; - } - QFileInfo info(fileName); - RasterModel *rm = meshDoc()->addNewRaster(); - qb->show(); - QElapsedTimer t; - t.start(); try { - pCurrentIOPlugin->openRaster(extension, fileName, *rm, QCallBack); + QElapsedTimer t; + t.start(); + meshlab::loadRaster(fileName, *meshDoc(), QCallBack); GLA()->Logf(0, "Opened raster %s in %i msec", qUtf8Printable(fileName), t.elapsed()); GLA()->resetTrackBall(); - GLA()->fov = rm->shot.GetFovFromFocal(); - rm->shot = GLA()->shotFromTrackball().first; + GLA()->fov = meshDoc()->rm()->shot.GetFovFromFocal(); + meshDoc()->rm()->shot = GLA()->shotFromTrackball().first; GLA()->resetTrackBall(); // and then we reset the trackball again, to have the standard view if (!layerDialog->isVisible()) layerDialog->setVisible(true); + GLA()->Logf(0,"All files opened in %i msec",allFileTime.elapsed()); } catch(const MLException& e){ QMessageBox::warning( this, tr("Opening Failure"), "While opening: " + fileName + "\n\n" + e.what()); - meshDoc()->delRaster(rm); GLA()->Logf(0, "Warning: Raster %s has not been opened", qUtf8Printable(fileName)); } }// end foreach file of the input list - GLA()->Logf(0,"All files opened in %i msec",allFileTime.elapsed()); - + if (_currviewcontainer != NULL) _currviewcontainer->updateAllDecoratorsForAllViewers(); @@ -2370,28 +2364,22 @@ bool MainWindow::importMeshWithLayerManagement(QString fileName) // Opening files in a transparent form (IO plugins contribution is hidden to user) bool MainWindow::importMesh(QString fileName) { - if (!GLA()) - { + if (!GLA()) { this->newProject(); if(!GLA()) return false; } - - //QStringList suffixList; - // HashTable storing all supported formats together with - // the (1-based) index of first plugin which is able to open it - //QHash allKnownFormats; - //PM.LoadFormats(suffixList, allKnownFormats,PluginManager::IMPORT); QStringList fileNameList; if (fileName.isEmpty()) fileNameList = QFileDialog::getOpenFileNames(this,tr("Import Mesh"), lastUsedDirectory.path(), PM.inputMeshFormatListDialog().join(";;")); else fileNameList.push_back(fileName); - if (fileNameList.isEmpty()) return false; - else - { + if (fileNameList.isEmpty()) { + return false; + } + else { //save path away so we can use it again QString path = fileNameList.first(); path.truncate(path.lastIndexOf("/")); @@ -2400,8 +2388,7 @@ bool MainWindow::importMesh(QString fileName) QElapsedTimer allFileTime; allFileTime.start(); - for(const QString& fileName : fileNameList) - { + for(const QString& fileName : fileNameList) { QFileInfo fi(fileName); if(!fi.exists()) { QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 does not exist."; @@ -2417,13 +2404,13 @@ bool MainWindow::importMesh(QString fileName) QString extension = fi.suffix(); IOPlugin *pCurrentIOPlugin = PM.inputMeshPlugin(extension); - if (pCurrentIOPlugin == nullptr) - { + if (pCurrentIOPlugin == nullptr) { QString errorMsgFormat("Unable to open file:\n\"%1\"\n\nError details: file format " + extension + " not supported."); QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName)); return false; } + pCurrentIOPlugin->setLog(&meshDoc()->Log); RichParameterList prePar; pCurrentIOPlugin->initPreOpenParameter(extension,prePar); if(!prePar.isEmpty()) @@ -2449,14 +2436,22 @@ bool MainWindow::importMesh(QString fileName) meshList.push_back(mm); } qb->show(); - QElapsedTimer t; - t.start(); - Matrix44m mtr; - mtr.SetIdentity(); std::list masks; - bool open = loadMesh(fileName,pCurrentIOPlugin, meshList, masks,&prePar,mtr,false); - if(open) - { + try { + QElapsedTimer t; + t.start(); + meshlab::loadMesh(fileName, pCurrentIOPlugin, prePar, meshList, masks, QCallBack); + saveRecentFileList(fileName); + updateLayerDialog(); + for (MeshModel* mm : meshList) { + computeRenderingDataOnLoading(mm, false, nullptr); + if (! (mm->cm.textures.empty())) + updateTexture(mm->id()); + } + QString warningString = pCurrentIOPlugin->warningMessageString(); + if (!warningString.isEmpty()){ + QMessageBox::warning(this, "Meshlab Opening Warning", warningString); + } GLA()->Logf(0, "Opened mesh %s in %i msec", qUtf8Printable(fileName), t.elapsed()); RichParameterList par; @@ -2470,22 +2465,12 @@ bool MainWindow::importMesh(QString fileName) for (MeshModel* mm : meshList) pCurrentIOPlugin->applyOpenParameter(extension, *mm, par); } - /*MultiViewer_Container* mv = GLA()->mvc(); - if (mv != NULL) - { - for(int glarid = 0;glarid < mv->viewerCounter();++glarid) - { - GLArea* ar = mv->getViewer(glarid); - if (ar != NULL) - MLSceneRenderModeAdapter::setupRequestedAttributesAccordingToRenderMode(mm->id(),*ar); - } - }*/ } - else - { + catch (const MLException& e){ for (MeshModel* mm : meshList) meshDoc()->delMesh(mm); - GLA()->Logf(0, "Warning: Mesh %s has not been opened", qUtf8Printable(fileName)); + GLA()->Logf(0, "Error: File %s has not been loaded", qUtf8Printable(fileName)); + QMessageBox::critical(this, "Meshlab Opening Error", e.what()); } }// end foreach file of the input list GLA()->Logf(0,"All files opened in %i msec",allFileTime.elapsed()); @@ -2566,13 +2551,35 @@ void MainWindow::reloadAllMesh() // Discards changes and reloads current file // save current file name qb->show(); - foreach(MeshModel *mmm,meshDoc()->meshList) - { - QString fileName = mmm->fullName(); - Matrix44m mat; - mat.SetIdentity(); - loadMeshWithStandardParams(fileName,mmm,mat,true); + QElapsedTimer t; + t.start(); + MeshDocument* md = meshDoc(); + for(MeshModel *mmm : md->meshIterator()) { + if (mmm->idInFile() <= 0){ + QString fileName = mmm->fullName(); + if (!fileName.isEmpty()){ + std::list meshList = meshDoc()->getMeshesLoadedFromSameFile(mmm); + std::vector isReload(meshList.size(), true); + unsigned int i = 0; + for (MeshModel* m : meshList) { + if (m->cm.VN() == 0) + isReload[i] = false; + i++; + } + try { + meshlab::reloadMesh(fileName, meshList, QCallBack); + i = 0; + for (MeshModel* m : meshList){ + computeRenderingDataOnLoading(m, i++, nullptr); + } + } + catch (const MLException& e) { + QMessageBox::critical(this, "Reload Error", e.what()); + } + } + } } + GLA()->Log(0, ("All meshes reloaded in " + std::to_string(t.elapsed()) + " msec.").c_str()); qb->reset(); if (_currviewcontainer != NULL) @@ -2589,15 +2596,35 @@ void MainWindow::reload() // Discards changes and reloads current file // save current file name qb->show(); + QString fileName = meshDoc()->mm()->fullName(); - if (fileName.isEmpty()) - { + if (fileName.isEmpty()) { QMessageBox::critical(this, "Reload Error", "Impossible to reload an unsaved mesh model!!"); return; } - Matrix44m mat; - mat.SetIdentity(); - loadMeshWithStandardParams(fileName,meshDoc()->mm(),mat,true); + + std::list meshList = meshDoc()->getMeshesLoadedFromSameFile(meshDoc()->mm()); + std::vector isReload(meshList.size(), true); + unsigned int i = 0; + for (MeshModel* m : meshList){ + if (m->cm.VN() == 0) + isReload[i] = false; + i++; + } + + try { + QElapsedTimer t; + t.start(); + meshlab::reloadMesh(fileName, meshList, QCallBack); + i = 0; + for (MeshModel* m : meshList){ + computeRenderingDataOnLoading(m, i++, nullptr); + } + GLA()->Log(0, ("File reloaded in " + std::to_string(t.elapsed()) + " msec.").c_str()); + } + catch (const MLException& e) { + QMessageBox::critical(this, "Reload Error", e.what()); + } qb->reset(); if (_currviewcontainer != NULL) { @@ -2938,17 +2965,19 @@ void MainWindow::updateTexture(int meshid) { QImage img; QFileInfo fi(mymesh->cm.textures[i].c_str()); + QFileInfo mfi(mymesh->fullName()); QString filename = fi.absoluteFilePath(); bool res = img.load(filename); - sometextfailed = sometextfailed || !res; if(!res) { - res = img.load(filename); + QString fn2 = mfi.absolutePath() + "/" + fi.fileName(); + res = img.load(fn2); if(!res) { QString errmsg = QString("Failure of loading texture %1").arg(fi.fileName()); meshDoc()->Log.log(GLLogStream::WARNING,qUtf8Printable(errmsg)); - unexistingtext += "" + filename + "
"; + unexistingtext += "" + fi.fileName() + "
"; + sometextfailed = sometextfailed || !res; } } @@ -2962,12 +2991,9 @@ void MainWindow::updateTexture(int meshid) /*PLEASE EXPLAIN ME!*********************************************************************************************************************************************************************************/ if (!res) - res = img.load(":/images/dummy.png"); + img.load(":/images/dummy.png"); GLuint textid = shared->allocateTexturePerMesh(meshid,img,singleMaxTextureSizeMpx); - if (sometextfailed) - QMessageBox::warning(this,"Texture file has not been correctly loaded",unexistingtext); - for(int tt = 0;tt < mvc->viewerCounter();++tt) { GLArea* ar = mvc->getViewer(tt); diff --git a/src/meshlabplugins/io_3ds/meshio.cpp b/src/meshlabplugins/io_3ds/meshio.cpp index 6bbeda306..9154eb210 100644 --- a/src/meshlabplugins/io_3ds/meshio.cpp +++ b/src/meshlabplugins/io_3ds/meshio.cpp @@ -75,28 +75,75 @@ void ExtraMeshIOPlugin::exportMaskCapability(const QString &format, int &capabil return; } -void ExtraMeshIOPlugin::initPreOpenParameter( +unsigned int ExtraMeshIOPlugin::numberMeshesContainedInFile( const QString& format, - RichParameterList& parameters) + const QString& fileName) const { - if (format.toUpper() == tr("3DS")){ - parameters.addParam(RichBool(paramNames[SEPARATE_LAYERS], true, "Separate layers", "Import each mesh contained in the file as a separate layer")); + if (format.toUpper() == tr("3DS")) { + Lib3dsFile *file = NULL; + file = lib3ds_file_load(fileName.toStdString().c_str()); + if (!file) + throw MLException("Malformed file."); + // No nodes? Fabricate nodes to display all the meshes. + if( !file->nodes && file->meshes) { + Lib3dsMesh *mesh; + Lib3dsNode *node; + + for (mesh = file->meshes; mesh != NULL; mesh = mesh->next) { + node = lib3ds_node_new_object(); + strcpy(node->name, mesh->name); + node->parent_id = LIB3DS_NO_PARENT; + lib3ds_file_insert_node(file, node); + } + } + if( !file->nodes) { + lib3ds_file_free(file); + throw MLException("Malformed file."); + } + lib3ds_file_eval(file, 0); + unsigned int i = 0; + Lib3dsNode *p = file->nodes; + while (p) { + i++; + p = p->next; + } + log("Expected meshes in file: " + std::to_string(i) ); + lib3ds_file_free(file); + return i; } + else { + wrongOpenFormat(format); + return 0; + } +} + +void ExtraMeshIOPlugin::open( + const QString& formatName, + const QString&, + MeshModel&, + int&, + const RichParameterList&, + CallBackPos*) +{ + wrongOpenFormat(formatName); } void ExtraMeshIOPlugin::open( const QString &formatName, const QString &fileName, - MeshModel &m, - int& mask, - const RichParameterList& params, + const std::list& meshList, + std::list& maskList, + const RichParameterList&, CallBackPos *cb) { // initializing mask - mask = 0; + maskList.clear(); + for (unsigned int i = 0; i < meshList.size(); i++) + maskList.push_back(0); // initializing progress bar status - if (cb != NULL) (*cb)(0, "Loading..."); + if (cb != nullptr) + (*cb)(0, "Loading..."); QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2"; //QString error_2MsgFormat = "Error encountered while loading file:\n\"%1\"\n\n File with more than a mesh.\n Load only the first!"; @@ -136,103 +183,58 @@ void ExtraMeshIOPlugin::open( } lib3ds_file_eval(file, 0); - - bool singleLayer = true; - if ( file->nodes->next) { - singleLayer = params.getBool(paramNames[SEPARATE_LAYERS]); - } - - if (!singleLayer) - { - Lib3dsNode *p; - mask = 0; - int i=1; - for (p=file->nodes; p!=0; p=p->next, ++i) - { - bool normalsUpdated = false; - - MeshModel &mm = *m.parent->addNewMesh(qUtf8Printable(fileName), QString(p->name), false); - if (cb != NULL) (*cb)(i, (QString("Loading Mesh ")+QString(p->name)).toStdString().c_str()); - - vcg::tri::io::Importer3DS::LoadMask(file, p, info); - mm.Enable(info.mask); - - int result = vcg::tri::io::Importer3DS::Load(mm.cm, file, p, info); - if (result != vcg::tri::io::Importer3DS::E_NOERROR) { - reportWarning("3DS Opening Error: " + errorMsgFormat.arg(fileName, vcg::tri::io::Importer3DS::ErrorMsg(result))); - continue; - } - - if(info.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) - normalsUpdated = true; - - mask |= info.mask; - - // verify if texture files are present - QString missingTextureFilesMsg = "The following texture files were not found:\n"; - bool someTextureNotFound = false; - for ( unsigned textureIdx = 0; textureIdx < mm.cm.textures.size(); ++textureIdx) - { - FILE* pFile = fopen (mm.cm.textures[textureIdx].c_str(), "r"); - if (pFile == NULL) { - missingTextureFilesMsg.append("\n"); - missingTextureFilesMsg.append(mm.cm.textures[textureIdx].c_str()); - someTextureNotFound = true; - } - fclose (pFile); - } - if (someTextureNotFound){ - reportWarning("Missing texture files: " + missingTextureFilesMsg); - } - - vcg::tri::UpdateBounding::Box(mm.cm); // updates bounding box - if (!normalsUpdated) - vcg::tri::UpdateNormal::PerVertex(mm.cm); // updates normals - } - } - else + + Lib3dsNode *p; + int i=1; + auto iter = meshList.begin(); + auto miter = maskList.begin(); + for (p=file->nodes; p!=nullptr; p=p->next, ++iter, ++miter) { bool normalsUpdated = false; - - vcg::tri::io::Importer3DS::LoadMask(file, 0, info); - m.Enable(info.mask); - - int result = vcg::tri::io::Importer3DS::Load(m.cm, file, 0, info); - if (result != vcg::tri::io::Importer3DS::E_NOERROR) - { - lib3ds_file_free(file); - throw MLException("3DS Opening Error: " + errorMsgFormat.arg(fileName, vcg::tri::io::Importer3DS::ErrorMsg(result))); + + MeshModel &mm = *(*iter); + mm.setLabel(QString(p->name)); + if (cb != nullptr) + (*cb)(i/meshList.size() * 100, (QString("Loading Mesh ")+QString(p->name)).toStdString().c_str()); + + vcg::tri::io::Importer3DS::LoadMask(file, p, info); + mm.Enable(info.mask); + + int result = vcg::tri::io::Importer3DS::Load(mm.cm, file, p, info); + if (result != vcg::tri::io::Importer3DS::E_NOERROR) { + reportWarning("3DS Opening Error: " + errorMsgFormat.arg(fileName, vcg::tri::io::Importer3DS::ErrorMsg(result))); + continue; } - + if(info.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) normalsUpdated = true; - - mask = info.mask; - - + + (*miter) |= info.mask; + // verify if texture files are present QString missingTextureFilesMsg = "The following texture files were not found:\n"; bool someTextureNotFound = false; - for ( unsigned textureIdx = 0; textureIdx < m.cm.textures.size(); ++textureIdx) + for ( unsigned textureIdx = 0; textureIdx < mm.cm.textures.size(); ++textureIdx) { - FILE* pFile = fopen (m.cm.textures[textureIdx].c_str(), "r"); - if (pFile == NULL) - { + FILE* pFile = fopen (mm.cm.textures[textureIdx].c_str(), "r"); + if (pFile == nullptr) { missingTextureFilesMsg.append("\n"); - missingTextureFilesMsg.append(m.cm.textures[textureIdx].c_str()); + missingTextureFilesMsg.append(mm.cm.textures[textureIdx].c_str()); someTextureNotFound = true; } - fclose (pFile); + else { + fclose (pFile); + } } if (someTextureNotFound){ reportWarning("Missing texture files: " + missingTextureFilesMsg); } - - vcg::tri::UpdateBounding::Box(m.cm); // updates bounding box - if (!normalsUpdated) - vcg::tri::UpdateNormal::PerVertex(m.cm); // updates normals + + vcg::tri::UpdateBounding::Box(mm.cm); // updates bounding box + if (!normalsUpdated) + vcg::tri::UpdateNormal::PerVertex(mm.cm); // updates normals } - + if (cb != NULL) (*cb)(99, "Done"); // freeing memory diff --git a/src/meshlabplugins/io_3ds/meshio.h b/src/meshlabplugins/io_3ds/meshio.h index 0dd8506d7..23ea813d1 100644 --- a/src/meshlabplugins/io_3ds/meshio.h +++ b/src/meshlabplugins/io_3ds/meshio.h @@ -44,15 +44,24 @@ public: void exportMaskCapability(const QString& format, int &capability, int &defaultBits) const; - void initPreOpenParameter( - const QString& format, - RichParameterList& parameters); + unsigned int numberMeshesContainedInFile( + const QString& format, + const QString& fileName) const; - void open(const QString &formatName, + void open( + const QString &formatName, const QString &fileName, - MeshModel &m, + MeshModel& m, int& mask, - const RichParameterList ¶ms, + const RichParameterList& params, + vcg::CallBackPos *cb=0); + + void open( + const QString &formatName, + const QString &fileName, + const std::list& meshList, + std::list& maskList, + const RichParameterList& params, vcg::CallBackPos *cb=0); void save( diff --git a/src/vcglib b/src/vcglib index 0a17efe9a..0882d6258 160000 --- a/src/vcglib +++ b/src/vcglib @@ -1 +1 @@ -Subproject commit 0a17efe9a809d2fc82838affe5d0a239e9e546fc +Subproject commit 0882d6258252174ee6635b3d1d337bdedad97ab8