/**************************************************************************** * MeshLab o o * * An extendible mesh processor o o * * _ O _ * * Copyright(C) 2005, 2009 \/)\/ * * 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 __VCGLIB_EXPORTERIDTF #define __VCGLIB_EXPORTERIDTF #include #include #include #include #include #include #include #include #include #include class TextUtility { public: template static std::string nmbToStr(NUMERICTYPE n) { std::stringstream ss; ss.setf(std::ios::fixed); ss << n; ss.setf(std::ios::scientific); return ss.str(); } }; class Output_File { public: Output_File(const std::string& file) :_file() { _file.open(file.c_str(),std::ios::out); } void write(unsigned int tabl,const std::string& st) { std::string tmp; for(unsigned int ii = 0;ii < tabl;++ii) tmp += '\t'; _file << tmp << st << std::endl; } ~Output_File() { _file.close(); } private: std::ofstream _file; std::string _tab; }; #include #include #include #include namespace vcg { namespace tri { namespace io { namespace QtUtilityFunctions { static void splitFilePath(const QString& filepath,QStringList& trim_path) { QString file_uniformed = filepath; file_uniformed.replace(QString("\\"),QString("/")); trim_path = file_uniformed.split("/"); } static QString fileNameFromTrimmedPath(const QStringList& file_path) { if (file_path.size() > 0) return file_path.at(file_path.size() - 1); else return QString(); } static QString fileNameFromPath(const QString& filepath) { QStringList list; splitFilePath(filepath,list); return fileNameFromTrimmedPath(list); } static QString pathWithoutFileName(const QString& filepath) { QString tmp(filepath); tmp.remove(fileNameFromPath(filepath)); return tmp; } static QString fileExtension(const QString& filepath) { QStringList trim_list; splitFilePath(filepath,trim_list); QString file = fileNameFromTrimmedPath(trim_list); trim_list = file.split("."); return trim_list.at(trim_list.size() - 1); } } class TGA_Exporter { public: struct TGAHeader { unsigned char identsize; unsigned char colourmaptype; unsigned char imagetype; unsigned char colormapspecs[5]; short xstart; short ystart; short width; short height; unsigned char bits; unsigned char descriptor; }; static void convert(const QString& outfile,const QImage& im) { TGAHeader tga; tga.identsize = 0; tga.colourmaptype = 0; tga.imagetype = 2; memset(tga.colormapspecs,0,5); tga.xstart = (short) im.offset().x(); tga.ystart = (short) im.offset().y(); tga.height = (short) im.height(); tga.width = (short) im.width(); //QString moutfile = QString("C:/Users/Guido/AppData/Local/Temp/duckCM.tga"); QFile file(qPrintable(outfile)); file.setPermissions(QFile::WriteOther); file.open(QIODevice::WriteOnly); QString err = file.errorString(); //bool val = file.failbit; unsigned char* tmpchan; int totbyte; if (im.hasAlphaChannel()) { //is a 8-digits binary number code // always 0 0 | mirroring | bits //(future uses)| image | for alpha-channel //-------------------------------------------- // 7 6 | 5 4 | 3 2 1 0 //-------------------------------------------- // 0 0 | 1 0 | 1 0 0 0 tga.descriptor = (char) 40; tga.bits = (char) 32; } else { //is a 8-digits binary number code // always 0 0 | mirroring | bits //(future uses)| image | for alpha-channel //-------------------------------------------- // 7 6 | 5 4 | 3 2 1 0 //-------------------------------------------- // 0 0 | 1 0 | 0 0 0 0 tga.descriptor = (char) 32; tga.bits = (char) 24; } totbyte = tga.height * tga.width * (tga.bits / 8); if (im.hasAlphaChannel()) tmpchan = const_cast(im.bits()); else { tmpchan = new unsigned char[totbyte]; int ii = 0; while(ii < totbyte) { tmpchan[ii] = const_cast(im.bits())[ii + (ii/3)]; ++ii; } } file.write((char *) &tga,qint64(sizeof(tga))); file.write(reinterpret_cast(tmpchan),qint64(totbyte)); file.close(); } template static void convertTexturesFiles(SaveMeshType& m,const QString& file_path,QStringList& conv_file) { for(unsigned int ii = 0; ii < m.textures.size(); ++ii) { QString qtmp(m.textures[ii].c_str()); QString ext = QtUtilityFunctions::fileExtension(qtmp); QString filename = QtUtilityFunctions::fileNameFromPath(qtmp); if (ext.toLower() != "tga") { QImage img(qtmp); QString stmp; if ((file_path.at(file_path.length() - 1) != '/') || (file_path.at(file_path.length() - 1) != '\\')) stmp = file_path + QString("/"); else stmp = file_path; filename = stmp + filename.remove(ext) + "tga"; m.textures[ii] = filename.toStdString(); TGA_Exporter::convert(filename,img); conv_file.push_back(filename); } } } static void removeConvertedTexturesFiles(const QStringList& conv_file) { for(QStringList::size_type ii = 0;ii < conv_file.size();++ii) { QDir dir(QtUtilityFunctions::pathWithoutFileName(conv_file[ii])); dir.remove(QtUtilityFunctions::fileNameFromPath(conv_file[ii])); } } }; template class ExporterIDTF { public: typedef typename SaveMeshType::VertexPointer VertexPointer; typedef typename SaveMeshType::ScalarType ScalarType; typedef typename SaveMeshType::VertexType VertexType; typedef typename SaveMeshType::FaceType FaceType; typedef typename SaveMeshType::ConstVertexIterator ConstVertexIterator; typedef typename SaveMeshType::VertexIterator VertexIterator; typedef typename SaveMeshType::FaceIterator FaceIterator; typedef typename SaveMeshType::ConstFaceIterator ConstFaceIterator; typedef typename SaveMeshType::CoordType CoordType; enum IDTFError { E_NOERROR // 0 }; static const char *ErrorMsg(int error) { static const char * dae_error_msg[] = { "No errors" }; if(error>0 || error<0) return "Unknown error"; else return dae_error_msg[error]; }; static QStringList convertInTGATextures(SaveMeshType& m,const QString& path,QStringList& textures_to_be_restored) { //if there are textures file that aren't in tga format I have to convert them //I maintain the converted file name (i.e. file_path + originalname without extension + tga) in mesh.textures but I have to revert to the original ones //before the function return. for(unsigned int ii = 0; ii < m.textures.size();++ii) textures_to_be_restored.push_back(m.textures[ii].c_str()); //tmp vector to save the tga created files that should be deleted. QStringList convfile; vcg::tri::io::TGA_Exporter::convertTexturesFiles(m,path,convfile); return convfile; } static void removeConvertedTGATextures(const QStringList& convfile) { //if some tga files have been created I have to delete them vcg::tri::io::TGA_Exporter::removeConvertedTexturesFiles(convfile); } static void restoreConvertedTextures(SaveMeshType& mesh_with_textures_to_be_restored,const QStringList& textures_to_be_restored) { mesh_with_textures_to_be_restored.textures.clear(); for(QStringList::ConstIterator it = textures_to_be_restored.begin();it != textures_to_be_restored.end();++it) mesh_with_textures_to_be_restored.textures.push_back(it->toStdString()); } static int Save(SaveMeshType& m,const char* file,const int mask) { Output_File idtf(file); idtf.write(0,"FILE_FORMAT \"IDTF\""); idtf.write(0,"FORMAT_VERSION 100\n"); idtf.write(0,"NODE \"MODEL\" {"); idtf.write(1,"NODE_NAME \"VcgMesh01\""); idtf.write(1,"PARENT_LIST {"); idtf.write(2,"PARENT_COUNT 1"); idtf.write(2,"PARENT 0 {"); idtf.write(3,"PARENT_NAME \"\""); idtf.write(3,"PARENT_TM {"); idtf.write(4,"1.000000 0.000000 0.000000 0.000000"); idtf.write(4,"0.000000 1.000000 0.000000 0.000000"); idtf.write(4,"0.000000 0.000000 1.000000 0.000000"); idtf.write(4,"0.000000 0.000000 0.000000 1.000000"); idtf.write(3,"}"); idtf.write(2,"}"); idtf.write(1,"}"); idtf.write(1,"RESOURCE_NAME \"MyVcgMesh01\""); idtf.write(0,"}"); if ((mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) | (mask & vcg::tri::io::Mask::IOM_VERTCOLOR) | (mask & vcg::tri::io::Mask::IOM_FACECOLOR)) { idtf.write(0,""); idtf.write(0,"RESOURCE_LIST \"SHADER\" {"); idtf.write(1,"RESOURCE_COUNT " + TextUtility::nmbToStr(m.textures.size())); for(unsigned int ii = 0; ii < m.textures.size(); ++ii) { idtf.write(1,"RESOURCE " + TextUtility::nmbToStr(ii) + " {"); idtf.write(2,"RESOURCE_NAME \"ModelShader" + TextUtility::nmbToStr(ii) +"\""); std::string vertcol; if (mask & vcg::tri::io::Mask::IOM_VERTCOLOR) vertcol = "TRUE"; else vertcol = "FALSE"; idtf.write(2,"ATTRIBUTE_USE_VERTEX_COLOR \"" + vertcol + "\""); idtf.write(2,"SHADER_MATERIAL_NAME \"Mat01\""); size_t texcount = 0; if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) texcount = m.textures.size(); idtf.write(2,"SHADER_ACTIVE_TEXTURE_COUNT " + TextUtility::nmbToStr(texcount)); if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) { idtf.write(2,"SHADER_TEXTURE_LAYER_LIST {"); idtf.write(3,"TEXTURE_LAYER 0 {"); idtf.write(4,"TEXTURE_NAME \"Texture" + TextUtility::nmbToStr(ii) +"\""); idtf.write(3,"}"); idtf.write(2,"}"); } idtf.write(1,"}"); } idtf.write(0,"}"); idtf.write(0,""); } if ((mask & Mask::IOM_WEDGTEXCOORD) | (mask & vcg::tri::io::Mask::IOM_VERTCOLOR) | (mask & vcg::tri::io::Mask::IOM_FACECOLOR)) { idtf.write(0,"RESOURCE_LIST \"MATERIAL\" {"); idtf.write(1,"RESOURCE_COUNT 1"); idtf.write(1,"RESOURCE 0 {"); idtf.write(2,"RESOURCE_NAME \"Mat01\""); idtf.write(2,"MATERIAL_AMBIENT 0.2 0.2 0.2"); idtf.write(2,"MATERIAL_DIFFUSE 0.8 0.8 0.8"); idtf.write(2,"MATERIAL_SPECULAR 0.0 0.0 0.0"); idtf.write(2,"MATERIAL_EMISSIVE 0.0 0.0 0.0"); idtf.write(2,"MATERIAL_REFLECTIVITY 0.000000"); idtf.write(2,"MATERIAL_OPACITY 1.000000"); idtf.write(1,"}"); idtf.write(0,"}"); idtf.write(0,""); if ((mask & Mask::IOM_WEDGTEXCOORD)) { idtf.write(0,"RESOURCE_LIST \"TEXTURE\" {"); idtf.write(1,"RESOURCE_COUNT " + TextUtility::nmbToStr(m.textures.size())); for(unsigned int ii = 0; ii < m.textures.size();++ii) { idtf.write(1,"RESOURCE " + TextUtility::nmbToStr(ii) + " {"); idtf.write(2,"RESOURCE_NAME \"Texture" + TextUtility::nmbToStr(ii) + "\""); idtf.write(2,"TEXTURE_PATH \"" + m.textures[ii] + "\""); idtf.write(1,"}"); } idtf.write(0,"}"); } } idtf.write(0,""); idtf.write(0,"RESOURCE_LIST \"MODEL\" {"); idtf.write(1,"RESOURCE_COUNT 1"); idtf.write(1,"RESOURCE 0 {"); idtf.write(2,"RESOURCE_NAME \"MyVcgMesh01\""); idtf.write(2,"MODEL_TYPE \"MESH\""); idtf.write(2,"MESH {"); idtf.write(3,"FACE_COUNT " + TextUtility::nmbToStr(m.face.size())); idtf.write(3,"MODEL_POSITION_COUNT " + TextUtility::nmbToStr(m.vert.size())); idtf.write(3,"MODEL_NORMAL_COUNT " + TextUtility::nmbToStr(m.face.size() * 3)); if ((mask & vcg::tri::io::Mask::IOM_VERTCOLOR) | (mask & vcg::tri::io::Mask::IOM_FACECOLOR)) idtf.write(3,"MODEL_DIFFUSE_COLOR_COUNT " + TextUtility::nmbToStr(m.face.size() * 3)); else idtf.write(3,"MODEL_DIFFUSE_COLOR_COUNT 0"); idtf.write(3,"MODEL_SPECULAR_COLOR_COUNT 0"); if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) idtf.write(3,"MODEL_TEXTURE_COORD_COUNT " + TextUtility::nmbToStr(m.face.size() * 3)); else idtf.write(3,"MODEL_TEXTURE_COORD_COUNT 0"); idtf.write(3,"MODEL_BONE_COUNT 0"); size_t mod_sha; if (m.textures.size() == 0) mod_sha = 1; else mod_sha = m.textures.size(); idtf.write(3,"MODEL_SHADING_COUNT " + TextUtility::nmbToStr(mod_sha)); idtf.write(3,"MODEL_SHADING_DESCRIPTION_LIST {"); unsigned int hh = 0; do { idtf.write(4,"SHADING_DESCRIPTION " + TextUtility::nmbToStr(hh) + " {"); if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) { idtf.write(5,"TEXTURE_LAYER_COUNT 1"); idtf.write(5,"TEXTURE_COORD_DIMENSION_LIST {"); idtf.write(6,"TEXTURE_LAYER 0 DIMENSION: 2"); idtf.write(5,"}"); idtf.write(5,"SHADER_ID 0"); } else { idtf.write(5,"TEXTURE_LAYER_COUNT 0"); idtf.write(5,"SHADER_ID 0"); } idtf.write(4,"}"); ++hh; } while(hh < m.textures.size()); idtf.write(3,"}"); idtf.write(3,"MESH_FACE_POSITION_LIST {"); for(ConstFaceIterator fit = m.face.begin();fit != m.face.end();++fit) { idtf.write(4,TextUtility::nmbToStr(fit->cV(0) - &(*m.vert.begin())) + " " + TextUtility::nmbToStr(fit->cV(1) - &(*m.vert.begin())) + " " + TextUtility::nmbToStr(fit->cV(2) - &(*m.vert.begin()))); } idtf.write(3,"}"); idtf.write(3,"MESH_FACE_NORMAL_LIST {"); unsigned int nn = 0; for(ConstFaceIterator fit = m.face.begin();fit != m.face.end();++fit) { idtf.write(4,TextUtility::nmbToStr(nn) + " " + TextUtility::nmbToStr(nn + 1) + " " + TextUtility::nmbToStr(nn + 2)); nn += 3; } idtf.write(3,"}"); idtf.write(3,"MESH_FACE_SHADING_LIST {"); for(FaceIterator fit = m.face.begin();fit != m.face.end();++fit) { unsigned int texind = 0; if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) texind = fit->WT(0).N(); idtf.write(4,TextUtility::nmbToStr(texind)); } idtf.write(3,"}"); if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) { idtf.write(3,"MESH_FACE_TEXTURE_COORD_LIST {"); for(unsigned int ii = 0; ii < m.face.size();++ii) { idtf.write(4,"FACE " + TextUtility::nmbToStr(ii) + " {"); idtf.write(5,"TEXTURE_LAYER 0 TEX_COORD: " + TextUtility::nmbToStr(ii * 3) + " " + TextUtility::nmbToStr(ii * 3 + 1) + " " + TextUtility::nmbToStr(ii * 3 + 2)); idtf.write(4,"}"); } idtf.write(3,"}"); } if ((mask & vcg::tri::io::Mask::IOM_VERTCOLOR) | (mask & vcg::tri::io::Mask::IOM_FACECOLOR)) { idtf.write(3,"MESH_FACE_DIFFUSE_COLOR_LIST {"); nn = 0; for(FaceIterator fit = m.face.begin();fit != m.face.end();++fit) { idtf.write(4,TextUtility::nmbToStr(nn) + " " + TextUtility::nmbToStr(nn + 1) + " " + TextUtility::nmbToStr(nn + 2)); nn += 3; } idtf.write(3,"}"); } idtf.write(3,"MODEL_POSITION_LIST {"); //vcg::tri::UpdateBounding::Box(m); //ScalarType diag = m.bbox.Diag(); //CoordType center = m.bbox.Center(); for(ConstVertexIterator vit = m.vert.begin();vit != m.vert.end();++vit) { CoordType tmp = vit->P();// - center);// /diag; idtf.write(4,TextUtility::nmbToStr(-tmp.X()) + " " + TextUtility::nmbToStr(tmp.Z()) + " " + TextUtility::nmbToStr(tmp.Y())); } idtf.write(3,"}"); idtf.write(3,"MODEL_NORMAL_LIST {"); for(FaceIterator fitn = m.face.begin();fitn != m.face.end();++fitn) { for(unsigned int ii = 0;ii < 3;++ii) { fitn->N().Normalize(); idtf.write(4,TextUtility::nmbToStr(-fitn->N().X()) + " " + TextUtility::nmbToStr(fitn->N().Z()) + " " + TextUtility::nmbToStr(fitn->N().Y())); } } idtf.write(3,"}"); if ((mask & vcg::tri::io::Mask::IOM_VERTCOLOR) | (mask & vcg::tri::io::Mask::IOM_FACECOLOR)) { idtf.write(3,"MODEL_DIFFUSE_COLOR_LIST {"); //ScalarType diag = m.bbox.Diag(); //CoordType center = m.bbox.Center(); for(FaceIterator vit = m.face.begin();vit != m.face.end();++vit) { for (unsigned int ii =0; ii <3;++ii) { vcg::Color4b cc; if (mask & vcg::tri::io::Mask::IOM_VERTCOLOR) cc = vit->V(ii)->C(); else cc = vit->C(); idtf.write(4,TextUtility::nmbToStr(float(cc.X()) / 255.0f) + " " + TextUtility::nmbToStr(float(cc.Y()) / 255.0f) + " " + TextUtility::nmbToStr(float(cc.Z()) / 255.0f) + " " + TextUtility::nmbToStr(float(cc.W()) / 255.0f)); } } idtf.write(3,"}"); } if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) { idtf.write(3,"MODEL_TEXTURE_COORD_LIST {"); for(FaceIterator fitn = m.face.begin();fitn != m.face.end();++fitn) { for(unsigned int ii = 0;ii < 3;++ii) { idtf.write(4,TextUtility::nmbToStr(fitn->WT(ii).U()) + " " + TextUtility::nmbToStr(-fitn->WT(ii).V()) + " " + TextUtility::nmbToStr(0.0f) + " " + TextUtility::nmbToStr(0.0f)); } } idtf.write(3,"}"); } idtf.write(2,"}"); idtf.write(1,"}"); idtf.write(0,"}"); //if (!(mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) & (mask & vcg::tri::io::Mask::IOM_VERTCOLOR) | (mask & vcg::tri::io::Mask::IOM_FACECOLOR)) //{ // idtf.write(0,"RESOURCE_LIST \"SHADER\" {"); // idtf.write(1,"RESOURCE_COUNT 1"); // idtf.write(1,"RESOURCE 0 {"); // idtf.write(2,"RESOURCE_NAME \"VcgMesh010\""); // // //WARNING! IF VERTEX COLOR AND FACE COLOR ARE BOTH CHECKED THE FILTER SAVE ONLY VERTEX COLOR! THIS IS A DESIGN CHOICE A NOT A BUG! // std::string vertcol; // if (mask & vcg::tri::io::Mask::IOM_VERTCOLOR) // vertcol = "TRUE"; // else // vertcol = "FALSE"; // // idtf.write(2,"ATTRIBUTE_USE_VERTEX_COLOR \"" + vertcol + "\""); // idtf.write(2,"SHADER_MATERIAL_NAME \"Mat01\""); // idtf.write(2,"SHADER_ACTIVE_TEXTURE_COUNT 0"); // idtf.write(1,"}"); // idtf.write(0,"}"); //} if ((mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) | (mask & vcg::tri::io::Mask::IOM_VERTCOLOR) | (mask & vcg::tri::io::Mask::IOM_FACECOLOR)) { idtf.write(0,""); idtf.write(0,"MODIFIER \"SHADING\" {"); idtf.write(1,"MODIFIER_NAME \"VcgMesh01\""); idtf.write(1,"PARAMETERS {"); idtf.write(2,"SHADER_LIST_COUNT " + TextUtility::nmbToStr(m.textures.size())); idtf.write(2,"SHADING_GROUP {"); for(unsigned int ii = 0; ii < m.textures.size();++ii) { idtf.write(3,"SHADER_LIST " + TextUtility::nmbToStr(ii) + "{"); idtf.write(4,"SHADER_COUNT 1"); idtf.write(4,"SHADER_NAME_LIST {"); idtf.write(5,"SHADER 0 NAME: \"ModelShader" + TextUtility::nmbToStr(ii) + "\""); idtf.write(4,"}"); idtf.write(3,"}"); } idtf.write(2,"}"); idtf.write(1,"}"); idtf.write(0,"}"); } return E_NOERROR; } static int GetExportMaskCapability() { int capability = 0; //vert capability |= vcg::tri::io::Mask::IOM_VERTNORMAL; capability |= vcg::tri::io::Mask::IOM_VERTCOLOR; //face capability |= vcg::tri::io::Mask::IOM_FACECOLOR; ////wedg capability |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD; capability |= vcg::tri::io::Mask::IOM_WEDGNORMAL; return capability; } }; } } } #endif