filter_texture initial texture atlas code

This commit is contained in:
Paolo Cignoni cignoni 2008-05-10 19:53:29 +00:00
parent 9d7a39e8ae
commit ca5bc0e064
3 changed files with 74 additions and 15 deletions

View File

@ -26,10 +26,11 @@ $Log: samplefilter.cpp,v $
****************************************************************************/
#include <QtGui>
#include <QImage>
#include <QColor>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <meshlab/meshmodel.h>
#include <meshlab/interfaces.h>
@ -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<int, int> Xoffset;//stl map mapping texture indeces to new U offsets
std::map<int, int> 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; index<numTextures; ++index)
{
painter.drawPixmap(currentX, 0, images[index]);//use drawPixmap instead of deprecated bitBlt() to paste image to a certain position in the texture atlas
currentX += images[index].width();
Xoffset[index] = currentX;//as do, add index & coords to 'conversions' map
}
int tmpX=0,tmpY=0;
CMeshO::FaceIterator fit;
for (fit=m.cm.face.begin(); fit != m.cm.face.end(); ++fit)//iterate through faces with textures
{
if (!(*fit).IsD())//only iterates over non-deleted faces
{
int mat = fit->WT(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)

View File

@ -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
#endif

View File

@ -27,7 +27,6 @@ bool rect_packer::pack(const std::vector<point2i> & 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<point2i> & sizes, const point2i & max_s
for(i=0;i<n;i++) // reset initial positions
posiz[i][0] = -1;
std::vector<int> grid(gdim); // grid creation
for(i=0;i<gdim;++i) grid[i] = 0;
@ -50,7 +48,7 @@ bool rect_packer::pack(const std::vector<point2i> & 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<point2i> & 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<n;++i)
{
j = perm[i];
@ -82,8 +80,8 @@ bool rect_packer::pack(const std::vector<point2i> & 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<point2i> & 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)