From 039e972a4b1735bad63bdd458e182d2caec3fccf Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 28 Jul 2018 11:08:03 +0200 Subject: [PATCH] implement fast mesh rendering for Qt5 port (7x faster) --- src/Mod/Mesh/Gui/AppMeshGui.cpp | 1 + src/Mod/Mesh/Gui/Command.cpp | 1 + src/Mod/Mesh/Gui/MeshSelection.cpp | 16 +- src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp | 600 +++++++++++++++---- src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h | 52 +- src/Mod/Mesh/Gui/ViewProvider.cpp | 8 + src/Mod/Mesh/Gui/ViewProvider.h | 1 + src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp | 8 +- 8 files changed, 565 insertions(+), 122 deletions(-) diff --git a/src/Mod/Mesh/Gui/AppMeshGui.cpp b/src/Mod/Mesh/Gui/AppMeshGui.cpp index d85fccf5d9..4b6d1e7dca 100644 --- a/src/Mod/Mesh/Gui/AppMeshGui.cpp +++ b/src/Mod/Mesh/Gui/AppMeshGui.cpp @@ -130,6 +130,7 @@ PyMOD_INIT_FUNC(MeshGui) MeshGui::SoFCMeshObjectShape ::initClass(); MeshGui::SoFCMeshSegmentShape ::initClass(); MeshGui::SoFCMeshObjectBoundary ::initClass(); + MeshGui::SoFCMaterialEngine ::initClass(); MeshGui::SoFCIndexedFaceSet ::initClass(); MeshGui::SoFCMeshPickNode ::initClass(); MeshGui::SoFCMeshGridNode ::initClass(); diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 76425536a5..57de70f214 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -450,6 +450,7 @@ void CmdMeshExport::activated(int) ext << qMakePair(QString::fromLatin1("%1 (*.ast)").arg(QObject::tr("ASCII STL")), "AST"); ext << qMakePair(QString::fromLatin1("%1 (*.bms)").arg(QObject::tr("Binary Mesh")), "BMS"); ext << qMakePair(QString::fromLatin1("%1 (*.obj)").arg(QObject::tr("Alias Mesh")), "OBJ"); + ext << qMakePair(QString::fromLatin1("%1 (*.smf)").arg(QObject::tr("Simple Model Format")), "SMF"); ext << qMakePair(QString::fromLatin1("%1 (*.off)").arg(QObject::tr("Object File Format")), "OFF"); ext << qMakePair(QString::fromLatin1("%1 (*.iv)").arg(QObject::tr("Inventor V2.1 ascii")), "IV"); ext << qMakePair(QString::fromLatin1("%1 (*.x3d)").arg(QObject::tr("X3D Extensible 3D")), "X3D"); diff --git a/src/Mod/Mesh/Gui/MeshSelection.cpp b/src/Mod/Mesh/Gui/MeshSelection.cpp index 60f1ef0a9d..3a4fa01baa 100644 --- a/src/Mod/Mesh/Gui/MeshSelection.cpp +++ b/src/Mod/Mesh/Gui/MeshSelection.cpp @@ -329,21 +329,7 @@ void MeshSelection::invertSelection() { std::list views = getViewProviders(); for (std::list::iterator it = views.begin(); it != views.end(); ++it) { - Mesh::Feature* mf = static_cast((*it)->getObject()); - const Mesh::MeshObject* mo = mf->Mesh.getValuePtr(); - const MeshCore::MeshFacetArray& faces = mo->getKernel().GetFacets(); - unsigned long num_notsel = std::count_if(faces.begin(), faces.end(), - std::bind2nd(MeshCore::MeshIsNotFlag(), - MeshCore::MeshFacet::SELECTED)); - std::vector notselect; - notselect.reserve(num_notsel); - MeshCore::MeshFacetArray::_TConstIterator beg = faces.begin(); - MeshCore::MeshFacetArray::_TConstIterator end = faces.end(); - for (MeshCore::MeshFacetArray::_TConstIterator jt = beg; jt != end; ++jt) { - if (!jt->IsFlag(MeshCore::MeshFacet::SELECTED)) - notselect.push_back(jt-beg); - } - (*it)->setSelection(notselect); + (*it)->invertSelection(); } } diff --git a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp index 7ba2a3c796..bd64e04e2d 100644 --- a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp +++ b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp @@ -38,10 +38,12 @@ # include # include # include +# include # include # include # include # include +# include #endif #include @@ -49,11 +51,332 @@ #include #include #include "SoFCIndexedFaceSet.h" +#include + +#ifdef HAVE_QT5_OPENGL +#define RENDER_GL_VAO +#endif +//#define RENDER_GLARRAYS + +#ifdef RENDER_GL_VAO +#include +#include +#endif + + using namespace MeshGui; +#if defined RENDER_GL_VAO +class MeshRenderer::Private : protected QOpenGLFunctions { +public: + QOpenGLBuffer vertices; + QOpenGLBuffer indices; + const SbColor * pcolors; + SoMaterialBindingElement::Binding matbinding; -//#define RENDER_GLARRAYS + Private(); + void generateGLArrays(SoMaterialBindingElement::Binding matbind, + std::vector& vertex, std::vector& index); + void renderFacesGLArray(SoGLRenderAction*); + void renderCoordsGLArray(SoGLRenderAction *action); +}; + +MeshRenderer::Private::Private() + : vertices(QOpenGLBuffer::VertexBuffer) + , indices(QOpenGLBuffer::IndexBuffer) + , pcolors(0) + , matbinding(SoMaterialBindingElement::OVERALL) +{ + initializeOpenGLFunctions(); + + vertices.create(); + indices.create(); + + vertices.setUsagePattern(QOpenGLBuffer::StaticDraw); + indices.setUsagePattern(QOpenGLBuffer::StaticDraw); +} + +void MeshRenderer::Private::generateGLArrays(SoMaterialBindingElement::Binding matbind, + std::vector& vertex, std::vector& index) +{ + if (vertex.empty() || index.empty()) + return; + vertices.bind(); + vertices.allocate(&(vertex[0]), + vertex.size() * sizeof(float)); + vertices.release(); + + indices.bind(); + indices.allocate(&(index[0]), + index.size() * sizeof(int32_t)); + indices.release(); + this->matbinding = matbind; +} + +void MeshRenderer::Private::renderFacesGLArray(SoGLRenderAction *) +{ + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + vertices.bind(); + indices.bind(); + + if (matbinding != SoMaterialBindingElement::OVERALL) + glInterleavedArrays(GL_C4F_N3F_V3F, 0, 0); + else + glInterleavedArrays(GL_N3F_V3F, 0, 0); + glDrawElements(GL_TRIANGLES, indices.size() / sizeof(uint32_t), + GL_UNSIGNED_INT, NULL); + + vertices.release(); + indices.release(); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +} + +void MeshRenderer::Private::renderCoordsGLArray(SoGLRenderAction *) +{ + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + vertices.bind(); + indices.bind(); + + if (matbinding != SoMaterialBindingElement::OVERALL) + glInterleavedArrays(GL_C4F_N3F_V3F, 0, 0); + else + glInterleavedArrays(GL_N3F_V3F, 0, 0); + glDrawElements(GL_POINTS, indices.size() / sizeof(uint32_t), + GL_UNSIGNED_INT, NULL); + + vertices.release(); + indices.release(); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +} +#elif defined RENDER_GLARRAYS +class MeshRenderer::Private { +public: + std::vector index_array; + std::vector vertex_array; + const SbColor * pcolors; + SoMaterialBindingElement::Binding matbinding; + + Private() + : pcolors(0) + , matbinding(SoMaterialBindingElement::OVERALL) + { + } + + void generateGLArrays(SoMaterialBindingElement::Binding matbind, + std::vector& vertex, std::vector& index); + void renderFacesGLArray(SoGLRenderAction *action); + void renderCoordsGLArray(SoGLRenderAction *action); +}; + +void MeshRenderer::Private::generateGLArrays(SoMaterialBindingElement::Binding matbind, + std::vector& vertex, std::vector& index) +{ + if (vertex.empty() || index.empty()) + return; + + this->index_array.resize(0); + this->vertex_array.resize(0); + + this->index_array.swap(index); + this->vertex_array.swap(vertex); + this->matbinding = matbind; +} + +void MeshRenderer::Private::renderFacesGLArray(SoGLRenderAction *action) +{ +#if 0 // use Inventor's coordIndex saves memory but the rendering is very slow then + const cc_glglue * glue = cc_glglue_instance(action->getCacheContext()); + PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) + cc_glglue_getprocaddress(glue, "glPrimitiveRestartIndex"); + + int cnt = coordIndex.getNum(); + + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + // https://www.opengl.org/discussion_boards/archive/index.php/t-180767.html + // https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart + glPrimitiveRestartIndex(0xffffffff); + glEnable(GL_PRIMITIVE_RESTART); + //glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + + glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); + glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, coordIndex.getValues(0)); + + glDisable(GL_PRIMITIVE_RESTART); + //glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +#else // Needs more memory but makes it very fast + (void)action; + int cnt = index_array.size(); + + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + if (matbinding != SoMaterialBindingElement::OVERALL) + glInterleavedArrays(GL_C4F_N3F_V3F, 0, &(vertex_array[0])); + else + glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); + glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, &(index_array[0])); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +#endif +} + +void MeshRenderer::Private::renderCoordsGLArray(SoGLRenderAction *) +{ + int cnt = index_array.size(); + + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + if (matbinding != SoMaterialBindingElement::OVERALL) + glInterleavedArrays(GL_C4F_N3F_V3F, 0, &(vertex_array[0])); + else + glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); + glDrawElements(GL_POINTS, cnt, GL_UNSIGNED_INT, &(index_array[0])); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); +} +#else +class MeshRenderer::Private { +public: + const SbColor * pcolors; + SoMaterialBindingElement::Binding matbinding; + + Private() + : pcolors(0) + , matbinding(SoMaterialBindingElement::OVERALL) + { + } + + void generateGLArrays(SoMaterialBindingElement::Binding, + std::vector&, std::vector&) + { + } + void renderFacesGLArray(SoGLRenderAction *) + { + } + void renderCoordsGLArray(SoGLRenderAction *) + { + } +}; +#endif + +MeshRenderer::MeshRenderer() + : p(new Private) +{ +} + +MeshRenderer::~MeshRenderer() +{ + delete p; +} + +void MeshRenderer::generateGLArrays(SoState* state, SoMaterialBindingElement::Binding matbind, + std::vector& vertex, std::vector& index) +{ + SoGLLazyElement* gl = SoGLLazyElement::getInstance(state); + if (gl) { + p->pcolors = gl->getDiffusePointer(); + } + p->generateGLArrays(matbind, vertex, index); +} + +// Implementation | FPS +// ================================================ +// drawCoords (every 4th vertex) | 20.0 +// renderCoordsGLArray (all vertexes) | 20.0 +// +void MeshRenderer::renderCoordsGLArray(SoGLRenderAction *action) +{ + p->renderCoordsGLArray(action); +} + +//**************************************************************************** +// renderFacesGLArray: normal and coord from vertex_array; +// no texture, color, highlight or selection but highest possible speed; +// all vertices written in one go! +// +// Benchmark tests with an 256 MB STL file: +// +// Implementation | FPS +// ================================================ +// OpenInventor (SoIndexedFaceSet) | 3.0 +// Custom OpenInventor (SoFCMeshObjectShape) | 8.5 +// With GL_PRIMITIVE_RESTART | 0.9 +// With GL_PRIMITIVE_RESTART_FIXED_INDEX | 0.9 +// Without GL_PRIMITIVE_RESTART | 8.5 +// Vertex-Array-Object (RENDER_GL_VAO) | 60.0 +void MeshRenderer::renderFacesGLArray(SoGLRenderAction *action) +{ + p->renderFacesGLArray(action); +} + +bool MeshRenderer::matchMaterial(SoState* state) const +{ + SoMaterialBindingElement::Binding matbind = + SoMaterialBindingElement::get(state); + const SbColor * pcolors = 0; + SoGLLazyElement* gl = SoGLLazyElement::getInstance(state); + if (gl) { + pcolors = gl->getDiffusePointer(); + } + return p->matbinding == matbind && p->pcolors == pcolors; +} + +bool MeshRenderer::shouldRenderDirectly(bool direct) +{ +#ifdef RENDER_GL_VAO + Q_UNUSED(direct); + return false; +#else + return direct; +#endif +} + +// ---------------------------------------------------------------------------- + +SO_ENGINE_SOURCE(SoFCMaterialEngine); + +SoFCMaterialEngine::SoFCMaterialEngine() +{ + SO_ENGINE_CONSTRUCTOR(SoFCMaterialEngine); + + SO_ENGINE_ADD_INPUT(diffuseColor, (SbColor(0.0, 0.0, 0.0))); + SO_ENGINE_ADD_OUTPUT(trigger, SoSFBool); +} + +SoFCMaterialEngine::~SoFCMaterialEngine() +{ +} + +void SoFCMaterialEngine::initClass() +{ + SO_ENGINE_INIT_CLASS(SoFCMaterialEngine, SoEngine, "Engine"); +} + +void SoFCMaterialEngine::inputChanged(SoField *) +{ + SO_ENGINE_OUTPUT(trigger, SoSFBool, setValue(true)); +} + +void SoFCMaterialEngine::evaluate() +{ + // do nothing here +} + +// ---------------------------------------------------------------------------- SO_NODE_SOURCE(SoFCIndexedFaceSet); @@ -62,9 +385,13 @@ void SoFCIndexedFaceSet::initClass() SO_NODE_INIT_CLASS(SoFCIndexedFaceSet, SoIndexedFaceSet, "IndexedFaceSet"); } -SoFCIndexedFaceSet::SoFCIndexedFaceSet() : renderTriangleLimit(100000), updateGLArray(false), selectBuf(0) +SoFCIndexedFaceSet::SoFCIndexedFaceSet() + : renderTriangleLimit(100000) + , selectBuf(0) { SO_NODE_CONSTRUCTOR(SoFCIndexedFaceSet); + SO_NODE_ADD_FIELD(updateGLArray, (false)); + updateGLArray.setFieldType(SoField::EVENTOUT_FIELD); setName(SoFCIndexedFaceSet::getClassTypeId().getName()); } @@ -90,9 +417,15 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action) SoState * state = action->getState(); SbBool mode = Gui::SoFCInteractiveElement::get(state); +#if defined(RENDER_GL_VAO) + if (mode == false || render.matchMaterial(state)) { +#else unsigned int num = this->coordIndex.getNum()/4; if (mode == false || num <= this->renderTriangleLimit) { -#ifdef RENDER_GLARRAYS +#endif +#if defined (RENDER_GLARRAYS) || defined(RENDER_GL_VAO) + +#if 0 SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); @@ -103,11 +436,26 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action) updateGLArray = false; generateGLArrays(state); } - renderFacesGLArray(action); + render.renderFacesGLArray(action); } else { inherited::GLRender(action); } +#else + if (updateGLArray.getValue()) { + updateGLArray = false; + generateGLArrays(state); + } + + if (render.matchMaterial(state)) { + SoMaterialBundle mb(action); + mb.sendFirst(); + render.renderFacesGLArray(action); + } + else { + inherited::GLRender(action); + } +#endif #else inherited::GLRender(action); #endif @@ -116,7 +464,7 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action) #if 0 && defined (RENDER_GLARRAYS) SoMaterialBundle mb(action); mb.sendFirst(); - renderCoordsGLArray(action); + render.renderCoordsGLArray(action); #else SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); @@ -235,13 +583,12 @@ void SoFCIndexedFaceSet::invalidate() void SoFCIndexedFaceSet::generateGLArrays(SoState * state) { - this->index_array.resize(0); - this->vertex_array.resize(0); - const SoCoordinateElement * coords; const SbVec3f * normals; const int32_t * cindices; - int numindices; + const SbColor * pcolors = 0; + const float * transp = 0; + int numindices, numcolors = 0, numtransp = 0; const int32_t * nindices; const int32_t * tindices; const int32_t * mindices; @@ -255,115 +602,166 @@ void SoFCIndexedFaceSet::generateGLArrays(SoState * state) const SbVec3f * points = coords->getArrayPtr3(); + SoMaterialBindingElement::Binding matbind = + SoMaterialBindingElement::get(state); + SoGLLazyElement* gl = SoGLLazyElement::getInstance(state); + if (gl) { + pcolors = gl->getDiffusePointer(); + numcolors = gl->getNumDiffuse(); + transp = gl->getTransparencyPointer(); + numtransp = gl->getNumTransparencies(); + Q_UNUSED(numtransp); + } + std::vector face_vertices; std::vector face_indices; std::size_t numTria = numindices / 4; + if (!mindices && matbind == SoMaterialBindingElement::PER_VERTEX_INDEXED) { + mindices = cindices; + } + SoNormalBindingElement::Binding normbind = SoNormalBindingElement::get(state); if (normbind == SoNormalBindingElement::PER_VERTEX_INDEXED) { - face_vertices.reserve(3 * numTria * 6); // duplicate each vertex - face_indices.resize(3 * numTria); + if (matbind == SoMaterialBindingElement::PER_FACE) { + face_vertices.reserve(3 * numTria * 10); // duplicate each vertex (rgba, normal, vertex) + face_indices.resize(3 * numTria); + + if (numcolors != static_cast(numTria)) { + SoDebugError::postWarning("SoFCIndexedFaceSet::generateGLArrays", + "The number of faces (%d) doesn't match with the number of colors (%d).", numTria, numcolors); + } + + // the nindices must have the length of numindices + int32_t vertex = 0; + int index = 0; + float t = transp[0]; + for (std::size_t i=0; igetNum()) { + SoDebugError::postWarning("SoFCIndexedFaceSet::generateGLArrays", + "The number of points (%d) doesn't match with the number of colors (%d).", coords->getNum(), numcolors); + } + + // the nindices must have the length of numindices + int32_t vertex = 0; + int index = 0; + float t = transp[0]; + for (std::size_t i=0; igetNum(); + face_vertices.reserve(6 * numPts); + for (std::size_t i=0; iget3(i); + face_vertices.push_back(p[0]); + face_vertices.push_back(p[1]); + face_vertices.push_back(p[2]); + + } + + face_indices.reserve(3 * numTria); - // the nindices must have the length of numindices - int32_t vertex = 0; int index = 0; for (std::size_t i=0; iindex_array.swap(face_indices); - this->vertex_array.swap(face_vertices); -} - -//**************************************************************************** -// renderFacesGLArray: normal and coord from vertex_array; -// no texture, color, highlight or selection but highest possible speed; -// all vertices written in one go! -// -// Benchmark tests with an 256 MB STL file: -// -// Implementation | FPS -// ================================================ -// OpenInventor | 3.5 -// With GL_PRIMITIVE_RESTART | 0.9 -// With GL_PRIMITIVE_RESTART_FIXED_INDEX | 0.9 -// Without GL_PRIMITIVE_RESTART | 12.5 -// -void SoFCIndexedFaceSet::renderFacesGLArray(SoGLRenderAction *action) -{ -#if 0 // use Inventor's coordIndex saves memory but the rendering is very slow then - const cc_glglue * glue = cc_glglue_instance(action->getCacheContext()); - PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) - cc_glglue_getprocaddress(glue, "glPrimitiveRestartIndex"); - - int cnt = coordIndex.getNum(); - - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - - // https://www.opengl.org/discussion_boards/archive/index.php/t-180767.html - // https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart - glPrimitiveRestartIndex(0xffffffff); - glEnable(GL_PRIMITIVE_RESTART); - //glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); - - glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); - glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, coordIndex.getValues(0)); - - glDisable(GL_PRIMITIVE_RESTART); - //glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); -#else // Needs more memory but makes it very fast - (void)action; - int cnt = index_array.size(); - - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - - glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); - glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, &(index_array[0])); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); -#endif -} - -// Implementation | FPS -// ================================================ -// drawCoords (every 4th vertex) | 20.0 -// renderCoordsGLArray (all vertexes) | 20.0 -// -void SoFCIndexedFaceSet::renderCoordsGLArray(SoGLRenderAction *action) -{ - (void)action; - int cnt = index_array.size(); - - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - - glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0])); - glDrawElements(GL_POINTS, cnt, GL_UNSIGNED_INT, &(index_array[0])); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); + render.generateGLArrays(state, matbind, face_vertices, face_indices); } void SoFCIndexedFaceSet::doAction(SoAction * action) diff --git a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h index b9880fc051..01b9420807 100644 --- a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h +++ b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h @@ -24,6 +24,10 @@ #define MESHGUI_SOFCINDEXEDFACESET_H #include +#include +#include +#include +#include class SoGLCoordinateElement; class SoTextureCoordinateBundle; @@ -34,6 +38,47 @@ typedef float GLfloat; namespace MeshGui { +class MeshRenderer +{ +public: + MeshRenderer(); + ~MeshRenderer(); + void generateGLArrays(SoState*, SoMaterialBindingElement::Binding binding, + std::vector& vertex, std::vector& index); + void renderFacesGLArray(SoGLRenderAction *action); + void renderCoordsGLArray(SoGLRenderAction *action); + bool matchMaterial(SoState*) const; + static bool shouldRenderDirectly(bool); + +private: + class Private; + Private* p; +}; + +/** + * class SoFCMaterialEngine + * \brief The SoFCMaterialEngine class is used to notify an + * SoFCIndexedFaceSet node about material changes. + * + * @author Werner Mayer + */ +class MeshGuiExport SoFCMaterialEngine : public SoEngine +{ + SO_ENGINE_HEADER(SoFCMaterialEngine); + +public: + SoFCMaterialEngine(); + static void initClass(); + + SoMFColor diffuseColor; + SoEngineOutput trigger; + +private: + virtual ~SoFCMaterialEngine(); + virtual void evaluate(); + virtual void inputChanged(SoField *); +}; + /** * class SoFCIndexedFaceSet * \brief The SoFCIndexedFaceSet class is designed to optimize redrawing a mesh @@ -50,6 +95,7 @@ public: static void initClass(); SoFCIndexedFaceSet(); + SoSFBool updateGLArray; unsigned int renderTriangleLimit; void invalidate(); @@ -80,13 +126,9 @@ private: void renderVisibleFaces(const SbVec3f *); void generateGLArrays(SoState * state); - void renderFacesGLArray(SoGLRenderAction *action); - void renderCoordsGLArray(SoGLRenderAction *action); private: - std::vector index_array; - std::vector vertex_array; - SbBool updateGLArray; + MeshRenderer render; GLuint *selectBuf; }; diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index ee27b42f11..1fca2a1934 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -1823,6 +1823,14 @@ void ViewProviderMesh::deleteSelection() } } +bool ViewProviderMesh::hasSelection() const +{ + std::vector indices; + Mesh::PropertyMeshKernel& meshProp = static_cast(pcObject)->Mesh; + const Mesh::MeshObject& rMesh = meshProp.getValue(); + return rMesh.hasSelectedFacets(); +} + void ViewProviderMesh::selectArea(short x, short y, short w, short h, const SbViewportRegion& region, SoCamera* camera) diff --git a/src/Mod/Mesh/Gui/ViewProvider.h b/src/Mod/Mesh/Gui/ViewProvider.h index e8dd0992cb..8adc3b0354 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.h +++ b/src/Mod/Mesh/Gui/ViewProvider.h @@ -151,6 +151,7 @@ public: void invertSelection(); void clearSelection(); void deleteSelection(); + bool hasSelection() const; void getFacetsFromPolygon(const std::vector& picked, const Base::ViewProjMethod& proj, SbBool inner, std::vector& indices) const; diff --git a/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp b/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp index 9aec8a2237..4e89d5ea02 100644 --- a/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp +++ b/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp @@ -100,6 +100,12 @@ ViewProviderMeshFaceSet::ViewProviderMeshFaceSet() pcMeshCoord->ref(); pcMeshFaces = new SoFCIndexedFaceSet; pcMeshFaces->ref(); + + // setup engine to notify 'pcMeshFaces' node about material changes. + // When the affected nodes are deleted the engine will be deleted, too. + SoFCMaterialEngine* engine = new SoFCMaterialEngine(); + engine->diffuseColor.connectFrom(&pcShapeMaterial->diffuseColor); + pcMeshFaces->updateGLArray.connectFrom(&engine->trigger); } ViewProviderMeshFaceSet::~ViewProviderMeshFaceSet() @@ -132,7 +138,7 @@ void ViewProviderMeshFaceSet::updateData(const App::Property* prop) if (prop->getTypeId() == Mesh::PropertyMeshKernel::getClassTypeId()) { const Mesh::MeshObject* mesh = static_cast(prop)->getValuePtr(); - bool direct = (mesh->countFacets() > this->triangleCount); + bool direct = MeshRenderer::shouldRenderDirectly(mesh->countFacets() > this->triangleCount); if (direct) { this->pcMeshNode->mesh.setValue(mesh); // Needs to update internal bounding box caches