diff --git a/src/Mod/Mesh/App/Core/Approximation.h b/src/Mod/Mesh/App/Core/Approximation.h index 7a2f249455..272c85c900 100644 --- a/src/Mod/Mesh/App/Core/Approximation.h +++ b/src/Mod/Mesh/App/Core/Approximation.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -260,7 +261,9 @@ public: /** * Construction */ - QuadraticFit() : Approximation() {}; + QuadraticFit() : Approximation() { + std::fill(_fCoeff, _fCoeff+10, 0.0); + } /** * Destruction */ diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index 562d37ad13..c4797808e7 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -1610,6 +1610,12 @@ MeshIO::Format MeshOutput::GetFormat(const char* FileName) else if (file.hasExtension("ply")) { return MeshIO::PLY; } + else if (file.hasExtension("idtf")) { + return MeshIO::IDTF; + } + else if (file.hasExtension("mgl")) { + return MeshIO::MGL; + } else if (file.hasExtension("iv")) { return MeshIO::IV; } @@ -1676,7 +1682,6 @@ bool MeshOutput::SaveAny(const char* FileName, MeshIO::Format format) const ok = aWriter.SaveAsciiSTL( str ); if (!ok) throw Base::FileException("Export of STL mesh failed",FileName); - } else if (fileformat == MeshIO::OBJ) { // write file @@ -1698,6 +1703,16 @@ bool MeshOutput::SaveAny(const char* FileName, MeshIO::Format format) const if (!SaveAsciiPLY(str)) throw Base::FileException("Export of PLY mesh failed",FileName); } + else if (fileformat == MeshIO::IDTF) { + // write file + if (!SaveIDTF(str)) + throw Base::FileException("Export of IDTF mesh failed",FileName); + } + else if (fileformat == MeshIO::MGL) { + // write file + if (!SaveMGL(str)) + throw Base::FileException("Export of MGL mesh failed",FileName); + } else if (fileformat == MeshIO::IV) { // write file if (!SaveInventor(str)) @@ -1756,6 +1771,10 @@ bool MeshOutput::SaveFormat(std::ostream &str, MeshIO::Format fmt) const return SaveOBJ(str); case MeshIO::OFF: return SaveOFF(str); + case MeshIO::IDTF: + return SaveIDTF(str); + case MeshIO::MGL: + return SaveMGL(str); case MeshIO::IV: return SaveInventor(str); case MeshIO::X3D: @@ -2403,6 +2422,152 @@ void MeshOutput::SaveXML (Base::Writer &writer) const writer.decInd(); } +/** Writes an IDTF file. */ +bool MeshOutput::SaveIDTF (std::ostream &str) const +{ + if ((!str) || (str.bad() == true) || (_rclMesh.CountFacets() == 0)) + return false; + + const MeshPointArray& pts = _rclMesh.GetPoints(); + const MeshFacetArray& fts = _rclMesh.GetFacets(); + std::string resource = objectName; + if (resource.empty()) + resource = "Resource"; + + str.precision(6); + str.setf(std::ios::fixed | std::ios::showpoint); + + str << "FILE_FORMAT \"IDTF\"" << std::endl + << "FORMAT_VERSION 100" << std::endl << std::endl; + + str << Base::tabs(0) << "NODE \"MODEL\" {" << std::endl; + str << Base::tabs(1) << "NODE_NAME \"FreeCAD\"" << std::endl; + str << Base::tabs(1) << "PARENT_LIST {" << std::endl; + str << Base::tabs(2) << "PARENT_COUNT 1" << std::endl; + str << Base::tabs(2) << "PARENT 0 {" << std::endl; + str << Base::tabs(3) << "PARENT_NAME \"\"" << std::endl; + str << Base::tabs(3) << "PARENT_TM {" << std::endl; + str << Base::tabs(4) << "1.000000 0.000000 0.000000 0.000000" << std::endl; + str << Base::tabs(4) << "0.000000 1.000000 0.000000 0.000000" << std::endl; + str << Base::tabs(4) << "0.000000 0.000000 1.000000 0.000000" << std::endl; + str << Base::tabs(4) << "0.000000 0.000000 0.000000 1.000000" << std::endl; + str << Base::tabs(3) << "}" << std::endl; + str << Base::tabs(2) << "}" << std::endl; + str << Base::tabs(1) << "}" << std::endl; + str << Base::tabs(1) << "RESOURCE_NAME \"FreeCAD\"" << std::endl; + str << Base::tabs(0) << "}" << std::endl << std::endl; + + str << Base::tabs(0) << "RESOURCE_LIST \"MODEL\" {" << std::endl; + str << Base::tabs(1) << "RESOURCE_COUNT 1" << std::endl; + str << Base::tabs(1) << "RESOURCE 0 {" << std::endl; + str << Base::tabs(2) << "RESOURCE_NAME \"" << resource << "\"" << std::endl; + str << Base::tabs(2) << "MODEL_TYPE \"MESH\"" << std::endl; + str << Base::tabs(2) << "MESH {" << std::endl; + str << Base::tabs(3) << "FACE_COUNT " << fts.size() << std::endl; + str << Base::tabs(3) << "MODEL_POSITION_COUNT " << pts.size() << std::endl; + str << Base::tabs(3) << "MODEL_NORMAL_COUNT " << 3*fts.size() << std::endl; + str << Base::tabs(3) << "MODEL_DIFFUSE_COLOR_COUNT 0" << std::endl; + str << Base::tabs(3) << "MODEL_SPECULAR_COLOR_COUNT 0" << std::endl; + str << Base::tabs(3) << "MODEL_TEXTURE_COORD_COUNT 0" << std::endl; + str << Base::tabs(3) << "MODEL_BONE_COUNT 0" << std::endl; + str << Base::tabs(3) << "MODEL_SHADING_COUNT 1" << std::endl; + str << Base::tabs(3) << "MODEL_SHADING_DESCRIPTION_LIST {" << std::endl; + str << Base::tabs(4) << "SHADING_DESCRIPTION 0 {" << std::endl; + str << Base::tabs(5) << "TEXTURE_LAYER_COUNT 0" << std::endl; + str << Base::tabs(5) << "SHADER_ID 0" << std::endl; + str << Base::tabs(4) << "}" << std::endl; + str << Base::tabs(3) << "}" << std::endl; + str << Base::tabs(3) << "MESH_FACE_POSITION_LIST {" << std::endl; + for (MeshFacetArray::_TConstIterator it = fts.begin(); it != fts.end(); ++it) { + str << Base::tabs(4) << it->_aulPoints[0] << " " << it->_aulPoints[1] << " " << it->_aulPoints[2] << std::endl; + } + str << Base::tabs(3) << "}" << std::endl; + str << Base::tabs(3) << "MESH_FACE_NORMAL_LIST {" << std::endl; + int index = 0; + for (MeshFacetArray::_TConstIterator it = fts.begin(); it != fts.end(); ++it) { + str << Base::tabs(4) << index << " " << index + 1 << " " << index + 2 << std::endl; + index += 3; + } + str << Base::tabs(3) << "}" << std::endl; + str << Base::tabs(3) << "MESH_FACE_SHADING_LIST {" << std::endl; + for (MeshFacetArray::_TConstIterator it = fts.begin(); it != fts.end(); ++it) { + str << Base::tabs(4) << "0" << std::endl; + } + str << Base::tabs(3) << "}" << std::endl; + str << Base::tabs(3) << "MODEL_POSITION_LIST {" << std::endl; + for (MeshPointArray::_TConstIterator it = pts.begin(); it != pts.end(); ++it) { + str << Base::tabs(4) << it->x << " " << it->y << " " << it->z << std::endl; + } + str << Base::tabs(3) << "}" << std::endl; + str << Base::tabs(3) << "MODEL_NORMAL_LIST {" << std::endl; + for (MeshFacetArray::_TConstIterator it = fts.begin(); it != fts.end(); ++it) { + MeshGeomFacet face = _rclMesh.GetFacet(*it); + Base::Vector3f normal = face.GetNormal(); + str << Base::tabs(4) << normal.x << " " << normal.y << " " << normal.z << std::endl; + str << Base::tabs(4) << normal.x << " " << normal.y << " " << normal.z << std::endl; + str << Base::tabs(4) << normal.x << " " << normal.y << " " << normal.z << std::endl; + } + + str << Base::tabs(3) << "}" << std::endl; + str << Base::tabs(2) << "}" << std::endl; + str << Base::tabs(1) << "}" << std::endl; + str << Base::tabs(0) << "}" << std::endl; + + return true; +} + +/** Writes an MGL file. */ +bool MeshOutput::SaveMGL (std::ostream &str) const +{ +/* +light on +list t 0 1 2 | 0 1 3 | 0 2 3 | 1 2 3 +list xt 1 1 0 0 +list yt -1 -1 1 0 +list zt -1 -1 -1 1 +triplot t xt yt zt 'b' +#triplot t xt yt zt '#k' +*/ + if ((!str) || (str.bad() == true) || (_rclMesh.CountFacets() == 0)) + return false; + + const MeshPointArray& pts = _rclMesh.GetPoints(); + const MeshFacetArray& fts = _rclMesh.GetFacets(); + + str.precision(2); + str.setf(std::ios::fixed | std::ios::showpoint); + + str << "light on" << std::endl; + str << "list t "; + for (MeshFacetArray::_TConstIterator it = fts.begin(); it != fts.end(); ++it) { + str << it->_aulPoints[0] << " " << it->_aulPoints[1] << " " << it->_aulPoints[2] << " | "; + } + str << std::endl; + + str << "list xt "; + for (MeshPointArray::_TConstIterator it = pts.begin(); it != pts.end(); ++it) { + str << it->x << " "; + } + str << std::endl; + + str << "list yt "; + for (MeshPointArray::_TConstIterator it = pts.begin(); it != pts.end(); ++it) { + str << it->y << " "; + } + str << std::endl; + + str << "list zt "; + for (MeshPointArray::_TConstIterator it = pts.begin(); it != pts.end(); ++it) { + str << it->z << " "; + } + str << std::endl; + + str << "triplot t xt yt zt 'b'" << std::endl; + str << "#triplot t xt yt zt '#k'" << std::endl; + + return true; +} + /** Writes an OpenInventor file. */ bool MeshOutput::SaveInventor (std::ostream &rstrOut) const { diff --git a/src/Mod/Mesh/App/Core/MeshIO.h b/src/Mod/Mesh/App/Core/MeshIO.h index afcce6111a..582b00c5ad 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.h +++ b/src/Mod/Mesh/App/Core/MeshIO.h @@ -46,6 +46,8 @@ namespace MeshIO { BSTL, OBJ, OFF, + IDTF, + MGL, IV, X3D, VRML, @@ -178,6 +180,10 @@ public: void SaveXML (Base::Writer &writer) const; /** Saves a node to an OpenInventor file. */ bool SaveMeshNode (std::ostream &rstrIn); + /** Writes an IDTF file. */ + bool SaveIDTF (std::ostream &rstrOut) const; + /** Writes an MGL file. */ + bool SaveMGL (std::ostream &rstrOut) const; /** Writes an OpenInventor file. */ bool SaveInventor (std::ostream &rstrOut) const; /** Writes an X3D file. */ diff --git a/src/Mod/Mesh/App/Core/SetOperations.h b/src/Mod/Mesh/App/Core/SetOperations.h index bdf580d648..860dc85d7f 100644 --- a/src/Mod/Mesh/App/Core/SetOperations.h +++ b/src/Mod/Mesh/App/Core/SetOperations.h @@ -122,6 +122,8 @@ private: { fcounter[0] = 0; fcounter[1] = 0; + facet[0] = 0; + facet[1] = 0; } }; diff --git a/src/Mod/Mesh/App/FeatureMeshSetOperations.cpp b/src/Mod/Mesh/App/FeatureMeshSetOperations.cpp index 5312c50ea0..16ed3460b9 100644 --- a/src/Mod/Mesh/App/FeatureMeshSetOperations.cpp +++ b/src/Mod/Mesh/App/FeatureMeshSetOperations.cpp @@ -91,20 +91,20 @@ App::DocumentObjectExecReturn *SetOperations::execute(void) else if (ot == "outer") type = MeshCore::SetOperations::Outer; else - throw new Base::ValueError("Operation type must either be 'union' or 'intersection'" - " or 'difference' or 'inner' or 'outer'"); + throw Base::ValueError("Operation type must either be 'union' or 'intersection'" + " or 'difference' or 'inner' or 'outer'"); MeshCore::SetOperations setOp(meshKernel1.getKernel(), meshKernel2.getKernel(), pcKernel->getKernel(), type, 1.0e-5f); setOp.Do(); Mesh.setValuePtr(pcKernel.release()); } - else { + else { // Error mesh property if (!mesh1) - throw new Base::ValueError("First input mesh not set"); + throw Base::ValueError("First input mesh not set"); if (!mesh2) - throw new Base::ValueError("Second input mesh not set"); + throw Base::ValueError("Second input mesh not set"); } return App::DocumentObject::StdReturn; diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 502baeec3d..101ede6ba6 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -596,12 +596,16 @@ void MeshObject::addMesh(const MeshCore::MeshKernel& kernel) void MeshObject::deleteFacets(const std::vector& removeIndices) { + if (removeIndices.empty()) + return; _kernel.DeleteFacets(removeIndices); deletedFacets(removeIndices); } void MeshObject::deletePoints(const std::vector& removeIndices) { + if (removeIndices.empty()) + return; _kernel.DeletePoints(removeIndices); this->_segments.clear(); } diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml index bda9ff1231..e0be9f6dfd 100644 --- a/src/Mod/Mesh/App/MeshPy.xml +++ b/src/Mod/Mesh/App/MeshPy.xml @@ -405,7 +405,8 @@ The argument int is the mode: 0=inner, 1=outer - Smooth the mesh + Smooth the mesh +smooth([iteration=1,maxError=FLT_MAX]) diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index 8f945172b2..769bbcd21b 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -212,6 +212,8 @@ PyObject* MeshPy::write(PyObject *args, PyObject *kwds) ext["AST" ] = MeshCore::MeshIO::ASTL; ext["OBJ" ] = MeshCore::MeshIO::OBJ; ext["OFF" ] = MeshCore::MeshIO::OFF; + ext["IDTF"] = MeshCore::MeshIO::IDTF; + ext["MGL" ] = MeshCore::MeshIO::MGL; ext["IV" ] = MeshCore::MeshIO::IV; ext["X3D" ] = MeshCore::MeshIO::X3D; ext["VRML"] = MeshCore::MeshIO::VRML; diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt index 795b01ff44..9716585872 100644 --- a/src/Mod/Mesh/Gui/CMakeLists.txt +++ b/src/Mod/Mesh/Gui/CMakeLists.txt @@ -7,6 +7,12 @@ include_directories( ${XercesC_INCLUDE_DIRS} ) +if(MSVC) + include_directories( + ${CMAKE_SOURCE_DIR}/src/3rdParty/OpenGL/api + ) +endif(MSVC) + set(MeshGui_LIBS ${Boost_LIBRARIES} ${OPENGL_glu_LIBRARY} diff --git a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp index 4a985d65cd..1ae60aea65 100644 --- a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp +++ b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.cpp @@ -37,10 +37,14 @@ # include # include # include +# include # include # include #endif +#include +#include + #include #include #include "SoFCIndexedFaceSet.h" @@ -48,6 +52,8 @@ using namespace MeshGui; +//#define RENDER_GLARRAYS + SO_NODE_SOURCE(SoFCIndexedFaceSet); void SoFCIndexedFaceSet::initClass() @@ -55,7 +61,7 @@ void SoFCIndexedFaceSet::initClass() SO_NODE_INIT_CLASS(SoFCIndexedFaceSet, SoIndexedFaceSet, "IndexedFaceSet"); } -SoFCIndexedFaceSet::SoFCIndexedFaceSet() : renderTriangleLimit(100000), selectBuf(0) +SoFCIndexedFaceSet::SoFCIndexedFaceSet() : renderTriangleLimit(100000), updateGLArray(false), selectBuf(0) { SO_NODE_CONSTRUCTOR(SoFCIndexedFaceSet); setName(SoFCIndexedFaceSet::getClassTypeId().getName()); @@ -77,9 +83,32 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action) unsigned int num = this->coordIndex.getNum()/4; if (mode == false || num <= this->renderTriangleLimit) { +#ifdef RENDER_GLARRAYS + SoMaterialBindingElement::Binding matbind = + SoMaterialBindingElement::get(state); + + if (matbind == SoMaterialBindingElement::OVERALL) { + SoMaterialBundle mb(action); + mb.sendFirst(); + if (updateGLArray) { + updateGLArray = false; + generateGLArrays(state); + } + renderFacesGLArray(action); + } + else { + inherited::GLRender(action); + } +#else inherited::GLRender(action); +#endif } else { +#if 0 && defined (RENDER_GLARRAYS) + SoMaterialBundle mb(action); + mb.sendFirst(); + renderCoordsGLArray(action); +#else SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state); int32_t binding = (int32_t)(matbind); @@ -108,6 +137,7 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action) normals, nindices, &mb, mindices, binding, &tb, tindices); // Disable caching for this node SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE); +#endif } } @@ -189,6 +219,144 @@ void SoFCIndexedFaceSet::drawCoords(const SoGLCoordinateElement * const vertexli glEnd(); } +void SoFCIndexedFaceSet::invalidate() +{ + updateGLArray = true; +} + +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 int32_t * nindices; + const int32_t * tindices; + const int32_t * mindices; + SbBool normalCacheUsed; + + SbBool sendNormals = true; + + this->getVertexData(state, coords, normals, cindices, + nindices, tindices, mindices, numindices, + sendNormals, normalCacheUsed); + + const SbVec3f * points = coords->getArrayPtr3(); + + std::vector face_vertices; + std::vector face_indices; + + std::size_t numTria = numindices / 4; + + 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); + + // 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); +} + void SoFCIndexedFaceSet::doAction(SoAction * action) { if (action->getTypeId() == Gui::SoGLSelectAction::getClassTypeId()) { diff --git a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h index d6f9a7d752..b9880fc051 100644 --- a/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h +++ b/src/Mod/Mesh/Gui/SoFCIndexedFaceSet.h @@ -23,7 +23,6 @@ #ifndef MESHGUI_SOFCINDEXEDFACESET_H #define MESHGUI_SOFCINDEXEDFACESET_H - #include class SoGLCoordinateElement; @@ -53,6 +52,8 @@ public: unsigned int renderTriangleLimit; + void invalidate(); + protected: // Force using the reference count mechanism. virtual ~SoFCIndexedFaceSet() {} @@ -78,6 +79,14 @@ private: void stopVisibility(SoAction * action); 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; GLuint *selectBuf; }; diff --git a/src/Mod/Mesh/Gui/SoFCMeshObject.cpp b/src/Mod/Mesh/Gui/SoFCMeshObject.cpp index 8db69e00ae..c4948d5272 100644 --- a/src/Mod/Mesh/Gui/SoFCMeshObject.cpp +++ b/src/Mod/Mesh/Gui/SoFCMeshObject.cpp @@ -590,19 +590,25 @@ void SoFCMeshObjectShape::initClass() SoFCMeshObjectShape::SoFCMeshObjectShape() : renderTriangleLimit(100000) - , meshChanged(true) , selectBuf(0) + , updateGLArray(false) { SO_NODE_CONSTRUCTOR(SoFCMeshObjectShape); setName(SoFCMeshObjectShape::getClassTypeId().getName()); } +SoFCMeshObjectShape::~SoFCMeshObjectShape() +{ +} + void SoFCMeshObjectShape::notify(SoNotList * node) { inherited::notify(node); - meshChanged = true; + updateGLArray = true; } +#define RENDER_GLARRAYS + /** * Either renders the complete mesh or only a subset of the points. */ @@ -634,13 +640,27 @@ void SoFCMeshObjectShape::GLRender(SoGLRenderAction *action) ccw = false; if (mode == false || mesh->countFacets() <= this->renderTriangleLimit) { - if (mbind != OVERALL) + if (mbind != OVERALL) { drawFaces(mesh, &mb, mbind, needNormals, ccw); - else + } + else { +#ifdef RENDER_GLARRAYS + if (updateGLArray) { + updateGLArray = false; + generateGLArrays(state); + } + renderFacesGLArray(action); +#else drawFaces(mesh, 0, mbind, needNormals, ccw); +#endif + } } else { +#if 0 && defined (RENDER_GLARRAYS) + renderCoordsGLArray(action); +#else drawPoints(mesh, needNormals, ccw); +#endif } // Disable caching for this node @@ -845,6 +865,102 @@ void SoFCMeshObjectShape::drawPoints(const Mesh::MeshObject * mesh, SbBool needN } } +void SoFCMeshObjectShape::generateGLArrays(SoState * state) +{ + const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state); + + this->index_array.resize(0); + this->vertex_array.resize(0); + + std::vector face_vertices; + std::vector face_indices; + + const MeshCore::MeshKernel& kernel = mesh->getKernel(); + const MeshCore::MeshPointArray& cP = kernel.GetPoints(); + const MeshCore::MeshFacetArray& cF = kernel.GetFacets(); + +#if 0 + // Smooth shading + face_vertices.resize(cP.size() * 6); + face_indices.resize(3 * cF.size()); + + int indexed = 0; + for (MeshCore::MeshPointArray::const_iterator it = cP.begin(); it != cP.end(); ++it) { + face_vertices[indexed * 6 + 3] += it->x; + face_vertices[indexed * 6 + 4] += it->y; + face_vertices[indexed * 6 + 5] += it->z; + indexed++; + } + + indexed = 0; + for (MeshCore::MeshFacetArray::const_iterator it = cF.begin(); it != cF.end(); ++it) { + Base::Vector3f n = kernel.GetFacet(*it).GetNormal(); + for (int i=0; i<3; i++) { + int32_t idx = it->_aulPoints[i]; + face_vertices[idx * 6 + 0] += n.x; + face_vertices[idx * 6 + 1] += n.y; + face_vertices[idx * 6 + 2] += n.z; + + face_indices[indexed++] = idx; + } + } +#else + // Flat shading + face_vertices.reserve(3 * cF.size() * 6); // duplicate each vertex + face_indices.resize(3 * cF.size()); + + int indexed = 0; + for (MeshCore::MeshFacetArray::const_iterator it = cF.begin(); it != cF.end(); ++it) { + Base::Vector3f n = kernel.GetFacet(*it).GetNormal(); + for (int i=0; i<3; i++) { + face_vertices.push_back(n.x); + face_vertices.push_back(n.y); + face_vertices.push_back(n.z); + const Base::Vector3f& v = cP[it->_aulPoints[i]]; + face_vertices.push_back(v.x); + face_vertices.push_back(v.y); + face_vertices.push_back(v.z); + + face_indices[indexed] = indexed; + indexed++; + } + } +#endif + + this->index_array.swap(face_indices); + this->vertex_array.swap(face_vertices); +} + +void SoFCMeshObjectShape::renderFacesGLArray(SoGLRenderAction *action) +{ + (void)action; + GLsizei cnt = static_cast(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); +} + +void SoFCMeshObjectShape::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); +} + void SoFCMeshObjectShape::doAction(SoAction * action) { if (action->getTypeId() == Gui::SoGLSelectAction::getClassTypeId()) { diff --git a/src/Mod/Mesh/Gui/SoFCMeshObject.h b/src/Mod/Mesh/Gui/SoFCMeshObject.h index 1baeb5952c..946413cd40 100644 --- a/src/Mod/Mesh/Gui/SoFCMeshObject.h +++ b/src/Mod/Mesh/Gui/SoFCMeshObject.h @@ -194,7 +194,7 @@ private: private: // Force using the reference count mechanism. - virtual ~SoFCMeshObjectShape() {}; + virtual ~SoFCMeshObjectShape(); virtual void notify(SoNotList * list); Binding findMaterialBinding(SoState * const state) const; // Draw faces @@ -207,11 +207,18 @@ private: void stopSelection(SoAction * action, const Mesh::MeshObject*); void renderSelectionGeometry(const Mesh::MeshObject*); + void generateGLArrays(SoState * state); + void renderFacesGLArray(SoGLRenderAction *action); + void renderCoordsGLArray(SoGLRenderAction *action); + private: - bool meshChanged; GLuint *selectBuf; GLfloat modelview[16]; GLfloat projection[16]; + // Vertex array handling + std::vector index_array; + std::vector vertex_array; + SbBool updateGLArray; }; class MeshGuiExport SoFCMeshSegmentShape : public SoShape { diff --git a/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp b/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp index dd04200e58..9aec8a2237 100644 --- a/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp +++ b/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.cpp @@ -143,6 +143,7 @@ void ViewProviderMeshFaceSet::updateData(const App::Property* prop) else { ViewProviderMeshBuilder builder; builder.createMesh(prop, pcMeshCoord, pcMeshFaces); + pcMeshFaces->invalidate(); } if (direct != directRendering) { diff --git a/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.h b/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.h index 2e873e5a40..dd07001703 100644 --- a/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.h +++ b/src/Mod/Mesh/Gui/ViewProviderMeshFaceSet.h @@ -26,6 +26,7 @@ #include namespace MeshGui { +class SoFCIndexedFaceSet; /** * The ViewProviderMeshFaceSet class creates nodes for representing the mesh @@ -65,7 +66,7 @@ private: bool directRendering; unsigned long triangleCount; SoCoordinate3 * pcMeshCoord; - SoIndexedFaceSet * pcMeshFaces; + SoFCIndexedFaceSet * pcMeshFaces; SoFCMeshObjectNode * pcMeshNode; SoFCMeshObjectShape * pcMeshShape; };