/**************************************************************************** * 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 "meshmodel.h" #include #include "scriptinterface.h" #include #include "mlexception.h" using namespace vcg; //deletes each meshModel MeshDocument::~MeshDocument() { foreach(MeshModel *mmp, meshList) delete mmp; foreach(RasterModel* rmp,rasterList) delete rmp; delete filterHistory; } //returns the mesh ata given position in the list MeshModel *MeshDocument::getMesh(int i) { foreach(MeshModel *mmp, meshList) { if(mmp->id() == i) return mmp; } //assert(0); return 0; } MeshModel *MeshDocument::getMesh(QString name) { foreach(MeshModel *mmp, meshList) { if(mmp->shortName() == name) return mmp; } //assert(0); return 0; } MeshModel *MeshDocument::getMeshByFullName(QString pathName) { foreach(MeshModel *mmp, meshList) { if(mmp->fullName() == pathName) return mmp; } //assert(0); return 0; } void MeshDocument::setCurrentMesh( int i) { if(i<0) { currentMesh=0; return; } currentMesh = getMesh(i); emit currentMeshChanged(i); assert(currentMesh); } //returns the raster at a given position in the list RasterModel *MeshDocument::getRaster(int i) { foreach(RasterModel *rmp, rasterList) { if(rmp->id() == i) return rmp; } //assert(0); return 0; } //if i is <0 it means that no currentRaster is set void MeshDocument::setCurrentRaster( int i) { if(i<0) { currentRaster=0; return; } foreach(RasterModel *rmp, rasterList) { if(rmp->id() == i) { currentRaster = rmp; return; } } assert(0); return; } template QString NameDisambiguator(QList &elemList, QString meshLabel ) { QString newName=meshLabel; typename QList::iterator mmi; for(mmi=elemList.begin(); mmi!=elemList.end(); ++mmi) { if((*mmi)->label() == newName) // if duplicated name found { QFileInfo fi((*mmi)->label()); QString baseName = fi.baseName(); // all characters in the file up to the first '.' Eg "/tmp/archive.tar.gz" -> "archive" QString suffix = fi.suffix(); bool ok; // if name ends with a number between parenthesis (XXX), // it was himself a duplicated name, and we need to // just increase the number between parenthesis int numDisamb; int startDisamb; int endDisamb; startDisamb = baseName.lastIndexOf("("); endDisamb = baseName.lastIndexOf(")"); if((startDisamb!=-1)&&(endDisamb!=-1)) numDisamb = (baseName.mid((startDisamb+1),(endDisamb-startDisamb-1))).toInt(&ok); else numDisamb = 0; if(startDisamb!=-1) newName = baseName.left(startDisamb)+ "(" + QString::number(numDisamb+1) + ")"; else newName = baseName + "(" + QString::number(numDisamb+1) + ")"; if (suffix != QString("")) newName = newName + "." + suffix; // now recurse to see if the new name is free newName = NameDisambiguator(elemList, newName); } } return newName; } /* When you create a new mesh it can be either a newly created one or an opened one. If it is an opened one the fullpathname is meaningful and the label, by default is just the short name. If it is a newly created one the fullpath is an empty string and the user has to provide a label. */ MeshModel * MeshDocument::addOrGetMesh(QString fullPath, QString label, bool setAsCurrent,const RenderMode& rm) { MeshModel*newMM = this->getMesh(label); if(newMM==0) newMM=this->addNewMesh(fullPath,label,setAsCurrent,rm); return newMM; } MeshModel * MeshDocument::addNewMesh(QString fullPath, QString label, bool setAsCurrent,const RenderMode& rm) { QString newlabel = NameDisambiguator(this->meshList,label); if(!fullPath.isEmpty()) { QFileInfo fi(fullPath); fullPath = fi.absoluteFilePath(); } MeshModel *newMesh = new MeshModel(this,qPrintable(fullPath),newlabel); meshList.push_back(newMesh); emit meshSetChanged(); qRegisterMetaType("RenderMode"); emit meshAdded(newMesh->id(),rm); if(setAsCurrent) this->setCurrentMesh(newMesh->id()); return newMesh; } bool MeshDocument::delMesh(MeshModel *mmToDel) { if(!meshList.removeOne(mmToDel)) return false; if((currentMesh == mmToDel) && (meshList.size() != 0)) setCurrentMesh(this->meshList.at(0)->id()); else if (meshList.size() == 0) setCurrentMesh(-1); int index = mmToDel->id(); delete mmToDel; emit meshSetChanged(); emit meshRemoved(index); return true; } RasterModel * MeshDocument::addNewRaster(/*QString fullPathFilename*/) { QFileInfo info(fullPathFilename); QString newLabel=info.fileName(); QString newName = NameDisambiguator(this->rasterList, newLabel); RasterModel *newRaster=new RasterModel(this, newLabel); rasterList.push_back(newRaster); //Add new plane //Plane *plane = new Plane(newRaster, fullPathFilename, QString()); //newRaster->addPlane(plane); this->setCurrentRaster(newRaster->id()); emit rasterSetChanged(); return newRaster; } bool MeshDocument::delRaster(RasterModel *rasterToDel) { QMutableListIterator i(rasterList); while (i.hasNext()) { RasterModel *r = i.next(); if (r==rasterToDel) { i.remove(); delete rasterToDel; } } if(currentRaster == rasterToDel) { if (rasterList.size() > 0) setCurrentRaster(rasterList.at(0)->id()); else setCurrentRaster(-1); } emit rasterSetChanged(); return true; } bool MeshDocument::hasBeenModified() { foreach(MeshModel *m, meshList) if(m->meshModified()) return true; return false; } //void MeshDocument::updateRenderStateMeshes(const QList& mm,const int meshupdatemask) //{ // static QTime currTime = QTime::currentTime(); // if(currTime.elapsed()< 100) // return; // for (QList::const_iterator mit = mm.begin();mit != mm.end();++mit) // { // MeshModel* mesh = getMesh(*mit); // if (mesh != NULL) // mesh->bor.update(mesh->cm,meshupdatemask); // } // if ((mm.size() > 0) && (meshupdatemask != MeshModel::MM_NONE)) // emit documentUpdated(); // currTime.start(); //} //void MeshDocument::updateRenderStateRasters(const QList& rm,const int rasterupdatemask) //{ // static QTime currTime = QTime::currentTime(); // if(currTime.elapsed()< 100) // return; // for (QList::const_iterator rit = rm.begin();rit != rm.end();++rit) // { // RasterModel* raster = getRaster(*rit); // // /**********READD*****/ // /* if (raster != NULL) // renderState().update(raster->id(),*raster,rasterupdatemask);*/ // /********************/ // } // if ((rm.size() > 0) && (rasterupdatemask != RasterModel::RM_NONE)) // emit documentUpdated(); // currTime.start(); //} // //void MeshDocument::updateRenderState(const QList& mm,const int meshupdatemask,const QList& rm,const int rasterupdatemask) //{ // static QTime currTime = QTime::currentTime(); // if(currTime.elapsed()< 100) // return; // /* for (QList::const_iterator mit = mm.begin();mit != mm.end();++mit) // { // MeshModel* mesh = getMesh(*mit); // if (mesh != NULL) // renderState().update(mesh->id(),mesh->cm,meshupdatemask); // } // for (QList::const_iterator rit = rm.begin();rit != rm.end();++rit) // { // RasterModel* raster = getRaster(*rit); // if (raster != NULL) // renderState().update(raster->id(),*raster,rasterupdatemask); // }*/ // if (((mm.size() > 0) && (meshupdatemask != MeshModel::MM_NONE)) || (rm.size() > 0 && (rasterupdatemask != RasterModel::RM_NONE))) // emit documentUpdated(); // currTime.start(); //} MeshDocument::MeshDocument() : QObject(),Log(),xmlhistory() { meshIdCounter=0; rasterIdCounter=0; currentMesh = 0; currentRaster = 0; busy=false; filterHistory = new FilterScript(); } void MeshModel::Clear() { meshModified() = false; glw.m=&cm; // These data are always active on the mesh currentDataMask = MM_NONE; currentDataMask |= MM_VERTCOORD | MM_VERTNORMAL | MM_VERTFLAG ; currentDataMask |= MM_FACEVERT | MM_FACENORMAL | MM_FACEFLAG ; visible=true; cm.Tr.SetIdentity(); cm.sfn=0; cm.svn=0; } void MeshModel::UpdateBoxAndNormals() { tri::UpdateBounding::Box(cm); if(cm.fn>0) { tri::UpdateNormal::PerFaceNormalized(cm); tri::UpdateNormal::PerVertexAngleWeighted(cm); } } MeshModel::MeshModel(MeshDocument *_parent, QString fullFileName, QString labelName) :bor(false),glw() { Clear(); parent=_parent; _id=parent->newMeshId(); if(!fullFileName.isEmpty()) this->fullPathFileName=fullFileName; if(!labelName.isEmpty()) this->_label=labelName; } QString MeshModel::relativePathName() const { QDir documentDir (documentPathName()); QString relPath=documentDir.relativeFilePath(this->fullPathFileName); if(relPath.size()>1 && relPath[0]=='.' && relPath[1]=='.') qDebug("Error we have a mesh that is not in the same folder of the project: %s ",qPrintable(relPath)); return relPath; } QString MeshModel::documentPathName() const { return parent->pathName(); } 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; } ; } Plane::Plane(const Plane& pl) { semantic = pl.semantic; fullPathFileName = pl.fullPathFileName; image = QImage(pl.image); } Plane::Plane(const QString pathName, const int _semantic) { semantic =_semantic; fullPathFileName = pathName; image = QImage(pathName); } RasterModel::RasterModel(MeshDocument *parent, QString _rasterName) : MeshLabRenderRaster() { _id=parent->newRasterId(); par = parent; this->_label= _rasterName; visible=true; } RasterModel::RasterModel() : MeshLabRenderRaster() { } MeshLabRenderRaster::MeshLabRenderRaster() { } MeshLabRenderRaster::MeshLabRenderRaster( const MeshLabRenderRaster& rm ) :shot(rm.shot),planeList() { for(QList::const_iterator it = rm.planeList.begin();it != rm.planeList.end();++it) { planeList.push_back(new Plane(**it)); if (rm.currentPlane == *it) currentPlane = planeList[planeList.size() - 1]; } } void MeshLabRenderRaster::addPlane(Plane *plane) { planeList.append(plane); currentPlane = plane; } MeshLabRenderRaster::~MeshLabRenderRaster() { currentPlane = NULL; for(int ii = 0;ii < planeList.size();++ii) delete planeList[ii]; } void MeshModelState::create(int _mask, MeshModel* _m) { m=_m; changeMask=_mask; if(changeMask & MeshModel::MM_VERTCOLOR) { vertColor.resize(m->cm.vert.size()); std::vector::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_VERTQUALITY) { vertQuality.resize(m->cm.vert.size()); std::vector::iterator qi; CMeshO::VertexIterator vi; for(vi = m->cm.vert.begin(), qi = vertQuality.begin(); vi != m->cm.vert.end(); ++vi, ++qi) if(!(*vi).IsD()) (*qi)=(*vi).Q(); } if(changeMask & MeshModel::MM_VERTCOORD) { vertCoord.resize(m->cm.vert.size()); std::vector::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::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_FACENORMAL) { faceNormal.resize(m->cm.face.size()); std::vector::iterator ci; CMeshO::FaceIterator fi; for(fi = m->cm.face.begin(), ci = faceNormal.begin(); fi != m->cm.face.end(); ++fi, ++ci) if(!(*fi).IsD()) (*ci) = (*fi).N(); } if(changeMask & MeshModel::MM_FACECOLOR) { m->updateDataMask(MeshModel::MM_FACECOLOR); faceColor.resize(m->cm.face.size()); std::vector::iterator ci; CMeshO::FaceIterator fi; for(fi = m->cm.face.begin(), ci = faceColor.begin(); fi != m->cm.face.end(); ++fi, ++ci) if(!(*fi).IsD()) (*ci) = (*fi).C(); } if(changeMask & MeshModel::MM_FACEFLAGSELECT) { faceSelection.resize(m->cm.face.size()); std::vector::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::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; if(changeMask & MeshModel::MM_CAMERA) this->shot = m->cm.shot; } 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::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_FACECOLOR) { if(faceColor.size() != m->cm.face.size()) return false; std::vector::iterator ci; CMeshO::FaceIterator fi; for(fi = m->cm.face.begin(), ci = faceColor.begin(); fi != m->cm.face.end(); ++fi, ++ci) if(!(*fi).IsD()) (*fi).C()=(*ci); } if(changeMask & MeshModel::MM_VERTQUALITY) { if(vertQuality.size() != m->cm.vert.size()) return false; std::vector::iterator qi; CMeshO::VertexIterator vi; for(vi = m->cm.vert.begin(), qi = vertQuality.begin(); vi != m->cm.vert.end(); ++vi, ++qi) if(!(*vi).IsD()) (*vi).Q()=(*qi); } if(changeMask & MeshModel::MM_VERTCOORD) { if(vertCoord.size() != m->cm.vert.size()) return false; std::vector::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::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); } if(changeMask & MeshModel::MM_FACENORMAL) { if(faceNormal.size() != m->cm.face.size()) return false; std::vector::iterator ci; CMeshO::FaceIterator fi; for(fi = m->cm.face.begin(), ci=faceNormal.begin(); fi != m->cm.face.end(); ++fi, ++ci) if(!(*fi).IsD()) (*fi).N()=(*ci); } if(changeMask & MeshModel::MM_FACEFLAGSELECT) { if(faceSelection.size() != m->cm.face.size()) return false; std::vector::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::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; if(changeMask & MeshModel::MM_CAMERA) m->cm.shot = this->shot; return true; } /**** DATAMASK STUFF ****/ void MeshDocument::setVisible(int meshId, bool val) { getMesh(meshId)->visible=val; emit meshSetChanged(); } 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) { cm.face.EnableFFAdjacency(); tri::UpdateTopology::FaceFace(cm); } if((neededDataMask & MM_VERTFACETOPO)!=0) { cm.vert.EnableVFAdjacency(); cm.face.EnableVFAdjacency(); tri::UpdateTopology::VertexFace(cm); } if((neededDataMask & MM_WEDGTEXCOORD)!=0) cm.face.EnableWedgeTexCoord(); if((neededDataMask & MM_FACECOLOR)!=0) cm.face.EnableColor(); if((neededDataMask & MM_FACEQUALITY)!=0) cm.face.EnableQuality(); if((neededDataMask & MM_FACECURVDIR)!=0) cm.face.EnableCurvatureDir(); if((neededDataMask & MM_FACEMARK)!=0) cm.face.EnableMark(); if((neededDataMask & MM_VERTMARK)!=0) cm.vert.EnableMark(); if((neededDataMask & MM_VERTCURV)!=0) cm.vert.EnableCurvature(); if((neededDataMask & MM_VERTCURVDIR)!=0) cm.vert.EnableCurvatureDir(); if((neededDataMask & MM_VERTRADIUS)!=0) cm.vert.EnableRadius(); if((neededDataMask & MM_VERTTEXCOORD)!=0) cm.vert.EnableTexCoord(); 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.DisableWedgeTexCoord(); 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); } bool& MeshModel::meshModified() { return this->modified; } int MeshModel::dataMask() const { return currentDataMask; } BufferObjectsRendering::BufferObjectsRendering(bool highprecmode) :QObject(),_lock(QReadWriteLock::Recursive) { this->HighPrecisionMode =highprecmode; } BufferObjectsRendering::~BufferObjectsRendering() { clearState(); } void BufferObjectsRendering::DrawWire( vcg::GLW::ColorMode colm,vcg::GLW::NormalMode norm) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); DrawTriangles(colm,norm,vcg::GLW::TMNone); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } void BufferObjectsRendering::DrawFlatWire(vcg::GLW::ColorMode colm,vcg::GLW::TextureMode textm) { glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT ); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0, 1); DrawTriangles(colm,vcg::GLW::NMPerFace,textm); glDisable(GL_POLYGON_OFFSET_FILL); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); glColor3f(.3f,.3f,.3f); DrawWire(vcg::GLW::CMNone,vcg::GLW::NMPerFace); glPopAttrib(); } void BufferObjectsRendering::DrawPoints(vcg::GLW::ColorMode colm) { glBindBuffer(GL_ARRAY_BUFFER, positionBO); glVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array glBindBuffer(GL_ARRAY_BUFFER, normalBO); glNormalPointer(GL_FLOAT, 0, 0); // last param is offset, not ptr glEnableClientState(GL_NORMAL_ARRAY); // activate vertex coords array if(colm == GLW::CMPerVert) { glBindBuffer(GL_ARRAY_BUFFER, colorBO); glColorPointer(4,GL_UNSIGNED_BYTE, 0, 0); // last param is offset, not ptr glEnableClientState(GL_COLOR_ARRAY); // activate vertex coords array } for(size_t i=0;i::CompactEveryVector(mm); QTime aa; aa.start(); bool res = false; switch (drawm) { case(GLW::DMPoints): { res = updateIndexedAttributesPipeline(mm,updateattributesmask,colm,nolm,vcg::GLW::TMNone); break; } case(GLW::DMWire): { if ((nolm == vcg::GLW::NMPerFace) || (colm == vcg::GLW::CMPerFace) && (vcg::tri::HasPerFaceColor(mm))) { res = updateReplicatedAttributesPipeline(mm,updateattributesmask,colm,nolm,vcg::GLW::TMNone); } else { res = updateIndexedAttributesPipeline(mm,updateattributesmask,colm,nolm,vcg::GLW::TMNone); } break; } case(GLW::DMFlatWire): { res = updateReplicatedAttributesPipeline(mm,updateattributesmask,colm,nolm,textm); break; } case(GLW::DMSmooth): { if (((textm == vcg::GLW::TMPerWedge) || (textm == vcg::GLW::TMPerWedgeMulti)) && (vcg::tri::HasPerWedgeTexCoord(mm)) || (colm == vcg::GLW::CMPerFace) && (vcg::tri::HasPerFaceColor(mm))) { res = updateReplicatedAttributesPipeline(mm,updateattributesmask,colm,nolm,textm); } else { res = updateIndexedAttributesPipeline(mm,updateattributesmask,colm,nolm,textm); } break; } case(GLW::DMFlat): { res = updateReplicatedAttributesPipeline(mm,updateattributesmask,colm,nolm,textm); break; } } qDebug("Buffer feed in %i",aa.elapsed()); return res; } bool BufferObjectsRendering::updateIndexedAttributesPipeline(CMeshO& mm, int updateattributesmask,vcg::GLW::ColorMode colm, vcg::GLW::NormalMode nolm, vcg::GLW::TextureMode textm ) { QWriteLocker locker(&_lock); std::vector pv; std::vector nv; std::vector cv; // Per vertex Colors std::vector tv; vn = mm.vn; // In HighPrecisionMode each vertex is pretransformed in double in its final position. // but we save the coord of the centered bbox after the transformation. if ((colm == vcg::GLW::CMPerVert) || (textm == vcg::GLW::TMPerVert)) importPerVertexAttributes(mm,pv,nv,cv,tv); else importPerVertexAttributes(mm,pv,nv); tn = mm.fn; std::map< short, std::vector > ti; if(tri::HasPerVertexTexCoord(mm) && (textm == vcg::GLW::TMPerVert)) { for(size_t i=0;iT().n(); ti[tid].push_back(tri::Index(mm,mm.face[i].V(0))); ti[tid].push_back(tri::Index(mm,mm.face[i].V(1))); ti[tid].push_back(tri::Index(mm,mm.face[i].V(2))); } glGenBuffers(1, &textureBO); glBindBuffer(GL_ARRAY_BUFFER, textureBO); glBufferData(GL_ARRAY_BUFFER, vn *2 *sizeof(GLfloat), &tv[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } else { ti[-1].resize(tn*3); for(size_t i=0;i >::const_iterator cit = ti.cbegin();cit != ti.cend();++cit) { short ind = cit->first; indexTriBOSz[ii]=ti[ind].size(); glGenBuffers(1, &indexTriBO[ii]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexTriBO[ii]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, ti[ind].size() *sizeof(GLuint), &ti[ind][0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); ++ii; } return true; } bool BufferObjectsRendering::updateReplicatedAttributesPipeline(CMeshO& mm, int updateattributesmask,vcg::GLW::ColorMode colm, vcg::GLW::NormalMode norm, vcg::GLW::TextureMode textm ) { QWriteLocker locker(&_lock); std::vector pv; std::vector nv; std::vector cv; // Per vertex Colors std::vector tv; vn = mm.vn; // In HighPrecisionMode each vertex is pretransformed in double in its final position. // but we save the coord of the centered bbox after the transformation. importPerVertexAttributes(mm,pv,nv,cv,tv); tn = mm.fn; std::vector rpv(mm.fn*3); std::vector rnv(mm.fn*3); std::vector rcv(mm.fn*3); //std::vector rnt(mm.fn*3); //std::vector rct(mm.fn*3); bool perfcol = tri::HasPerFaceColor(mm) && (colm == vcg::GLW::CMPerFace); bool perfnorm = tri::HasPerFaceNormal(mm) && (norm == vcg::GLW::NMPerFace); bool pervertcol = tri::HasPerVertexColor(mm) && (colm == vcg::GLW::CMPerVert); bool pervertnorm = tri::HasPerVertexNormal(mm) && (norm == vcg::GLW::NMPerVert); if (tri::HasPerWedgeTexCoord(mm) /*& (updateattributesmask & MeshModel::MM_WEDGTEXCOORD)*/) { //std::vector wtv(mm.fn*3); std::vector wtv(mm.fn*3*2); std::map< short, std::vector > chunkMap; //AggregatedTriangleChunkMap for(size_t i=0;i >::iterator it = chunkMap.begin();it != chunkMap.end();++it) { texIndNumTrianglesV[t] = std::make_pair(it->first,GLuint(it->second.size())); for(size_t j = 0;jsecond.size();++j) { size_t indf(it->second[j]); rpv[k*3+0].Import(mm.face[indf].V(0)->P()); rpv[k*3+1].Import(mm.face[indf].V(1)->P()); rpv[k*3+2].Import(mm.face[indf].V(2)->P()); if (pervertnorm) { rnv[k*3+0].Import(mm.face[indf].V(0)->N().Normalize()); rnv[k*3+1].Import(mm.face[indf].V(1)->N().Normalize()); rnv[k*3+2].Import(mm.face[indf].V(2)->N().Normalize()); } else if (perfnorm) { rnv[k*3+0].Import(mm.face[indf].N().Normalize()); rnv[k*3+1].Import(mm.face[indf].N().Normalize()); rnv[k*3+2].Import(mm.face[indf].N().Normalize()); } if (pervertcol) { rcv[k*3+0] = mm.face[indf].V(0)->C(); rcv[k*3+1] = mm.face[indf].V(1)->C(); rcv[k*3+2] = mm.face[indf].V(2)->C(); } else if (perfcol) { rcv[k*3+0] = mm.face[indf].C(); rcv[k*3+1] = mm.face[indf].C(); rcv[k*3+2] = mm.face[indf].C(); } wtv[k*6+0]=mm.face[indf].WT(0).U(); wtv[k*6+1]=mm.face[indf].WT(0).V(); wtv[k*6+2]=mm.face[indf].WT(1).U(); wtv[k*6+3]=mm.face[indf].WT(1).V(); wtv[k*6+4]=mm.face[indf].WT(2).U(); wtv[k*6+5]=mm.face[indf].WT(2).V(); ++k; } ++t; } if (k != tn) throw MeshLabException("Mesh has not been properly partitioned"); glGenBuffers(1, &textureBO); glBindBuffer(GL_ARRAY_BUFFER, textureBO); glBufferData(GL_ARRAY_BUFFER, wtv.size() * sizeof(GLfloat), &wtv[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } else { //std::vector > ev; // Now doing the replicated stuff for(size_t i=0;i& pv,std::vector& nv) { int vn = mm.vn; bool textureperv = vcg::tri::HasPerVertexTexCoord(mm); pv.resize(vn); nv.resize(vn); if (HighPrecisionMode) { Box3m localBB; localBB.Add(mm.Tr,mm.bbox); Point3m localBBC =localBB.Center(); Tr.SetTranslate(localBBC); bbCenter.Import(localBBC); Matrix33m mat33(mm.Tr,3); for(size_t i=0;i& pv,std::vector& nv,std::vector& cv,std::vector& tv ) { int vn = mm.vn; bool textureperv = vcg::tri::HasPerVertexTexCoord(mm); pv.resize(vn); nv.resize(vn); cv.resize(vn); if (textureperv) tv.resize(vn*2); if (HighPrecisionMode) { Box3m localBB; localBB.Add(mm.Tr,mm.bbox); Point3m localBBC =localBB.Center(); Tr.SetTranslate(localBBC); bbCenter.Import(localBBC); Matrix33m mat33(mm.Tr,3); for(size_t i=0;i() { m = NULL; } GLWRendering::GLWRendering( CMeshO& mm ) :vcg::GlTrimesh() { m = &mm; } GLWRendering::~GLWRendering() { m = NULL; } void GLWRendering::render(vcg::GLW::DrawMode dm,vcg::GLW::NormalMode nm,vcg::GLW::ColorMode colm,vcg::GLW::TextureMode tm ) { if (m != NULL) { glPushAttrib(GL_ALL_ATTRIB_BITS); glPushMatrix(); glMultMatrix(m->Tr); if( (colm == vcg::GLW::CMPerFace) && (!vcg::tri::HasPerFaceColor(*m)) ) colm=vcg::GLW::CMNone; if( (tm == vcg::GLW::TMPerWedge )&& (!vcg::tri::HasPerWedgeTexCoord(*m)) ) tm=vcg::GLW::TMNone; if( (tm == vcg::GLW::TMPerWedgeMulti )&& (!vcg::tri::HasPerWedgeTexCoord(*m))) tm=vcg::GLW::TMNone; if( (tm == vcg::GLW::TMPerVert )&& (!vcg::tri::HasPerVertexTexCoord(*m))) tm=vcg::GLW::TMNone; Draw(dm,colm,tm); glPopMatrix(); glPopAttrib(); return; } }