mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-17 10:04:38 +00:00
410 lines
15 KiB
C++
410 lines
15 KiB
C++
/****************************************************************************
|
|
* 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 <QString>
|
|
#include <QtGlobal>
|
|
#include <QFileInfo>
|
|
#include "meshmodel.h"
|
|
#include <wrap/gl/math.h>
|
|
|
|
using namespace vcg;
|
|
|
|
MeshModel *MeshDocument::getMesh(const char *name)
|
|
{
|
|
foreach(MeshModel *mmp, meshList)
|
|
{
|
|
if(mmp->shortName() == name) return mmp;
|
|
}
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
void MeshDocument::setCurrentMesh(unsigned int i)
|
|
{
|
|
assert(i < (unsigned int)meshList.size());
|
|
currentMesh=meshList.at(i);
|
|
emit currentMeshChanged(i);
|
|
}
|
|
|
|
MeshModel *MeshDocument::addNewMesh(const char *meshName, MeshModel *newMesh)
|
|
{
|
|
QString newName=meshName;
|
|
|
|
for(QList<MeshModel*>::iterator mmi=meshList.begin();mmi!=meshList.end();++mmi)
|
|
{
|
|
if((*mmi)->shortName() == newName)
|
|
{
|
|
QFileInfo info(newName);
|
|
QString baseName=info.baseName();
|
|
int lastNum = baseName.right(1).toInt();
|
|
if( baseName.right(2).toInt() >= 10) lastNum = baseName.right(1).toInt();
|
|
if(lastNum) newName = baseName.left(baseName.length()-1)+QString::number(lastNum+1);
|
|
else newName = baseName+"_1";
|
|
}
|
|
// newName = newName+"_copy";
|
|
|
|
}
|
|
|
|
if(newMesh==0)
|
|
newMesh=new MeshModel(qPrintable(newName));
|
|
else
|
|
newMesh->setFileName(newName);
|
|
|
|
meshList.push_back(newMesh);
|
|
currentMesh=meshList.back();
|
|
emit currentMeshChanged(meshList.size()-1);
|
|
|
|
return newMesh;
|
|
}
|
|
|
|
bool MeshDocument::delMesh(MeshModel *mmToDel)
|
|
{
|
|
if(meshList.size()==1) return false;
|
|
|
|
QMutableListIterator<MeshModel *> i(meshList);
|
|
|
|
while (i.hasNext())
|
|
{
|
|
MeshModel *md = i.next();
|
|
|
|
if (md==mmToDel)
|
|
{
|
|
i.remove();
|
|
delete mmToDel;
|
|
}
|
|
}
|
|
|
|
if(currentMesh == mmToDel)
|
|
{
|
|
setCurrentMesh(0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
bool MeshModel::Render(GLW::DrawMode _dm, GLW::ColorMode _cm, GLW::TextureMode _tm)
|
|
{
|
|
// Needed to be defined here for splatrender as long there is no "MeshlabCore" library.
|
|
using namespace vcg;
|
|
glPushMatrix();
|
|
glMultMatrix(cm.Tr);
|
|
if( (_cm == GLW::CMPerFace) && (!tri::HasPerFaceColor(cm)) ) _cm=GLW::CMNone;
|
|
if( (_tm == GLW::TMPerWedge )&& (!tri::HasPerWedgeTexCoord(cm)) ) _tm=GLW::TMNone;
|
|
if( (_tm == GLW::TMPerWedgeMulti )&& (!tri::HasPerWedgeTexCoord(cm)) ) _tm=GLW::TMNone;
|
|
glw.Draw(_dm,_cm,_tm);
|
|
glPopMatrix();
|
|
return true;
|
|
}
|
|
|
|
bool MeshModel::RenderSelectedFace()
|
|
{
|
|
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glDepthMask(GL_FALSE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
|
|
glColor4f(1.0f,0.0,0.0,.3f);
|
|
glPolygonOffset(-1.0, -1);
|
|
CMeshO::FaceIterator fi;
|
|
glPushMatrix();
|
|
glMultMatrix(cm.Tr);glBegin(GL_TRIANGLES);
|
|
cm.sfn=0;
|
|
for(fi=cm.face.begin();fi!=cm.face.end();++fi)
|
|
if(!(*fi).IsD() && (*fi).IsS())
|
|
{
|
|
glVertex((*fi).cP(0));
|
|
glVertex((*fi).cP(1));
|
|
glVertex((*fi).cP(2));
|
|
++cm.sfn;
|
|
}
|
|
glEnd();
|
|
glPopMatrix();
|
|
glPopAttrib();
|
|
return true;
|
|
}
|
|
bool MeshModel::RenderSelectedVert()
|
|
{
|
|
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glDepthMask(GL_FALSE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
|
|
glColor4f(1.0f,0.0,0.0,.3f);
|
|
glDepthRange(0.00,0.999);
|
|
glPointSize(3.0);
|
|
glPushMatrix();
|
|
glMultMatrix(cm.Tr);
|
|
glBegin(GL_POINTS);
|
|
cm.svn=0;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi=cm.vert.begin();vi!=cm.vert.end();++vi)
|
|
if(!(*vi).IsD() && (*vi).IsS())
|
|
{
|
|
glVertex((*vi).cP());
|
|
++cm.svn;
|
|
}
|
|
glEnd();
|
|
glPopMatrix();
|
|
glPopAttrib();
|
|
return true;
|
|
}
|
|
|
|
int MeshModel::io2mm(int single_iobit)
|
|
{
|
|
switch(single_iobit)
|
|
{
|
|
case tri::io::Mask::IOM_NONE : return MM_NONE;
|
|
case tri::io::Mask::IOM_VERTCOORD : return MM_VERTCOORD;
|
|
case tri::io::Mask::IOM_VERTCOLOR : return MM_VERTCOLOR;
|
|
case tri::io::Mask::IOM_VERTFLAGS : return MM_VERTFLAG;
|
|
case tri::io::Mask::IOM_VERTQUALITY : return MM_VERTQUALITY;
|
|
case tri::io::Mask::IOM_VERTNORMAL : return MM_VERTNORMAL;
|
|
case tri::io::Mask::IOM_VERTTEXCOORD : return MM_VERTTEXCOORD;
|
|
case tri::io::Mask::IOM_VERTRADIUS : return MM_VERTRADIUS;
|
|
|
|
case tri::io::Mask::IOM_FACEINDEX : return MM_FACEVERT ;
|
|
case tri::io::Mask::IOM_FACEFLAGS : return MM_FACEFLAG ;
|
|
case tri::io::Mask::IOM_FACECOLOR : return MM_FACECOLOR ;
|
|
case tri::io::Mask::IOM_FACEQUALITY : return MM_FACEQUALITY;
|
|
case tri::io::Mask::IOM_FACENORMAL : return MM_FACENORMAL ;
|
|
|
|
case tri::io::Mask::IOM_WEDGTEXCOORD : return MM_WEDGTEXCOORD;
|
|
case tri::io::Mask::IOM_WEDGCOLOR : return MM_WEDGCOLOR;
|
|
case tri::io::Mask::IOM_WEDGNORMAL : return MM_WEDGNORMAL ;
|
|
|
|
case tri::io::Mask::IOM_BITPOLYGONAL : return MM_POLYGONAL ;
|
|
|
|
default:
|
|
assert(0);
|
|
return MM_NONE; // FIXME: Returning this is not the best solution (!)
|
|
break;
|
|
} ;
|
|
}
|
|
|
|
void MeshModelState::create(int _mask, MeshModel* _m)
|
|
{
|
|
m=_m;
|
|
changeMask=_mask;
|
|
if(changeMask & MeshModel::MM_VERTCOLOR)
|
|
{
|
|
vertColor.resize(m->cm.vert.size());
|
|
std::vector<Color4b>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci = vertColor.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
if(!(*vi).IsD()) (*ci)=(*vi).C();
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_VERTCOORD)
|
|
{
|
|
vertCoord.resize(m->cm.vert.size());
|
|
std::vector<Point3f>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci = vertCoord.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
if(!(*vi).IsD()) (*ci)=(*vi).P();
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_VERTNORMAL)
|
|
{
|
|
vertNormal.resize(m->cm.vert.size());
|
|
std::vector<Point3f>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci = vertNormal.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
if(!(*vi).IsD()) (*ci)=(*vi).N();
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_FACEFLAGSELECT)
|
|
{
|
|
faceSelection.resize(m->cm.face.size());
|
|
std::vector<bool>::iterator ci;
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = m->cm.face.begin(), ci = faceSelection.begin(); fi != m->cm.face.end(); ++fi, ++ci)
|
|
if(!(*fi).IsD()) (*ci) = (*fi).IsS();
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_VERTFLAGSELECT)
|
|
{
|
|
vertSelection.resize(m->cm.vert.size());
|
|
std::vector<bool>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci = vertSelection.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
if(!(*vi).IsD()) (*ci) = (*vi).IsS();
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_TRANSFMATRIX)
|
|
Tr = m->cm.Tr;
|
|
}
|
|
|
|
bool MeshModelState::apply(MeshModel *_m)
|
|
{
|
|
if(_m != m) return false;
|
|
if(changeMask & MeshModel::MM_VERTCOLOR)
|
|
{
|
|
if(vertColor.size() != m->cm.vert.size()) return false;
|
|
std::vector<Color4b>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci = vertColor.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
if(!(*vi).IsD()) (*vi).C()=(*ci);
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_VERTCOORD)
|
|
{
|
|
if(vertCoord.size() != m->cm.vert.size()) return false;
|
|
std::vector<Point3f>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci = vertCoord.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
if(!(*vi).IsD()) (*vi).P()=(*ci);
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_VERTNORMAL)
|
|
{
|
|
if(vertNormal.size() != m->cm.vert.size()) return false;
|
|
std::vector<Point3f>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci=vertNormal.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
if(!(*vi).IsD()) (*vi).N()=(*ci);
|
|
|
|
//now reset the face normals
|
|
tri::UpdateNormals<CMeshO>::PerFaceNormalized(m->cm);
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_FACEFLAGSELECT)
|
|
{
|
|
if(faceSelection.size() != m->cm.face.size()) return false;
|
|
std::vector<bool>::iterator ci;
|
|
CMeshO::FaceIterator fi;
|
|
for(fi = m->cm.face.begin(), ci = faceSelection.begin(); fi != m->cm.face.end(); ++fi, ++ci)
|
|
{
|
|
if((*ci))
|
|
(*fi).SetS();
|
|
else
|
|
(*fi).ClearS();
|
|
}
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_VERTFLAGSELECT)
|
|
{
|
|
if(vertSelection.size() != m->cm.vert.size()) return false;
|
|
std::vector<bool>::iterator ci;
|
|
CMeshO::VertexIterator vi;
|
|
for(vi = m->cm.vert.begin(), ci = vertSelection.begin(); vi != m->cm.vert.end(); ++vi, ++ci)
|
|
{
|
|
if((*ci))
|
|
(*vi).SetS();
|
|
else
|
|
(*vi).ClearS();
|
|
}
|
|
}
|
|
|
|
if(changeMask & MeshModel::MM_TRANSFMATRIX)
|
|
m->cm.Tr=Tr;
|
|
|
|
return true;
|
|
}
|
|
|
|
const QString MeshModel::shortName() const
|
|
{
|
|
return QFileInfo(fullPathFileName).fileName();
|
|
}
|
|
|
|
|
|
/**** DATAMASK STUFF ****/
|
|
|
|
bool MeshModel::hasDataMask(const int maskToBeTested) const
|
|
{
|
|
return ((currentDataMask & maskToBeTested)!= 0);
|
|
}
|
|
void MeshModel::updateDataMask(MeshModel *m)
|
|
{
|
|
updateDataMask(m->currentDataMask);
|
|
}
|
|
|
|
void MeshModel::updateDataMask(int neededDataMask)
|
|
{
|
|
if( ( (neededDataMask & MM_FACEFACETOPO)!=0) && !hasDataMask(MM_FACEFACETOPO) )
|
|
{
|
|
cm.face.EnableFFAdjacency();
|
|
tri::UpdateTopology<CMeshO>::FaceFace(cm);
|
|
}
|
|
if( ( (neededDataMask & MM_VERTFACETOPO)!=0) && !hasDataMask(MM_VERTFACETOPO) )
|
|
{
|
|
cm.vert.EnableVFAdjacency();
|
|
cm.face.EnableVFAdjacency();
|
|
tri::UpdateTopology<CMeshO>::VertexFace(cm);
|
|
}
|
|
if( ( (neededDataMask & MM_WEDGTEXCOORD)!=0) && !hasDataMask(MM_WEDGTEXCOORD)) cm.face.EnableWedgeTex();
|
|
if( ( (neededDataMask & MM_FACECOLOR)!=0) && !hasDataMask(MM_FACECOLOR)) cm.face.EnableColor();
|
|
if( ( (neededDataMask & MM_FACEQUALITY)!=0) && !hasDataMask(MM_FACEQUALITY)) cm.face.EnableQuality();
|
|
if( ( (neededDataMask & MM_FACEMARK)!=0) && !hasDataMask(MM_FACEMARK)) cm.face.EnableMark();
|
|
if( ( (neededDataMask & MM_VERTMARK)!=0) && !hasDataMask(MM_VERTMARK)) cm.vert.EnableMark();
|
|
if( ( (neededDataMask & MM_VERTCURV)!=0) && !hasDataMask(MM_VERTCURV)) cm.vert.EnableCurvature();
|
|
if( ( (neededDataMask & MM_VERTCURVDIR)!=0) && !hasDataMask(MM_VERTCURVDIR)) cm.vert.EnableCurvatureDir();
|
|
if( ( (neededDataMask & MM_VERTRADIUS)!=0) && !hasDataMask(MM_VERTRADIUS)) cm.vert.EnableRadius();
|
|
if( ( (neededDataMask & MM_VERTTEXCOORD)!=0) && !hasDataMask(MM_VERTTEXCOORD)) cm.vert.EnableTexCoord();
|
|
|
|
if( ( (neededDataMask & MM_FACEFLAGBORDER) && !hasDataMask(MM_FACEFLAGBORDER) ) ||
|
|
( (neededDataMask & MM_VERTFLAGBORDER) && !hasDataMask(MM_VERTFLAGBORDER) ) )
|
|
{
|
|
if( (currentDataMask & MM_FACEFACETOPO) || (neededDataMask & MM_FACEFACETOPO))
|
|
tri::UpdateFlags<CMeshO>::FaceBorderFromFF(cm);
|
|
else tri::UpdateFlags<CMeshO>::FaceBorderFromNone(cm);
|
|
tri::UpdateFlags<CMeshO>::VertexBorderFromFace(cm);
|
|
}
|
|
|
|
currentDataMask |= neededDataMask;
|
|
}
|
|
|
|
void MeshModel::clearDataMask(int unneededDataMask)
|
|
{
|
|
if( ( (unneededDataMask & MM_VERTFACETOPO)!=0) && hasDataMask(MM_VERTFACETOPO)) {cm.face.DisableVFAdjacency();
|
|
cm.vert.DisableVFAdjacency(); }
|
|
if( ( (unneededDataMask & MM_FACEFACETOPO)!=0) && hasDataMask(MM_FACEFACETOPO)) cm.face.DisableFFAdjacency();
|
|
|
|
if( ( (unneededDataMask & MM_WEDGTEXCOORD)!=0) && hasDataMask(MM_WEDGTEXCOORD)) cm.face.DisableWedgeTex();
|
|
if( ( (unneededDataMask & MM_FACECOLOR)!=0) && hasDataMask(MM_FACECOLOR)) cm.face.DisableColor();
|
|
if( ( (unneededDataMask & MM_FACEQUALITY)!=0) && hasDataMask(MM_FACEQUALITY)) cm.face.DisableQuality();
|
|
if( ( (unneededDataMask & MM_FACEMARK)!=0) && hasDataMask(MM_FACEMARK)) cm.face.DisableMark();
|
|
if( ( (unneededDataMask & MM_VERTMARK)!=0) && hasDataMask(MM_VERTMARK)) cm.vert.DisableMark();
|
|
if( ( (unneededDataMask & MM_VERTCURV)!=0) && hasDataMask(MM_VERTCURV)) cm.vert.DisableCurvature();
|
|
if( ( (unneededDataMask & MM_VERTCURVDIR)!=0) && hasDataMask(MM_VERTCURVDIR)) cm.vert.DisableCurvatureDir();
|
|
if( ( (unneededDataMask & MM_VERTRADIUS)!=0) && hasDataMask(MM_VERTRADIUS)) cm.vert.DisableRadius();
|
|
if( ( (unneededDataMask & MM_VERTTEXCOORD)!=0) && hasDataMask(MM_VERTTEXCOORD)) cm.vert.DisableTexCoord();
|
|
|
|
currentDataMask = currentDataMask & (~unneededDataMask);
|
|
}
|
|
|
|
void MeshModel::Enable(int openingFileMask)
|
|
{
|
|
if( openingFileMask & tri::io::Mask::IOM_VERTTEXCOORD ) updateDataMask(MM_VERTTEXCOORD);
|
|
if( openingFileMask & tri::io::Mask::IOM_WEDGTEXCOORD ) updateDataMask(MM_WEDGTEXCOORD);
|
|
if( openingFileMask & tri::io::Mask::IOM_VERTCOLOR ) updateDataMask(MM_VERTCOLOR);
|
|
if( openingFileMask & tri::io::Mask::IOM_FACECOLOR ) updateDataMask(MM_FACECOLOR);
|
|
if( openingFileMask & tri::io::Mask::IOM_VERTRADIUS ) updateDataMask(MM_VERTRADIUS);
|
|
if( openingFileMask & tri::io::Mask::IOM_CAMERA ) updateDataMask(MM_CAMERA);
|
|
if( openingFileMask & tri::io::Mask::IOM_VERTQUALITY ) updateDataMask(MM_VERTQUALITY);
|
|
if( openingFileMask & tri::io::Mask::IOM_FACEQUALITY ) updateDataMask(MM_FACEQUALITY);
|
|
if( openingFileMask & tri::io::Mask::IOM_BITPOLYGONAL ) updateDataMask(MM_POLYGONAL);
|
|
}
|