// Copyright (c) 2011 CNRS and LIRIS' Establishments (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Guillaume Damiand #ifndef CGAL_BASIC_VIEWER_H #define CGAL_BASIC_VIEWER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NB_VBO_BUFFERS 8 #define NB_VAO_BUFFERS 4 typedef CGAL::Exact_predicates_inexact_constructions_kernel Local_kernel; typedef Local_kernel::Point_3 Local_point; typedef Local_kernel::Vector_3 Local_vector; //Vertex source code const char vertex_source_mono[] = { "#version 150 \n" "in highp vec4 vertex;\n" "in highp vec3 normal;\n" "uniform highp mat4 mvp_matrix;\n" "uniform highp mat4 mv_matrix; \n" "out highp vec4 fP; \n" "out highp vec3 fN; \n" "void main(void)\n" "{\n" " fP = mv_matrix * vertex; \n" " fN = mat3(mv_matrix)* normal; \n" " gl_Position = mvp_matrix * vertex;\n" "}" }; const char vertex_source_color[] = { "#version 150 \n" "in highp vec4 vertex;\n" "in highp vec3 normal;\n" "in highp vec3 color;\n" "uniform highp mat4 mvp_matrix;\n" "uniform highp mat4 mv_matrix; \n" "out highp vec4 fP; \n" "out highp vec3 fN; \n" "out highp vec4 fColor; \n" "void main(void)\n" "{\n" " fP = mv_matrix * vertex; \n" " fN = mat3(mv_matrix)* normal; \n" " fColor = vec4(color, 1.0); \n" " gl_Position = mvp_matrix * vertex;\n" "}" }; //Vertex source code const char fragment_source_mono[] = { "#version 150 \n" "in highp vec4 fP; \n" "in highp vec3 fN; \n" "uniform highp vec4 color; \n" "uniform highp vec4 light_pos; \n" "uniform highp vec4 light_diff; \n" "uniform highp vec4 light_spec; \n" "uniform highp vec4 light_amb; \n" "uniform float spec_power ; \n" "out highp vec4 out_color; \n" "void main(void) { \n" " highp vec3 L = light_pos.xyz - fP.xyz; \n" " highp vec3 V = -fP.xyz; \n" " highp vec3 N = normalize(fN); \n" " L = normalize(L); \n" " V = normalize(V); \n" " highp vec3 R = reflect(-L, N); \n" " highp vec4 diffuse = max(dot(N,L), 0.0) * light_diff * color; \n" " highp vec4 specular = pow(max(dot(R,V), 0.0), spec_power) * light_spec; \n" "out_color = light_amb*color + diffuse ; \n" "} \n" "\n" }; const char fragment_source_color[] = { "#version 150 \n" "in highp vec4 fP; \n" "in highp vec3 fN; \n" "in highp vec4 fColor; \n" "uniform highp vec4 light_pos; \n" "uniform highp vec4 light_diff; \n" "uniform highp vec4 light_spec; \n" "uniform highp vec4 light_amb; \n" "uniform float spec_power ; \n" "out highp vec4 out_color; \n" "void main(void) { \n" " highp vec3 L = light_pos.xyz - fP.xyz; \n" " highp vec3 V = -fP.xyz; \n" " highp vec3 N = normalize(fN); \n" " L = normalize(L); \n" " V = normalize(V); \n" " highp vec3 R = reflect(-L, N); \n" " highp vec4 diffuse = max(dot(N,L), 0.0) * light_diff * fColor; \n" " highp vec4 specular = pow(max(dot(R,V), 0.0), spec_power) * light_spec; \n" "out_color = light_amb*fColor + diffuse ; \n" "} \n" "\n" }; //Vertex source code const char vertex_source_p_l[] = { "#version 150 \n" "in highp vec4 vertex;\n" "uniform highp mat4 mvp_matrix;\n" "void main(void)\n" "{\n" " gl_Position = mvp_matrix * vertex;\n" "}" }; //Vertex source code const char fragment_source_p_l[] = { "#version 150 \n" "uniform highp vec4 color; \n" "out highp vec4 out_color; \n" "void main(void) { \n" "out_color = color; \n" "} \n" "\n" }; namespace internal { template void newell_single_step_3(const Point& p, const Point& q, Vector& n) { // Compute normal of the face by using Newell's method: for each edge PQ // Nx += (Py - Qy) * (Pz + Qz); // Ny += (Pz - Qz) * (Px + Qx); // Nz += (Px - Qx) * (Py + Qy); n = Vector(n.x()+((p.y()-q.y())*(p.z()+q.z())), n.y()+((p.z()-q.z())*(p.x()+q.x())), n.z()+((p.x()-q.x())*(p.y()+q.y()))); } } // End namespace internal template typename K::Vector_3 compute_normal_of_face(const std::vector& points) { typename K::Vector_3 normal(CGAL::NULL_VECTOR); unsigned int nb = 0; for (std::size_t i=0; i0); return (typename K::Construct_scaled_vector_3()(normal, 1.0/nb)); } class Basic_viewer : public CGAL::QGLViewer, public QOpenGLFunctions { struct Vertex_info { Local_vector v; }; struct Face_info { bool exist_edge[3]; bool is_external; bool is_process; }; typedef CGAL::Projection_traits_3 P_traits; typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; typedef CGAL::Triangulation_face_base_with_info_2 Fb1; typedef CGAL::Constrained_triangulation_face_base_2 Fb; typedef CGAL::Triangulation_data_structure_2 TDS; typedef CGAL::Exact_predicates_tag Itag; typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; public: // Constructor/Destructor Basic_viewer(const char* title="") : CGAL::QGLViewer(CGAL::Qt::createOpenGLContext()), m_draw_vertices(true), m_draw_edges(true), m_draw_faces(true), m_flatShading(true), m_use_mono_color(false), m_inverse_normal(false), m_empty(true), m_size_points(7.), m_size_edges(3.1), m_vertices_mono_color(51, 51, 178), m_edges_mono_color(51, 51, 148), m_faces_mono_color(180, 125, 200), m_ambient_color(0.6f, 0.5f, 0.5f, 0.5f), m_are_buffers_initialized(false), m_face_started(false) { if (title[0]==0) setWindowTitle("CGAL Basic Viewer"); else setWindowTitle(title); resize(500, 450); if ( is_empty() ) { bb=Local_point(CGAL::ORIGIN).bbox(); bb=bb + Local_point(1,1,1).bbox(); // To avoid a warning from Qglviewer } } ~Basic_viewer() { for (int i=0; i& point_vector) { point_vector.push_back(p.x()); point_vector.push_back(p.y()); point_vector.push_back(p.z()); if (is_empty()) { bb=p.bbox(); m_empty=false; } else { bb=bb+p.bbox(); } } void add_color(const CGAL::IO::Color& acolor, std::vector& color_vector) { color_vector.push_back((double)color_of_face.red()/(double)255); color_vector.push_back((double)color_of_face.green()/(double)255); color_vector.push_back((double)color_of_face.blue()/(double)255); } void add_normal(const Local_vector& n, std::vector& normal_vector) { normal_vector.push_back(n.x()); normal_vector.push_back(n.y()); normal_vector.push_back(n.z()); } void add_mono_point(const Local_point& p) { add_point(p, arrays[POS_MONO_POINTS]); } void add_colored_point(const Local_point& p, const CGAL::IO::Color& acolor) { add_point(p, arrays[POS_COLORED_POINTS]); add_color(acolor, arrays[COLOR_POINTS]); } void add_mono_segment(const Local_point& p1, const Local_point& p2) { add_point(p1, arrays[POS_MONO_SEGMENTS]); add_point(p2, arrays[POS_MONO_SEGMENTS]); } void add_colored_segment(const Local_point& p1, const Local_point& p2, const CGAL::IO::Color& acolor) { add_point(p1, arrays[POS_COLORED_SEGMENTS]); add_point(p2, arrays[POS_COLORED_SEGMENTS]); add_color(acolor, arrays[COLOR_SEGMENTS]); } void face_begin() { if (m_face_started) { std::cerr<<"You cannot start a new face before to finish the previous one."<(points_of_face); if (points_of_face.size()==3) // Triangle: no need to triangulate { for (int i=0; i<3; ++i) { // The point add_point(points_of_face[i], arrays[m_started_face_is_colored? POS_COLORED_FACES: POS_MONO_FACES]); // Its color if (m_started_face_is_colored) { add_color(color_of_face, arrays[COLOR_FACES]); } // Its flat normal add_normal(normal, arrays[m_started_face_is_colored? FLAT_NORMAL_COLORED_FACES: FLAT_NORMAL_MONO_FACES]); // Its smoth normal (if given by the user) if (vertex_normals_for_face.size()==3) { // Here we have 3 vertex normals; we can use Gourod add_normal(vertex_normals_for_face[i], arrays[m_started_face_is_colored? SMOOTH_NORMAL_COLORED_FACES: SMOOTH_NORMAL_MONO_FACES]); } else { // Here user does not provide all vertex normals: we use face normal istead // and thus we will not be able to use Gourod add_normal(normal, arrays[m_started_face_is_colored? SMOOTH_NORMAL_COLORED_FACES: SMOOTH_NORMAL_MONO_FACES]); } } } // TODO CASE OF 4 POINTS ? PB HOW TO FIND (EASILY) THE TWO POINTS TO LINK ? // else if (points_of_face.size()==4) else { // More than 3 points: we triangulate try { P_traits cdt_traits(normal); CDT cdt(cdt_traits); bool with_vertex_normal=(vertex_normals_for_face.size()==points_of_face.size()); // (1) We insert all the edges as contraint in the CDT. typename CDT::Vertex_descriptor previous=NULL, first=NULL; for (int i=0; iinfo().v=vertex_normals_for_face[i]; } else { vh->info().v=normal; } if(previous!=NULL && previous!=vh) { cdt.insert_constraint(previous, vh); } previous=vh; } if (previous!=NULL && previous!=first) cdt.insert_constraint(previous, first); // (2) We mark all external triangles // (2.1) We initialize is_external and is_process values for(typename CDT::All_faces_iterator fit = cdt.all_faces_begin(), fitend = cdt.all_faces_end(); fit!=fitend; ++fit) { fit->info().is_external = true; fit->info().is_process = false; } // (2.2) We check if the facet is external or internal std::queue face_queue; typename CDT::Face_descriptor face_internal = NULL; if (cdt.infinite_vertex()->face()!=NULL) face_queue.push(cdt.infinite_vertex()->face()); while(! face_queue.empty() ) { typename CDT::Face_descriptor fh = face_queue.front(); face_queue.pop(); if(!fh->info().is_process) { fh->info().is_process = true; for(int i=0; i<3; ++i) { if(!cdt.is_constrained(std::make_pair(fh, i))) { if (fh->neighbor(i)!=NULL) face_queue.push(fh->neighbor(i)); } else if (face_internal==NULL) { face_internal = fh->neighbor(i); } } } } if ( face_internal!=NULL ) face_queue.push(face_internal); while(! face_queue.empty() ) { typename CDT::Face_descriptor fh = face_queue.front(); face_queue.pop(); if(!fh->info().is_process) { fh->info().is_process = true; fh->info().is_external = false; for(int i=0; i<3; ++i) { if(!cdt.is_constrained(std::make_pair(fh, i))) { if (fh->neighbor(i)!=NULL) face_queue.push(fh->neighbor(i)); } } } } // (3) Now we iterates on the internal faces to add the vertices to the // positions and the normals to the appropriate vectors for(typename CDT::Finite_faces_iterator ffit=cdt.finite_faces_begin(), ffitend = cdt.finite_faces_end(); ffit!=ffitend; ++ffit) { if(!ffit->info().is_external) { for(int i=0; i<3; ++i) { // The point add_point(ffit->vertex(i)->point(), arrays[m_started_face_is_colored? POS_COLORED_FACES: POS_MONO_FACES]); // Its color if (m_started_face_is_colored) { add_color(color_of_face, arrays[COLOR_FACES]); } // Its flat normal add_normal(normal, arrays[m_started_face_is_colored? FLAT_NORMAL_COLORED_FACES: FLAT_NORMAL_MONO_FACES]); // Its smoth normal (if given by the user) add_normal(ffit->vertex(i)->info().v, arrays[m_started_face_is_colored? SMOOTH_NORMAL_COLORED_FACES: SMOOTH_NORMAL_MONO_FACES]); } } } } catch(...) { // Triangulation crash: the face is not filled std::cout<<"Catch: face not filled."<compileSourceCode(vertex_source_mono)) { std::cerr<<"Compiling vertex source FAILED"<compileSourceCode(fragment_source_mono)) { std::cerr<<"Compiling fragmentsource FAILED"<compileSourceCode(vertex_source_mono)) { std::cerr<<"Compiling vertex source FAILED"<compileSourceCode(fragment_source_mono)) { std::cerr<<"Compiling fragmentsource FAILED"<compileSourceCode(vertex_source_color)) { std::cerr<<"Compiling vertex source FAILED"<compileSourceCode(fragment_source_color)) { std::cerr<<"Compiling fragmentsource FAILED"<compileSourceCode(vertex_source_p_l)) { std::cerr<<"Compiling vertex source FAILED"<compileSourceCode(fragment_source_p_l)) { std::cerr<<"Compiling fragmentsource FAILED"<(arrays[POS_MONO_FACES].size()*sizeof(float))); vertexLocation[vaon] = rendering_program_mono.attributeLocation("vertex"); rendering_program_mono.bind(); rendering_program_mono.enableAttributeArray(vertexLocation[vaon]); rendering_program_mono.setAttributeBuffer(vertexLocation[vaon],GL_FLOAT,0,3); rendering_program_mono.release(); buffers[bufn].release(); ++bufn; // 3.1.2) normals of the mono faces assert(bufn(arrays[FLAT_NORMAL_MONO_FACES].size()* sizeof(float))); } else { buffers[bufn].allocate(arrays[SMOOTH_NORMAL_MONO_FACES].data(), static_cast(arrays[SMOOTH_NORMAL_MONO_FACES].size()* sizeof(float))); } normalsLocation = rendering_program_mono.attributeLocation("normal"); rendering_program_mono.bind(); rendering_program_mono.enableAttributeArray(normalsLocation); rendering_program_mono.setAttributeBuffer(normalsLocation,GL_FLOAT,0,3); rendering_program_mono.release(); buffers[bufn].release(); ++bufn; vao[vaon].release(); ++vaon; // 3.2) Color faces assert(vaon(arrays[POS_COLORED_FACES].size()*sizeof(float))); vertexLocation[vaon] = rendering_program_color.attributeLocation("vertex"); rendering_program_color.bind(); rendering_program_color.enableAttributeArray(vertexLocation[vaon]); rendering_program_color.setAttributeBuffer(vertexLocation[vaon],GL_FLOAT,0,3); rendering_program_color.release(); buffers[bufn].release(); ++bufn; // 3.2.2) normals of the color faces assert(bufn(arrays[FLAT_NORMAL_COLORED_FACES].size()* sizeof(float))); } else { buffers[bufn].allocate(arrays[SMOOTH_NORMAL_COLORED_FACES].data(), static_cast(arrays[SMOOTH_NORMAL_COLORED_FACES].size()* sizeof(float))); } normalsLocation = rendering_program_color.attributeLocation("normal"); rendering_program_color.bind(); rendering_program_color.enableAttributeArray(normalsLocation); rendering_program_color.setAttributeBuffer(normalsLocation,GL_FLOAT,0,3); rendering_program_color.release(); buffers[bufn].release(); ++bufn; // 3.2.3) colors of the faces if (!m_use_mono_color) { assert(bufn(arrays[COLOR_FACES].size()*sizeof(float))); colorsLocation = rendering_program_color.attributeLocation("color"); rendering_program_color.bind(); rendering_program_color.enableAttributeArray(colorsLocation); rendering_program_color.setAttributeBuffer(colorsLocation,GL_FLOAT,0,3); rendering_program_color.release(); buffers[bufn].release(); ++bufn; } vao[vaon].release(); ++vaon; m_are_buffers_initialized = true; } void attrib_buffers(CGAL::QGLViewer* viewer) { QMatrix4x4 mvpMatrix; QMatrix4x4 mvMatrix; double mat[16]; viewer->camera()->getModelViewProjectionMatrix(mat); for(int i=0; i < 16; i++) { mvpMatrix.data()[i] = (float)mat[i]; } viewer->camera()->getModelViewMatrix(mat); for(int i=0; i < 16; i++) { mvMatrix.data()[i] = (float)mat[i]; } // define material QVector4D diffuse( 0.9f, 0.9f, 0.9f, 0.9f ); QVector4D specular( 0.0f, 0.0f, 0.0f, 1.0f ); QVector4D position((bb.xmax()-bb.xmin())/2, (bb.ymax()-bb.ymin())/2,bb.zmax(), 0.0 ); GLfloat shininess = 1.0f; rendering_program_mono.bind(); mvpLocation[0] = rendering_program_mono.uniformLocation("mvp_matrix"); mvLocation = rendering_program_mono.uniformLocation("mv_matrix"); lightLocation[0] = rendering_program_mono.uniformLocation("light_pos"); lightLocation[1] = rendering_program_mono.uniformLocation("light_diff"); lightLocation[2] = rendering_program_mono.uniformLocation("light_spec"); lightLocation[3] = rendering_program_mono.uniformLocation("light_amb"); lightLocation[4] = rendering_program_mono.uniformLocation("spec_power"); rendering_program_mono.setUniformValue(lightLocation[0], position); rendering_program_mono.setUniformValue(lightLocation[1], diffuse); rendering_program_mono.setUniformValue(lightLocation[2], specular); rendering_program_mono.setUniformValue(lightLocation[3], m_ambient_color); rendering_program_mono.setUniformValue(lightLocation[4], shininess); rendering_program_mono.setUniformValue(mvpLocation[0], mvpMatrix); rendering_program_mono.setUniformValue(mvLocation, mvMatrix); colorLocation1 = rendering_program_mono.uniformLocation("color"); rendering_program_mono.release(); rendering_program_color.bind(); mvpLocation[0] = rendering_program_color.uniformLocation("mvp_matrix"); mvLocation = rendering_program_color.uniformLocation("mv_matrix"); lightLocation[0] = rendering_program_color.uniformLocation("light_pos"); lightLocation[1] = rendering_program_color.uniformLocation("light_diff"); lightLocation[2] = rendering_program_color.uniformLocation("light_spec"); lightLocation[3] = rendering_program_color.uniformLocation("light_amb"); lightLocation[4] = rendering_program_color.uniformLocation("spec_power"); rendering_program_color.setUniformValue(lightLocation[0], position); rendering_program_color.setUniformValue(lightLocation[1], diffuse); rendering_program_color.setUniformValue(lightLocation[2], specular); rendering_program_color.setUniformValue(lightLocation[3], m_ambient_color); rendering_program_color.setUniformValue(lightLocation[4], shininess); rendering_program_color.setUniformValue(mvpLocation[0], mvpMatrix); rendering_program_color.setUniformValue(mvLocation, mvMatrix); if (m_use_mono_color) { colorLocation2 = rendering_program_color.uniformLocation("color"); } rendering_program_color.release(); /* rendering_program_p_l_.bind(); mvpLocation[1] = rendering_program_p_l.uniformLocation("mvp_matrix"); colorLocation = rendering_program_p_l.uniformLocation("color"); rendering_program.setUniformValue(mvpLocation[1], mvpMatrix); rendering_program_p_l.release();*/ } virtual void draw() { glEnable(GL_DEPTH_TEST); if(!m_are_buffers_initialized) initialize_buffers(); QColor color; if (m_draw_faces) { vao[0].bind(); attrib_buffers(this); rendering_program_mono.bind(); color.setRgbF((double)m_faces_mono_color.red()/(double)255, (double)m_faces_mono_color.green()/(double)255, (double)m_faces_mono_color.blue()/(double)255); rendering_program_mono.setUniformValue(colorLocation1,color); glDrawArrays(GL_TRIANGLES, 0, static_cast(arrays[POS_MONO_FACES].size()/3)); rendering_program_mono.release(); vao[0].release(); vao[1].bind(); attrib_buffers(this); rendering_program_color.bind(); if (m_use_mono_color) { color.setRgbF((double)m_faces_mono_color.red()/(double)255, (double)m_faces_mono_color.green()/(double)255, (double)m_faces_mono_color.blue()/(double)255); rendering_program_color.setUniformValue(colorLocation2,color); } glDrawArrays(GL_TRIANGLES, 0, static_cast(arrays[POS_COLORED_FACES].size()/3)); rendering_program_color.release(); vao[1].release(); } } virtual void init() { // Restore previous viewer state. initializeOpenGLFunctions(); // Define 'Control+Q' as the new exit shortcut (default was 'Escape') setShortcut(EXIT_VIEWER, Qt::CTRL+Qt::Key_Q); // Add custom key description (see keyPressEvent). setKeyDescription(Qt::Key_E, "Toggles edges display"); setKeyDescription(Qt::Key_F, "Toggles faces display"); setKeyDescription(Qt::Key_G, "Switch between flat/Gouraud shading display"); setKeyDescription(Qt::Key_M, "Toggles mono color for all faces"); setKeyDescription(Qt::Key_N, "Inverse direction of normals"); setKeyDescription(Qt::Key_V, "Toggles vertices display"); setKeyDescription(Qt::Key_Plus, "Increase size of edges"); setKeyDescription(Qt::Key_Minus, "Decrease size of edges"); setKeyDescription(Qt::Key_Plus+Qt::ShiftModifier, "Increase size of vertices"); setKeyDescription(Qt::Key_Minus+Qt::ShiftModifier, "Decrease size of vertices"); setKeyDescription(Qt::Key_PageDown, "Increase light (all colors, use shift/alt/ctrl for one rgb component)"); setKeyDescription(Qt::Key_PageUp, "Decrease light (all colors, use shift/alt/ctrl for one rgb component)"); // Light default parameters ::glLineWidth(m_size_edges); ::glEnable(GL_POLYGON_OFFSET_FILL); ::glPolygonOffset(1.f,1.f); ::glClearColor(1.0f,1.0f,1.0f,0.0f); ::glDisable(GL_BLEND); ::glEnable(GL_LINE_SMOOTH); ::glDisable(GL_POLYGON_SMOOTH_HINT); ::glBlendFunc(GL_ONE, GL_ZERO); ::glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST); compile_shaders(); this->camera()->setSceneBoundingBox(CGAL::qglviewer::Vec(bb.xmin(), bb.ymin(), bb.zmin()), CGAL::qglviewer::Vec(bb.xmax(), bb.ymax(), bb.zmax())); this->showEntireScene(); } void negate_all_normals() { for (unsigned int k=BEGIN_NORMAL; kmodifiers(); if ((e->key()==Qt::Key_E) && (modifiers==Qt::NoButton)) { m_draw_edges=!m_draw_edges; displayMessage(QString("Draw edges=%1.").arg(m_draw_edges?"true":"false")); updateGL(); } else if ((e->key()==Qt::Key_F) && (modifiers==Qt::NoButton)) { m_draw_faces=!m_draw_faces; displayMessage(QString("Draw faces=%1.").arg(m_draw_faces?"true":"false")); updateGL(); } else if ((e->key()==Qt::Key_G) && (modifiers==Qt::NoButton)) { m_flatShading=!m_flatShading; if (m_flatShading) displayMessage("Flat shading."); else displayMessage("Gouraud shading."); compile_shaders(); initialize_buffers(); updateGL(); } else if ((e->key()==Qt::Key_M) && (modifiers==Qt::NoButton)) { m_use_mono_color=!m_use_mono_color; displayMessage(QString("Mono color=%1.").arg(m_use_mono_color?"true":"false")); compile_shaders(); initialize_buffers(); updateGL(); } else if ((e->key()==Qt::Key_N) && (modifiers==Qt::NoButton)) { m_inverse_normal=!m_inverse_normal; negate_all_normals(); compile_shaders(); initialize_buffers(); displayMessage(QString("Inverse normal=%1.").arg(m_inverse_normal?"true":"false")); updateGL(); } else if ((e->key()==Qt::Key_V) && (modifiers==Qt::NoButton)) { m_draw_vertices=!m_draw_vertices; displayMessage(QString("Draw vertices=%1.").arg(m_draw_vertices?"true":"false")); updateGL(); } else if ((e->key()==Qt::Key_Plus) && (modifiers==Qt::KeypadModifier)) { m_size_edges+=.5; displayMessage(QString("Size of edges=%1.").arg(m_size_edges)); updateGL(); } else if ((e->key()==Qt::Key_Minus) && (modifiers==Qt::KeypadModifier)) { if (m_size_edges>.5) m_size_edges-=.5; displayMessage(QString("Size of edges=%1.").arg(m_size_edges)); updateGL(); } else if ((e->key()==Qt::Key_Plus) && (modifiers==(Qt::ShiftModifier|Qt::KeypadModifier))) { m_size_points+=.5; displayMessage(QString("Size of points=%1.").arg(m_size_points)); updateGL(); } else if ((e->key()==Qt::Key_Minus) && (modifiers==(Qt::ShiftModifier|Qt::KeypadModifier))) { if (m_size_points>.5) m_size_points-=.5; displayMessage(QString("Size of points=%1.").arg(m_size_points)); updateGL(); } else if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { m_ambient_color.setX(m_ambient_color.x()+.1); if (m_ambient_color.x()>1.) m_ambient_color.setX(1.); m_ambient_color.setY(m_ambient_color.x()+.1); if (m_ambient_color.y()>1.) m_ambient_color.setY(1.); m_ambient_color.setZ(m_ambient_color.x()+.1); if (m_ambient_color.z()>1.) m_ambient_color.setZ(1.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else if ((e->key()==Qt::Key_PageDown) && (modifiers==Qt::NoButton)) { m_ambient_color.setX(m_ambient_color.x()-.1); if (m_ambient_color.x()<0.) m_ambient_color.setX(0.); m_ambient_color.setY(m_ambient_color.y()-.1); if (m_ambient_color.y()<0.) m_ambient_color.setY(0.); m_ambient_color.setZ(m_ambient_color.z()-.1); if (m_ambient_color.z()<0.) m_ambient_color.setZ(0.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::ShiftModifier)) { m_ambient_color.setX(m_ambient_color.x()+.1); if (m_ambient_color.x()>1.) m_ambient_color.setX(1.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::AltModifier)) { m_ambient_color.setY(m_ambient_color.y()+.1); if (m_ambient_color.y()>1.) m_ambient_color.setY(1.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::ControlModifier)) { m_ambient_color.setZ(m_ambient_color.z()+.1); if (m_ambient_color.z()>1.) m_ambient_color.setZ(1.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else if ((e->key()==Qt::Key_PageDown) && (modifiers==Qt::ShiftModifier)) { m_ambient_color.setX(m_ambient_color.x()-.1); if (m_ambient_color.x()<0.) m_ambient_color.setX(0.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else if ((e->key()==Qt::Key_PageDown) && (modifiers==Qt::AltModifier)) { m_ambient_color.setY(m_ambient_color.y()-.1); if (m_ambient_color.y()<0.) m_ambient_color.setY(0.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else if ((e->key()==Qt::Key_PageDown) && (modifiers==Qt::ControlModifier)) { m_ambient_color.setZ(m_ambient_color.z()-.1); if (m_ambient_color.z()<0.) m_ambient_color.setZ(0.); displayMessage(QString("Light color=(%1 %2 %3)."). arg(m_ambient_color.x()).arg(m_ambient_color.y()).arg(m_ambient_color.z())); updateGL(); } else CGAL::QGLViewer::keyPressEvent(e); } virtual QString helpString() const { QString text("

