diff --git a/src/meshlabplugins/filter_texture/filter_texture.cpp b/src/meshlabplugins/filter_texture/filter_texture.cpp index 4150d2a57..9cf213444 100644 --- a/src/meshlabplugins/filter_texture/filter_texture.cpp +++ b/src/meshlabplugins/filter_texture/filter_texture.cpp @@ -26,10 +26,11 @@ $Log: samplefilter.cpp,v $ ****************************************************************************/ #include +#include +#include #include #include -#include #include #include @@ -75,7 +76,7 @@ const PluginInfo &FilterTexturePlugin::pluginInfo() static PluginInfo ai; ai.Date=tr(__DATE__); ai.Version = tr("1.0"); - ai.Author = ("imran"); + ai.Author = ("Imran Akbar"); return ai; } @@ -86,7 +87,7 @@ const PluginInfo &FilterTexturePlugin::pluginInfo() // - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -void FilterTexturePlugin::initParameterSet(QAction *action,MeshDocument & /*m*/, FilterParameterSet & parlst) +void FilterTexturePlugin::initParameterSet(QAction *action,MeshDocument &m, FilterParameterSet &parlst) //void ExtraSamplePlugin::initParList(QAction *action, MeshModel &m, FilterParameterSet &parlst) { switch(ID(action)) { @@ -96,9 +97,69 @@ void FilterTexturePlugin::initParameterSet(QAction *action,MeshDocument & /*m*/, // The Real Core Function doing the actual mesh processing. // Move Vertex of a random quantity -bool applyFilter(QAction *filter, MeshModel &, FilterParameterSet & /*parent*/, vcg::CallBackPos * cb) +bool applyFilter(QAction *filter, MeshModel &m, FilterParameterSet &par, vcg::CallBackPos * cb) { - return true; + //this function takes every texture in the model and creates a single texture composed of all the individual textures - necessary before calling the Quadric-with-texture filter + //QT has support for all the major image formats (GIF/JPEG/PNG/BMP/TIFF) - though you need to compile QT with -qt-gif to get GIF support (on Ubuntu the package for qt already has this - check your /usr/share/qt4/plugins/imageformats folder) + //can't do any file-format-specific calls, this has to be generalizable to any model + //the general 'packing problem' is NP-complete, so you have to use a heuristic or genetic algorithm to get an approximate answer + //this is not an optimal packing - we are not rotating textures, for example + //TODO:how read image data from images already loaded into Meshlab, to prevent from opening files again? + //TODO:improve atlas-generation algorithm so it tries to minimize whitespace (though saved PNG files don't increase in file size due to whitespace) + int totalWidth=0, totalHeight=0; + int numTextures = m.cm.textures.size(); + if ((numTextures == 0)||(numTextures == 1)) + return false;//return false if numTextures == 0 or 1 (no need for an atlas) + QPixmap images[numTextures];//array of images + for (unsigned textureIdx = 0; textureIdx < numTextures; ++textureIdx)//iterate through textures, loading each + { + images[textureIdx] = QPixmap(m.cm.textures[textureIdx].c_str());//loads image, if fails is a null image. will guess extension from file name + totalWidth += images[textureIdx].width();//get total x dimensions + totalHeight += images[textureIdx].height();//get total y dimensions + } + + std::map Xoffset;//stl map mapping texture indeces to new U offsets + std::map Yoffset;//stl map mapping texture indeces to new V offsets + //query with conversions[integer variable] (will return null array if no match?), or .find + //set with conversions.insert + + int dimension; + totalWidth > totalHeight ? dimension = totalWidth : dimension = totalHeight;//if/else shortcut: if totalWidth is greater than totalHeight, assign dimension to totalWidth, otherwise totalHeight + QImage atlas = QImage(dimension, dimension, QImage::Format_ARGB32);//make a square texture of that dimension + + //insert textures one after another in one row, starting at 0,0 + QPainter painter(&atlas); + int currentX=0; //currentY=0; + for (int index=0; indexWT(0).N();//fit->cWT the 'c' is for const + if (mat!=-1) + fit->WT(0).N() = 0;//re-assign N to 0 (only one texture now) + tmpX = Xoffset[mat];//retrieve offsets (currently only x) + for(unsigned int ii = 0; ii < 3;++ii)//UVs are per-vertex? + { + fit->WT(ii).U() = (fit->WT(ii).U()*images[mat].width() + tmpX)/dimension;//offset U by coord in map array, then normalize (between 0 & 1) + fit->WT(ii).V() = (fit->WT(ii).V()*images[mat].height() + tmpY)/dimension;//offset V by coord in map array, then normalize (between 0 & 1) + } + } + } + + bool result = atlas.save("texture.png","PNG",0);//save image, highest compression + m.cm.textures.clear();//empty mm.cm.textures vector + m.cm.textures.push_back("texture.png");//add the texture atlas (at position 0) + //update display-load texture atlas? + return result; } Q_EXPORT_PLUGIN(FilterTexturePlugin) diff --git a/src/meshlabplugins/filter_texture/filter_texture.h b/src/meshlabplugins/filter_texture/filter_texture.h index ed9b4cc8d..613a0f887 100644 --- a/src/meshlabplugins/filter_texture/filter_texture.h +++ b/src/meshlabplugins/filter_texture/filter_texture.h @@ -48,8 +48,8 @@ public: virtual const QString filterInfo(FilterIDType filter); virtual const PluginInfo &pluginInfo(); virtual bool autoDialog(QAction *) {return true;} - virtual void initParameterSet(QAction *,MeshDocument &/*m*/, FilterParameterSet & /*parent*/); - virtual bool applyFilter(QAction *filter, MeshModel &, FilterParameterSet & /*parent*/, vcg::CallBackPos * cb); + virtual void initParameterSet(QAction *,MeshDocument &m, FilterParameterSet &parlst); + virtual bool applyFilter(QAction *filter, MeshModel &m, FilterParameterSet &par, vcg::CallBackPos * cb); }; -#endif \ No newline at end of file +#endif diff --git a/src/meshlabplugins/filter_texture/rect_packer.cpp b/src/meshlabplugins/filter_texture/rect_packer.cpp index e667d3275..522464749 100644 --- a/src/meshlabplugins/filter_texture/rect_packer.cpp +++ b/src/meshlabplugins/filter_texture/rect_packer.cpp @@ -27,7 +27,6 @@ bool rect_packer::pack(const std::vector & sizes, const point2i & max_s assert(max_size[0]>0); assert(max_size[1]>0); - int gdim = max_size[0]*max_size[1]; // grid size int i,j,x,y; @@ -35,7 +34,6 @@ bool rect_packer::pack(const std::vector & sizes, const point2i & max_s for(i=0;i grid(gdim); // grid creation for(i=0;i & sizes, const point2i & max_s sizes[perm[0]][1]>max_size[1] ) return false; - // Find the position of the first one + // Find the position of the first one j = perm[0]; global_size[0] = sizes[j][0]; global_size[1] = sizes[j][1]; @@ -66,7 +64,7 @@ bool rect_packer::pack(const std::vector & sizes, const point2i & max_s grid[x+y*max_size[0]] = j+1; } - // Lets position all the others + // Lets position all the others for(i=1;i & sizes, const point2i & max_s int sy = sizes[j][1]; assert(sx>0); assert(sy>0); - - // limit positions + + // limit positions int lx = min(global_size[0],max_size[0]-sx); int ly = min(global_size[1],max_size[1]-sy); @@ -98,7 +96,7 @@ bool rect_packer::pack(const std::vector & sizes, const point2i & max_s { int px; int c; - // intersection check + // intersection check c = Grid(x,y+sy-1); if(!c) c = Grid(x+sx-1,y+sy-1); if(!c)