/**************************************************************************** * MeshLab o o * * A versatile mesh processing toolbox o o * * _ O _ * * Copyright(C) 2005 \/)\/ * * 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 #include #include #include #include #include #include class FilterData { public: FilterData(); QString name; QString info; int filterClass; bool operator <(const FilterData &d) const {return nameactions()) fprintf(fp, "*%s
%s
\n",qPrintable(filterAction->text()), qPrintable(iFilter->filterInfo(filterAction))); } void dumpPluginInfoDoxygen(FILE *fp) { if(!fp) return; int i=0; QMap FPM = PM.generateFilterParameterMap(); fprintf(fp,"/*! \\mainpage MeshLab Filter Documentation\n"); //fprintf(fp,"\\AtBeginDocument{\\setcounter{tocdepth}{1}}"); foreach(MeshFilterInterface *iFilter, PM.meshFilterPlugins()) { foreach(QAction *filterAction, iFilter->actions()) { fprintf(fp, "\n\\section f%i %s \n\n" "%s\n" ,i++,qPrintable(filterAction->text()),qPrintable(iFilter->filterInfo(filterAction))); fprintf(fp, "

Parameters

\n"); // fprintf(fp, "\\paragraph fp%i Parameters\n",i); if(! FPM[filterAction->text()].paramList.empty()) { fprintf(fp,"\n"); foreach(RichParameter* pp, FPM[filterAction->text()].paramList) { fprintf(fp,"\n", qPrintable(pp->val->typeName()),qPrintable(pp->pd->fieldDesc),qPrintable(pp->pd->tooltip)); } fprintf(fp,"
\\c %s %s %s --
\n"); } else fprintf(fp,"No parameters.
"); } } fprintf(fp,"*/"); } bool importMesh(MeshModel &mm, const QString& fileName,FILE* fp = stdout) { // Opening files in a transparent form (IO plugins contribution is hidden to user) QStringList filters; // HashTable storing all supported formats togheter with // the (1-based) index of first plugin which is able to open it QHash allKnownFormats; //PM.LoadFormats(filters, allKnownFormats,PluginManager::IMPORT); QFileInfo fi(fileName); // this change of dir is needed for subsequent textures/materials loading QDir curDir = QDir::current(); QDir::setCurrent(fi.absolutePath()); QString extension = fi.suffix(); qDebug("Opening a file with extention %s",qPrintable(extension)); // retrieving corresponding IO plugin MeshIOInterface* pCurrentIOPlugin = PM.allKnowInputFormats[extension.toLower()]; if (pCurrentIOPlugin == 0) { fprintf(fp,"Error encountered while opening file: "); QDir::setCurrent(curDir.absolutePath()); return false; } int mask = 0; RichParameterSet prePar; pCurrentIOPlugin->initPreOpenParameter(extension, fileName,prePar); if (!pCurrentIOPlugin->open(extension, fileName, mm ,mask,prePar)) { fprintf(fp,"MeshLabServer: Failed loading of %s from dir %s\n",qPrintable(fileName),qPrintable(QDir::currentPath())); QDir::setCurrent(curDir.absolutePath()); return false; } // 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) fprintf(fp,"Warning model contains %i degenerate faces. Removed them.",degNum); mm.updateDataMask(MeshModel::MM_FACEFACETOPO); vcg::tri::UpdateNormal::PerBitQuadFaceNormalized(mm.cm); vcg::tri::UpdateNormal::PerVertexFromCurrentFaceNormal(mm.cm); } // standard case else { if( mask & vcg::tri::io::Mask::IOM_VERTNORMAL) // the mesh already has its per vertex normals (point clouds) { vcg::tri::UpdateNormal::PerFace(mm.cm); vcg::tri::UpdateBounding::Box(mm.cm); // updates bounding box } else mm.UpdateBoxAndNormals(); // the very standard case } if(mm.cm.fn==0) { if (mask & vcg::tri::io::Mask::IOM_VERTNORMAL) mm.updateDataMask(MeshModel::MM_VERTNORMAL); } else mm.updateDataMask(MeshModel::MM_VERTNORMAL); //vcg::tri::UpdateBounding::Box(mm.cm); QDir::setCurrent(curDir.absolutePath()); return true; } bool exportMesh(MeshModel *mm, const int mask, const QString& fileName,FILE* fp = stdout) { QFileInfo fi(fileName); // this change of dir is needed for subsequent textures/materials loading QDir curDir = QDir::current(); QDir::setCurrent(fi.absolutePath()); QString extension = fi.suffix(); // retrieving corresponding IO plugin MeshIOInterface* pCurrentIOPlugin = PM.allKnowOutputFormats[extension.toLower()]; if (pCurrentIOPlugin == 0) { fprintf(fp,"Error encountered while opening file: "); //QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension does not correspond to any supported format."; //QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(fileName, extension)); QDir::setCurrent(curDir.absolutePath()); return false; } // optional saving parameters (like ascii/binary encoding) RichParameterSet savePar; pCurrentIOPlugin->initSaveParameter(extension, *mm, savePar); int formatmask = 0; int defbits = 0; pCurrentIOPlugin->GetExportMaskCapability(extension,formatmask,defbits); if (!pCurrentIOPlugin->save(extension, fileName, *mm ,mask & formatmask, savePar)) { fprintf(fp,"Failed saving\n"); QDir::setCurrent(curDir.absolutePath()); return false; } QDir::setCurrent(curDir.absolutePath()); return true; } bool openProject(MeshDocument& md,const QString& filename) { QDir curDir = QDir::current(); QFileInfo fi(filename); bool opened = MeshDocumentFromXML(md,fi.absoluteFilePath()); if (!opened) return false; QDir::setCurrent(fi.absolutePath()); //WARNING! I'm not putting inside MeshDocumentFromXML function because I'm too scared of what can happen inside MeshLab code.... md.setFileName(fi.absoluteFilePath()); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// for (int i=0; ifullName(); md.setBusy(true); Matrix44m trm = md.meshList[i]->cm.Tr; // save the matrix, because loadMeshClear it... if (!importMesh(*md.meshList[i],fullPath)) { md.delMesh(md.meshList[i]); md.setBusy(false); QDir::setCurrent(curDir.absolutePath()); return false; } else md.meshList[i]->cm.Tr=trm; md.setCurrentMesh(md.meshList[i]->id()); md.setBusy(false); } } QDir::setCurrent(curDir.absolutePath()); return true; } bool saveProject(MeshDocument& md,const QString& filename,const QString& outfilemeshmiddlename = QString()) { QFileInfo outprojinfo(filename); QString outdir = outprojinfo.absolutePath(); QDir curDir = QDir::current(); QDir::setCurrent(outprojinfo.absolutePath()); foreach(MeshModel* m,md.meshList) { if (m != NULL) { QString outfilename; QFileInfo fi(m->fullName()); if (!fi.exists()) outfilename = outdir + "/" + m->label().remove(" ") + outfilemeshmiddlename + ".ply"; else outfilename = fi.absolutePath() + "/" + fi.completeBaseName() + outfilemeshmiddlename + "." + fi.completeSuffix(); m->setFileName(outfilename); QFileInfo of(outfilename); m->setLabel(of.fileName()); exportMesh(m,m->dataMask(),outfilename); } } QDir::setCurrent(curDir.absolutePath()); return MeshDocumentToXMLFile(md,filename,false); } bool script(MeshDocument &meshDocument,const QString& scriptfile,FILE* fp) { MeshModel* mm = meshDocument.mm(); FilterScript scriptPtr; //Open/Load FilterScript if (scriptfile.isEmpty()) { printf("No script specified\n"); return false; } if (!scriptPtr.open(scriptfile)) { printf("File %s was not found.\n",qPrintable(scriptfile)); return false; } fprintf(fp,"Starting Script of %i actions",scriptPtr.filtparlist.size()); GLLogStream log; for(FilterScript::iterator ii = scriptPtr.filtparlist.begin();ii!= scriptPtr.filtparlist.end();++ii) { bool ret = false; //RichParameterSet &par = (*ii).second; QString fname = (*ii)->filterName(); fprintf(fp,"filter: %s\n",qPrintable(fname)); if (!(*ii)->isXMLFilter()) { QAction *action = PM.actionFilterMap[ fname]; if (action == NULL) { fprintf(fp,"filter %s not found",qPrintable(fname)); return false; } MeshFilterInterface *iFilter = qobject_cast(action->parent()); iFilter->setLog(&log); int req = iFilter->getRequirements(action); mm->updateDataMask(req); //make sure the PARMESH parameters are initialized //A filter in the script file couldn't have all the required parameter not defined (a script file not generated by MeshLab). //So we have to ask to the filter the default values for all the parameters and integrate them with the parameters' values //defined in the script file. RichParameterSet required; iFilter->initParameterSet(action,meshDocument,required); OldFilterNameParameterValuesPair* pairold = reinterpret_cast(*ii); RichParameterSet ¶meterSet = pairold->pair.second; //The parameters in the script file are more than the required parameters of the filter. The script file is not correct. if (required.paramList.size() < parameterSet.paramList.size()) { fprintf(fp,"The parameters in the script file are more than the filter %s requires.\n",qPrintable(fname)); return false; } for(int i = 0; i < required.paramList.size(); i++) { RichParameterCopyConstructor v; if (!parameterSet.hasParameter(required.paramList[i]->name)) { required.paramList[i]->accept(v); parameterSet.addParam(v.lastCreated); } assert(parameterSet.paramList.size() == required.paramList.size()); RichParameter* parameter = parameterSet.paramList[i]; //if this is a mesh paramter and the index is valid if(parameter->val->isMesh()) { RichMesh* md = reinterpret_cast(parameter); if( md->meshindex < meshDocument.size() && md->meshindex >= 0 ) { RichMesh* rmesh = new RichMesh(parameter->name,meshDocument.getMesh(md->meshindex),&meshDocument); parameterSet.paramList.replace(i,rmesh); } else { fprintf(fp,"Meshes loaded: %i, meshes asked for: %i \n", meshDocument.size(), md->meshindex ); fprintf(fp,"One of the filters in the script needs more meshes than you have loaded.\n"); exit(-1); } delete parameter; } } QGLWidget wid; iFilter->glContext = new QGLContext(QGLFormat::defaultFormat(),wid.context()->device()); bool created = iFilter->glContext->create(); if ((!created) || (!iFilter->glContext->isValid())) { fprintf(fp,"A valid GLContext is required by the filter to work.\n"); return false; } meshDocument.setBusy(true); ret = iFilter->applyFilter( action, meshDocument, pairold->pair.second, filterCallBack); meshDocument.setBusy(false); delete iFilter->glContext; } else { MeshLabXMLFilterContainer cont = PM.stringXMLFilterMap[ fname]; MLXMLPluginInfo* info = cont.xmlInfo; MeshLabFilterInterface* cppfilt = cont.filterInterface; try { if (cppfilt != NULL) { cppfilt->setLog(&log); Env env; env.loadMLScriptEnv(meshDocument,PM); XMLFilterNameParameterValuesPair* xmlfilt = reinterpret_cast(*ii); QMap& parmap = xmlfilt->pair.second; for(QMap::const_iterator it = parmap.constBegin();it != parmap.constEnd();++it) env.insertExpressionBinding(it.key(),it.value()); EnvWrap envwrap(env); MLXMLPluginInfo::XMLMapList params = info->filterParameters(fname); for(int i = 0; i < params.size(); ++i) { MLXMLPluginInfo::XMLMap& parinfo = params[i]; //if this is a mesh parameter and the index is valid if(parinfo[MLXMLElNames::paramType] == MLXMLElNames::meshType) { QString& parnm = parinfo[MLXMLElNames::paramName]; MeshModel* meshmdl = envwrap.evalMesh(parnm); if( meshmdl == NULL) { //parnm is associated with , printf("Meshes loaded: %i, meshes asked for: %i \n", meshDocument.size(), envwrap.evalInt(parnm) ); printf("One of the filters in the script needs more meshes than you have loaded.\n"); return false; } } } QGLWidget wid; cppfilt->glContext = new QGLContext(QGLFormat::defaultFormat(),wid.context()->device()); bool created = cppfilt->glContext->create(); if ((!created) || (!cppfilt->glContext->isValid())) { fprintf(fp,"A valid GLContext is required by the filter to work.\n"); return false; } //WARNING!!!!!!!!!!!! /* 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*/ meshDocument.setBusy(true); ret = cppfilt->applyFilter( fname, meshDocument, envwrap, filterCallBack ); meshDocument.setBusy(false); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delete cppfilt->glContext; } else throw MeshLabException("WARNING! The MeshLab Script System is able to manage just the C++ XML filters."); } catch (MeshLabException& e) { meshDocument.Log.Log(GLLogStream::WARNING,e.what()); } } QStringList logOutput; log.print(logOutput); foreach(QString logEntry, logOutput) fprintf(fp,"%s\n",qPrintable(logEntry)); if(!ret) { fprintf(fp,"Problem with filter: %s\n",qPrintable(fname)); return false; } } return true; } private: PluginManager PM; RichParameterSet defaultGlobal; }; namespace commandline { const char inproject('p'); const char outproject('w'); const char overwrite('v'); const char inputmeshes('i'); const char outputmesh('o'); const char mask('m'); const char vertex('v'); const char face('f'); const char wedge('w'); const char color('c'); const char flags('f'); const char normal('n'); const char quality('q'); const char texture('t'); const char log('l'); const char dump('d'); const char script('s'); void usage() { QFile docum(":/meshlabserver.txt"); if (!docum.open(QIODevice::ReadOnly)) { printf("MeshLabServer was not able to locate meshlabserver.txt file. The program will be closed\n"); exit(-1); } QString help(docum.readAll()); printf("\nUsage:\n%s",qPrintable(help)); docum.close(); } QString optionValueExpression(const char cmdlineopt) { return QString ("-" + QString(cmdlineopt) + "\\s+\\S+"); } QString outputmeshExpression() { return optionValueExpression(outputmesh) + "(\\s+-" + QString(mask) + "(\\s+(" + QString(vertex) + "|" + QString(face) + "|" + QString(wedge) + ")+(" + QString(color) + "|" + QString(quality) + "|" + QString(flags) + "|" + QString(normal) + "|" + QString(texture) + ")+)+)?"; } bool validateCommandLine(const QString& str) { QString logstring("(" + optionValueExpression(log) + "\\s+" + optionValueExpression(dump) + "|" + optionValueExpression(dump) + "\\s+" + optionValueExpression(log) + "|" + optionValueExpression(dump) + "|" + optionValueExpression(log) + ")"); //QString remainstring("(" + optionValueExpression(inproject) + "|" + optionValueExpression(inputmeshes,true) + ")" + "(\\s+" + optionValueExpression(inproject) + "|\\s+" + optionValueExpression(inputmeshes,true) + ")*(\\s+" + optionValueExpression(outproject) + "|\\s+" + optionValueExpression(script) + "|\\s+" + outputmeshExpression() + ")*"); QString arg("(" + optionValueExpression(inproject) + "|" + optionValueExpression(inputmeshes) + "|" + optionValueExpression(outproject) + "(\\s+-v)?" + "|" + optionValueExpression(script) + "|" + outputmeshExpression() + ")"); QString args("(" + arg + ")(\\s+" + arg + ")*"); QString completecommandline("(" + logstring + "|" + logstring + "\\s+" + args + "|" + args + ")"); QRegExp completecommandlineexp(completecommandline); completecommandlineexp.indexIn(str); QString rr = completecommandlineexp.cap(); return (completecommandlineexp.matchedLength() == str.size()); } } struct OutFileMesh { QString filename; int mask; }; struct OutProject { QString filename; bool overwrite; }; int main(int argc, char *argv[]) { FILE* logfp = stdout; FILE* dumpfp = NULL; MeshLabApplication app(argc, argv); MeshLabServer server; if(argc == 1) { commandline::usage(); system("pause"); exit(-1); } QStringList scriptfiles; QList outmeshlist; QList outprojectfiles; QString cmdline; for(int ii = 1;ii < argc;++ii) cmdline = cmdline + argv[ii] + " "; if (!commandline::validateCommandLine(cmdline.trimmed())) { printf("CommandLine Syntax Error: please refer to the following documentation for a complete list of the MeshLabServer parameters.\n"); commandline::usage(); system("pause"); exit(-1); } printf("Loading Plugins:\n"); server.loadPlugins(); MeshDocument meshDocument; int i = 1; while(i < argc) { QString tmp = argv[i]; switch(argv[i][1]) { case commandline::inproject : { if (((i+1) < argc) && (argv[i+1][0] != '-')) { QFileInfo finfo(argv[i+1]); QString inputproject = finfo.absoluteFilePath(); if (finfo.completeSuffix().toLower() != "mlp") { fprintf(logfp,"Project %s is not a valid \'mlp\' file format. MeshLabServer application will exit.\n",qPrintable(inputproject)); exit(-1); } bool opened = server.openProject(meshDocument,inputproject); if (!opened) { fprintf(logfp,"MeshLab Project %s has not been correctly opened. MeshLabServer application will exit.\n",qPrintable(inputproject)); exit(-1); } else fprintf(logfp,"MeshLab Project %s has been loaded.\n",qPrintable(inputproject)); ++i; } else { fprintf(logfp,"Missing project name. MeshLabServer application will exit.\n"); exit(-1); } ++i; break; } case commandline::outproject : { if (((i+1) < argc) && (argv[i+1][0] != '-')) { QFileInfo finfo(argv[i+1]); OutProject pr; pr.overwrite = false; pr.filename = finfo.absoluteFilePath(); if (finfo.completeSuffix().toLower() != "mlp") { fprintf(logfp,"Project %s is not a valid \'mlp\' file format. Output file will be renamed as %s.mlp .\n",qPrintable(pr.filename),qPrintable(pr.filename + ".mlp")); pr.filename += ".mlp"; } ++i; if (((i + 1) < argc) && (QString(argv[i+1]) == QString("-" + commandline::overwrite))) { pr.overwrite = true; ++i; } outprojectfiles << pr; } ++i; break; } case commandline::inputmeshes : { while( ((i+1) < argc) && argv[i+1][0] != '-') { QFileInfo info(argv[i+1]); //now add it to the document MeshModel* mmod = meshDocument.addNewMesh(info.absoluteFilePath(),""); if (mmod == NULL) { fprintf(logfp,"It was not possible to add new mesh %s to MeshLabServer. The program will exit\n",qPrintable(info.absoluteFilePath())); exit(-1); } bool opened = server.importMesh(*mmod, info.absoluteFilePath(),logfp); if (!opened) { fprintf(logfp,"It was not possible to import mesh %s into MeshLabServer. The program will exit\n ",qPrintable(info.absoluteFilePath())); exit(-1); } fprintf(logfp,"Mesh %s loaded has %i vn %i fn\n", qPrintable(info.absoluteFilePath()), mmod->cm.vn, mmod->cm.fn); i++; } i++; break; } case commandline::outputmesh : { QString fileout; int mask = 0; OutFileMesh outfl; if( ((i+1) < argc) && argv[i+1][0] != '-') { QFileInfo info(argv[i+1]); outfl.filename = info.absoluteFilePath(); fprintf(logfp,"output mesh %s\n", qPrintable(outfl.filename)); i++; } if (((i + 1) < argc) && (QString(argv[i+1]) == (QString("-") + commandline::mask))) { i = i + 2; do { switch (argv[i][0]) { case commandline::vertex : { switch (argv[i][1]) { case commandline::color : i++; fprintf(logfp,"vertex color, " ); mask |= vcg::tri::io::Mask::IOM_VERTCOLOR; break; case commandline::flags : i++; fprintf(logfp,"vertex flags, " ); mask |= vcg::tri::io::Mask::IOM_VERTFLAGS; break; case commandline::normal : i++; fprintf(logfp,"vertex normals, " ); mask |= vcg::tri::io::Mask::IOM_VERTNORMAL; break; case commandline::quality : i++; fprintf(logfp,"vertex quality, " ); mask |= vcg::tri::io::Mask::IOM_VERTQUALITY; break; case commandline::texture : i++; fprintf(logfp,"vertex tex coords, "); mask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD; break; default : i++; fprintf(logfp,"WARNING: unknowns per VERTEX attribute '%s'",argv[i+1]);break; } break; } case commandline::face : { switch (argv[i][1]) { case commandline::color : i++; fprintf(logfp,"face color, " ); mask |= vcg::tri::io::Mask::IOM_FACECOLOR; break; case commandline::flags : i++; fprintf(logfp,"face flags, " ); mask |= vcg::tri::io::Mask::IOM_FACEFLAGS; break; case commandline::normal : i++; fprintf(logfp,"face normals, "); mask |= vcg::tri::io::Mask::IOM_FACENORMAL; break; case commandline::quality : i++; fprintf(logfp,"face quality, "); mask |= vcg::tri::io::Mask::IOM_FACEQUALITY; break; default : i++; fprintf(logfp,"WARNING: unknowns per FACE attribute '%s'",argv[i+1]);break; } break; } case commandline::wedge : { switch (argv[i][1]) { case commandline::color : i++; fprintf(logfp,"wedge color, " ); mask |= vcg::tri::io::Mask::IOM_WEDGCOLOR; break; case commandline::normal : i++; fprintf(logfp,"wedge normals, " ); mask |= vcg::tri::io::Mask::IOM_WEDGNORMAL; break; case commandline::texture : i++; fprintf(logfp,"wedge tex coords, "); mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;break; default : i++; fprintf(logfp,"WARNING: unknowns per WEDGE attribute '%s'",argv[i+1]);break; } break; } default : i++; fprintf(logfp,"WARNING: unknowns attribute '%s'",argv[i]);break; } }while (((i) < argc) && (argv[i][0] != '-')); } else ++i; outfl.mask = mask; outmeshlist << outfl; break; } case commandline::script : { QFileInfo fi(argv[i+1]); QString scriptName = fi.absoluteFilePath(); scriptfiles << scriptName; i += 2; break; } case commandline::log : { //freopen redirect both std::cout and printf. Now I'm quite sure i will get everything the plugins will print in the standard output (i hope no one used std::cerr...) logfp = fopen(argv[i+1],"a"); if (logfp == NULL) printf("Error occurred opening file %s. It's not possible to redirect the output from the stdout\n",argv[i+1]); else printf("Log is saved in %s\n", argv[i+1]); i += 2; break; } case commandline::dump : { dumpfp = fopen(argv[i+1],"w"); if (dumpfp == NULL) fprintf(logfp,"Error occurred opening file %s. It's not possible to redirect the output from the stdout\n",argv[i+1]); else { server.dumpPluginInfoDoxygen(dumpfp); fclose(dumpfp); fprintf(logfp,"Dump file is saved in %s\n", argv[i+1]); } i+=2; break; } default: { printf("Something bad happened parsing the document. String %s\n",qPrintable(argv[i])); system("pause"); exit(-1); } } } for(int ii = 0; ii < scriptfiles.size();++ii) { fprintf(logfp,"Apply FilterScript: '%s'\n",qPrintable(scriptfiles[ii])); bool returnValue = server.script(meshDocument, scriptfiles[ii],logfp); if(!returnValue) { fprintf(logfp,"Failed to apply script file %s\n",qPrintable(scriptfiles[ii])); exit(-1); } } for(int ii = 0;ii < outprojectfiles.size();++ii) { QString outfilemiddlename = ""; if (!outprojectfiles[ii].overwrite) { outfilemiddlename = "_out"; if (ii >= 1) outfilemiddlename += QString::number(ii); } bool saved = server.saveProject(meshDocument,outprojectfiles[ii].filename,outfilemiddlename); if (saved) fprintf(logfp,"Output project has been saved in %s.\n",qPrintable(outprojectfiles[ii].filename)); else { fprintf(logfp,"Project %s has not been correctly saved in. MeshLabServer Application will exit.\n",qPrintable(outprojectfiles[ii].filename)); exit(-1); } } for(int ii = 0;ii < outmeshlist.size();++ii) { if (meshDocument.mm() != NULL) { bool exported = server.exportMesh(meshDocument.mm(), outmeshlist[ii].mask, outmeshlist[ii].filename,logfp); if (exported) fprintf(logfp,"Mesh %s saved as %s (%i vn %i fn)\n", qPrintable(meshDocument.mm()->fullName()), qPrintable(outmeshlist[ii].filename), meshDocument.mm()->cm.vn, meshDocument.mm()->cm.fn); else fprintf(logfp,"Output mesh %s has NOT been saved\n",qPrintable(outmeshlist[ii].filename)); } else fprintf(logfp,"Invalid current mesh. Output mesh %s will not be saved\n",qPrintable(outmeshlist[ii].filename)); } if((logfp != NULL) && (logfp != stdout)) fclose(logfp); return 0; }