diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 0f5863cd9..d03cbc0f7 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -125,6 +125,8 @@ set(SOURCES
mlapplication.cpp
searcher.cpp)
+set(RESOURCES meshlab-common.qrc)
+
set(TARGET_TYPE SHARED)
if(WIN32)
set(TARGET_TYPE STATIC)
diff --git a/src/common/common.pro b/src/common/common.pro
index 1b2c4e8bc..f443f098f 100644
--- a/src/common/common.pro
+++ b/src/common/common.pro
@@ -122,6 +122,9 @@ SOURCES += \
ml_selection_buffers.cpp \
$$MESHLAB_EXTERNAL_DIRECTORY/easyexif/exif.cpp
+RESOURCES += \
+ meshlab-common.qrc
+
macx:QMAKE_POST_LINK = "\
if [ -d $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks/ ]; \
then \
diff --git a/src/common/img/dummy.png b/src/common/img/dummy.png
new file mode 100644
index 000000000..03c4c8d2c
Binary files /dev/null and b/src/common/img/dummy.png differ
diff --git a/src/common/meshlab-common.qrc b/src/common/meshlab-common.qrc
new file mode 100644
index 000000000..e7301593c
--- /dev/null
+++ b/src/common/meshlab-common.qrc
@@ -0,0 +1,5 @@
+
+
+ img/dummy.png
+
+
diff --git a/src/common/ml_document/mesh_model.cpp b/src/common/ml_document/mesh_model.cpp
index e41085e54..17bf989f0 100644
--- a/src/common/ml_document/mesh_model.cpp
+++ b/src/common/ml_document/mesh_model.cpp
@@ -26,6 +26,7 @@
#include
#include "mesh_model.h"
+#include "../utilities/load_save.h"
#include
@@ -78,6 +79,66 @@ QString MeshModel::relativePathName(const QString& path) const
return relPath;
}
+/**
+ * @brief Starting from the (still unloaded) textures contained in the contained
+ * CMeshO, loads the textures in the map of QImages contained in the MeshModel.
+ *
+ * The contained CMeshO will have a list of texture names like ":filename.png",
+ * and these names will be mapped with the actual loaded image in the map
+ * "textures".
+ *
+ * When a texture is not found, a dummy texture will be used (":dummy.png").
+ *
+ * Returns the list of non-loaded textures that have been modified with
+ * ":dummy.png" in the contained mesh.
+ */
+std::list MeshModel::loadTextures(
+ GLLogStream* log,
+ vcg::CallBackPos* cb)
+{
+ std::list unloadedTextures;
+ for (std::string& textName : cm.textures){
+ if (textName.front() != ':'){
+ QImage img(":/img/dummy.png");
+ QFileInfo finfo(QString::fromStdString(textName));
+ try {
+ img = meshlab::loadImage(finfo.absoluteFilePath(), log, cb);
+ textName = ":" + finfo.fileName().toStdString();
+ } catch (const MLException& e) {
+ try { //could be relative to the meshmodel
+ QFileInfo mfi(fullName());
+ QString fn2 = mfi.absolutePath() + "/" + finfo.fileName();
+ img = meshlab::loadImage(fn2, log, cb);
+ textName = ":" + finfo.fileName().toStdString();
+ } catch (const MLException& e) {
+ if (log){
+ log->log(
+ GLLogStream::WARNING, "Failed loading " + textName +
+ "; using a dummy texture");
+ }
+ else {
+ std::cerr <<
+ "Failed loading " + textName + "; using a dummy texture\n";
+ }
+ unloadedTextures.push_back(textName);
+ textName = ":dummy.png";
+ }
+ }
+ textures[textName] = img;
+ }
+ }
+ return unloadedTextures;
+}
+
+QImage MeshModel::getTexture(const std::string& tn)
+{
+ auto it = textures.find(tn);
+ if (it != textures.end())
+ return it->second;
+ else
+ return QImage();
+}
+
int MeshModel::io2mm(int single_iobit)
{
switch(single_iobit)
diff --git a/src/common/ml_document/mesh_model.h b/src/common/ml_document/mesh_model.h
index d885ad0b1..75e5d8227 100644
--- a/src/common/ml_document/mesh_model.h
+++ b/src/common/ml_document/mesh_model.h
@@ -133,7 +133,6 @@ public:
int idInFile() const {return idInsideFile;}
void setIdInFile(int id) {idInsideFile = id;}
-
// Some notes about the files and naming.
// Each mesh when shown in the layer dialog has a label.
// By default the label is just the name of the file, but the
@@ -168,6 +167,10 @@ public:
bool visible; // used in rendering; Needed for toggling on and off the meshes
bool isVisible() const { return visible; }
+ std::list loadTextures(GLLogStream* log = nullptr, vcg::CallBackPos* cb = nullptr);
+
+ QImage getTexture(const std::string& tn);
+
// This function is roughly equivalent to the updateDataMask,
// but it takes in input a mask coming from a filetype instead of a filter requirement (like topology etc)
void enable(int openingFileMask);
diff --git a/src/common/utilities/load_save.cpp b/src/common/utilities/load_save.cpp
index b20d2b887..a153e0254 100644
--- a/src/common/utilities/load_save.cpp
+++ b/src/common/utilities/load_save.cpp
@@ -33,8 +33,15 @@
namespace meshlab {
-void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterList& prePar, const std::list& meshList, std::list& maskList, vcg::CallBackPos *cb)
+std::list loadMesh(
+ const QString& fileName,
+ IOPlugin* ioPlugin,
+ const RichParameterList& prePar,
+ const std::list& meshList,
+ std::list& maskList,
+ vcg::CallBackPos *cb)
{
+ std::list unloadedTextures;
QFileInfo fi(fileName);
QString extension = fi.suffix();
@@ -61,6 +68,9 @@ void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterLi
MeshModel* mm = *itmesh;
int mask = *itmask;
+ std::list tmp = mm->loadTextures(nullptr, cb);
+ unloadedTextures.insert(unloadedTextures.end(), tmp.begin(), tmp.end());
+
// 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...
@@ -100,6 +110,7 @@ void loadMesh(const QString& fileName, IOPlugin* ioPlugin, const RichParameterLi
++itmask;
}
QDir::setCurrent(origDir); // undo the change of directory before leaving
+ return unloadedTextures;
}
diff --git a/src/common/utilities/load_save.h b/src/common/utilities/load_save.h
index 3eab98aa5..33fb3d719 100644
--- a/src/common/utilities/load_save.h
+++ b/src/common/utilities/load_save.h
@@ -34,7 +34,7 @@
namespace meshlab {
-void loadMesh(
+std::list loadMesh(
const QString& fileName,
IOPlugin* ioPlugin,
const RichParameterList& prePar,
diff --git a/src/meshlab/mainwindow_RunTime.cpp b/src/meshlab/mainwindow_RunTime.cpp
index 8c00a58f3..e617e93d2 100644
--- a/src/meshlab/mainwindow_RunTime.cpp
+++ b/src/meshlab/mainwindow_RunTime.cpp
@@ -2164,19 +2164,19 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c
{
if ((GLA() == NULL))
return false;
-
+
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();
-
+
// retrieving corresponding IO plugin
if (pCurrentIOPlugin == 0)
{
@@ -2187,7 +2187,7 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c
}
meshDoc()->setBusy(true);
pCurrentIOPlugin->setLog(&meshDoc()->Log);
-
+
unsigned int nMeshes = pCurrentIOPlugin->numberMeshesContainedInFile(extension, fileNameSansDir, prePar);
if (nMeshes != meshList.size()) {
QMessageBox::warning(
@@ -2200,7 +2200,7 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c
}
try {
- pCurrentIOPlugin->open(extension, fileNameSansDir, meshList ,maskList, prePar, QCallBack);
+ meshlab::loadMesh(fileName, pCurrentIOPlugin, prePar, meshList, maskList, QCallBack);
}
catch(const MLException& e) {
QMessageBox::warning(
@@ -2211,8 +2211,7 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c
QDir::setCurrent(origDir); // undo the change of directory before leaving
return false;
}
-
-
+
//std::cout << "Opened mesh: in " << tm.elapsed() << " secs\n";
// After opening the mesh lets ask to the io plugin if this format
// requires some optional, or userdriven post-opening processing.
@@ -2221,15 +2220,15 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c
//RichParameterSet par;
//pCurrentIOPlugin->initOpenParameter(extension, *mm, par);
//pCurrentIOPlugin->applyOpenParameter(extension, *mm, par);
-
+
QString err = pCurrentIOPlugin->warningMessageString();
if (!err.isEmpty())
{
QMessageBox::warning(this, tr("Opening Problems"), QString("While opening: '%1'\n\n").arg(fileName)+ err);
}
-
+
saveRecentFileList(fileName);
-
+
auto itmesh = meshList.begin();
auto itmask = maskList.begin();
for (unsigned int i = 0; i < meshList.size(); ++i){
@@ -2284,12 +2283,11 @@ bool MainWindow::loadMesh(const QString& fileName, IOPlugin *pCurrentIOPlugin, c
}
updateLayerDialog();
-
-
+
meshDoc()->setBusy(false);
-
+
QDir::setCurrent(origDir); // undo the change of directory before leaving
-
+
return true;
}
@@ -2442,7 +2440,8 @@ bool MainWindow::importMesh(QString fileName)
try {
QElapsedTimer t;
t.start();
- meshlab::loadMesh(fileName, pCurrentIOPlugin, prePar, meshList, masks, QCallBack);
+ std::list unloadedTextures =
+ meshlab::loadMesh(fileName, pCurrentIOPlugin, prePar, meshList, masks, QCallBack);
saveRecentFileList(fileName);
updateLayerDialog();
for (MeshModel* mm : meshList) {
@@ -2451,6 +2450,11 @@ bool MainWindow::importMesh(QString fileName)
updateTexture(mm->id());
}
QString warningString = pCurrentIOPlugin->warningMessageString();
+ if (unloadedTextures.size() > 0){
+ warningString += "\n\nThe following textures have not been loaded: \n";
+ for (const std::string& txt : unloadedTextures)
+ warningString += QString::fromStdString(txt) + "\n";
+ }
if (!warningString.isEmpty()){
QMessageBox::warning(this, "Meshlab Opening Warning", warningString);
}
@@ -2947,39 +2951,15 @@ void MainWindow::updateTexture(int meshid)
totalTextureNum+=mp->cm.textures.size();
int singleMaxTextureSizeMpx = int(textmemMB/((totalTextureNum != 0)? totalTextureNum : 1));
- bool sometextfailed = false;
- QString unexistingtext = "In mesh file " + mymesh->fullName() + " : Failure loading textures:
";
- for(size_t i =0; i< mymesh->cm.textures.size();++i)
+
+ bool sometextnotfound = false;
+ for(const std::string& textname : mymesh->cm.textures)
{
- QImage img;
- QFileInfo fi(mymesh->cm.textures[i].c_str());
- QFileInfo mfi(mymesh->fullName());
- QString filename = fi.absoluteFilePath();
- bool res = img.load(filename);
- if(!res)
- {
- 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 += "" + fi.fileName() + "
";
- sometextfailed = sometextfailed || !res;
- }
- }
-
- /*PLEASE EXPLAIN ME!*********************************************************************************************************************************************************************************/
- //if(!res && filename.endsWith("dds",Qt::CaseInsensitive))
- //{
- // qDebug("DDS binding!");
- // int newTexId = shared->bindTexture(filename);
- // shared->txtcont.push_back(newTexId);
- //}
- /*PLEASE EXPLAIN ME!*********************************************************************************************************************************************************************************/
-
- if (!res)
+ QImage img = mymesh->getTexture(textname);
+
+ if (img.isNull()){
img.load(":/images/dummy.png");
+ }
GLuint textid = shared->allocateTexturePerMesh(meshid,img,singleMaxTextureSizeMpx);
for(int tt = 0;tt < mvc->viewerCounter();++tt)
@@ -2989,8 +2969,8 @@ void MainWindow::updateTexture(int meshid)
ar->setupTextureEnv(textid);
}
}
- if (sometextfailed)
- QMessageBox::warning(this,"Texture file has not been correctly loaded",unexistingtext);
+ if (sometextnotfound)
+ QMessageBox::warning(this,"Texture error", "Some texture has not been found. Using dummy texture.");
QDir::setCurrent(cwd);
}