C G A L B a s i c V i e w e r

"); text += "Use the mouse to move the camera around the object. "; text += "You can respectively revolve around, zoom and translate with " "the three mouse buttons. "; text += "Left and middle buttons pressed together rotate around the " "camera view direction axis

"; text += "Pressing Alt and one of the function keys " "(F1..F12) defines a camera keyFrame. "; text += "Simply press the function key again to restore it. " "Several keyFrames define a "; text += "camera path. Paths are saved when you quit the application " "and restored at next start.

"; text += "Press F to display the frame rate, A for the " "world axis, "; text += "Alt+Return for full screen mode and Control+S " "to save a snapshot. "; text += "See the Keyboard tab in this window for a complete " "shortcut list.

"; text += "Double clicks automates single click actions: A left button " "double click aligns the closer axis with the camera (if close enough). "; text += "A middle button double click fits the zoom of the camera and " "the right button re-centers the scene.

"; text += "A left button double click while holding right button pressed " "defines the camera Revolve Around Point. "; text += "See the Mouse tab and the documentation web pages for " "details.

"; text += "Press Escape to exit the viewer."; return text; } private: bool m_draw_vertices; bool m_draw_edges; bool m_draw_faces; bool m_flatShading; bool m_use_mono_color; bool m_inverse_normal; bool m_empty; double m_size_points; double m_size_edges; CGAL::IO::Color m_vertices_mono_color; CGAL::IO::Color m_edges_mono_color; CGAL::IO::Color m_faces_mono_color; QVector4D m_ambient_color; bool m_are_buffers_initialized; CGAL::Bbox_3 bb; //Shaders elements int vertexLocation[NB_VAO_BUFFERS]; int normalsLocation; int mvpLocation[2]; int mvLocation; int colorLocation1; int colorLocation2; int lightLocation[5]; enum { POS_MONO_POINTS=0, POS_COLORED_POINTS, POS_MONO_SEGMENTS, POS_COLORED_SEGMENTS, POS_MONO_FACES, POS_COLORED_FACES, BEGIN_NORMAL, SMOOTH_NORMAL_MONO_FACES=BEGIN_NORMAL, FLAT_NORMAL_MONO_FACES, SMOOTH_NORMAL_COLORED_FACES, FLAT_NORMAL_COLORED_FACES, END_NORMAL, COLOR_POINTS=END_NORMAL, COLOR_SEGMENTS, COLOR_FACES, LAST_INDEX }; std::vector arrays[LAST_INDEX]; QGLBuffer buffers[NB_VBO_BUFFERS]; QOpenGLVertexArrayObject vao[NB_VAO_BUFFERS]; int colorsLocation; QOpenGLShaderProgram rendering_program_mono; QOpenGLShaderProgram rendering_program_color; QOpenGLShaderProgram rendering_program_p_l_mono; QOpenGLShaderProgram rendering_program_p_l_color; // Local variables, used when we started a new face. bool m_face_started; bool m_started_face_is_colored; std::vector points_of_face; std::vector vertex_normals_for_face; CGAL::IO::Color color_of_face; }; #endif // CGAL_BASIC_VIEWER_H