From 05afd8510d84a4fab5bb4903dfd82203f6e02f79 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Wed, 13 Jan 2021 10:39:26 +0100 Subject: [PATCH] new optional glContext requirement for FilterPlugins --- .../interfaces/filter_plugin_interface.h | 183 ++- src/meshlabplugins/filter_ao/filter_ao.cpp | 150 +- src/meshlabplugins/filter_ao/filter_ao.h | 1 + .../filter_color_projection.cpp | 1415 +++++++++-------- .../filter_color_projection.h | 47 +- .../filter_img_patch_param.cpp | 338 ++-- .../filter_img_patch_param.h | 1 + .../filter_mutualglobal.cpp | 17 +- .../filter_mutualglobal/filter_mutualglobal.h | 1 + .../filter_mutualinfo/filter_mutualinfo.cpp | 15 + .../filter_mutualinfo/filter_mutualinfo.h | 1 + .../filter_sample_gpu/filter_sample_gpu.cpp | 25 +- .../filter_sample_gpu/filter_sample_gpu.h | 1 + .../filter_sdfgpu/filter_sdfgpu.cpp | 46 +- .../filter_sdfgpu/filter_sdfgpu.h | 225 +-- 15 files changed, 1305 insertions(+), 1161 deletions(-) diff --git a/src/common/interfaces/filter_plugin_interface.h b/src/common/interfaces/filter_plugin_interface.h index 1a10aa5aa..6b064ce47 100644 --- a/src/common/interfaces/filter_plugin_interface.h +++ b/src/common/interfaces/filter_plugin_interface.h @@ -28,15 +28,16 @@ #include "../ml_document/mesh_document.h" /** -\brief The FilterPluginInterface class provide the interface of the filter plugins. - -*/ + *\brief The FilterPluginInterface class provide the interface of the filter plugins. + * + */ class FilterPluginInterface : public PluginInterface { public: - /** The FilterClass enum represents the set of keywords that must be used to categorize a filter. - Each filter can belong to one or more filtering class, or-ed together. - */ + /** + * @brief The FilterClass enum represents the set of keywords that must be used to categorize a filter. + * Each filter can belong to one or more filtering class, or-ed together. + */ enum FilterClass { Generic = 0x00000, /*!< Should be avoided if possible. */ // @@ -63,111 +64,131 @@ public: - FilterPluginInterface() : PluginInterface(), glContext(NULL) + FilterPluginInterface() : PluginInterface(), glContext(nullptr) { } virtual ~FilterPluginInterface() {} - /** The very short string (a few words) describing each filtering action - // This string is used also to define the menu entry - */ + /** + * @brief The very short string (a few words) describing each filtering action + * This string is used also to define the menu entry + */ virtual QString filterName(FilterIDType) const = 0; - /** The long, formatted string describing each filtering action. - // This string is printed in the top of the parameter window - // so it should be at least one or two paragraphs long. The more the better. - // you can use simple html formatting tags (like "
" "" and "") to improve readability. - // This string is used in the 'About plugin' dialog and by meshlabserver to create the filter list wiki page and the doxygen documentation of the filters. - // Here is the place where you should put you bibliographic references in a form like this: -
- See:
- Luiz Velho, Denis Zorin
- "4-8 Subdivision"
- CAGD, volume 18, Issue 5, Pages 397-427.
-
- e.g. italic for authors, bold for title (quoted) and plain for bib ref. - */ + /** + * @brief The long, formatted string describing each filtering action. + * This string is printed in the top of the parameter window + * so it should be at least one or two paragraphs long. The more the better. + * you can use simple html formatting tags (like "
" "" and "") to improve readability. + * This string is used in the 'About plugin' dialog and by meshlabserver to create the filter list wiki page and the doxygen documentation of the filters. + * Here is the place where you should put you bibliographic references in a form like this: + *
+ * See:
+ * Luiz Velho, Denis Zorin
+ * "4-8 Subdivision"
+ * CAGD, volume 18, Issue 5, Pages 397-427.
+ *
+ * e.g. italic for authors, bold for title (quoted) and plain for bib ref. + */ virtual QString filterInfo(FilterIDType filter) const = 0; - /** The FilterClass describes in which generic class of filters it fits. - // This choice affect the submenu in which each filter will be placed - // For example filters that perform an action only on the selection will be placed in the Selection Class - */ + /** + * @brief The FilterClass describes in which generic class of filters it fits. + * This choice affect the submenu in which each filter will be placed + * For example filters that perform an action only on the selection will be placed in the Selection Class + */ virtual FilterClass getClass(const QAction*) const { return FilterPluginInterface::Generic; } /** - The filters can have some additional requirements on the mesh capabiliteis. - // For example if a filters requires Face-Face Adjacency you should re-implement - // this function making it returns MeshModel::MM_FACEFACETOPO. - // The framework will ensure that the mesh has the requirements satisfied before invoking the applyFilter function - // - // Furthermore, requirements are checked just before the invocation of a filter. If your filter - // outputs a never used before mesh property (e.g. face colors), it will be allocated by a call - // to MeshModel::updateDataMask(...) - */ + * @brief The filters can have some additional requirements on the mesh capabiliteis. + * For example if a filters requires Face-Face Adjacency you should re-implement + * this function making it returns MeshModel::MM_FACEFACETOPO. + * The framework will ensure that the mesh has the requirements satisfied before invoking the applyFilter function + * + * Furthermore, requirements are checked just before the invocation of a filter. If your filter + * outputs a never used before mesh property (e.g. face colors), it will be allocated by a call + * to MeshModel::updateDataMask(...) + */ virtual int getRequirements(const QAction*) { return MeshModel::MM_NONE; } + + /** + * @brief This function should require true if the glContext is used by the + * filter. Without this, the glContext will remain set to nullptr on non-GUI + * softwares that will use the filter (E.G. PyMeshLab). + * Note: every filter that uses the glContext should first check if + * glContext != nullptr. + */ + virtual bool requiresGLContext(const QAction*) const {return false;} - /** The FilterPrecondition mask is used to explicitate what kind of data a filter really needs to be applied. - // For example algorithms that compute per face quality have as precondition the existence of faces - // (but quality per face is not a precondition, because quality per face is created by these algorithms) - // on the other hand an algorithm that deletes faces according to the stored quality has both FaceQuality - // and Face as precondition. - // These conditions do NOT include computed properties like borderFlags, manifoldness or watertightness. - // They are also used to grayout menus un-appliable entries. - */ + /** + * @brief The FilterPrecondition mask is used to explicitate what kind of data a filter really needs to be applied. + * For example algorithms that compute per face quality have as precondition the existence of faces + * (but quality per face is not a precondition, because quality per face is created by these algorithms) + * on the other hand an algorithm that deletes faces according to the stored quality has both FaceQuality + * and Face as precondition. + * These conditions do NOT include computed properties like borderFlags, manifoldness or watertightness. + * They are also used to grayout menus un-appliable entries. + */ virtual int getPreConditions(const QAction*) const { return MeshModel::MM_NONE; } - /** Function used by the framework to get info about the mesh properties changed by the filter. - // It is widely used by the meshlab's preview system. - //TO BE REPLACED WITH = 0 - */ + /** + * @brief Function used by the framework to get info about the mesh properties changed by the filter. + * It is widely used by the meshlab's preview system. + * TO BE REPLACED WITH = 0 + */ virtual int postCondition(const QAction*) const { return MeshModel::MM_ALL; } - /** \brief applies the selected filter with the already stabilished parameters - * This function is called by the framework after getting values for the parameters specified in the \ref InitParameterSet - * NO GUI interaction should be done here. No dialog asking, no messagebox errors. - * Think that his function will also be called by the commandline framework. - * If you want report errors, use the \ref errorMsg() string. It will displayed in case of filters returning false. - * When implementing your applyFilter, you should use the cb function to report to the framework the current state of the processing. - * During your (long) processing you should call from time to time cb(perc,descriptiveString), where perc is an int (0..100) - * saying what you are doing and at what point of the computation you currently are. - * \sa errorMsg - * \sa initParameterSet - */ + /** + * @brief applies the selected filter with the already stabilished parameters + * This function is called by the framework after getting values for the parameters specified in the \ref InitParameterSet + * NO GUI interaction should be done here. No dialog asking, no messagebox errors. + * Think that his function will also be called by the commandline framework. + * If you want report errors, use the \ref errorMsg() string. It will displayed in case of filters returning false. + * When implementing your applyFilter, you should use the cb function to report to the framework the current state of the processing. + * During your (long) processing you should call from time to time cb(perc,descriptiveString), where perc is an int (0..100) + * saying what you are doing and at what point of the computation you currently are. + * @sa errorMsg + * @sa initParameterSet + */ virtual bool applyFilter(const QAction* filter, MeshDocument& md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList& par, vcg::CallBackPos* cb) = 0; - /** \brief tests if a filter is applicable to a mesh. - This function is a handy wrapper used by the framework for the \a getPreConditions callback; - For instance a colorize by quality filter cannot be applied to a mesh without per-vertex-quality. - On failure (returning false) the function fills the MissingItems list with strings describing the missing items. - */ + /** + * \brief tests if a filter is applicable to a mesh. + * This function is a handy wrapper used by the framework for the \a getPreConditions callback; + * For instance a colorize by quality filter cannot be applied to a mesh without per-vertex-quality. + * On failure (returning false) the function fills the MissingItems list with strings describing the missing items. + */ bool isFilterApplicable(const QAction* act, const MeshModel& m, QStringList &MissingItems) const; enum FILTER_ARITY { NONE = 0, SINGLE_MESH = 1, FIXED = 2, VARIABLE = 3, UNKNOWN_ARITY = 4 }; - /** \brief this function informs the MeshLab core on how many meshes the filter will work on. - Valid value: - - SINGLE_MESH: the filter works just on the current mesh - - FIXED: the number (and the names) of the meshes involved in the filter computation is determined by the parameters selected in the filter's parameters form - - VARIABLE: the filter works on a not predetermined number of meshes. The meshes involved are typically selected by the user checking on the correspondent layer on the layer dialog - */ + /** + * @brief this function informs the MeshLab core on how many meshes the filter will work on. + * Valid value: + * - SINGLE_MESH: the filter works just on the current mesh + * - FIXED: the number (and the names) of the meshes involved in the filter computation is determined by the parameters selected in the filter's parameters form + * - VARIABLE: the filter works on a not predetermined number of meshes. The meshes involved are typically selected by the user checking on the correspondent layer on the layer dialog + */ virtual FILTER_ARITY filterArity(const QAction *act) const = 0; - // This function is called to initialized the list of parameters. - // it is always called. If a filter does not need parameter it leave it empty and the framework - // will not create a dialog (unless for previewing) + /** + * @brief This function is called to initialized the list of parameters. + * it is always called. If a filter does not need parameter it leave it empty and the framework + * will not create a dialog (unless for previewing) + */ virtual void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*par*/) {} virtual void initParameterList(const QAction* filter, MeshDocument &md, RichParameterList &par) { initParameterList(filter, *(md.mm()), par); } - /** \brief is invoked by the framework when the applyFilter fails to give some info to the user about the filter failure - * Filters \b must never use QMessageBox for reporting errors. - * Failing filters should put some meaningful information inside the errorMessage string and return false with the \ref applyFilter - */ + /** + * @brief is invoked by the framework when the applyFilter fails to give some info to the user about the filter failure + * Filters \b must never use QMessageBox for reporting errors. + * Failing filters should put some meaningful information inside the errorMessage string and return false with the \ref applyFilter + */ const QString& errorMsg() const { return this->errorMessage; } virtual QString filterInfo(const QAction* a) const { return this->filterInfo(ID(a)); } virtual QString filterName(const QAction* a) const { return this->filterName(ID(a)); } @@ -181,8 +202,10 @@ public: virtual QList actions() const { return actionList; } virtual QList types() const { return typeList; } - /** Generate the mask of attributes would be created IF the MeshFilterInterface filt would has been called on MeshModel mm - BE CAREFUL! this function does NOT change in anyway the state of the MeshModel!!!! **/ + /** + * Generate the mask of attributes would be created IF the MeshFilterInterface filt would has been called on MeshModel mm + * BE CAREFUL! this function does NOT change in anyway the state of the MeshModel!!!! + */ int previewOnCreatedAttributes(const QAction* act, const MeshModel& mm) const; QString generatedScriptCode; diff --git a/src/meshlabplugins/filter_ao/filter_ao.cpp b/src/meshlabplugins/filter_ao/filter_ao.cpp index 630bdab07..bdbd5dc2f 100644 --- a/src/meshlabplugins/filter_ao/filter_ao.cpp +++ b/src/meshlabplugins/filter_ao/filter_ao.cpp @@ -84,19 +84,29 @@ QString AmbientOcclusionPlugin::filterName(FilterIDType filterId) const QString AmbientOcclusionPlugin::filterInfo(FilterIDType filterId) const { - switch(filterId) - { - case FP_AMBIENT_OCCLUSION: return QString("Compute ambient occlusions values; it takes a number of well distributed view direction and for point of the surface it computes how many time it is visible from these directions. This value is saved into quality and automatically mapped into a gray shade. The average direction is saved into an attribute named 'BentNormal'"); - default : assert(0); - } - - return QString(""); + switch(filterId) { + case FP_AMBIENT_OCCLUSION: + return QString("Compute ambient occlusions values; it takes a number of well distributed view direction and for point of the surface it computes how many time it is visible from these directions. This value is saved into quality and automatically mapped into a gray shade. The average direction is saved into an attribute named 'BentNormal'"); + default : assert(0); + } + return QString(""); } int AmbientOcclusionPlugin::getRequirements(const QAction * /*action*/) { - //no requirements needed - return 0; + //no requirements needed + return 0; +} + +bool AmbientOcclusionPlugin::requiresGLContext(const QAction* action) const +{ + switch (ID(action)) { + case FP_AMBIENT_OCCLUSION: + return true; + default: + assert(0); + } + return false; } FilterPluginInterface::FILTER_ARITY AmbientOcclusionPlugin::filterArity(const QAction*) const @@ -134,65 +144,71 @@ void AmbientOcclusionPlugin::initParameterList(const QAction *action, MeshModel } bool AmbientOcclusionPlugin::applyFilter(const QAction * /*filter*/, MeshDocument &md, std::map&, unsigned int& /*postConditionMask*/, const RichParameterList & par, vcg::CallBackPos *cb) { - MeshModel &m=*(md.mm()); + if (glContext != nullptr) { + MeshModel &m=*(md.mm()); - int occlusionMode = par.getEnum("occMode"); - if (occlusionMode == 1) - perFace = true; - else - perFace = false; - - useGPU = par.getBool("useGPU"); - if (perFace) //GPU only works per-vertex - useGPU = false; - depthTexSize = par.getInt("depthTexSize"); - depthTexArea = depthTexSize*depthTexSize; - numViews = par.getInt("reqViews"); - errInit = false; - Scalarm dirBias = par.getFloat("dirBias"); - Point3m coneDir = par.getPoint3m("coneDir"); - Scalarm coneAngle = par.getFloat("coneAngle"); - - if(perFace) - m.updateDataMask(MeshModel::MM_FACEQUALITY | MeshModel::MM_FACECOLOR); - else - m.updateDataMask(MeshModel::MM_VERTQUALITY | MeshModel::MM_VERTCOLOR); - - std::vector unifDirVec; - GenNormal::Fibonacci(numViews,unifDirVec); - - std::vector coneDirVec; - GenNormal::UniformCone(numViews, coneDirVec, math::ToRad(coneAngle), coneDir); - - std::random_shuffle(unifDirVec.begin(),unifDirVec.end()); - std::random_shuffle(coneDirVec.begin(),coneDirVec.end()); - - int unifNum = floor(unifDirVec.size() * (1.0 - dirBias )); - int coneNum = floor(coneDirVec.size() * (dirBias )); - - viewDirVec.clear(); - viewDirVec.insert(viewDirVec.end(),unifDirVec.begin(),unifDirVec.begin()+unifNum); - viewDirVec.insert(viewDirVec.end(),coneDirVec.begin(),coneDirVec.begin()+coneNum); - numViews = viewDirVec.size(); - - this->glContext->makeCurrent(); - this->initGL(cb,m.cm.vn); - unsigned int widgetSize = std::min(maxTexSize, depthTexSize); - QSize fbosize(widgetSize,widgetSize); - QGLFramebufferObjectFormat frmt; - frmt.setInternalTextureFormat(GL_RGBA); - frmt.setAttachment(QGLFramebufferObject::Depth); - QGLFramebufferObject fbo(fbosize,frmt); - qDebug("Start Painting window size %i %i", fbo.width(), fbo.height()); - GLenum err = glGetError(); - fbo.bind(); - processGL(m,viewDirVec); - fbo.release(); - err = glGetError(); - const GLubyte* errname = gluErrorString(err); (void)errname; - qDebug("End Painting"); - this->glContext->doneCurrent(); - return !errInit; + int occlusionMode = par.getEnum("occMode"); + if (occlusionMode == 1) + perFace = true; + else + perFace = false; + + useGPU = par.getBool("useGPU"); + if (perFace) //GPU only works per-vertex + useGPU = false; + depthTexSize = par.getInt("depthTexSize"); + depthTexArea = depthTexSize*depthTexSize; + numViews = par.getInt("reqViews"); + errInit = false; + Scalarm dirBias = par.getFloat("dirBias"); + Point3m coneDir = par.getPoint3m("coneDir"); + Scalarm coneAngle = par.getFloat("coneAngle"); + + if(perFace) + m.updateDataMask(MeshModel::MM_FACEQUALITY | MeshModel::MM_FACECOLOR); + else + m.updateDataMask(MeshModel::MM_VERTQUALITY | MeshModel::MM_VERTCOLOR); + + std::vector unifDirVec; + GenNormal::Fibonacci(numViews,unifDirVec); + + std::vector coneDirVec; + GenNormal::UniformCone(numViews, coneDirVec, math::ToRad(coneAngle), coneDir); + + std::random_shuffle(unifDirVec.begin(),unifDirVec.end()); + std::random_shuffle(coneDirVec.begin(),coneDirVec.end()); + + int unifNum = floor(unifDirVec.size() * (1.0 - dirBias )); + int coneNum = floor(coneDirVec.size() * (dirBias )); + + viewDirVec.clear(); + viewDirVec.insert(viewDirVec.end(),unifDirVec.begin(),unifDirVec.begin()+unifNum); + viewDirVec.insert(viewDirVec.end(),coneDirVec.begin(),coneDirVec.begin()+coneNum); + numViews = viewDirVec.size(); + + this->glContext->makeCurrent(); + this->initGL(cb,m.cm.vn); + unsigned int widgetSize = std::min(maxTexSize, depthTexSize); + QSize fbosize(widgetSize,widgetSize); + QGLFramebufferObjectFormat frmt; + frmt.setInternalTextureFormat(GL_RGBA); + frmt.setAttachment(QGLFramebufferObject::Depth); + QGLFramebufferObject fbo(fbosize,frmt); + qDebug("Start Painting window size %i %i", fbo.width(), fbo.height()); + GLenum err = glGetError(); + fbo.bind(); + processGL(m,viewDirVec); + fbo.release(); + err = glGetError(); + const GLubyte* errname = gluErrorString(err); (void)errname; + qDebug("End Painting"); + this->glContext->doneCurrent(); + return !errInit; + } + else { + errorMessage = "Fatal error: glContext not initialized"; + return false; + } } bool AmbientOcclusionPlugin::processGL(MeshModel &m, vector &posVect) diff --git a/src/meshlabplugins/filter_ao/filter_ao.h b/src/meshlabplugins/filter_ao/filter_ao.h index 5461764c1..6c73fe305 100644 --- a/src/meshlabplugins/filter_ao/filter_ao.h +++ b/src/meshlabplugins/filter_ao/filter_ao.h @@ -73,6 +73,7 @@ public: QString filterInfo(FilterIDType filterId) const; FILTER_ARITY filterArity(const QAction*) const; int getRequirements (const QAction* action); + bool requiresGLContext(const QAction* action) const; FilterClass getClass(const QAction* filter) const; void initParameterList(const QAction*, MeshModel &/*m*/, RichParameterList & /*parent*/); diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp index 89ce0c5b9..08b915473 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.cpp @@ -103,7 +103,20 @@ int FilterColorProjectionPlugin::getRequirements(const QAction *action){ case FP_MULTIIMAGETRIVIALPROJTEXTURE : return 0; default: assert(0); return 0; } - return 0; + return 0; +} + +bool FilterColorProjectionPlugin::requiresGLContext(const QAction* action) const +{ + switch(ID(action)){ + case FP_SINGLEIMAGEPROJ: + case FP_MULTIIMAGETRIVIALPROJ: + case FP_MULTIIMAGETRIVIALPROJTEXTURE : + return true; + default: + assert(0); + } + return false; } @@ -220,703 +233,709 @@ void FilterColorProjectionPlugin::initParameterList(const QAction *action, MeshD // Core Function doing the actual mesh processing. bool FilterColorProjectionPlugin::applyFilter(const QAction *filter, MeshDocument &md, std::map&, unsigned int& /*postConditionMask*/, const RichParameterList & par, vcg::CallBackPos *cb) { - //CMeshO::FaceIterator fi; - CMeshO::VertexIterator vi; - - RenderHelper *rendermanager=NULL; - - switch(ID(filter)) - { - - ////--------------------------- project single trivial ---------------------------------- - - case FP_SINGLEIMAGEPROJ : - { - bool use_depth = par.getBool("usedepth"); - bool onselection = par.getBool("onselection"); - Scalarm eta = par.getFloat("deptheta"); - QColor blank = par.getColor("blankColor"); - - - Scalarm depth=0; // depth of point (distance from camera) - Scalarm pdepth=0; // depth value of projected point (from depth map) - - // get current raster and model - RasterModel *raster = md.rm(); - MeshModel *model = md.mm(); - - // no projection if camera not valid - if(!raster->shot.IsValid()) - return false; - - // the mesh has to be correctly transformed before mapping - tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); - tri::UpdateBounding::Box(model->cm); - - // making context current - glContext->makeCurrent(); - - if(use_depth) - { - // init rendermanager - rendermanager = new RenderHelper(); - if( rendermanager->initializeGL(cb) != 0 ) - { - delete rendermanager; - return false; - } - log("init GL"); - //if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) - // return false; - //Log("init Buffers"); - - // render depth - rendermanager->renderScene(raster->shot, model, RenderHelper::FLAT, glContext); - } - - // unmaking context current - glContext->doneCurrent(); - - qDebug("Viewport %i %i",raster->shot.Intrinsics.ViewportPx[0],raster->shot.Intrinsics.ViewportPx[1]); - for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) - { - if(!(*vi).IsD() && (!onselection || (*vi).IsS())) - { - Point2m pp = raster->shot.Project((*vi).P()); - // pray is the vector from the point-to-be-colored to the camera center - Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); - - if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || (blank.alpha() != 0)) - (*vi).C() = vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); - - //if inside image - if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) - { - if((pray.dot(-raster->shot.Axis(2))) <= 0.0) - { - if(use_depth) - { - depth = raster->shot.Depth((*vi).P()); - pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1]));//rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; - } - - if(!use_depth || (depth <= (pdepth + eta))) - { - QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); - (*vi).C() = vcg::Color4b(qRed(pcolor), qGreen(pcolor), qBlue(pcolor), 255); - } - } - } - } - } - - // the mesh has to return to its original position - tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); - tri::UpdateBounding::Box(model->cm); - - // delete rendermanager - if(rendermanager != NULL) - delete rendermanager; - } - - break; - - - ////--------------------------- project multi trivial ---------------------------------- - - case FP_MULTIIMAGETRIVIALPROJ : - { - bool onselection = par.getBool("onselection"); - Scalarm eta = par.getFloat("deptheta"); - bool useangle = par.getBool("useangle"); - bool usedistance = par.getBool("usedistance"); - bool useborders = par.getBool("useborders"); - bool usesilhouettes = par.getBool("usesilhouettes"); - bool usealphamask = par.getBool("usealpha"); - QColor blank = par.getColor("blankColor"); - - Scalarm depth=0; // depth of point (distance from camera) - Scalarm pdepth=0; // depth value of projected point (from depth map) - double pweight; // pixel weight - MeshModel *model; - bool do_project; - int cam_ind; - - // min max depth for depth weight normalization - float allcammaxdepth; - float allcammindepth; - - // max image size for border weight normalization - float allcammaximagesize; - - // accumulation buffers for colors and weights - int buff_ind; - double *weights; - double *acc_red; - double *acc_grn; - double *acc_blu; - - // get current model - model = md.mm(); - - // the mesh has to be correctly transformed before mapping - tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); - tri::UpdateBounding::Box(model->cm); - - // init accumulation buffers for colors and weights - log("init color accumulation buffers"); - weights = new double[model->cm.vn]; - acc_red = new double[model->cm.vn]; - acc_grn = new double[model->cm.vn]; - acc_blu = new double[model->cm.vn]; - for(int buff_ind=0; buff_indcm.vn; buff_ind++) - { - weights[buff_ind] = 0.0; - acc_red[buff_ind] = 0.0; - acc_grn[buff_ind] = 0.0; - acc_blu[buff_ind] = 0.0; - } - - // calculate accuratenear/far for all cameras - std::vector my_near; - std::vector my_far; - calculateNearFarAccurate(md, &my_near, &my_far); - - allcammaxdepth = -1000000; - allcammindepth = 1000000; - allcammaximagesize = -1000000; - for(cam_ind = 0; cam_ind < md.rasterList.size(); cam_ind++) - { - if(my_far[cam_ind] > allcammaxdepth) - allcammaxdepth = my_far[cam_ind]; - if(my_near[cam_ind] < allcammindepth) - allcammindepth = my_near[cam_ind]; - - float imgdiag = sqrt(double(md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[0] * md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[1])); - if (imgdiag > allcammaximagesize) - allcammaximagesize = imgdiag; - } - - //-- cycle all cameras - cam_ind = 0; - for(RasterModel *raster : md.rasterList){ - if(raster->visible) - { - do_project = true; - - // no drawing if camera not valid - if(!raster->shot.IsValid()) - do_project = false; - - // no drawing if raster is not active - //if(!raster->shot.IsValid()) - // do_project = false; - - if(do_project) - { - // making context current - glContext->makeCurrent(); - - // delete & reinit rendermanager - if(rendermanager != NULL) - delete rendermanager; - rendermanager = new RenderHelper(); - if( rendermanager->initializeGL(cb) != 0 ) - return false; - log("init GL"); - /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) - return false; - Log("init Buffers");*/ - - // render normal & depth - rendermanager->renderScene(raster->shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); - - // unmaking context current - glContext->doneCurrent(); - - buff_ind=0; - - // If should be used silhouette weighting, it is needed to compute depth discontinuities - // and per-pixel distance from detected borders on the entire image here - // the weight is then applied later, per-vertex, when needed - floatbuffer *silhouette_buff=NULL; - float maxsildist = rendermanager->depth->sx + rendermanager->depth->sy; - if(usesilhouettes) - { - silhouette_buff = new floatbuffer(); - silhouette_buff->init(rendermanager->depth->sx, rendermanager->depth->sy); - - silhouette_buff->applysobel(rendermanager->depth); - //sprintf(dumpFileName,"Abord%i.pfm",cam_ind); - //silhouette_buff->dumppfm(dumpFileName); - - silhouette_buff->initborder(rendermanager->depth); - //sprintf(dumpFileName,"Bbord%i.pfm",cam_ind); - //silhouette_buff->dumppfm(dumpFileName); - - maxsildist = silhouette_buff->distancefield(); - //sprintf(dumpFileName,"Cbord%i.pfm",cam_ind); - //silhouette_buff->dumppfm(dumpFileName); - } - - for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) - { - if(!(*vi).IsD() && (!onselection || (*vi).IsS())) - { - // pp is the projected point in image space - Point2m pp = raster->shot.Project((*vi).P()); - // pray is the vector from the point-to-be-colored to the camera center - Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); - - //if inside image - if(pp[0]>=0 && pp[1]>=0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) - { - if((pray.dot(-raster->shot.Axis(2))) <= 0.0) - { - - depth = raster->shot.Depth((*vi).P()); - pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; - - if(depth <= (pdepth + eta)) - { - // determine color - QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); - // determine weight - pweight = 1.0; - - if(useangle) - { - Point3m pixnorm = (*vi).N(); - Point3m viewaxis = raster->shot.GetViewPoint() - (*vi).P(); - pixnorm.Normalize(); - viewaxis.Normalize(); - - float ang = abs(pixnorm * viewaxis); - ang = min(1.0f, ang); - - pweight *= ang; - } - - if(usedistance) - { - float distw = depth; - distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); - - pweight *= distw; - pweight *= distw; - } - - if(useborders) - { - double xdist = 1.0 - (abs(pp[0] - (raster->shot.Intrinsics.ViewportPx[0] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[0] / 2.0)); - double ydist = 1.0 - (abs(pp[1] - (raster->shot.Intrinsics.ViewportPx[1] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[1] / 2.0)); - double borderw = min (xdist , ydist); - //borderw = min(1.0,borderw); //debug debug - //borderw = max(0.0,borderw); //debug debug - - pweight *= borderw; - } - - if(usesilhouettes) - { - // here the silhouette weight is applied, but it is calculated before, on a per-image basis - float silw = 1.0; - silw = silhouette_buff->getval(int(pp[0]), int(pp[1])) / maxsildist; - //silw = min(1.0f,silw); //debug debug - //silw = max(0.0f,silw); //debug debug - - pweight *= silw; - } - - if(usealphamask) //alpha channel of image is an additional mask - { - pweight *= (qAlpha(pcolor) / 255.0); - } - - weights[buff_ind] += pweight; - acc_red[buff_ind] += (qRed(pcolor) * pweight / 255.0); - acc_grn[buff_ind] += (qGreen(pcolor) * pweight / 255.0); - acc_blu[buff_ind] += (qBlue(pcolor) * pweight / 255.0); - } - } - } - } - buff_ind++; - } - cam_ind ++; - - if(usesilhouettes) - { - delete silhouette_buff; - } - - } // end foreach camera - } // end foreach camera - } - - buff_ind = 0; - for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) - { - if(!(*vi).IsD() && (!onselection || (*vi).IsS())) - { - if (weights[buff_ind] != 0) // if 0, it has not found any valid projection on any camera - { - (*vi).C() = vcg::Color4b( (acc_red[buff_ind] / weights[buff_ind]) *255.0, - (acc_grn[buff_ind] / weights[buff_ind]) *255.0, - (acc_blu[buff_ind] / weights[buff_ind]) *255.0, - 255); - } - else - { - if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || (blank.alpha() != 0)) - (*vi).C() = vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); - } - } - buff_ind++; - } - - // the mesh has to return to its original position - tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); - tri::UpdateBounding::Box(model->cm); - - // delete rendermanager - if(rendermanager != NULL) - delete rendermanager; - - // delete accumulation buffers - delete[] weights; - delete[] acc_red; - delete[] acc_grn; - delete[] acc_blu; - - } - break; - - - case FP_MULTIIMAGETRIVIALPROJTEXTURE : - { - - if(!tri::HasPerWedgeTexCoord(md.mm()->cm)) - { - errorMessage="Warning: nothing have been done. Mesh has no Texture Coordinates."; - return false; - } - - //bool onselection = par.getBool("onselection"); - int texsize = par.getInt("texsize"); - bool dorefill = par.getBool("dorefill"); - Scalarm eta = par.getFloat("deptheta"); - bool useangle = par.getBool("useangle"); - bool usedistance = par.getBool("usedistance"); - bool useborders = par.getBool("useborders"); - bool usesilhouettes = par.getBool("usesilhouettes"); - bool usealphamask = par.getBool("usealpha"); - QString textName = par.getString("textName"); - - int textW = texsize; - int textH = texsize; - - Scalarm depth=0; // depth of point (distance from camera) - Scalarm pdepth=0; // depth value of projected point (from depth map) - double pweight; // pixel weight - MeshModel *model; - bool do_project; - int cam_ind; - - // min max depth for depth weight normalization - float allcammaxdepth; - float allcammindepth; - - // max image size for border weight normalization - float allcammaximagesize; - - // get the working model - model = md.mm(); - - // the mesh has to be correctly transformed before mapping - tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); - tri::UpdateBounding::Box(model->cm); - - // texture file name - QString filePath(model->fullName()); - filePath = filePath.left(std::max(filePath.lastIndexOf('\\'),filePath.lastIndexOf('/'))+1); - // Check textName and eventually add .png ext - CheckError(textName.length() == 0, "Texture file not specified"); - CheckError(std::max(textName.lastIndexOf("\\"),textName.lastIndexOf("/")) != -1, "Path in Texture file not allowed"); - if (!textName.endsWith(".png", Qt::CaseInsensitive)) - textName.append(".png"); - filePath.append(textName); - - // Image creation - CheckError(textW <= 0, "Texture Width has an incorrect value"); - CheckError(textH <= 0, "Texture Height has an incorrect value"); - QImage img(QSize(textW,textH), QImage::Format_ARGB32); - img.fill(qRgba(0,0,0,0)); // transparent black - - // Compute (texture-space) border edges - if(dorefill) - { - model->updateDataMask(MeshModel::MM_FACEFACETOPO); - tri::UpdateTopology::FaceFaceFromTexCoord(model->cm); - tri::UpdateFlags::FaceBorderFromFF(model->cm); - } - - // create a list of to-be-filled texels and accumulators - // storing texel 2d coords, texel mesh-space point, texel mesh normal - - vector texels; - texels.clear(); - texels.reserve(textW*textH); // just to avoid the 2x reallocate rule... - - vector accums; - accums.clear(); - accums.reserve(textW*textH); // just to avoid the 2x reallocate rule... - - // Rasterizing triangles in the list of voxels - TexFillerSampler tfs(img); - tfs.texelspointer = &texels; - tfs.accumpointer = &accums; - tfs.InitCallback(cb, model->cm.fn, 0, 80); - tri::SurfaceSampling::Texture(model->cm,tfs,textW,textH,true); - - // Revert alpha values for border edge pixels to 255 - cb(81, "Cleaning up texture ..."); - for (int y=0; y 0) - img.setPixel(x,y, px | 0xff000000); - } - } - - // calculate accuratenear/far for all cameras - std::vector my_near; - std::vector my_far; - calculateNearFarAccurate(md, &my_near, &my_far); - - allcammaxdepth = -1000000; - allcammindepth = 1000000; - allcammaximagesize = -1000000; - for(cam_ind = 0; cam_ind < md.rasterList.size(); cam_ind++) - { - if(my_far[cam_ind] > allcammaxdepth) - allcammaxdepth = my_far[cam_ind]; - if(my_near[cam_ind] < allcammindepth) - allcammindepth = my_near[cam_ind]; - - float imgdiag = sqrt(double(md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[0] * md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[1])); - if (imgdiag > allcammaximagesize) - allcammaximagesize = imgdiag; - } - - //-- cycle all cameras - cam_ind = 0; - for(RasterModel *raster : md.rasterList) - { - if(raster->visible) - { - do_project = true; - - // no drawing if camera not valid - if(!raster->shot.IsValid()) - do_project = false; - - // no drawing if raster is not active - //if(!raster->shot.IsValid()) - // do_project = false; - - if(do_project) - { - // making context current - glContext->makeCurrent(); - - // delete & reinit rendermanager - if(rendermanager != NULL) - delete rendermanager; - rendermanager = new RenderHelper(); - if( rendermanager->initializeGL(cb) != 0 ) - return false; - log("init GL"); - /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) - return false; - Log("init Buffers");*/ - - // render normal & depth - rendermanager->renderScene(raster->shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); - - // unmaking context current - glContext->doneCurrent(); - - // If should be used silhouette weighting, it is needed to compute depth discontinuities - // and per-pixel distance from detected borders on the entire image here - // the weight is then applied later, per-vertex, when needed - floatbuffer *silhouette_buff=NULL; - float maxsildist = rendermanager->depth->sx + rendermanager->depth->sy; - if(usesilhouettes) - { - silhouette_buff = new floatbuffer(); - silhouette_buff->init(rendermanager->depth->sx, rendermanager->depth->sy); - - silhouette_buff->applysobel(rendermanager->depth); - //sprintf(dumpFileName,"Abord%i.bmp",cam_ind); - //silhouette_buff->dumpbmp(dumpFileName); - - silhouette_buff->initborder(rendermanager->depth); - //sprintf(dumpFileName,"Bbord%i.bmp",cam_ind); - //silhouette_buff->dumpbmp(dumpFileName); - - maxsildist = silhouette_buff->distancefield(); - //sprintf(dumpFileName,"Cbord%i.bmp",cam_ind); - //silhouette_buff->dumpbmp(dumpFileName); - } - - for(size_t texcount=0; texcount < texels.size(); texcount++) - { - Point2m pp = raster->shot.Project(texels[texcount].meshpoint); - // pray is the vector from the point-to-be-colored to the camera center - Point3m pray = (raster->shot.GetViewPoint() - texels[texcount].meshpoint).Normalize(); - - //if inside image - if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) - { - if((pray.dot(-raster->shot.Axis(2))) <= 0.0) - { - - depth = raster->shot.Depth(texels[texcount].meshpoint); - pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; - - if(depth <= (pdepth + eta)) - { - // determine color - QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); - // determine weight - pweight = 1.0; - - if(useangle) - { - Point3m pixnorm = texels[texcount].meshnormal; - pixnorm.Normalize(); - - Point3m viewaxis = raster->shot.GetViewPoint() - texels[texcount].meshpoint; - viewaxis.Normalize(); - - float ang = abs(pixnorm * viewaxis); - ang = min(1.0f, ang); - - pweight *= ang; - } - - if(usedistance) - { - float distw = depth; - distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); - - pweight *= distw; - pweight *= distw; - } - - if(useborders) - { - double xdist = 1.0 - (abs(pp[0] - (raster->shot.Intrinsics.ViewportPx[0] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[0] / 2.0)); - double ydist = 1.0 - (abs(pp[1] - (raster->shot.Intrinsics.ViewportPx[1] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[1] / 2.0)); - double borderw = min (xdist , ydist); - - pweight *= borderw; - } - - if(usesilhouettes) - { - // here the silhouette weight is applied, but it is calculated before, on a per-image basis - float silw = 1.0; - silw = silhouette_buff->getval(int(pp[0]), int(pp[1])) / maxsildist; - pweight *= silw; - } - - if(usealphamask) //alpha channel of image is an additional mask - { - pweight *= (qAlpha(pcolor) / 255.0); - } - - accums[texcount].weights += pweight; - accums[texcount].acc_red += (qRed(pcolor) * pweight / 255.0); - accums[texcount].acc_grn += (qGreen(pcolor) * pweight / 255.0); - accums[texcount].acc_blu += (qBlue(pcolor) * pweight / 255.0); - } - } - } - - } // end foreach texel - cam_ind ++; - - if(usesilhouettes) - { - delete silhouette_buff; - } - - } // end if(do_project) - - } - } // end foreach camera - - // for each texel.... divide accumulated values by weight and write to texture - for(size_t texcount=0; texcount < texels.size(); texcount++) - { - if(accums[texcount].weights > 0.0) - { - float texel_red = accums[texcount].acc_red / accums[texcount].weights; - float texel_green = accums[texcount].acc_grn / accums[texcount].weights; - float texel_blue = accums[texcount].acc_blu / accums[texcount].weights; - - img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(texel_red*255.0, texel_green*255.0, texel_blue*255.0, 255)); - } - else // if no projected data available, black (to be refilled later on - { - img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(0, 0, 0, 0)); - } - } - - // cleaning - texels.clear(); - accums.clear(); - - // PullPush - if(dorefill) - { - cb(85, "Filling texture holes..."); - - PullPush(img, qRgba(0,0,0,0)); // atlas gaps - } - - // Undo topology changes - if(dorefill) - { - tri::UpdateTopology::FaceFace(model->cm); - tri::UpdateFlags::FaceBorderFromFF(model->cm); - } - - // Save texture - cb(90, "Saving texture ..."); - CheckError(!img.save(filePath), "Texture file cannot be saved"); - log( "Texture \"%s\" Created", filePath.toStdString().c_str()); - assert(QFile(filePath).exists()); - - // Assign texture - model->cm.textures.clear(); - model->cm.textures.push_back(textName.toStdString()); - - // the mesh has to return to its original position - tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); - tri::UpdateBounding::Box(model->cm); - - - } break; - - - } - - return true; + if (glContext != nullptr){ + //CMeshO::FaceIterator fi; + CMeshO::VertexIterator vi; + + RenderHelper *rendermanager=NULL; + + switch(ID(filter)) + { + + ////--------------------------- project single trivial ---------------------------------- + + case FP_SINGLEIMAGEPROJ : + { + bool use_depth = par.getBool("usedepth"); + bool onselection = par.getBool("onselection"); + Scalarm eta = par.getFloat("deptheta"); + QColor blank = par.getColor("blankColor"); + + + Scalarm depth=0; // depth of point (distance from camera) + Scalarm pdepth=0; // depth value of projected point (from depth map) + + // get current raster and model + RasterModel *raster = md.rm(); + MeshModel *model = md.mm(); + + // no projection if camera not valid + if(!raster->shot.IsValid()) + return false; + + // the mesh has to be correctly transformed before mapping + tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); + tri::UpdateBounding::Box(model->cm); + + // making context current + glContext->makeCurrent(); + + if(use_depth) + { + // init rendermanager + rendermanager = new RenderHelper(); + if( rendermanager->initializeGL(cb) != 0 ) + { + delete rendermanager; + return false; + } + log("init GL"); + //if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) + // return false; + //Log("init Buffers"); + + // render depth + rendermanager->renderScene(raster->shot, model, RenderHelper::FLAT, glContext); + } + + // unmaking context current + glContext->doneCurrent(); + + qDebug("Viewport %i %i",raster->shot.Intrinsics.ViewportPx[0],raster->shot.Intrinsics.ViewportPx[1]); + for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) + { + if(!(*vi).IsD() && (!onselection || (*vi).IsS())) + { + Point2m pp = raster->shot.Project((*vi).P()); + // pray is the vector from the point-to-be-colored to the camera center + Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); + + if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || (blank.alpha() != 0)) + (*vi).C() = vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); + + //if inside image + if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) + { + if((pray.dot(-raster->shot.Axis(2))) <= 0.0) + { + if(use_depth) + { + depth = raster->shot.Depth((*vi).P()); + pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1]));//rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; + } + + if(!use_depth || (depth <= (pdepth + eta))) + { + QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); + (*vi).C() = vcg::Color4b(qRed(pcolor), qGreen(pcolor), qBlue(pcolor), 255); + } + } + } + } + } + + // the mesh has to return to its original position + tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); + tri::UpdateBounding::Box(model->cm); + + // delete rendermanager + if(rendermanager != NULL) + delete rendermanager; + } + + break; + + + ////--------------------------- project multi trivial ---------------------------------- + + case FP_MULTIIMAGETRIVIALPROJ : + { + bool onselection = par.getBool("onselection"); + Scalarm eta = par.getFloat("deptheta"); + bool useangle = par.getBool("useangle"); + bool usedistance = par.getBool("usedistance"); + bool useborders = par.getBool("useborders"); + bool usesilhouettes = par.getBool("usesilhouettes"); + bool usealphamask = par.getBool("usealpha"); + QColor blank = par.getColor("blankColor"); + + Scalarm depth=0; // depth of point (distance from camera) + Scalarm pdepth=0; // depth value of projected point (from depth map) + double pweight; // pixel weight + MeshModel *model; + bool do_project; + int cam_ind; + + // min max depth for depth weight normalization + float allcammaxdepth; + float allcammindepth; + + // max image size for border weight normalization + float allcammaximagesize; + + // accumulation buffers for colors and weights + int buff_ind; + double *weights; + double *acc_red; + double *acc_grn; + double *acc_blu; + + // get current model + model = md.mm(); + + // the mesh has to be correctly transformed before mapping + tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); + tri::UpdateBounding::Box(model->cm); + + // init accumulation buffers for colors and weights + log("init color accumulation buffers"); + weights = new double[model->cm.vn]; + acc_red = new double[model->cm.vn]; + acc_grn = new double[model->cm.vn]; + acc_blu = new double[model->cm.vn]; + for(int buff_ind=0; buff_indcm.vn; buff_ind++) + { + weights[buff_ind] = 0.0; + acc_red[buff_ind] = 0.0; + acc_grn[buff_ind] = 0.0; + acc_blu[buff_ind] = 0.0; + } + + // calculate accuratenear/far for all cameras + std::vector my_near; + std::vector my_far; + calculateNearFarAccurate(md, &my_near, &my_far); + + allcammaxdepth = -1000000; + allcammindepth = 1000000; + allcammaximagesize = -1000000; + for(cam_ind = 0; cam_ind < md.rasterList.size(); cam_ind++) + { + if(my_far[cam_ind] > allcammaxdepth) + allcammaxdepth = my_far[cam_ind]; + if(my_near[cam_ind] < allcammindepth) + allcammindepth = my_near[cam_ind]; + + float imgdiag = sqrt(double(md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[0] * md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[1])); + if (imgdiag > allcammaximagesize) + allcammaximagesize = imgdiag; + } + + //-- cycle all cameras + cam_ind = 0; + for(RasterModel *raster : md.rasterList){ + if(raster->visible) + { + do_project = true; + + // no drawing if camera not valid + if(!raster->shot.IsValid()) + do_project = false; + + // no drawing if raster is not active + //if(!raster->shot.IsValid()) + // do_project = false; + + if(do_project) + { + // making context current + glContext->makeCurrent(); + + // delete & reinit rendermanager + if(rendermanager != NULL) + delete rendermanager; + rendermanager = new RenderHelper(); + if( rendermanager->initializeGL(cb) != 0 ) + return false; + log("init GL"); + /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) + return false; + Log("init Buffers");*/ + + // render normal & depth + rendermanager->renderScene(raster->shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); + + // unmaking context current + glContext->doneCurrent(); + + buff_ind=0; + + // If should be used silhouette weighting, it is needed to compute depth discontinuities + // and per-pixel distance from detected borders on the entire image here + // the weight is then applied later, per-vertex, when needed + floatbuffer *silhouette_buff=NULL; + float maxsildist = rendermanager->depth->sx + rendermanager->depth->sy; + if(usesilhouettes) + { + silhouette_buff = new floatbuffer(); + silhouette_buff->init(rendermanager->depth->sx, rendermanager->depth->sy); + + silhouette_buff->applysobel(rendermanager->depth); + //sprintf(dumpFileName,"Abord%i.pfm",cam_ind); + //silhouette_buff->dumppfm(dumpFileName); + + silhouette_buff->initborder(rendermanager->depth); + //sprintf(dumpFileName,"Bbord%i.pfm",cam_ind); + //silhouette_buff->dumppfm(dumpFileName); + + maxsildist = silhouette_buff->distancefield(); + //sprintf(dumpFileName,"Cbord%i.pfm",cam_ind); + //silhouette_buff->dumppfm(dumpFileName); + } + + for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) + { + if(!(*vi).IsD() && (!onselection || (*vi).IsS())) + { + // pp is the projected point in image space + Point2m pp = raster->shot.Project((*vi).P()); + // pray is the vector from the point-to-be-colored to the camera center + Point3m pray = (raster->shot.GetViewPoint() - (*vi).P()).Normalize(); + + //if inside image + if(pp[0]>=0 && pp[1]>=0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) + { + if((pray.dot(-raster->shot.Axis(2))) <= 0.0) + { + + depth = raster->shot.Depth((*vi).P()); + pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; + + if(depth <= (pdepth + eta)) + { + // determine color + QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); + // determine weight + pweight = 1.0; + + if(useangle) + { + Point3m pixnorm = (*vi).N(); + Point3m viewaxis = raster->shot.GetViewPoint() - (*vi).P(); + pixnorm.Normalize(); + viewaxis.Normalize(); + + float ang = abs(pixnorm * viewaxis); + ang = min(1.0f, ang); + + pweight *= ang; + } + + if(usedistance) + { + float distw = depth; + distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); + + pweight *= distw; + pweight *= distw; + } + + if(useborders) + { + double xdist = 1.0 - (abs(pp[0] - (raster->shot.Intrinsics.ViewportPx[0] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[0] / 2.0)); + double ydist = 1.0 - (abs(pp[1] - (raster->shot.Intrinsics.ViewportPx[1] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[1] / 2.0)); + double borderw = min (xdist , ydist); + //borderw = min(1.0,borderw); //debug debug + //borderw = max(0.0,borderw); //debug debug + + pweight *= borderw; + } + + if(usesilhouettes) + { + // here the silhouette weight is applied, but it is calculated before, on a per-image basis + float silw = 1.0; + silw = silhouette_buff->getval(int(pp[0]), int(pp[1])) / maxsildist; + //silw = min(1.0f,silw); //debug debug + //silw = max(0.0f,silw); //debug debug + + pweight *= silw; + } + + if(usealphamask) //alpha channel of image is an additional mask + { + pweight *= (qAlpha(pcolor) / 255.0); + } + + weights[buff_ind] += pweight; + acc_red[buff_ind] += (qRed(pcolor) * pweight / 255.0); + acc_grn[buff_ind] += (qGreen(pcolor) * pweight / 255.0); + acc_blu[buff_ind] += (qBlue(pcolor) * pweight / 255.0); + } + } + } + } + buff_ind++; + } + cam_ind ++; + + if(usesilhouettes) + { + delete silhouette_buff; + } + + } // end foreach camera + } // end foreach camera + } + + buff_ind = 0; + for(vi=model->cm.vert.begin();vi!=model->cm.vert.end();++vi) + { + if(!(*vi).IsD() && (!onselection || (*vi).IsS())) + { + if (weights[buff_ind] != 0) // if 0, it has not found any valid projection on any camera + { + (*vi).C() = vcg::Color4b( (acc_red[buff_ind] / weights[buff_ind]) *255.0, + (acc_grn[buff_ind] / weights[buff_ind]) *255.0, + (acc_blu[buff_ind] / weights[buff_ind]) *255.0, + 255); + } + else + { + if ((blank.red() != 0) || (blank.green() != 0) || (blank.blue() != 0) || (blank.alpha() != 0)) + (*vi).C() = vcg::Color4b(blank.red(), blank.green(), blank.blue(), blank.alpha()); + } + } + buff_ind++; + } + + // the mesh has to return to its original position + tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); + tri::UpdateBounding::Box(model->cm); + + // delete rendermanager + if(rendermanager != NULL) + delete rendermanager; + + // delete accumulation buffers + delete[] weights; + delete[] acc_red; + delete[] acc_grn; + delete[] acc_blu; + + } + break; + + + case FP_MULTIIMAGETRIVIALPROJTEXTURE : + { + + if(!tri::HasPerWedgeTexCoord(md.mm()->cm)) + { + errorMessage="Warning: nothing have been done. Mesh has no Texture Coordinates."; + return false; + } + + //bool onselection = par.getBool("onselection"); + int texsize = par.getInt("texsize"); + bool dorefill = par.getBool("dorefill"); + Scalarm eta = par.getFloat("deptheta"); + bool useangle = par.getBool("useangle"); + bool usedistance = par.getBool("usedistance"); + bool useborders = par.getBool("useborders"); + bool usesilhouettes = par.getBool("usesilhouettes"); + bool usealphamask = par.getBool("usealpha"); + QString textName = par.getString("textName"); + + int textW = texsize; + int textH = texsize; + + Scalarm depth=0; // depth of point (distance from camera) + Scalarm pdepth=0; // depth value of projected point (from depth map) + double pweight; // pixel weight + MeshModel *model; + bool do_project; + int cam_ind; + + // min max depth for depth weight normalization + float allcammaxdepth; + float allcammindepth; + + // max image size for border weight normalization + float allcammaximagesize; + + // get the working model + model = md.mm(); + + // the mesh has to be correctly transformed before mapping + tri::UpdatePosition::Matrix(model->cm,model->cm.Tr,true); + tri::UpdateBounding::Box(model->cm); + + // texture file name + QString filePath(model->fullName()); + filePath = filePath.left(std::max(filePath.lastIndexOf('\\'),filePath.lastIndexOf('/'))+1); + // Check textName and eventually add .png ext + CheckError(textName.length() == 0, "Texture file not specified"); + CheckError(std::max(textName.lastIndexOf("\\"),textName.lastIndexOf("/")) != -1, "Path in Texture file not allowed"); + if (!textName.endsWith(".png", Qt::CaseInsensitive)) + textName.append(".png"); + filePath.append(textName); + + // Image creation + CheckError(textW <= 0, "Texture Width has an incorrect value"); + CheckError(textH <= 0, "Texture Height has an incorrect value"); + QImage img(QSize(textW,textH), QImage::Format_ARGB32); + img.fill(qRgba(0,0,0,0)); // transparent black + + // Compute (texture-space) border edges + if(dorefill) + { + model->updateDataMask(MeshModel::MM_FACEFACETOPO); + tri::UpdateTopology::FaceFaceFromTexCoord(model->cm); + tri::UpdateFlags::FaceBorderFromFF(model->cm); + } + + // create a list of to-be-filled texels and accumulators + // storing texel 2d coords, texel mesh-space point, texel mesh normal + + vector texels; + texels.clear(); + texels.reserve(textW*textH); // just to avoid the 2x reallocate rule... + + vector accums; + accums.clear(); + accums.reserve(textW*textH); // just to avoid the 2x reallocate rule... + + // Rasterizing triangles in the list of voxels + TexFillerSampler tfs(img); + tfs.texelspointer = &texels; + tfs.accumpointer = &accums; + tfs.InitCallback(cb, model->cm.fn, 0, 80); + tri::SurfaceSampling::Texture(model->cm,tfs,textW,textH,true); + + // Revert alpha values for border edge pixels to 255 + cb(81, "Cleaning up texture ..."); + for (int y=0; y 0) + img.setPixel(x,y, px | 0xff000000); + } + } + + // calculate accuratenear/far for all cameras + std::vector my_near; + std::vector my_far; + calculateNearFarAccurate(md, &my_near, &my_far); + + allcammaxdepth = -1000000; + allcammindepth = 1000000; + allcammaximagesize = -1000000; + for(cam_ind = 0; cam_ind < md.rasterList.size(); cam_ind++) + { + if(my_far[cam_ind] > allcammaxdepth) + allcammaxdepth = my_far[cam_ind]; + if(my_near[cam_ind] < allcammindepth) + allcammindepth = my_near[cam_ind]; + + float imgdiag = sqrt(double(md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[0] * md.rasterList[cam_ind]->shot.Intrinsics.ViewportPx[1])); + if (imgdiag > allcammaximagesize) + allcammaximagesize = imgdiag; + } + + //-- cycle all cameras + cam_ind = 0; + for(RasterModel *raster : md.rasterList) + { + if(raster->visible) + { + do_project = true; + + // no drawing if camera not valid + if(!raster->shot.IsValid()) + do_project = false; + + // no drawing if raster is not active + //if(!raster->shot.IsValid()) + // do_project = false; + + if(do_project) + { + // making context current + glContext->makeCurrent(); + + // delete & reinit rendermanager + if(rendermanager != NULL) + delete rendermanager; + rendermanager = new RenderHelper(); + if( rendermanager->initializeGL(cb) != 0 ) + return false; + log("init GL"); + /*if( rendermanager->initializeMeshBuffers(model, cb) != 0 ) + return false; + Log("init Buffers");*/ + + // render normal & depth + rendermanager->renderScene(raster->shot, model, RenderHelper::NORMAL, glContext, my_near[cam_ind]*0.5, my_far[cam_ind]*1.25); + + // unmaking context current + glContext->doneCurrent(); + + // If should be used silhouette weighting, it is needed to compute depth discontinuities + // and per-pixel distance from detected borders on the entire image here + // the weight is then applied later, per-vertex, when needed + floatbuffer *silhouette_buff=NULL; + float maxsildist = rendermanager->depth->sx + rendermanager->depth->sy; + if(usesilhouettes) + { + silhouette_buff = new floatbuffer(); + silhouette_buff->init(rendermanager->depth->sx, rendermanager->depth->sy); + + silhouette_buff->applysobel(rendermanager->depth); + //sprintf(dumpFileName,"Abord%i.bmp",cam_ind); + //silhouette_buff->dumpbmp(dumpFileName); + + silhouette_buff->initborder(rendermanager->depth); + //sprintf(dumpFileName,"Bbord%i.bmp",cam_ind); + //silhouette_buff->dumpbmp(dumpFileName); + + maxsildist = silhouette_buff->distancefield(); + //sprintf(dumpFileName,"Cbord%i.bmp",cam_ind); + //silhouette_buff->dumpbmp(dumpFileName); + } + + for(size_t texcount=0; texcount < texels.size(); texcount++) + { + Point2m pp = raster->shot.Project(texels[texcount].meshpoint); + // pray is the vector from the point-to-be-colored to the camera center + Point3m pray = (raster->shot.GetViewPoint() - texels[texcount].meshpoint).Normalize(); + + //if inside image + if(pp[0]>0 && pp[1]>0 && pp[0]shot.Intrinsics.ViewportPx[0] && pp[1]shot.Intrinsics.ViewportPx[1]) + { + if((pray.dot(-raster->shot.Axis(2))) <= 0.0) + { + + depth = raster->shot.Depth(texels[texcount].meshpoint); + pdepth = rendermanager->depth->getval(int(pp[0]), int(pp[1])); // rendermanager->depth[(int(pp[1]) * raster->shot.Intrinsics.ViewportPx[0]) + int(pp[0])]; + + if(depth <= (pdepth + eta)) + { + // determine color + QRgb pcolor = raster->currentPlane->image.pixel(pp[0],raster->shot.Intrinsics.ViewportPx[1] - pp[1]); + // determine weight + pweight = 1.0; + + if(useangle) + { + Point3m pixnorm = texels[texcount].meshnormal; + pixnorm.Normalize(); + + Point3m viewaxis = raster->shot.GetViewPoint() - texels[texcount].meshpoint; + viewaxis.Normalize(); + + float ang = abs(pixnorm * viewaxis); + ang = min(1.0f, ang); + + pweight *= ang; + } + + if(usedistance) + { + float distw = depth; + distw = 1.0 - (distw - (allcammindepth*0.99)) / ((allcammaxdepth*1.01) - (allcammindepth*0.99)); + + pweight *= distw; + pweight *= distw; + } + + if(useborders) + { + double xdist = 1.0 - (abs(pp[0] - (raster->shot.Intrinsics.ViewportPx[0] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[0] / 2.0)); + double ydist = 1.0 - (abs(pp[1] - (raster->shot.Intrinsics.ViewportPx[1] / 2.0)) / (raster->shot.Intrinsics.ViewportPx[1] / 2.0)); + double borderw = min (xdist , ydist); + + pweight *= borderw; + } + + if(usesilhouettes) + { + // here the silhouette weight is applied, but it is calculated before, on a per-image basis + float silw = 1.0; + silw = silhouette_buff->getval(int(pp[0]), int(pp[1])) / maxsildist; + pweight *= silw; + } + + if(usealphamask) //alpha channel of image is an additional mask + { + pweight *= (qAlpha(pcolor) / 255.0); + } + + accums[texcount].weights += pweight; + accums[texcount].acc_red += (qRed(pcolor) * pweight / 255.0); + accums[texcount].acc_grn += (qGreen(pcolor) * pweight / 255.0); + accums[texcount].acc_blu += (qBlue(pcolor) * pweight / 255.0); + } + } + } + + } // end foreach texel + cam_ind ++; + + if(usesilhouettes) + { + delete silhouette_buff; + } + + } // end if(do_project) + + } + } // end foreach camera + + // for each texel.... divide accumulated values by weight and write to texture + for(size_t texcount=0; texcount < texels.size(); texcount++) + { + if(accums[texcount].weights > 0.0) + { + float texel_red = accums[texcount].acc_red / accums[texcount].weights; + float texel_green = accums[texcount].acc_grn / accums[texcount].weights; + float texel_blue = accums[texcount].acc_blu / accums[texcount].weights; + + img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(texel_red*255.0, texel_green*255.0, texel_blue*255.0, 255)); + } + else // if no projected data available, black (to be refilled later on + { + img.setPixel(texels[texcount].texcoord.X(), img.height() - 1 - texels[texcount].texcoord.Y(), qRgba(0, 0, 0, 0)); + } + } + + // cleaning + texels.clear(); + accums.clear(); + + // PullPush + if(dorefill) + { + cb(85, "Filling texture holes..."); + + PullPush(img, qRgba(0,0,0,0)); // atlas gaps + } + + // Undo topology changes + if(dorefill) + { + tri::UpdateTopology::FaceFace(model->cm); + tri::UpdateFlags::FaceBorderFromFF(model->cm); + } + + // Save texture + cb(90, "Saving texture ..."); + CheckError(!img.save(filePath), "Texture file cannot be saved"); + log( "Texture \"%s\" Created", filePath.toStdString().c_str()); + assert(QFile(filePath).exists()); + + // Assign texture + model->cm.textures.clear(); + model->cm.textures.push_back(textName.toStdString()); + + // the mesh has to return to its original position + tri::UpdatePosition::Matrix(model->cm,Inverse(model->cm.Tr),true); + tri::UpdateBounding::Box(model->cm); + + + } break; + + + } + + return true; + } + else { + errorMessage = "Fatal error: glContext not initialized"; + return false; + } } FilterColorProjectionPlugin::FilterClass FilterColorProjectionPlugin::getClass(const QAction *a) const diff --git a/src/meshlabplugins/filter_color_projection/filter_color_projection.h b/src/meshlabplugins/filter_color_projection/filter_color_projection.h index 2b4426595..2d621b6cf 100644 --- a/src/meshlabplugins/filter_color_projection/filter_color_projection.h +++ b/src/meshlabplugins/filter_color_projection/filter_color_projection.h @@ -29,31 +29,30 @@ class FilterColorProjectionPlugin : public QObject, public FilterPluginInterface { - Q_OBJECT - MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_INTERFACE_IID) - Q_INTERFACES(FilterPluginInterface) - -public: - enum { FP_SINGLEIMAGEPROJ, FP_MULTIIMAGETRIVIALPROJ, FP_MULTIIMAGETRIVIALPROJTEXTURE }; - - FilterColorProjectionPlugin(); - - QString pluginName() const; - virtual QString filterName(FilterIDType filter) const; - virtual QString filterInfo(FilterIDType filter) const; - int postCondition( const QAction* ) const; - - virtual FilterClass getClass(const QAction*) const; - virtual void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); - virtual int getRequirements(const QAction*); - virtual bool applyFilter(const QAction* filter, MeshDocument &md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList & /*parent*/, vcg::CallBackPos * cb); - - FILTER_ARITY filterArity(const QAction *) const {return SINGLE_MESH;} - + Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_INTERFACE_IID) + Q_INTERFACES(FilterPluginInterface) + + public: + enum { FP_SINGLEIMAGEPROJ, FP_MULTIIMAGETRIVIALPROJ, FP_MULTIIMAGETRIVIALPROJTEXTURE }; + + FilterColorProjectionPlugin(); + + QString pluginName() const; + QString filterName(FilterIDType filter) const; + QString filterInfo(FilterIDType filter) const; + int postCondition( const QAction* ) const; + + FilterClass getClass(const QAction*) const; + void initParameterList(const QAction*, MeshDocument &/*m*/, RichParameterList & /*parent*/); + int getRequirements(const QAction*); + bool requiresGLContext(const QAction* action) const; + bool applyFilter(const QAction* filter, MeshDocument &md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList & /*parent*/, vcg::CallBackPos * cb); + + FILTER_ARITY filterArity(const QAction *) const {return SINGLE_MESH;} + private: - - int calculateNearFarAccurate(MeshDocument &md, std::vector *near, std::vector *far); - + int calculateNearFarAccurate(MeshDocument &md, std::vector *near, std::vector *far); }; #endif diff --git a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp index 1bf19a505..b84827c82 100644 --- a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp +++ b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.cpp @@ -96,6 +96,20 @@ int FilterImgPatchParamPlugin::getRequirements(const QAction *act ) } } +bool FilterImgPatchParamPlugin::requiresGLContext(const QAction* action) const +{ + switch(ID(action)){ + case FP_PATCH_PARAM_ONLY: + case FP_PATCH_PARAM_AND_TEXTURING: + case FP_RASTER_VERT_COVERAGE: + case FP_RASTER_FACE_COVERAGE: + return true; + default: + assert(0); + } + return false; +} + FilterPluginInterface::FilterClass FilterImgPatchParamPlugin::getClass(const QAction *act ) const { @@ -199,97 +213,66 @@ bool FilterImgPatchParamPlugin::applyFilter( const RichParameterList &par, vcg::CallBackPos * /*cb*/ ) { - - - glContext->makeCurrent(); - if( !GLExtensionsManager::initializeGLextensions_notThrowing() ) - { - this->errorMessage="Failed GLEW initialization"; - return false; - } - - glPushAttrib(GL_ALL_ATTRIB_BITS); - - delete m_Context; - m_Context = new glw::Context(); - m_Context->acquire(); - - if( !VisibilityCheck::GetInstance(*m_Context) ) - { - this->errorMessage="VisibilityCheck failed"; - return false; - } - VisibilityCheck::ReleaseInstance(); - - - bool retValue = true; - - CMeshO &mesh = md.mm()->cm; - - std::list initialShots; - QList activeRasters; - foreach( RasterModel *rm, md.rasterList ) - { - initialShots.push_back( rm->shot ); - rm->shot.ApplyRigidTransformation( vcg::Inverse(mesh.Tr) ); - if( rm->visible ) - activeRasters.push_back( rm ); - } - - if( activeRasters.empty() ) { - this->errorMessage="No active Raster"; + if (glContext != nullptr){ + glContext->makeCurrent(); + if( !GLExtensionsManager::initializeGLextensions_notThrowing() ) { - glContext->doneCurrent(); - errorMessage = "You need to have at least one valid raster layer in your project, to apply this filter"; // text + this->errorMessage="Failed GLEW initialization"; return false; } - } - - switch( ID(act) ) - { - case FP_PATCH_PARAM_ONLY: - { - if (vcg::tri::Clean::CountNonManifoldEdgeFF(md.mm()->cm)>0) - { - glContext->doneCurrent(); - errorMessage = "Mesh has some not 2-manifold faces, this filter requires manifoldness"; // text - return false; // can't continue, mesh can't be processed - } - vcg::tri::Allocator::CompactFaceVector(md.mm()->cm); - vcg::tri::Allocator::CompactVertexVector(md.mm()->cm); - vcg::tri::UpdateTopology::FaceFace(md.mm()->cm); - vcg::tri::UpdateTopology::VertexFace(md.mm()->cm); - glContext->meshAttributesUpdated(md.mm()->id(),true,MLRenderingData::RendAtts()); - RasterPatchMap patches; - PatchVec nullPatches; - patchBasedTextureParameterization( patches, - nullPatches, - md.mm()->id(), - mesh, - activeRasters, - par ); - break; - } - case FP_PATCH_PARAM_AND_TEXTURING: - { - if (vcg::tri::Clean::CountNonManifoldEdgeFF(md.mm()->cm)>0) - { - glContext->doneCurrent(); - errorMessage = "Mesh has some not 2-manifold faces, this filter requires manifoldness"; // text - return false; // can't continue, mesh can't be processed - } - vcg::tri::Allocator::CompactEveryVector(md.mm()->cm); - vcg::tri::UpdateTopology::FaceFace(md.mm()->cm); - vcg::tri::UpdateTopology::VertexFace(md.mm()->cm); - glContext->meshAttributesUpdated(md.mm()->id(),true,MLRenderingData::RendAtts()); - QString texName = par.getString( "textureName" ).simplified(); - int pathEnd = std::max( texName.lastIndexOf('/'), texName.lastIndexOf('\\') ); - if( pathEnd != -1 ) - texName = texName.right( texName.size()-pathEnd-1 ); + glPushAttrib(GL_ALL_ATTRIB_BITS); - if( (retValue = texName.size()!=0) ) + delete m_Context; + m_Context = new glw::Context(); + m_Context->acquire(); + + if( !VisibilityCheck::GetInstance(*m_Context) ) { + this->errorMessage="VisibilityCheck failed"; + return false; + } + VisibilityCheck::ReleaseInstance(); + + + bool retValue = true; + + CMeshO &mesh = md.mm()->cm; + + std::list initialShots; + QList activeRasters; + foreach( RasterModel *rm, md.rasterList ) + { + initialShots.push_back( rm->shot ); + rm->shot.ApplyRigidTransformation( vcg::Inverse(mesh.Tr) ); + if( rm->visible ) + activeRasters.push_back( rm ); + } + + if( activeRasters.empty() ) { + this->errorMessage="No active Raster"; + { + glContext->doneCurrent(); + errorMessage = "You need to have at least one valid raster layer in your project, to apply this filter"; // text + return false; + } + } + + switch( ID(act) ) + { + case FP_PATCH_PARAM_ONLY: + { + if (vcg::tri::Clean::CountNonManifoldEdgeFF(md.mm()->cm)>0) + { + glContext->doneCurrent(); + errorMessage = "Mesh has some not 2-manifold faces, this filter requires manifoldness"; // text + return false; // can't continue, mesh can't be processed + } + vcg::tri::Allocator::CompactFaceVector(md.mm()->cm); + vcg::tri::Allocator::CompactVertexVector(md.mm()->cm); + vcg::tri::UpdateTopology::FaceFace(md.mm()->cm); + vcg::tri::UpdateTopology::VertexFace(md.mm()->cm); + glContext->meshAttributesUpdated(md.mm()->id(),true,MLRenderingData::RendAtts()); RasterPatchMap patches; PatchVec nullPatches; patchBasedTextureParameterization( patches, @@ -299,99 +282,134 @@ bool FilterImgPatchParamPlugin::applyFilter( activeRasters, par ); - TexturePainter painter( *m_Context, par.getInt("textureSize") ); - if( (retValue = painter.isInitialized()) ) + break; + } + case FP_PATCH_PARAM_AND_TEXTURING: + { + if (vcg::tri::Clean::CountNonManifoldEdgeFF(md.mm()->cm)>0) { - QElapsedTimer t; t.start(); - painter.paint( patches ); - if( par.getBool("colorCorrection") ) - painter.rectifyColor( patches, par.getInt("colorCorrectionFilterSize") ); - log( "TEXTURE PAINTING: %.3f sec.", 0.001f*t.elapsed() ); + glContext->doneCurrent(); + errorMessage = "Mesh has some not 2-manifold faces, this filter requires manifoldness"; // text + return false; // can't continue, mesh can't be processed + } + vcg::tri::Allocator::CompactEveryVector(md.mm()->cm); + vcg::tri::UpdateTopology::FaceFace(md.mm()->cm); + vcg::tri::UpdateTopology::VertexFace(md.mm()->cm); + glContext->meshAttributesUpdated(md.mm()->id(),true,MLRenderingData::RendAtts()); + QString texName = par.getString( "textureName" ).simplified(); + int pathEnd = std::max( texName.lastIndexOf('/'), texName.lastIndexOf('\\') ); + if( pathEnd != -1 ) + texName = texName.right( texName.size()-pathEnd-1 ); + + if( (retValue = texName.size()!=0) ) + { + RasterPatchMap patches; + PatchVec nullPatches; + patchBasedTextureParameterization( patches, + nullPatches, + md.mm()->id(), + mesh, + activeRasters, + par ); - QImage tex = painter.getTexture(); - if( tex.save(texName) ) + TexturePainter painter( *m_Context, par.getInt("textureSize") ); + if( (retValue = painter.isInitialized()) ) { - mesh.textures.clear(); - mesh.textures.push_back( texName.toStdString() ); + QElapsedTimer t; t.start(); + painter.paint( patches ); + if( par.getBool("colorCorrection") ) + painter.rectifyColor( patches, par.getInt("colorCorrectionFilterSize") ); + log( "TEXTURE PAINTING: %.3f sec.", 0.001f*t.elapsed() ); + + QImage tex = painter.getTexture(); + if( tex.save(texName) ) + { + mesh.textures.clear(); + mesh.textures.push_back( texName.toStdString() ); + } } } + + break; } - - break; - } - case FP_RASTER_VERT_COVERAGE: - { - VisibilityCheck &visibility = *VisibilityCheck::GetInstance( *m_Context ); - visibility.setMesh(md.mm()->id(),&mesh ); - visibility.m_plugcontext = glContext; - for( CMeshO::VertexIterator vi=mesh.vert.begin(); vi!=mesh.vert.end(); ++vi ) - vi->Q() = 0.0f; - - foreach( RasterModel *rm, activeRasters ) + case FP_RASTER_VERT_COVERAGE: { - visibility.setRaster( rm ); - visibility.checkVisibility(); + VisibilityCheck &visibility = *VisibilityCheck::GetInstance( *m_Context ); + visibility.setMesh(md.mm()->id(),&mesh ); + visibility.m_plugcontext = glContext; for( CMeshO::VertexIterator vi=mesh.vert.begin(); vi!=mesh.vert.end(); ++vi ) - if( visibility.isVertVisible(vi) ) - vi->Q() += 1.0f; + vi->Q() = 0.0f; + + foreach( RasterModel *rm, activeRasters ) + { + visibility.setRaster( rm ); + visibility.checkVisibility(); + for( CMeshO::VertexIterator vi=mesh.vert.begin(); vi!=mesh.vert.end(); ++vi ) + if( visibility.isVertVisible(vi) ) + vi->Q() += 1.0f; + } + + if( par.getBool("normalizeQuality") ) + { + const float normFactor = 1.0f / md.rasterList.size(); + for( CMeshO::VertexIterator vi=mesh.vert.begin(); vi!=mesh.vert.end(); ++vi ) + vi->Q() *= normFactor; + } + + break; } - - if( par.getBool("normalizeQuality") ) + case FP_RASTER_FACE_COVERAGE: { - const float normFactor = 1.0f / md.rasterList.size(); - for( CMeshO::VertexIterator vi=mesh.vert.begin(); vi!=mesh.vert.end(); ++vi ) - vi->Q() *= normFactor; - } - - break; - } - case FP_RASTER_FACE_COVERAGE: - { - VisibilityCheck &visibility = *VisibilityCheck::GetInstance( *m_Context ); - visibility.setMesh(md.mm()->id(),&mesh ); - visibility.m_plugcontext = glContext; - - for( CMeshO::FaceIterator fi=mesh.face.begin(); fi!=mesh.face.end(); ++fi ) - fi->Q() = 0.0f; - - foreach( RasterModel *rm, activeRasters ) - { - visibility.setRaster( rm ); - visibility.checkVisibility(); + VisibilityCheck &visibility = *VisibilityCheck::GetInstance( *m_Context ); + visibility.setMesh(md.mm()->id(),&mesh ); + visibility.m_plugcontext = glContext; + for( CMeshO::FaceIterator fi=mesh.face.begin(); fi!=mesh.face.end(); ++fi ) - if( visibility.isFaceVisible(fi) ) - fi->Q() += 1.0f; + fi->Q() = 0.0f; + + foreach( RasterModel *rm, activeRasters ) + { + visibility.setRaster( rm ); + visibility.checkVisibility(); + for( CMeshO::FaceIterator fi=mesh.face.begin(); fi!=mesh.face.end(); ++fi ) + if( visibility.isFaceVisible(fi) ) + fi->Q() += 1.0f; + } + + if( par.getBool("normalizeQuality") ) + { + const float normFactor = 1.0f / md.rasterList.size(); + for( CMeshO::FaceIterator fi=mesh.face.begin(); fi!=mesh.face.end(); ++fi ) + fi->Q() *= normFactor; + } + + break; + } } - if( par.getBool("normalizeQuality") ) + + foreach( RasterModel *rm, md.rasterList ) { - const float normFactor = 1.0f / md.rasterList.size(); - for( CMeshO::FaceIterator fi=mesh.face.begin(); fi!=mesh.face.end(); ++fi ) - fi->Q() *= normFactor; + rm->shot = *initialShots.begin(); + initialShots.erase( initialShots.begin() ); } - break; + VisibilityCheck::ReleaseInstance(); + + + delete m_Context; + m_Context = NULL; + + glPopAttrib(); + glContext->doneCurrent(); + + + return retValue; } + else { + errorMessage = "Fatal error: glContext not initialized"; + return false; } - - - foreach( RasterModel *rm, md.rasterList ) - { - rm->shot = *initialShots.begin(); - initialShots.erase( initialShots.begin() ); - } - - VisibilityCheck::ReleaseInstance(); - - - delete m_Context; - m_Context = NULL; - - glPopAttrib(); - glContext->doneCurrent(); - - - return retValue; } diff --git a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h index 127870089..3dd0241e3 100644 --- a/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h +++ b/src/meshlabplugins/filter_img_patch_param/filter_img_patch_param.h @@ -110,6 +110,7 @@ public: RichParameterList &par ); virtual int getRequirements(const QAction* act ); + bool requiresGLContext(const QAction* action) const; //virtual int postCondition( QAction *act ) const; virtual bool applyFilter( diff --git a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp index 6db398ecf..ce1210e7e 100644 --- a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp +++ b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.cpp @@ -93,7 +93,18 @@ FilterMutualGlobal::FilterClass FilterMutualGlobal::getClass(const QAction *a) c case FP_IMAGE_GLOBALIGN : return FilterPluginInterface::Camera; default : assert(0); } - return FilterPluginInterface::Generic; + return FilterPluginInterface::Generic; +} + +bool FilterMutualGlobal::requiresGLContext(const QAction* action) const +{ + switch(ID(action)) { + case FP_IMAGE_GLOBALIGN: + return true; + default: + assert(0); + } + return false; } // This function define the needed parameters for each filter. Return true if the filter has some parameters @@ -162,6 +173,10 @@ void FilterMutualGlobal::initParameterList(const QAction *action,MeshDocument & // Move Vertex of a random quantity bool FilterMutualGlobal::applyFilter(const QAction *action, MeshDocument &md, std::map&, unsigned int& /*postConditionMask*/, const RichParameterList & par, vcg::CallBackPos *cb) { + if (glContext == nullptr){ + errorMessage = "Fatal error: glContext not initialized"; + return false; + } QElapsedTimer filterTime; filterTime.start(); diff --git a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h index 31343e077..36f4ff159 100644 --- a/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h +++ b/src/meshlabplugins/filter_mutualglobal/filter_mutualglobal.h @@ -58,6 +58,7 @@ public: bool applyFilter(const QAction* filter, MeshDocument &md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList & /*parent*/, vcg::CallBackPos * cb) ; int postCondition(const QAction*) const { return MeshModel::MM_NONE; }; FilterClass getClass(const QAction* a) const; + bool requiresGLContext(const QAction* action) const; QString filterScriptFunctionName(FilterIDType filterID); bool preAlignment(MeshDocument &md, const RichParameterList& par, vcg::CallBackPos *cb); std::vector buildGraph(MeshDocument &md, bool globalign=true); diff --git a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp index ee3dae8e6..5e6d4cea9 100644 --- a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp +++ b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.cpp @@ -80,6 +80,17 @@ FilterMutualInfoPlugin::FilterClass FilterMutualInfoPlugin::getClass(const QActi } } +bool FilterMutualInfoPlugin::requiresGLContext(const QAction* action) const +{ + switch(ID(action)) { + case FP_IMAGE_MUTUALINFO: + return true; + default : + assert(0); + } + return false; +} + FilterPluginInterface::FILTER_ARITY FilterMutualInfoPlugin::filterArity(const QAction*) const { return SINGLE_MESH; @@ -112,6 +123,10 @@ void FilterMutualInfoPlugin::initParameterList(const QAction *action,MeshDocumen bool FilterMutualInfoPlugin::applyFilter(const QAction *action, MeshDocument &md, std::map&, unsigned int& /*postConditionMask*/, const RichParameterList & par, vcg::CallBackPos* ) { + if (glContext == nullptr){ + errorMessage = "Fatal error: glContext not initialized"; + return false; + } switch(ID(action)) { case FP_IMAGE_MUTUALINFO : return imageMutualInfoAlign( diff --git a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h index 9589c27e7..d7e1738be 100644 --- a/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h +++ b/src/meshlabplugins/filter_mutualinfo/filter_mutualinfo.h @@ -46,6 +46,7 @@ public: QString filterName(FilterIDType filter) const; QString filterInfo(FilterIDType filter) const; FilterClass getClass(const QAction* a) const; + bool requiresGLContext(const QAction* action) const; FILTER_ARITY filterArity(const QAction*) const; void initParameterList(const QAction*, MeshDocument &, RichParameterList & /*parent*/); bool applyFilter(const QAction* filter, MeshDocument &md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList & /*parent*/, vcg::CallBackPos * cb) ; diff --git a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp index 2abc08d10..7e50253b5 100644 --- a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp +++ b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.cpp @@ -58,14 +58,27 @@ QString ExtraSampleGPUPlugin::filterName(FilterIDType filterId) const // Info() must return the longer string describing each filtering action // (this string is used in the About plugin dialog) - QString ExtraSampleGPUPlugin::filterInfo(FilterIDType filterId) const +QString ExtraSampleGPUPlugin::filterInfo(FilterIDType filterId) const { - switch(filterId) { - case FP_GPU_EXAMPLE : return QString("Small useless filter added only to show how to work with a gl render context inside a filter."); - default : assert(0); + switch(filterId) { + case FP_GPU_EXAMPLE : + return QString("Small useless filter added only to show how to work with a gl render context inside a filter."); + default: + assert(0); } return QString("Unknown Filter"); } + +bool ExtraSampleGPUPlugin::requiresGLContext(const QAction* action) const +{ + switch(ID(action)){ + case FP_GPU_EXAMPLE : + return true; + default: + assert(0); + } + return false; +} // The FilterClass describes in which generic class of filters it fits. // This choice affect the submenu in which each filter will be placed @@ -110,6 +123,10 @@ void ExtraSampleGPUPlugin::initParameterList(const QAction * action, MeshModel & // Move Vertex of a random quantity bool ExtraSampleGPUPlugin::applyFilter(const QAction * a, MeshDocument & md , std::map&, unsigned int& /*postConditionMask*/, const RichParameterList & par, vcg::CallBackPos * /*cb*/) { + if (glContext == nullptr){ + errorMessage = "Fatal error: glContext not initialized"; + return false; + } switch(ID(a)) { case FP_GPU_EXAMPLE: diff --git a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h index 9dc16895b..476dc9439 100644 --- a/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h +++ b/src/meshlabplugins/filter_sample_gpu/filter_sample_gpu.h @@ -55,6 +55,7 @@ public: QString filterName(FilterIDType filter) const; QString filterInfo(FilterIDType filter) const; + bool requiresGLContext(const QAction* action) const; bool applyFilter(const QAction* filter, MeshDocument &md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList & /*parent*/, vcg::CallBackPos * cb) ; FilterClass getClass(const QAction* a) const; }; diff --git a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp index 94ce03b64..4c7432503 100644 --- a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp +++ b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.cpp @@ -41,7 +41,6 @@ QString SdfGpuPlugin::pluginName() const void SdfGpuPlugin::initParameterList(const QAction *action, MeshModel &/*m*/, RichParameterList &par) { - mAction = ID(action); QStringList onPrimitive; onPrimitive.push_back("On vertices"); onPrimitive.push_back("On Faces"); par.addParam( RichEnum("onPrimitive", 0, onPrimitive, "Metric:", "Choose whether to trace rays from faces or from vertices. " )); @@ -58,12 +57,12 @@ void SdfGpuPlugin::initParameterList(const QAction *action, MeshModel &/*m*/, Ri "Depth tolerance used during depth peeling. This is the threshold used to differentiate layers between each others." "Two elements whose distance is below this value will be considered as belonging to the same layer.")); - if(mAction != SDF_DEPTH_COMPLEXITY) + if(ID(action) != SDF_DEPTH_COMPLEXITY) par.addParam(RichFloat("coneAngle",120,"Cone amplitude", "Cone amplitude around normals in degrees. Rays are traced within this cone.")); - switch(mAction) + switch(ID(action)) { case SDF_OBSCURANCE: par.addParam(RichFloat("obscuranceExponent", 0.1f, "Obscurance Exponent", @@ -80,7 +79,7 @@ void SdfGpuPlugin::initParameterList(const QAction *action, MeshModel &/*m*/, Ri } } - if(mAction == SDF_SDF) + if(ID(action) == SDF_SDF) { par.addParam(RichBool("removeFalse",true,"Remove false intersections","For each" "ray we check the normal at the point of intersection," @@ -143,8 +142,12 @@ QString SdfGpuPlugin::filterInfo(FilterIDType filterId) const return QString(""); } -bool SdfGpuPlugin::applyFilter(const QAction */*filter*/, MeshDocument &md, std::map&, unsigned int& /*postConditionMask*/, const RichParameterList & pars, vcg::CallBackPos *cb) +bool SdfGpuPlugin::applyFilter(const QAction* action, MeshDocument &md, std::map&, unsigned int& /*postConditionMask*/, const RichParameterList & pars, vcg::CallBackPos *cb) { + if (glContext == nullptr){ + errorMessage = "Fatal error: glContext not initialized"; + return false; + } MeshModel* mm = md.mm(); //RETRIEVE PARAMETERS @@ -155,14 +158,14 @@ bool SdfGpuPlugin::applyFilter(const QAction */*filter*/, MeshDocument &md, std: mTolerance = pars.getFloat("peelingTolerance"); mPeelingTextureSize = pars.getInt("DepthTextureSize"); - if(mAction != SDF_DEPTH_COMPLEXITY) + if(ID(action) != SDF_DEPTH_COMPLEXITY) mMinCos = vcg::math::Cos(math::ToRad(pars.getFloat("coneAngle")/2.0)); std::vector coneDirVec; - if(mAction == SDF_OBSCURANCE) + if(ID(action) == SDF_OBSCURANCE) mTau = pars.getFloat("obscuranceExponent"); - else if(mAction==SDF_SDF) + else if(ID(action)==SDF_SDF) { mRemoveFalse = pars.getBool("removeFalse"); mRemoveOutliers = pars.getBool("removeOutliers"); @@ -195,7 +198,7 @@ bool SdfGpuPlugin::applyFilter(const QAction */*filter*/, MeshDocument &md, std: for(vector::iterator vi = unifDirVec.begin(); vi != unifDirVec.end(); vi++) { (*vi).Normalize(); - TraceRay(peel, (*vi), md.mm()); + TraceRay(action, peel, (*vi), md.mm()); cb(100*((float)tracedRays/(float)unifDirVec.size()), "Tracing rays..."); glContext->makeCurrent(); @@ -208,14 +211,14 @@ bool SdfGpuPlugin::applyFilter(const QAction */*filter*/, MeshDocument &md, std: } //read back the result texture and store result in the mesh - if(mAction == SDF_OBSCURANCE) + if(ID(action) == SDF_OBSCURANCE) { if(mOnPrimitive == ON_VERTICES) applyObscurancePerVertex(*mm,unifDirVec.size()); else applyObscurancePerFace(*mm,unifDirVec.size()); } - else if(mAction == SDF_SDF) + else if(ID(action) == SDF_SDF) { if(mOnPrimitive == ON_VERTICES) applySdfPerVertex(*mm); @@ -1012,7 +1015,7 @@ bool SdfGpuPlugin::postRender(unsigned int peelingIteration) return true; } -void SdfGpuPlugin::TraceRay(int peelingIteration,const Point3f& dir, MeshModel* mm ) +void SdfGpuPlugin::TraceRay(const QAction* action, int peelingIteration,const Point3f& dir, MeshModel* mm ) { unsigned int j = 0; @@ -1048,7 +1051,7 @@ void SdfGpuPlugin::TraceRay(int peelingIteration,const Point3f& dir, MeshModel* if(i%2) { //we use the same method as in sdf, see below - if(mAction==SDF_OBSCURANCE ) + if(ID(action)==SDF_OBSCURANCE ) { if(i>1) { @@ -1063,7 +1066,7 @@ void SdfGpuPlugin::TraceRay(int peelingIteration,const Point3f& dir, MeshModel* } } - else if(mAction == SDF_SDF) + else if(ID(action) == SDF_SDF) { if(i>1) { @@ -1097,7 +1100,20 @@ void SdfGpuPlugin::TraceRay(int peelingIteration,const Point3f& dir, MeshModel* FilterPluginInterface::FILTER_ARITY SdfGpuPlugin::filterArity(const QAction *) const { - return FilterPluginInterface::SINGLE_MESH; + return FilterPluginInterface::SINGLE_MESH; +} + +bool SdfGpuPlugin::requiresGLContext(const QAction* action) const +{ + switch(ID(action)){ + case SDF_SDF: + case SDF_DEPTH_COMPLEXITY: + case SDF_OBSCURANCE: + return true; + default: + assert(0); + } + return false; } MESHLAB_PLUGIN_NAME_EXPORTER(SdfGpuPlugin) diff --git a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h index a7a750a2d..6a54a99e8 100644 --- a/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h +++ b/src/meshlabplugins/filter_sdfgpu/filter_sdfgpu.h @@ -13,118 +13,119 @@ enum ONPRIMITIVE{ON_VERTICES=0, ON_FACES=1}; class SdfGpuPlugin : public QObject, public FilterPluginInterface { - Q_OBJECT - MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_INTERFACE_IID) - Q_INTERFACES(FilterPluginInterface) - -public: - - enum{ SDF_SDF, SDF_DEPTH_COMPLEXITY, SDF_OBSCURANCE }; - - SdfGpuPlugin(); - - QString pluginName() const; - - QString filterName(FilterIDType filterId) const; - - QString filterInfo(FilterIDType filterId) const; - - FilterClass getClass(const QAction *) const - { - return FilterPluginInterface::VertexColoring; - } - - FILTER_ARITY filterArity(const QAction* act) const; - - //Main plugin function - bool applyFilter(const QAction* filter, MeshDocument &md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList & par, vcg::CallBackPos *cb); - - //Parameters init for user interface - virtual void initParameterList(const QAction* action, MeshModel &m, RichParameterList &parlst); - - //Draw the mesh - void fillFrameBuffer(bool front, MeshModel* mm); - - //Mesh setup - void setupMesh(MeshDocument& md, ONPRIMITIVE onprim ); - - //Init OpenGL context - bool initGL(MeshModel& mm); - - //OpenGL clean up - void releaseGL(MeshModel &m); - - //Setup camera orientation - void setCamera(vcg::Point3f camDir, vcg::Box3f meshBBox); - - //Calculate sdf or obscurance along a ray - void TraceRay(int peelingIteration, const vcg::Point3f& dir, MeshModel* mm ); - - //Enable depth peeling shader - void useDepthPeelingShader(FramebufferObject* fbo); - - //Position and normal of each vertex are copied to two separate texture, to be used in sdf and obscurance GPU calculation - void vertexDataToTexture(MeshModel &m); - - void faceDataToTexture(MeshModel &m); - - //Sdf calculation for each depth peeling iteration - void calculateSdfHW(FramebufferObject* fboFront, FramebufferObject* fboBack, FramebufferObject* fboPrevBack, const vcg::Point3f& cameraDir ); - - //Copy sdf values from result texture to the mesh (vertex quality) - void applySdfPerVertex(MeshModel &m); - - //Copy sdf values from result texture to the mesh (face quality) - void applySdfPerFace(MeshModel &m); - - - //Obscurance calculation for each depth peeling iteration - void calculateObscurance(FramebufferObject* fboFront, FramebufferObject* fboBack, FramebufferObject* nextFront, const vcg::Point3f& cameraDir, float bbDiag ); - - //Copy obscurance values from result texture to the mesh (vertex color) - void applyObscurancePerVertex(MeshModel &m, float numberOfRays); - - //Copy obscurance values from result texture to the mesh (face color) - void applyObscurancePerFace(MeshModel &m, float numberOfRays); - - void preRender(unsigned int peelingIteration); - - bool postRender(unsigned int peelingIteration); - - protected: - - FilterIDType mAction; - ONPRIMITIVE mOnPrimitive; - unsigned int mResTextureDim; - unsigned int mNumberOfTexRows; //the number of rows of a texture actually used for the result texture - FloatTexture2D* mVertexCoordsTexture; - FloatTexture2D* mVertexNormalsTexture; - FramebufferObject* mFboResult; //Fbo and texture storing the result computation - FloatTexture2D* mResultTexture; - FloatTexture2D* mDirsResultTexture; - FramebufferObject* mFboArray[3]; //Fbos and textures for depth peeling - FloatTexture2D* mDepthTextureArray[3]; - FloatTexture2D* mColorTextureArray[3]; - unsigned int mPeelingTextureSize; - float mTolerance; - float mMinCos; - float mTau; //obscurance exponent - float mMinDist; //min dist between vertices to check too thin parts - float mScale; //Scaling factor used to setup camera - GPUProgram* mDeepthPeelingProgram; - GPUProgram* mSDFProgram; - GPUProgram* mObscuranceProgram; - bool mRemoveFalse; - bool mRemoveOutliers; - GLuint mOcclusionQuery; - GLuint mPixelCount; - unsigned int mTempDepthComplexity; - unsigned int mDepthComplexity; - bool mDepthComplexityWarning; - - CMeshO::PerFaceAttributeHandle mMaxQualityDirPerFace; - CMeshO::PerVertexAttributeHandle mMaxQualityDirPerVertex; - + Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_INTERFACE_IID) + Q_INTERFACES(FilterPluginInterface) + + public: + + enum{ SDF_SDF, SDF_DEPTH_COMPLEXITY, SDF_OBSCURANCE }; + + SdfGpuPlugin(); + + QString pluginName() const; + + QString filterName(FilterIDType filterId) const; + + QString filterInfo(FilterIDType filterId) const; + + FilterClass getClass(const QAction *) const + { + return FilterPluginInterface::VertexColoring; + } + + FILTER_ARITY filterArity(const QAction* act) const; + + bool requiresGLContext(const QAction* action) const; + + //Main plugin function + bool applyFilter(const QAction* filter, MeshDocument &md, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList & par, vcg::CallBackPos *cb); + + //Parameters init for user interface + virtual void initParameterList(const QAction* action, MeshModel &m, RichParameterList &parlst); + + //Draw the mesh + void fillFrameBuffer(bool front, MeshModel* mm); + + //Mesh setup + void setupMesh(MeshDocument& md, ONPRIMITIVE onprim ); + + //Init OpenGL context + bool initGL(MeshModel& mm); + + //OpenGL clean up + void releaseGL(MeshModel &m); + + //Setup camera orientation + void setCamera(vcg::Point3f camDir, vcg::Box3f meshBBox); + + //Calculate sdf or obscurance along a ray + void TraceRay(const QAction* action, int peelingIteration, const vcg::Point3f& dir, MeshModel* mm ); + + //Enable depth peeling shader + void useDepthPeelingShader(FramebufferObject* fbo); + + //Position and normal of each vertex are copied to two separate texture, to be used in sdf and obscurance GPU calculation + void vertexDataToTexture(MeshModel &m); + + void faceDataToTexture(MeshModel &m); + + //Sdf calculation for each depth peeling iteration + void calculateSdfHW(FramebufferObject* fboFront, FramebufferObject* fboBack, FramebufferObject* fboPrevBack, const vcg::Point3f& cameraDir ); + + //Copy sdf values from result texture to the mesh (vertex quality) + void applySdfPerVertex(MeshModel &m); + + //Copy sdf values from result texture to the mesh (face quality) + void applySdfPerFace(MeshModel &m); + + + //Obscurance calculation for each depth peeling iteration + void calculateObscurance(FramebufferObject* fboFront, FramebufferObject* fboBack, FramebufferObject* nextFront, const vcg::Point3f& cameraDir, float bbDiag ); + + //Copy obscurance values from result texture to the mesh (vertex color) + void applyObscurancePerVertex(MeshModel &m, float numberOfRays); + + //Copy obscurance values from result texture to the mesh (face color) + void applyObscurancePerFace(MeshModel &m, float numberOfRays); + + void preRender(unsigned int peelingIteration); + + bool postRender(unsigned int peelingIteration); + +protected: + + ONPRIMITIVE mOnPrimitive; + unsigned int mResTextureDim; + unsigned int mNumberOfTexRows; //the number of rows of a texture actually used for the result texture + FloatTexture2D* mVertexCoordsTexture; + FloatTexture2D* mVertexNormalsTexture; + FramebufferObject* mFboResult; //Fbo and texture storing the result computation + FloatTexture2D* mResultTexture; + FloatTexture2D* mDirsResultTexture; + FramebufferObject* mFboArray[3]; //Fbos and textures for depth peeling + FloatTexture2D* mDepthTextureArray[3]; + FloatTexture2D* mColorTextureArray[3]; + unsigned int mPeelingTextureSize; + float mTolerance; + float mMinCos; + float mTau; //obscurance exponent + float mMinDist; //min dist between vertices to check too thin parts + float mScale; //Scaling factor used to setup camera + GPUProgram* mDeepthPeelingProgram; + GPUProgram* mSDFProgram; + GPUProgram* mObscuranceProgram; + bool mRemoveFalse; + bool mRemoveOutliers; + GLuint mOcclusionQuery; + GLuint mPixelCount; + unsigned int mTempDepthComplexity; + unsigned int mDepthComplexity; + bool mDepthComplexityWarning; + + CMeshO::PerFaceAttributeHandle mMaxQualityDirPerFace; + CMeshO::PerVertexAttributeHandle mMaxQualityDirPerVertex; + }; #endif // FILTER_SDFGPU_H