diff --git a/src/main.cpp b/src/main.cpp index 0eab917..02d19ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,39 @@ #include "main_window.h" +#include "mesh_processor.h" #include +#include #include int main(int argc, char *argv[]) { using namespace std; + QSurfaceFormat format; + format.setRenderableType(QSurfaceFormat::RenderableType::OpenGL); + format.setMajorVersion(2); + format.setMinorVersion(1); + QSurfaceFormat::setDefaultFormat(format); QApplication app(argc, argv); + MeshProcessor *mesh_processor = nullptr; + MainWindow main_window; + MeshViewer *mesh_viewer = &main_window.mesh_viewer; + QObject::connect(mesh_viewer, &MeshViewer::initialized, + [&]() { + if (mesh_processor) { + mesh_viewer->addMesh(mesh_processor->mesh); + } + }); + if (argc > 2) { - cerr << "Utilisation : " << argv[0] << " [fichier OBJ]" << endl; + qWarning("Utilisation : %s [MAILLAGE]", argv[0]); return 1; + } else if (argc == 2) { + mesh_processor = new MeshProcessor(argv[1]); } - MainWindow mw; - mw.show(); + // QObject::connect(&main_window, &MainWindow::open, + // [&](const QString &path) { + // if (mesh_processor) delete mesh_processor; + // mesh_processor = new MeshProcessor(path); + // }); + main_window.show(); return app.exec(); } diff --git a/src/main_window.cpp b/src/main_window.cpp index 91cff0a..cb4c4bf 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -1,5 +1,5 @@ #include "main_window.h" -#include "mesh_processing.h" +#include "mesh_processor.h" #include #include @@ -13,7 +13,7 @@ MainWindow::MainWindow(QWidget *parent) setCentralWidget(&mesh_viewer); addToolBar(Qt::RightToolBarArea, &toolbar); open_action = toolbar.addAction("Ouvrir…", [&](){ - open(QFileDialog::getOpenFileName(this, "Ouvrir un fichier OBJ")); + emit open(QFileDialog::getOpenFileName(this, "Ouvrir un maillage")); }); // toolbar_actions.append(toolbar.addAction("Fractionner", [&](){ // QVector> fragments = shatter(mesh); @@ -33,33 +33,6 @@ MainWindow::MainWindow(QWidget *parent) } -void MainWindow::open(const QString &path) { - OpenMesh::IO::Options options; - options.set(OpenMesh::IO::Options::VertexColor); - if (!OpenMesh::IO::read_mesh(mesh, path.toUtf8().constData(), options)) { - qWarning() << "Failed to read" << path; - return; - } - for (const VertexHandle &vh : mesh.vertices()) { - mesh.set_color(vh, MyMesh::Color(0, 0, 0)); - } - - for (HalfedgeHandle border : findBorders(mesh)) { - setBorderColor(mesh, border, {1, 0, 0}); - fillHoleDumb(mesh, border); - } - - if (glm != nullptr) mesh_viewer.removeOpenGLMesh(glm); - glm = mesh_viewer.addOpenGLMeshFromOpenMesh(&mesh); - for (QAction *a : toolbar_actions) { - a->setEnabled(true); - } -} - - void MainWindow::meshViewerInitialized() { - if (qApp->arguments().size() == 2) { - open(qApp->arguments().at(1)); - } open_action->setEnabled(true); } diff --git a/src/main_window.h b/src/main_window.h index 54d3be2..e1b8666 100644 --- a/src/main_window.h +++ b/src/main_window.h @@ -11,21 +11,20 @@ class MainWindow : public QMainWindow { Q_OBJECT -public: - MainWindow(QWidget *parent=nullptr); - void open(const QString &path); - -private slots: - void meshViewerInitialized(); - -private: - MyMesh mesh; - MeshViewer mesh_viewer; - OpenGLMesh *glm = nullptr; QToolBar toolbar; QAction *open_action; QList toolbar_actions; +private slots: + void meshViewerInitialized(); + +signals: + void open(const QString &path); + +public: + MeshViewer mesh_viewer; + + MainWindow(QWidget *parent=nullptr); }; diff --git a/src/mesh_processing.cpp b/src/mesh_processing.cpp index 0d7f5f5..643abf0 100644 --- a/src/mesh_processing.cpp +++ b/src/mesh_processing.cpp @@ -1,4 +1,5 @@ #include "mesh_processing.h" +#include "util.h" #include #include diff --git a/src/mesh_processing.h b/src/mesh_processing.h deleted file mode 100644 index 76c6722..0000000 --- a/src/mesh_processing.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MESH_PROCESSING_H -#define MESH_PROCESSING_H - -#include "my_mesh.h" - -#include - - -std::vector findBorders(MyMesh &mesh); - -void setBorderColor(MyMesh &mesh, const HalfedgeHandle &border, - MyMesh::Color color); - -void fillHoleDumb(MyMesh &mesh, HalfedgeHandle &border); - - -#endif \ No newline at end of file diff --git a/src/mesh_processor.cpp b/src/mesh_processor.cpp new file mode 100644 index 0000000..670b377 --- /dev/null +++ b/src/mesh_processor.cpp @@ -0,0 +1,84 @@ +#include "mesh_processor.h" +#include "util.h" +#include +#include + + +static std::vector findHoles(MyMesh &mesh) { + std::vector holes; + std::set ignore; + for (HalfedgeHandle it : mesh.halfedges()) { + if (mesh.is_boundary(it) + && ignore.find(it) == ignore.end()) { + holes.push_back(it); + ignore.insert(it); + for (HalfedgeHandle it2 : HalfedgeLoopRange(mesh, it)) { + ignore.insert(it2); + } + } + } + return holes; +} + + +MeshProcessor::MeshProcessor(const QString &path) { + OpenMesh::IO::Options options; + options.set(OpenMesh::IO::Options::VertexColor); + if (!OpenMesh::IO::read_mesh(mesh, path.toUtf8().constData(), options)) { + qWarning() << "Failed to read" << path; + return; + } + for (const VertexHandle &vh : mesh.vertices()) { + mesh.set_color(vh, MyMesh::Color(0, 0, 0)); + } + holes = findHoles(mesh); + highlightHoles(); + fillHoles(); +} + + +static void setHoleBoundaryColor(MyMesh &mesh, + const HalfedgeHandle &hole, + MyMesh::Color color) { + for (HalfedgeHandle it : HalfedgeLoopRange(mesh, hole)) { + mesh.set_color(mesh.to_vertex_handle(it), color); + } +} + +void MeshProcessor::highlightHoles() { + for (auto hole : holes) { + setHoleBoundaryColor(mesh, hole, {1, 0, 0}); + } +} + + +void fillHoleDumb(MyMesh &mesh, HalfedgeHandle &hole) { + mesh.request_vertex_status(); + mesh.request_edge_status(); + mesh.request_face_status(); + + Point center(0, 0, 0); + size_t length = 0; + for (HalfedgeHandle it : HalfedgeLoopRange(mesh, hole)) { + VertexHandle vert = mesh.to_vertex_handle(it); + center += mesh.point(vert); + length++; + } + center /= length; + VertexHandle center_handle = mesh.new_vertex_dirty(center); + + for (HalfedgeHandle it = hole; + mesh.to_vertex_handle(it) != center_handle;) { + HalfedgeHandle next = mesh.next_halfedge_handle(it); + mesh.add_face(mesh.from_vertex_handle(it), + mesh.to_vertex_handle(it), + center_handle); + it = next; + } +} + +void MeshProcessor::fillHoles() { + for (auto hole : holes) { + fillHoleDumb(mesh, hole); + } +} \ No newline at end of file diff --git a/src/mesh_processor.h b/src/mesh_processor.h new file mode 100644 index 0000000..14106d4 --- /dev/null +++ b/src/mesh_processor.h @@ -0,0 +1,28 @@ +#ifndef MESH_PROCESSING_H +#define MESH_PROCESSING_H + +#include "my_mesh.h" +#include "mesh_processor_painter.h" +#include +#include + + +class MeshProcessor : public QObject { + Q_OBJECT + + std::vector holes; + + // friend class MeshProcessorPainter; + +public: + MyMesh mesh; + + MeshProcessor(const QString &path); + +public slots: + void highlightHoles(); + void fillHoles(); +}; + + +#endif \ No newline at end of file diff --git a/src/mesh_processor_painter.cpp b/src/mesh_processor_painter.cpp new file mode 100644 index 0000000..7c342a0 --- /dev/null +++ b/src/mesh_processor_painter.cpp @@ -0,0 +1,6 @@ +#include "mesh_processor_painter.h" + + +void MeshProcessorPainter::paint() { + +} diff --git a/src/mesh_processor_painter.h b/src/mesh_processor_painter.h new file mode 100644 index 0000000..9e65caa --- /dev/null +++ b/src/mesh_processor_painter.h @@ -0,0 +1,15 @@ +#ifndef MESH_PAINTER_H +#define MESH_PAINTER_H + +#include + + +class MeshProcessorPainter { + Q_OBJECT + +public slots: + void paint(); +}; + + +#endif \ No newline at end of file diff --git a/src/mesh_view.cpp b/src/mesh_view.cpp new file mode 100644 index 0000000..277e2db --- /dev/null +++ b/src/mesh_view.cpp @@ -0,0 +1,73 @@ +#include "mesh_view.h" +#include + + +MeshView::MeshView(QOpenGLExtraFunctions *glf, const MyMesh &mesh, + int pos_attr, int col_attr) + : glf(glf), + mesh(mesh) { + GLfloat *verts = new GLfloat[mesh.n_faces() * 3 * 6]; + size_t i = 0; + + for (const FaceHandle face : mesh.faces()) { + for (const VertexHandle vec : mesh.fv_range(face)) { + verts[6*i + 0] = mesh.point(vec)[0]; + verts[6*i + 1] = mesh.point(vec)[1]; + verts[6*i + 2] = mesh.point(vec)[2]; + verts[6*i + 3] = mesh.color.red(); + verts[6*i + 4] = mesh.color.green(); + verts[6*i + 5] = mesh.color.blue(); + i++; + } + } + + delete[] verts; + + GLuint vao, vbo; + glf->glGenVertexArrays(1, &vao); + glf->glGenBuffers(1, &vbo); + + glf->glBindVertexArray(vao); + glf->glBindBuffer(GL_ARRAY_BUFFER, vbo); + glf->glBufferData(GL_ARRAY_BUFFER, nverts * 6 * sizeof (GLfloat), verts, GL_DYNAMIC_DRAW); + glf->glVertexAttribPointer(pos_attr, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat), 0); + glf->glEnableVertexAttribArray(pos_attr); + glf->glVertexAttribPointer(col_attr, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat), + (const void *) (3 * sizeof (GLfloat))); + glf->glEnableVertexAttribArray(col_attr); + + glf->glBindVertexArray(0); +} + + +MeshView::~MeshView() { + glf->glDeleteVertexArrays(1, &vao); + glf->glDeleteBuffers(1, &vbo); +} + + +void MeshView::paint(QOpenGLContext *ctx, + int model_attr, int wireframe_attr) const { + void (*glPolygonMode)(GLenum, GLenum) = nullptr; + glPolygonMode = (typeof glPolygonMode) ctx->getProcAddress("glPolygonMode"); + if (!glPolygonMode) + qWarning("glPolygonMode not available"); + + glf->glUniformMatrix4fv(model_attr, 1, GL_FALSE, + mesh.transform.constData()); + + /* Mesh */ + glf->glBindVertexArray(vao); + glf->glEnable(GL_POLYGON_OFFSET_FILL); + glf->glPolygonOffset(1.0, 2); + glf->glDrawArrays(GL_TRIANGLES, 0, nverts); + if (glPolygonMode) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glf->glDisable(GL_POLYGON_OFFSET_FILL); + + /* Wireframe */ + glf->glUniform1f(wireframe_attr, 1); + glf->glDrawArrays(GL_TRIANGLES, 0, nverts); + if (glPolygonMode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glf->glLineWidth(3); + glf->glUniform1f(wireframe_attr, 0); +} diff --git a/src/mesh_view.h b/src/mesh_view.h new file mode 100644 index 0000000..ddd8e8e --- /dev/null +++ b/src/mesh_view.h @@ -0,0 +1,26 @@ +#ifndef MESH_VIEW_H +#define MESH_VIEW_H + +#include "my_mesh.h" +#include +#include + + +class MeshView { + GLuint vao; + GLuint vbo; + size_t nverts; + QOpenGLExtraFunctions *glf; + +public: + const MyMesh &mesh; + + MeshView(QOpenGLExtraFunctions *glf, const MyMesh &mesh, + int pos_attr, int col_attr); + ~MeshView(); + void paint(QOpenGLContext *ctx, + int model_attr, int wireframe_attr) const; +}; + + +#endif \ No newline at end of file diff --git a/src/mesh_viewer.cpp b/src/mesh_viewer.cpp index da532e0..60128b8 100644 --- a/src/mesh_viewer.cpp +++ b/src/mesh_viewer.cpp @@ -1,7 +1,7 @@ #include "mesh_viewer.h" #include -#include +#include const GLchar *vertex_shader_source = R"glsl( @@ -69,10 +69,9 @@ opengl_debug_cb(GLenum source, void MeshViewer::initializeGL() { // initializeOpenGLFunctions(); - GLint major, minor; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - qDebug("OpenGL version %d.%d", major, minor); + qDebug("OpenGL version %d.%d", + context()->format().majorVersion(), + context()->format().minorVersion()); glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(opengl_debug_cb, 0); @@ -138,6 +137,7 @@ void MeshViewer::initializeGL() { glEnable(GL_DEPTH_TEST); glEnable(GL_MULTISAMPLE); + qDebug("Mesh viewer initialized"); emit initialized(); } @@ -155,80 +155,28 @@ void MeshViewer::paintGL() { trans.translate(0, 0, -cam_dist); QMatrix4x4 view = trans * rot; glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data()); - for (const OpenGLMesh m : meshes) { - glUniformMatrix4fv(model_attr, 1, GL_FALSE, m.mat.data()); - - /* Mesh */ - glBindVertexArray(m.vao); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.0, 2); - glDrawArrays(GL_TRIANGLES, 0, m.nverts); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glDisable(GL_POLYGON_OFFSET_FILL); - - /* Wireframe */ - glUniform1f(wireframe_attr, 1); - glDrawArrays(GL_TRIANGLES, 0, m.nverts); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(3); - glUniform1f(wireframe_attr, 0); + for (const MeshView m : meshes) { + m.paint(context(), model_attr, wireframe_attr); } } -OpenGLMesh *MeshViewer::addOpenGLMesh(size_t nverts, const GLfloat *verts, QMatrix4x4 mat, QColor col) { +void MeshViewer::addMesh(const MyMesh &mesh) { makeCurrent(); - - GLuint vao, vbo; - glGenVertexArrays(1, &vao); - glGenBuffers(1, &vbo); - - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, nverts * 6 * sizeof (GLfloat), verts, GL_DYNAMIC_DRAW); - glVertexAttribPointer(pos_attr, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat), 0); - glEnableVertexAttribArray(pos_attr); - glVertexAttribPointer(col_attr, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat), - (const void *) (3 * sizeof (GLfloat))); - glEnableVertexAttribArray(col_attr); - - glBindVertexArray(0); - - meshes.append({vao, vbo, nverts, mat, col}); + meshes.emplace_back(context()->extraFunctions(), mesh, + pos_attr, col_attr); doneCurrent(); update(); - return &meshes.last(); } -OpenGLMesh *MeshViewer::addOpenGLMeshFromOpenMesh(MyMesh* mesh, QMatrix4x4 mat, QColor col) { - GLfloat *verts = new GLfloat[mesh->n_faces() * 3 * 6]; - size_t i = 0; - - for (MyMesh::FaceHandle face : mesh->faces()) { - for (MyMesh::VertexHandle vec : mesh->fv_range(face)) { - verts[6*i + 0] = mesh->point(vec)[0]; - verts[6*i + 1] = mesh->point(vec)[1]; - verts[6*i + 2] = mesh->point(vec)[2]; - verts[6*i + 3] = mesh->color(vec)[0]; - verts[6*i + 4] = mesh->color(vec)[1]; - verts[6*i + 5] = mesh->color(vec)[2]; - i++; - } - } - - OpenGLMesh *ret = addOpenGLMesh(i, verts, mat, col); - delete[] verts; - return ret; -} - - -void MeshViewer::removeOpenGLMesh(OpenGLMesh *mesh) { - glDeleteVertexArrays(1, &mesh->vao); - glDeleteBuffers(1, &mesh->vbo); - for (int i = 0; i < meshes.size(); i++) { - if (&meshes[i] == mesh) meshes.removeAt(i); - } +void MeshViewer::removeMesh(const MyMesh &mesh) { + makeCurrent(); + meshes.remove_if([&](const MeshView &mv) { + return &mv.mesh == &mesh; + }); + doneCurrent(); + update(); } diff --git a/src/mesh_viewer.h b/src/mesh_viewer.h index 55355c8..b2e9a76 100644 --- a/src/mesh_viewer.h +++ b/src/mesh_viewer.h @@ -3,6 +3,8 @@ #define GL_GLEXT_PROTOTYPES #include "my_mesh.h" +#include "mesh_view.h" +#include #include #include #include @@ -19,37 +21,27 @@ using namespace OpenMesh; -struct OpenGLMesh { - GLuint vao; - GLuint vbo; - size_t nverts; - QMatrix4x4 mat; - QColor col; -}; - - class MeshViewer : public QOpenGLWidget { Q_OBJECT + std::list meshes; + GLint pos_attr, col_attr, proj_attr, view_attr, model_attr; + GLint wf_col_attr, wireframe_attr, alpha_attr; + QMatrix4x4 proj; + QMatrix4x4 rot, rot_start; + GLfloat cam_dist = 1; + QPoint mouse_pos; + public: MeshViewer(QWidget *parent=nullptr); virtual QSize sizeHint() const override; void initializeGL() override; void resizeGL(int w, int h) override; void paintGL() override; - OpenGLMesh *addOpenGLMesh(size_t nverts, const GLfloat *verts, QMatrix4x4 mat=QMatrix4x4(), QColor col={153, 153, 153}); - OpenGLMesh *addOpenGLMeshFromOpenMesh(MyMesh* _mesh, QMatrix4x4 mat=QMatrix4x4(), QColor col={153, 153, 153}); - void removeOpenGLMesh(OpenGLMesh *mesh); - void setOpenGLMeshMatrix(OpenGLMesh *mv, QMatrix4x4 mat); -private: - QList meshes; - GLint pos_attr, col_attr, proj_attr, view_attr, model_attr; - GLint wf_col_attr, wireframe_attr, alpha_attr; - QMatrix4x4 proj; - QMatrix4x4 rot, rot_start; - GLfloat cam_dist = 1; - QPoint mouse_pos; +public slots: + void addMesh(const MyMesh &mesh); + void removeMesh(const MyMesh &mesh); protected: virtual void mousePressEvent(QMouseEvent *e); diff --git a/src/my_mesh.h b/src/my_mesh.h index 9274de3..3b196c3 100644 --- a/src/my_mesh.h +++ b/src/my_mesh.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include struct MyTraits : public OpenMesh::DefaultTraits { @@ -13,7 +15,13 @@ struct MyTraits : public OpenMesh::DefaultTraits { EdgeAttributes(OpenMesh::Attributes::Color); typedef OpenMesh::Vec3f Color; }; -typedef OpenMesh::PolyMesh_ArrayKernelT MyMesh; + +class MyMesh : public OpenMesh::PolyMesh_ArrayKernelT { +public: + QMatrix4x4 transform; + QColor color; +}; + typedef MyMesh::FaceHandle FaceHandle; typedef MyMesh::VertexHandle VertexHandle; typedef MyMesh::HalfedgeHandle HalfedgeHandle; @@ -21,20 +29,4 @@ typedef MyMesh::EdgeHandle EdgeHandle; typedef MyMesh::Point Point; -class HalfedgeLoopRange { - MyMesh &mesh; - const HalfedgeHandle &start; - - public: - HalfedgeLoopRange(MyMesh &mesh, const HalfedgeHandle &start) - :mesh(mesh), start(start) {} - MyMesh::HalfedgeLoopIter begin() { - return mesh.hl_begin(start); - } - MyMesh::HalfedgeLoopIter end() { - return mesh.hl_end(start); - } -}; - - #endif diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..d346abb --- /dev/null +++ b/src/util.h @@ -0,0 +1,23 @@ +#ifndef UTIL_H +#define UTIL_H + +#include "my_mesh.h" + + +class HalfedgeLoopRange { + MyMesh &mesh; + const HalfedgeHandle &start; + + public: + HalfedgeLoopRange(MyMesh &mesh, const HalfedgeHandle &start) + :mesh(mesh), start(start) {} + MyMesh::HalfedgeLoopIter begin() { + return mesh.hl_begin(start); + } + MyMesh::HalfedgeLoopIter end() { + return mesh.hl_end(start); + } +}; + + +#endif \ No newline at end of file diff --git a/tp.pro b/tp.pro index 7dcb269..a4cc9e0 100644 --- a/tp.pro +++ b/tp.pro @@ -19,9 +19,12 @@ win32 { HEADERS += src/my_mesh.h HEADERS += src/main_window.h HEADERS += src/mesh_viewer.h -HEADERS += src/mesh_processing.h +HEADERS += src/mesh_view.h +HEADERS += src/mesh_processor.h +HEADERS += src/util.h SOURCES += src/main.cpp SOURCES += src/main_window.cpp SOURCES += src/mesh_viewer.cpp -SOURCES += src/mesh_processing.cpp +SOURCES += src/mesh_view.cpp +SOURCES += src/mesh_processor.cpp