From 7551f8afe45c8cecbf5af8566c33b4df9e8565e7 Mon Sep 17 00:00:00 2001 From: zaza <zain.selman@rwth-aachen.de> Date: Wed, 12 Aug 2020 16:45:48 +0200 Subject: [PATCH] adds additional conditions that will reduce the number of materials written. so far the speed is already useable again --- FileOBJT_impl.hh | 524 ++++++++++++++++++++++++----------------------- 1 file changed, 264 insertions(+), 260 deletions(-) diff --git a/FileOBJT_impl.hh b/FileOBJT_impl.hh index 66f7104..c82599e 100644 --- a/FileOBJT_impl.hh +++ b/FileOBJT_impl.hh @@ -39,41 +39,36 @@ * * \*===========================================================================*/ - - - #define FILEOBJPLUGIN_C #include "FileOBJ.hh" -#include <OpenMesh/Core/Utils/color_cast.hh> #include <OpenMesh/Core/Geometry/VectorT.hh> - +#include <OpenMesh/Core/Utils/color_cast.hh> //----------------------------------------------------------------------------------------------------- -template< class MeshT > -bool FileOBJPlugin::writeMaterial(QString _filename, MeshT& _mesh, int _objId ) -{ - bool optionColorAlpha = false; - bool optionTextures = false; - bool optionCopyTextures = false; +template <class MeshT> +bool FileOBJPlugin::writeMaterial(QString _filename, MeshT& _mesh, int _objId) { + bool optionColorAlpha = false; + bool optionTextures = false; + bool optionCopyTextures = false; bool optionCreateTexFolder = false; // check options - if ( !OpenFlipper::Options::savingSettings() && saveOptions_ != 0) { - optionColorAlpha = saveAlpha_->isChecked(); - optionTextures = saveTextures_->isChecked(); - optionCopyTextures = saveCopyTextures_->isChecked(); - optionCreateTexFolder = saveCreateTexFolder_->isChecked(); + if (!OpenFlipper::Options::savingSettings() && saveOptions_ != 0) { + optionColorAlpha = saveAlpha_->isChecked(); + optionTextures = saveTextures_->isChecked(); + optionCopyTextures = saveCopyTextures_->isChecked(); + optionCreateTexFolder = saveCreateTexFolder_->isChecked(); } // \TODO Fetch options from ini states if dialog box is not available - std::fstream matStream( _filename.toStdString().c_str(), std::ios_base::out ); - - if ( !matStream ){ + std::fstream matStream(_filename.toStdString().c_str(), std::ios_base::out); - emit log(LOGERR, tr("writeMaterial : cannot not open file %1").arg(_filename) ); + if (!matStream) { + emit log(LOGERR, + tr("writeMaterial : cannot not open file %1").arg(_filename)); return false; } @@ -83,47 +78,49 @@ bool FileOBJPlugin::writeMaterial(QString _filename, MeshT& _mesh, int _objId ) materials_.clear(); - //iterate over faces + // iterate over faces typename MeshT::FaceIter f_it; typename MeshT::FaceIter f_end = _mesh.faces_end(); // Prepare materials ( getMaterial handles a list that is set up by this call) - for (f_it = _mesh.faces_begin(); f_it != f_end; ++f_it){ + for (f_it = _mesh.faces_begin(); f_it != f_end; ++f_it) { getMaterial(_mesh, *f_it, _objId); } - //write the materials - for(MaterialList::iterator it = materials_.begin(); it != materials_.end(); ++it) { - Material& mat = (*it).second; - matStream << "newmtl " << mat << '\n'; - matStream << "Ka 0.5000 0.5000 0.5000" << '\n'; - ACG::Vec3f c = mat.Kd(); - matStream << "Kd " << c[0] << " " << c[1] << " " << c[2] << '\n'; - if(optionColorAlpha) { - matStream << "Tr " << mat.Tr() << '\n'; - } - matStream << "illum 1" << '\n'; - - // Write out texture info - if(optionTextures && mat.has_Texture()) { - if(optionCopyTextures) { - // Use file path in target folder (relative) - QFileInfo file(mat.map_Kd().c_str()); - if(optionCreateTexFolder) { - QFileInfo materialFilename(_filename); - - matStream << "map_Kd " << materialFilename.baseName().toStdString() << "_textures" << QDir::separator().toLatin1() - << file.fileName().toStdString() << '\n'; - } else { - matStream << "map_Kd " << file.fileName().toStdString() << '\n'; - } - } else { - // Use original file path - matStream << "map_Kd " << mat.map_Kd() << '\n'; - } + // write the materials + for (MaterialList::iterator it = materials_.begin(); it != materials_.end(); + ++it) { + Material& mat = (*it).second; + matStream << "newmtl " << mat << '\n'; + matStream << "Ka 0.5000 0.5000 0.5000" << '\n'; + ACG::Vec3f c = mat.Kd(); + matStream << "Kd " << c[0] << " " << c[1] << " " << c[2] << '\n'; + if (optionColorAlpha) { + matStream << "Tr " << mat.Tr() << '\n'; + } + matStream << "illum 1" << '\n'; + + // Write out texture info + if (optionTextures && mat.has_Texture()) { + if (optionCopyTextures) { + // Use file path in target folder (relative) + QFileInfo file(mat.map_Kd().c_str()); + if (optionCreateTexFolder) { + QFileInfo materialFilename(_filename); + + matStream << "map_Kd " << materialFilename.baseName().toStdString() + << "_textures" << QDir::separator().toLatin1() + << file.fileName().toStdString() << '\n'; + } else { + matStream << "map_Kd " << file.fileName().toStdString() << '\n'; + } + } else { + // Use original file path + matStream << "map_Kd " << mat.map_Kd() << '\n'; } + } - matStream << '\n'; + matStream << '\n'; } matStream.close(); @@ -133,148 +130,151 @@ bool FileOBJPlugin::writeMaterial(QString _filename, MeshT& _mesh, int _objId ) //----------------------------------------------------------------------------------------------------- -template< class MeshT > -Material& FileOBJPlugin::getMaterial(MeshT& _mesh, const OpenMesh::FaceHandle& _fh, int _objId) -{ - // check options - bool optionColorAlpha = false; - if ( !OpenFlipper::Options::savingSettings() && saveOptions_ != 0) - optionColorAlpha = saveAlpha_->isChecked(); - // \TODO Fetch options from ini states if dialog box is not available - - OpenMesh::Vec4f c = _mesh.color( _fh ); - - // If one of the entries is out of range, assume uninitialized color and set to default - // Ugly hack to ensure that materials will only be generated if initialized - if ( c[0] > 255.0 || c[1] > 255.0 || c[2] > 255.0 || c[0] < 0.0 || c[1] < 0.0 || c[2] < 0.0) { - c[0] = 155.0; - c[1] = 155.0; - c[2] = 155.0; - c[3] = 1.0; - } +template <class MeshT> +Material& FileOBJPlugin::getMaterial(MeshT& _mesh, + const OpenMesh::FaceHandle& _fh, + int _objId) { + // check options + bool optionColorAlpha = false; + if (!OpenFlipper::Options::savingSettings() && saveOptions_ != 0) + optionColorAlpha = saveAlpha_->isChecked(); + // \TODO Fetch options from ini states if dialog box is not available - // First off, try to fetch texture index of current face/object... - if(!textureIndexPropFetched_) { - emit textureIndexPropertyName(_objId, textureIndexPropertyName_); - textureIndexPropFetched_ = true; - } + OpenMesh::Vec4f c = _mesh.color(_fh); + + // If one of the entries is out of range, assume uninitialized color and set + // to default Ugly hack to ensure that materials will only be generated if + // initialized + if (c[0] > 255.0 || c[1] > 255.0 || c[2] > 255.0 || c[0] < 0.0 || + c[1] < 0.0 || c[2] < 0.0 || std::isnan(c[0]) || std::isnan(c[1]) || + std::isnan(c[2])) { + c[0] = 155.0; + c[1] = 155.0; + c[2] = 155.0; + c[3] = 1.0; + } - int texIndex = -1; - OpenMesh::FPropHandleT< int > texture_index_property; - if ( _mesh.get_property_handle(texture_index_property, textureIndexPropertyName_.toStdString()) ) { - texIndex = _mesh.property(texture_index_property, _fh); - } else if ( _mesh.get_property_handle(texture_index_property, "f:textureindex") ) { - texIndex = _mesh.property(texture_index_property, _fh); - } else if(_mesh.has_face_texture_index()) { - texIndex = _mesh.texture_index(_fh); - } else { - QString texName; - emit getCurrentTexture(_objId, texName); - if(texName != "NONE") - emit textureIndex(texName, _objId, texIndex); - } + // First off, try to fetch texture index of current face/object... + if (!textureIndexPropFetched_) { + emit textureIndexPropertyName(_objId, textureIndexPropertyName_); + textureIndexPropFetched_ = true; + } - QString filename; - bool hasTexture = false; + int texIndex = -1; + OpenMesh::FPropHandleT<int> texture_index_property; + if (_mesh.get_property_handle(texture_index_property, + textureIndexPropertyName_.toStdString())) { + texIndex = _mesh.property(texture_index_property, _fh); + } else if (_mesh.get_property_handle(texture_index_property, + "f:textureindex")) { + texIndex = _mesh.property(texture_index_property, _fh); + } else if (_mesh.has_face_texture_index()) { + texIndex = _mesh.texture_index(_fh); + } else { + QString texName; + emit getCurrentTexture(_objId, texName); + if (texName != "NONE") emit textureIndex(texName, _objId, texIndex); + } - if(texIndex != -1) { + QString filename; + bool hasTexture = false; - // Search for texture index in local map - std::map<int,QString>::iterator it = texIndexFileMap_.find(texIndex); + if (texIndex != -1) { + // Search for texture index in local map + std::map<int, QString>::iterator it = texIndexFileMap_.find(texIndex); - if(it != texIndexFileMap_.end()) { - // We already know this file - filename = (*it).second; - hasTexture = true; - } else { - // A new texture file has been found - QString texName; - emit textureName(_objId, texIndex, texName); - - if(texName != "NOT_FOUND") { - emit textureFilename( _objId, texName, filename ); - // => Add to local map - texIndexFileMap_.insert(std::pair<int,QString>(texIndex, filename)); - hasTexture = true; - } - } + if (it != texIndexFileMap_.end()) { + // We already know this file + filename = (*it).second; + hasTexture = true; + } else { + // A new texture file has been found + QString texName; + emit textureName(_objId, texIndex, texName); + + if (texName != "NOT_FOUND") { + emit textureFilename(_objId, texName, filename); + // => Add to local map + texIndexFileMap_.insert(std::pair<int, QString>(texIndex, filename)); + hasTexture = true; + } } + } - for (MaterialList::iterator it = materials_.begin(); it != materials_.end(); ++it) { - - // No texture has been found - if(!hasTexture) { - // ... just look for diffuse color in materials list - if(((*it).second).Kd() == ACG::Vec3f(c[0], c[1], c[2]) && - ((optionColorAlpha && ((*it).second).Tr() == c[3]) || !optionColorAlpha)) - return (*it).second; - } else { - // Texture has been found, look for both, matching texture and color - QString mKd(((*it).second).map_Kd().c_str()); - if((((*it).second).Kd() == ACG::Vec3f(c[0], c[1], c[2]) && - ((optionColorAlpha && ((*it).second).Tr() == c[3]) || !optionColorAlpha)) && - (filename == mKd && ((*it).second).map_Kd_index() == texIndex)) - return (*it).second; - } + for (MaterialList::iterator it = materials_.begin(); it != materials_.end(); + ++it) { + // No texture has been found + if (!hasTexture) { + // ... just look for diffuse color in materials list + if (((*it).second).Kd() == ACG::Vec3f(c[0], c[1], c[2]) && + ((optionColorAlpha && ((*it).second).Tr() == c[3]) || + !optionColorAlpha)) + return (*it).second; + } else { + // Texture has been found, look for both, matching texture and color + QString mKd(((*it).second).map_Kd().c_str()); + if ((((*it).second).Kd() == ACG::Vec3f(c[0], c[1], c[2]) && + ((optionColorAlpha && ((*it).second).Tr() == c[3]) || + !optionColorAlpha)) && + (filename == mKd && ((*it).second).map_Kd_index() == texIndex)) + return (*it).second; } + } - // If not found, add new material(s) - Material mat; - // Set diffuse color - mat.set_Kd(c[0], c[1], c[2]); - // Add transparency if available - if(optionColorAlpha) mat.set_Tr(c[3]); - mat.material_number(materials_.size()); - // Set texture info - if(hasTexture) - mat.set_map_Kd(filename.toStdString(), texIndex); - - materials_.insert(std::make_pair(QString("Material%1").arg(mat.material_number()).toStdString(), mat)); - MaterialList::iterator it = materials_.end(); - --it; - return (*it).second; + // If not found, add new material(s) + Material mat; + // Set diffuse color + mat.set_Kd(c[0], c[1], c[2]); + // Add transparency if available + if (optionColorAlpha) mat.set_Tr(c[3]); + mat.material_number(materials_.size()); + // Set texture info + if (hasTexture) mat.set_map_Kd(filename.toStdString(), texIndex); + + materials_.insert(std::make_pair( + QString("Material%1").arg(mat.material_number()).toStdString(), mat)); + MaterialList::iterator it = materials_.end(); + --it; + return (*it).second; } - - - //----------------------------------------------------------------------------------------------------- -template< class MeshT > -bool FileOBJPlugin::writeMesh(std::ostream& _out, QString _filename, MeshT& _mesh, int _objId){ - +template <class MeshT> +bool FileOBJPlugin::writeMesh(std::ostream& _out, QString _filename, + MeshT& _mesh, int _objId) { unsigned int i, nV, idx; Vec3f v, n; - Vec2f t(0.0f,0.0f); + Vec2f t(0.0f, 0.0f); typename MeshT::VertexHandle vh; bool useMaterial = false; OpenMesh::Vec4f c; - bool optionFaceColors = false; - bool optionVertexNormals = false; + bool optionFaceColors = false; + bool optionVertexNormals = false; bool optionVertexTexCoords = true; - bool optionTextures = false; - bool optionCopyTextures = false; + bool optionTextures = false; + bool optionCopyTextures = false; bool optionCreateTexFolder = false; QFileInfo fi(_filename); // check options - if ( !OpenFlipper::Options::savingSettings() && saveOptions_ != 0) { - optionFaceColors = saveFaceColor_->isChecked(); - optionVertexNormals = saveNormals_->isChecked(); + if (!OpenFlipper::Options::savingSettings() && saveOptions_ != 0) { + optionFaceColors = saveFaceColor_->isChecked(); + optionVertexNormals = saveNormals_->isChecked(); optionVertexTexCoords = saveTexCoords_->isChecked(); - optionTextures = saveTextures_->isChecked(); - optionCopyTextures = saveCopyTextures_->isChecked(); + optionTextures = saveTextures_->isChecked(); + optionCopyTextures = saveCopyTextures_->isChecked(); optionCreateTexFolder = saveCreateTexFolder_->isChecked(); _out.precision(savePrecision_->value()); }; // \TODO Fetch options from ini states if dialog box is not available - //create material file if needed - if ( optionFaceColors || optionTextures ){ - - QString matFile = fi.absolutePath() + QDir::separator() + fi.baseName() + ".mtl"; + // create material file if needed + if (optionFaceColors || optionTextures) { + QString matFile = + fi.absolutePath() + QDir::separator() + fi.baseName() + ".mtl"; useMaterial = writeMaterial(matFile, _mesh, _objId); } @@ -284,7 +284,7 @@ bool FileOBJPlugin::writeMesh(std::ostream& _out, QString _filename, MeshT& _mes _out << _mesh.n_faces() << " faces" << '\n'; // Material file - if (useMaterial && optionFaceColors ) + if (useMaterial && optionFaceColors) _out << "mtllib " << fi.baseName().toStdString() << ".mtl" << '\n'; // Store indices of vertices in a map such that @@ -294,25 +294,25 @@ bool FileOBJPlugin::writeMesh(std::ostream& _out, QString _filename, MeshT& _mes int cf = 1; // vertex data (point, normals, texcoords) - for (i=0, nV=_mesh.n_vertices(); i<nV; ++i) - { + for (i = 0, nV = _mesh.n_vertices(); i < nV; ++i) { vh = typename MeshT::VertexHandle(i); - v = _mesh.point(vh); - n = _mesh.normal(vh); + v = _mesh.point(vh); + n = _mesh.normal(vh); - if ( _mesh.has_vertex_texcoords2D() && !_mesh.has_halfedge_texcoords2D() ) - t = _mesh.texcoord2D(vh); + if (_mesh.has_vertex_texcoords2D() && !_mesh.has_halfedge_texcoords2D()) + t = _mesh.texcoord2D(vh); // Write out vertex coordinates - _out << "v " << v[0] <<" "<< v[1] <<" "<< v[2] << '\n'; + _out << "v " << v[0] << " " << v[1] << " " << v[2] << '\n'; // Write out vertex coordinates - if ( optionVertexNormals) - _out << "vn " << n[0] <<" "<< n[1] <<" "<< n[2] << '\n'; + if (optionVertexNormals) + _out << "vn " << n[0] << " " << n[1] << " " << n[2] << '\n'; // Write out vertex texture coordinates - if ( optionVertexTexCoords && _mesh.has_vertex_texcoords2D() && !_mesh.has_halfedge_texcoords2D()) { - _out << "vt " << t[0] <<" "<< t[1] << '\n'; + if (optionVertexTexCoords && _mesh.has_vertex_texcoords2D() && + !_mesh.has_halfedge_texcoords2D()) { + _out << "vt " << t[0] << " " << t[1] << '\n'; vtMapV.insert(std::pair<typename MeshT::VertexHandle, int>(vh, cf)); cf++; } @@ -328,115 +328,123 @@ bool FileOBJPlugin::writeMesh(std::ostream& _out, QString _filename, MeshT& _mes std::map<typename MeshT::HalfedgeHandle, int> vtMap; // If mesh has halfedge tex coords, write them out instead of vertex texcoords - if(optionVertexTexCoords && _mesh.has_halfedge_texcoords2D()) { - int count = 1; - for ( auto f_it : _mesh.faces() ) { - for(fh_it=_mesh.fh_iter(f_it); fh_it.is_valid(); ++fh_it) { - typename MeshT::TexCoord2D t = _mesh.texcoord2D(*fh_it); - _out << "vt " << t[0] << " " << t[1] << '\n'; - vtMap.insert(std::pair<typename MeshT::HalfedgeHandle, int>(*fh_it, count)); - count++; - } + if (optionVertexTexCoords && _mesh.has_halfedge_texcoords2D()) { + int count = 1; + for (auto f_it : _mesh.faces()) { + for (fh_it = _mesh.fh_iter(f_it); fh_it.is_valid(); ++fh_it) { + typename MeshT::TexCoord2D t = _mesh.texcoord2D(*fh_it); + _out << "vt " << t[0] << " " << t[1] << '\n'; + vtMap.insert( + std::pair<typename MeshT::HalfedgeHandle, int>(*fh_it, count)); + count++; } + } } Material lastMat; + lastMat.material_number(std::numeric_limits<unsigned int>::max()); // we do not want to write separators if we only write vertex indices - bool vertexOnly = !(optionVertexTexCoords && _mesh.has_halfedge_texcoords2D()) - && !(optionVertexTexCoords && !_mesh.has_halfedge_texcoords2D() && _mesh.has_vertex_texcoords2D()) - && !(optionVertexNormals); - - for ( auto f_it : _mesh.faces() ){ + bool vertexOnly = + !(optionVertexTexCoords && _mesh.has_halfedge_texcoords2D()) && + !(optionVertexTexCoords && !_mesh.has_halfedge_texcoords2D() && + _mesh.has_vertex_texcoords2D()) && + !(optionVertexNormals); + for (auto f_it : _mesh.faces()) { if (useMaterial && optionFaceColors) { + Material& material = getMaterial(_mesh, f_it, _objId); - Material& material = getMaterial(_mesh, f_it, _objId); - - // If we are ina a new material block, specify in the file which material to use - if(lastMat.material_number() != material.material_number() ) { - _out << "usemtl " << material << '\n'; - lastMat = material; - } + // If we are ina a new material block, specify in the file which material + // to use + if (lastMat.material_number() != material.material_number()) { + _out << "usemtl " << material << '\n'; + lastMat = material; + } } _out << "f"; // Write out face information - for(fh_it=_mesh.fh_iter(f_it); fh_it.is_valid(); ++fh_it) { - - // Write vertex index - idx = _mesh.to_vertex_handle(*fh_it).idx() + 1; - _out << " " << idx; - - if (!vertexOnly) { - - // Write separator - _out << "/" ; - - if ( optionVertexTexCoords ) { - // Write vertex texture coordinate index - if ( optionVertexTexCoords && _mesh.has_halfedge_texcoords2D()) { - // Refer to halfedge texture coordinates - typename std::map<typename MeshT::HalfedgeHandle, int>::iterator it = vtMap.find(*fh_it); - if(it != vtMap.end()) - _out << (*it).second; - } else if (optionVertexTexCoords && !_mesh.has_halfedge_texcoords2D() && _mesh.has_vertex_texcoords2D()) { - // Refer to vertex texture coordinates - typename std::map<typename MeshT::VertexHandle, int>::iterator it = vtMapV.find(_mesh.to_vertex_handle(*fh_it)); - if(it != vtMapV.end()) - _out << (*it).second; - } + for (fh_it = _mesh.fh_iter(f_it); fh_it.is_valid(); ++fh_it) { + // Write vertex index + idx = _mesh.to_vertex_handle(*fh_it).idx() + 1; + _out << " " << idx; + + if (!vertexOnly) { + // Write separator + _out << "/"; + + if (optionVertexTexCoords) { + // Write vertex texture coordinate index + if (optionVertexTexCoords && _mesh.has_halfedge_texcoords2D()) { + // Refer to halfedge texture coordinates + typename std::map<typename MeshT::HalfedgeHandle, int>::iterator + it = vtMap.find(*fh_it); + if (it != vtMap.end()) _out << (*it).second; + } else if (optionVertexTexCoords && + !_mesh.has_halfedge_texcoords2D() && + _mesh.has_vertex_texcoords2D()) { + // Refer to vertex texture coordinates + typename std::map<typename MeshT::VertexHandle, int>::iterator it = + vtMapV.find(_mesh.to_vertex_handle(*fh_it)); + if (it != vtMapV.end()) _out << (*it).second; } + } - // Write vertex normal index - if ( optionVertexNormals ) { - // Write separator - _out << "/" ; + // Write vertex normal index + if (optionVertexNormals) { + // Write separator + _out << "/"; - _out << idx; - } + _out << idx; } + } } _out << '\n'; } // Copy texture files (if demanded) - if(optionCopyTextures) { - // Only test existence of folder once - // (for multiple textures) - bool testedOnce = false; - for(MaterialList::iterator it = materials_.begin(); it != materials_.end(); ++it) { - Material& mat = (*it).second; - - if(!mat.has_Texture()) continue; - - QImage img(mat.map_Kd().c_str()); - QFileInfo img_f(mat.map_Kd().c_str()); - - if(img.isNull()) { - // Something happened wrong - emit log(LOGERR, tr("An error occurred when trying to copy a texture file.")); - continue; + if (optionCopyTextures) { + // Only test existence of folder once + // (for multiple textures) + bool testedOnce = false; + for (MaterialList::iterator it = materials_.begin(); it != materials_.end(); + ++it) { + Material& mat = (*it).second; + + if (!mat.has_Texture()) continue; + + QImage img(mat.map_Kd().c_str()); + QFileInfo img_f(mat.map_Kd().c_str()); + + if (img.isNull()) { + // Something happened wrong + emit log(LOGERR, + tr("An error occurred when trying to copy a texture file.")); + continue; + } else { + if (optionCreateTexFolder) { + // Create folder + QDir dir(fi.absolutePath()); + if (!testedOnce && dir.exists(fi.absolutePath() + QDir::separator() + + fi.baseName() + "_textures")) { + emit log(LOGERR, tr("The specified target folder already contains " + "a subfolder called textures. Skipping!")); + continue; } else { - if(optionCreateTexFolder) { - // Create folder - QDir dir(fi.absolutePath()); - if(!testedOnce && dir.exists(fi.absolutePath() + QDir::separator() + fi.baseName() + "_textures")) { - emit log(LOGERR, tr("The specified target folder already contains a subfolder called textures. Skipping!")); - continue; - } else { - dir.mkdir(fi.baseName() + "_textures"); - img.save(fi.absolutePath() + QDir::separator() + fi.baseName() + "_textures" + QDir::separator() + img_f.fileName()); - testedOnce = true; - } - - } else { - img.save(fi.absolutePath() + QDir::separator() + img_f.fileName()); - } + dir.mkdir(fi.baseName() + "_textures"); + img.save(fi.absolutePath() + QDir::separator() + fi.baseName() + + "_textures" + QDir::separator() + img_f.fileName()); + testedOnce = true; } + + } else { + img.save(fi.absolutePath() + QDir::separator() + img_f.fileName()); + } } + } } materials_.clear(); @@ -445,7 +453,3 @@ bool FileOBJPlugin::writeMesh(std::ostream& _out, QString _filename, MeshT& _mes return true; } - - - - -- GitLab