This is an example where we want to display and select the different entities of a Mesh
structure. We define a processor called MeshDrawer
that displays the content of the Mesh
structure in order to display the 3D model and to enable selection. The different entities are the vertices, the edges and the faces.
In the global variables to the MeshDrawer
traversal, we store the variables necessary to the display for the GL selection mechanism.
In the visitor of the Core component of the code>MeshDrawer processor, we draw the different mesh entities and execute the GL commands relative to selection.
This is the facade of the processor.
This class contains all the processors necessary to the loading, updating and rendering of the 3D scene. It is also the intermediate between the MeshDrawer
and the Viewer
, the events being emitted by the Viewer
and treated by the MeshDrawer
.
This is the specialization of a QGLViewer
, redefining particularly the draw
and select
methods.
#ifndef MESH_DRAWER_GLOBALVARIABLES_H #define MESH_DRAWER_GLOBALVARIABLES_H #include <X3DTK/meshscenegraph.h> #include <list> #include <vector> namespace X3DTK { namespace MESH { // Global variables for the MeshDrawer processor. class MeshDrawerGlobalVariables : public GlobalVariables { public: MeshDrawerGlobalVariables(); // Initializes and finishes the traversal. void initTraversal(); void finishTraversal(); // Pushes the transformation matrix. void pushMatrix(const SFMatrix34f &transformation); // Pops the transformation matrix. void popMatrix(); // Saves current matrix state and returns index in saved vector. // Call storeMesh() before calling ths function int getCurrentMeshId(); // Saves mesh and associated current matrix. void storeMesh(Mesh* mesh); // Get i Mesh of the model. inline const Mesh* getMesh(int i) const {return _meshVector[i];}; // Gets stored transformation matrix associated with a given Mesh. inline SFMatrix34f getMatrix(int i) const {return _matrixVector[i];}; // Whether or not primitive IDs are pushed. inline void setSelectionMode(bool selectionMode) {_selectionMode = selectionMode;}; inline bool getSelectionMode() const {return _selectionMode;}; // Which mesh primitive type is rendered void setPrimitiveType(int primitiveType) {_primitiveType = primitiveType;}; inline int getPrimitiveType() const {return _primitiveType;}; // Whether each mesh is displayed with a specific color void changeOneColorPerMesh() {_oneColorPerMesh = !_oneColorPerMesh;}; inline bool getOneColorPerMesh() const {return _oneColorPerMesh;}; private: std::list<SFMatrix34f> _matrixStack; std::vector<SFMatrix34f> _matrixVector; std::vector<Mesh *> _meshVector; bool _selectionMode; bool _oneColorPerMesh; int _primitiveType; }; } } #endif
#include "MeshDrawerGlobalVariables.h" #include <qglobal.h> namespace X3DTK { namespace MESH { MeshDrawerGlobalVariables::MeshDrawerGlobalVariables() : GlobalVariables(), _selectionMode(false), _oneColorPerMesh(true), _primitiveType(1) {} void MeshDrawerGlobalVariables::initTraversal() { _matrixStack.push_front(identity34()); } void MeshDrawerGlobalVariables::finishTraversal() { _matrixStack.pop_front(); if (_matrixStack.size() != 0) { qWarning("Non empty matrix stack at the end of MeshDrawer traversal"); _matrixStack.clear(); } _matrixVector.clear(); _meshVector.clear(); } void MeshDrawerGlobalVariables::pushMatrix(const SFMatrix34f &transformation) { _matrixStack.push_front(_matrixStack.front()*transformation); } void MeshDrawerGlobalVariables::popMatrix() { _matrixStack.pop_front(); } void MeshDrawerGlobalVariables::storeMesh(Mesh* mesh) { _matrixVector.push_back(_matrixStack.front()); _meshVector.push_back(mesh); } int MeshDrawerGlobalVariables::getCurrentMeshId() { return _matrixVector.size() - 1; } } }
#ifndef MESH_DRAWER_COREVISITOR_H #define MESH_DRAWER_COREVISITOR_H #include <X3DTK/meshscenegraph.h> #include "MeshDrawerGlobalVariables.h" namespace X3DTK { namespace MESH { class Transform; class MeshDrawerCoreVisitor : public CoreVisitor { public: MeshDrawerCoreVisitor(); virtual void enterMesh(Mesh *M) const; virtual void enterTransform(Transform *T) const; virtual void leaveTransform(Transform *T) const; protected: MeshDrawerGlobalVariables *globalVariables; }; } } #endif
#include "MeshDrawerCoreVisitor.h" #include <GL/gl.h> #include <iostream> using namespace std; namespace X3DTK { namespace MESH { MeshDrawerCoreVisitor::MeshDrawerCoreVisitor() { // Enter and leave functions. defineNewEnterFunction(&MeshDrawerCoreVisitor::enterTransform); defineNewEnterFunction(&MeshDrawerCoreVisitor::enterMesh); defineNewLeaveFunction(&MeshDrawerCoreVisitor::leaveTransform); // GlobalVariables assignation. globalVariables = GVManager::getInstanceOf<MeshDrawerGlobalVariables>(); } void MeshDrawerCoreVisitor::enterTransform(Transform *T) const { globalVariables->pushMatrix(T->getTransform()); glPushMatrix(); glMultMatrixf(T->getTransform().toFloat16()); } void MeshDrawerCoreVisitor::leaveTransform(Transform *) const { globalVariables->popMatrix(); glPopMatrix(); } void MeshDrawerCoreVisitor::enterMesh(Mesh *M) const { globalVariables->storeMesh(M); int meshId = globalVariables->getCurrentMeshId(); if (globalVariables->getSelectionMode()) glPushName(meshId); bool colorPerVertex = M->data().hasVertexColor(); bool normalPerVertex = M->data().hasVertexNormal(); switch (globalVariables->getPrimitiveType()) { case 1 : // MeshViewer::VERTICES { glColor3f(1.0, 0.9, 0.8); glPointSize(6.0); const Mesh::MVertex& vertices = M->getVertices(); if (globalVariables->getSelectionMode()) { glPushName(1); for (Mesh::MVertex::const_iterator v = vertices.begin(), end = vertices.end() ; v != end; ++v) { glPushName((*v)->getIndex()); SFPoint3f point = (*v)->data().getPoint(); glRasterPos3fv(point.f_data()); glPopName(); } glPopName(); } else { glBegin(GL_POINTS); for (Mesh::MVertex::const_iterator v = vertices.begin(), end = vertices.end() ; v != end; ++v) { SFPoint3f point = (*v)->data().getPoint(); glVertex3fv(point.f_data()); } glEnd(); } break; } case 2 : // MeshViewer::EDGES { glLineWidth(2.0); const Mesh::MEdge& edges = M->getEdges(); if (globalVariables->getSelectionMode()) glPushName(2); int index = 0; for (Mesh::MEdge::const_iterator e = edges.begin(), end = edges.end() ; e != end; ++e) { if (globalVariables->getSelectionMode()) glPushName(index++); if ((*e)->isBoundary()) glColor3f(0.3, 0.3, 0.9); else glColor3f(0.7, 0.7, 0.7); // Normal Mesh::Face* firstFace = (*((*e)->getLeftFaces().begin())); if (!firstFace) firstFace = (*((*e)->getRightFaces().begin())); SFVec3f normal; if (normalPerVertex) normal = (*e)->getFromVertex()->data().getFaceData(firstFace)->getNormal(); else normal = firstFace->data().getNormal(); glNormal3fv(normal.f_data()); glBegin(GL_LINES); SFPoint3f point = (*e)->getFromVertex()->data().getPoint(); glVertex3fv(point.f_data()); point = (*e)->getToVertex()->data().getPoint(); glVertex3fv(point.f_data()); glEnd(); if (globalVariables->getSelectionMode()) glPopName(); } if (globalVariables->getSelectionMode()) glPopName(); break; } case 3 : // MeshViewer::FACES { const Mesh::MFace& faces = M->getFaces(); if (globalVariables->getSelectionMode()) glPushName(3); if (globalVariables->getOneColorPerMesh()) { SFColorRGBA color = SFColorRGBA(0.1*((3+meshId*3)%10), 0.1*((5+meshId*4)%10), 0.1*((7+meshId*5)%10), 1.0); glColor4f(color.r, color.g, color.b, color.a); } for (Mesh::MFace::const_iterator f = faces.begin(), end = faces.end() ; f != end; ++f) { if (!normalPerVertex) { SFVec3f normal = (*f)->data().getNormal(); glNormal3fv(normal.f_data()); } if ((!colorPerVertex) && (!globalVariables->getOneColorPerMesh())) { SFColorRGBA color = (*f)->data().getColor(); glColor4f(color.r, color.g, color.b, color.a); } if (globalVariables->getSelectionMode()) glPushName((*f)->getIndex()); glBegin(GL_POLYGON); const Mesh::MEdge& edges = (*f)->getEdges(); for (Mesh::MEdge::const_iterator e = edges.begin(), end = edges.end() ; e != end; ++e) { if (normalPerVertex) { SFVec3f normal = (*e)->getFromVertex()->data().getFaceData(*f)->getNormal(); glNormal3fv(normal.f_data()); } if ((colorPerVertex) && (!globalVariables->getOneColorPerMesh())) { SFColorRGBA color = (*e)->getFromVertex()->data().getFaceData(*f)->getColor(); glColor4f(color.r, color.g, color.b, color.a); } SFPoint3f point = (*e)->getFromVertex()->data().getPoint(); glVertex3fv(point.f_data()); } glEnd(); if (globalVariables->getSelectionMode()) glPopName(); } if (globalVariables->getSelectionMode()) glPopName(); break; } } if (globalVariables->getSelectionMode()) glPopName(); } } }
#ifndef MESH_DRAWER_H #define MESH_DRAWER_H #include "MeshDrawerGlobalVariables.h" #include <X3DTK/kernel.h> #include <X3DTK/meshscenegraph.h> namespace X3DTK { enum SelectedType {NOTHING, VERTICES, EDGES, FACES}; namespace MESH { // Processor drawing the mesh from the Mesh scene graph. class MeshDrawer : public X3DOnePassProcessor { public: MeshDrawer(); virtual ~MeshDrawer(); // Setting parameters. void changeDrawPoints(); void changeDrawEdges(); void changeDrawFaces(); inline void changeOneColorPerMesh() {globalVariables->changeOneColorPerMesh();}; void setSelectedType(SelectedType selectedType); void setSelectedMesh(int selectedMesh); void setSelectedId(int selectedId); // Getting parameters. inline SelectedType getSelectedType() const {return selectedType;}; inline int getSelectedMesh() const {return selectedMesh;}; inline int getSelectedId() const {return selectedId;}; // Draw methods. void drawMesh(X3DNode *N, bool selection = false); void drawSelected(); protected: MeshDrawerGlobalVariables* globalVariables; bool drawPoints, drawEdges, drawFaces; SelectedType selectedType; int selectedMesh; int selectedId; // Draw methods. void drawVertex(const Mesh::Vertex *vertex); void drawEdge(Mesh::Edge *edge); void drawFace(const Mesh::Face *face); }; } } #endif
#include "MeshDrawer.h" #include "MeshDrawerCoreVisitor.h" namespace X3DTK { namespace MESH { MeshDrawer::MeshDrawer() : X3DOnePassProcessor(), drawPoints(false), drawEdges(true), drawFaces(true) { graphTraversal = new DFSGraphTraversal(); graphTraversal->setComponentVisitor(new MeshDrawerCoreVisitor()); globalVariables = GVManager::getInstanceOf<MeshDrawerGlobalVariables>(); } MeshDrawer::~MeshDrawer() { delete graphTraversal; } void MeshDrawer::changeDrawPoints() { drawPoints = !drawPoints; } void MeshDrawer::changeDrawEdges() { drawEdges = !drawEdges; } void MeshDrawer::changeDrawFaces() { drawFaces = !drawFaces; } void MeshDrawer::setSelectedType(SelectedType selectedType) { this->selectedType = selectedType; } void MeshDrawer::setSelectedMesh(int selectedMesh) { this->selectedMesh = selectedMesh; } void MeshDrawer::setSelectedId(int selectedId) { this->selectedId = selectedId; } void MeshDrawer::drawMesh(X3DNode *N, bool selection) { globalVariables->setSelectionMode(selection); if (selection || drawPoints) { globalVariables->setPrimitiveType(VERTICES); globalVariables->initTraversal(); graphTraversal->traverse(N); globalVariables->finishTraversal(); } if (selection || drawEdges) { globalVariables->setPrimitiveType(EDGES); globalVariables->initTraversal(); graphTraversal->traverse(N); globalVariables->finishTraversal(); } if (selection || drawFaces) { globalVariables->setPrimitiveType(FACES); globalVariables->initTraversal(); graphTraversal->traverse(N); globalVariables->finishTraversal(); } } void MeshDrawer::drawSelected() { if (selectedType == NOTHING) return; glPushMatrix(); glMultMatrixf(globalVariables->getMatrix(selectedMesh).toFloat16()); const Mesh *mesh = globalVariables->getMesh(selectedMesh); bool normalPerVertex = mesh->data().hasVertexNormal(); glEnable(GL_POLYGON_OFFSET_FILL); #ifdef GL_POLYGON_OFFSET_LINES glEnable(GL_POLYGON_OFFSET_LINES); #endif glPointSize(15.0); glLineWidth(8.0); switch (selectedType) { case NOTHING : break; case VERTICES : { glPointSize(25.0); Mesh::Vertex* vertex = (mesh->getVertices())[selectedId]; const Mesh::MFace& faces = vertex->getFaces(); // Normal Mesh::Face* firstFace = (*(faces.begin())); SFVec3f normal; if (normalPerVertex) normal = vertex->data().getFaceData(firstFace)->getNormal(); else normal = firstFace->data().getNormal(); glNormal3fv(normal.f_data()); glColor3f(1.0, 1.0, 0.0); drawVertex(vertex); glColor3f(0.0, 0.8, 0.0); const Mesh::MEdge& edges = vertex->getEdges(); for (Mesh::MEdge::const_iterator e = edges.begin(), end = edges.end() ; e != end; ++e) drawEdge(*e); glColor3f(0.7, 0.9, 0.7); for (Mesh::MFace::const_iterator f = faces.begin(), end = faces.end() ; f != end; ++f) drawFace(*f); break; } case EDGES : { glLineWidth(15.0); Mesh::Edge* edge = (mesh->getEdges())[selectedId]; // Normal Mesh::Face* firstFace = (*(edge->getLeftFaces().begin())); if (!firstFace) firstFace = (*(edge->getRightFaces().begin())); SFVec3f normal; if (normalPerVertex) normal = edge->getFromVertex()->data().getFaceData(firstFace)->getNormal(); else normal = firstFace->data().getNormal(); glNormal3fv(normal.f_data()); glColor3f(1.0, 1.0, 0.0); drawEdge(edge); glColor3f(0.0, 0.8, 0.0); drawVertex(edge->getFromVertex()); drawVertex(edge->getToVertex()); glColor3f(0.9, 0.7, 0.7); const Mesh::MFace& lfaces = edge->getLeftFaces(); for (Mesh::MFace::const_iterator f = lfaces.begin(), end = lfaces.end() ; f != end; ++f) drawFace(*f); glColor3f(0.7, 0.9, 0.7); const Mesh::MFace& rfaces = edge->getRightFaces(); for (Mesh::MFace::const_iterator f = rfaces.begin(), end = rfaces.end() ; f != end; ++f) drawFace(*f); break; } case FACES : { Mesh::Face* face = (mesh->getFaces())[selectedId]; const Mesh::MEdge& edges = face->getEdges(); // Normal Mesh::Edge* firstEdge = (*(edges.begin())); SFVec3f normal; if (normalPerVertex) normal = firstEdge->getFromVertex()->data().getFaceData(face)->getNormal(); else normal = face->data().getNormal(); glNormal3fv(normal.f_data()); glColor3f(1.0, 1.0, 0.0); drawFace(face); for (Mesh::MEdge::const_iterator e = edges.begin(), end = edges.end() ; e != end; ++e) { glColor3f(0.0, 0.8, 0.0); drawEdge(*e); glColor3f(0.7, 0.7, 0.7); drawVertex((*e)->getFromVertex()); } break; } } glDisable(GL_POLYGON_OFFSET_FILL); #ifdef GL_POLYGON_OFFSET_LINES glDisable(GL_POLYGON_OFFSET_LINES); #endif glPopMatrix(); } void MeshDrawer::drawVertex(const Mesh::Vertex *vertex) { glBegin(GL_POINTS); SFPoint3f point = vertex->data().getPoint(); glVertex3fv(point.f_data()); glEnd(); } void MeshDrawer::drawEdge(Mesh::Edge *edge) { glPolygonOffset(-100, -100); glDisable(GL_LIGHTING); glBegin(GL_LINES); SFPoint3f point = edge->getFromVertex()->data().getPoint(); glVertex3fv(point.f_data()); point = edge->getToVertex()->data().getPoint(); glVertex3fv(point.f_data()); glEnd(); glEnable(GL_LIGHTING); glPolygonOffset(-2, -2); } void MeshDrawer::drawFace(const Mesh::Face *face) { const Mesh::MEdge& edges = face->getEdges(); glBegin(GL_POLYGON); for (Mesh::MEdge::const_iterator e = edges.begin(), end = edges.end() ; e != end; ++e) { SFPoint3f point = (*e)->getFromVertex()->data().getPoint(); glVertex3fv(point.f_data()); } glEnd(); } } }
#ifndef SIMPLEMESHGLSCENE_H #define SIMPLEMESHGLSCENE_H #include "MeshDrawer.h" #include <X3DTK/kernel.h> #include <X3DTK/meshbuilder.h> namespace X3DTK { class X3DMemReleaser; namespace X3D { class Scene; class Loader; class X3DBBoxUpdater; } namespace MESH { class Scene; class MeshNormalUpdater; class MeshDrawer; } class SimpleMeshGLScene { public: SimpleMeshGLScene(); virtual ~SimpleMeshGLScene(); virtual void load(const char *file); virtual void drawMesh(bool selection = false); virtual void drawSelected(); inline SFVec3f getBBoxMin() const {return min;}; inline SFVec3f getBBoxMax() const {return max;}; void release(); // Events dispatched to the MeshDrawer. inline void changeDrawPoints() {_drawer->changeDrawPoints();}; inline void changeDrawEdges() {_drawer->changeDrawEdges();}; inline void changeDrawFaces() {_drawer->changeDrawFaces();}; inline void changeOneColorPerMesh() {_drawer->changeOneColorPerMesh();}; inline void setSelectedType(SelectedType selectedType) {_drawer->setSelectedType(selectedType);}; inline void setSelectedMesh(int selectedMesh) {_drawer->setSelectedMesh(selectedMesh);}; inline void setSelectedId(int selectedId) {_drawer->setSelectedId(selectedId);}; // Gets the parameters. inline SelectedType getSelectedType() const {return _drawer->getSelectedType();}; inline int getSelectedMesh() const {return _drawer->getSelectedMesh();}; inline int getSelectedId() const {return _drawer->getSelectedId();}; protected: X3D::Scene *scene; MESH::Scene *meshScene; SFVec3f min; SFVec3f max; void loadFile(const char *file); void computeBBox(); void buildMeshScene(); private: X3D::Loader *_loader; X3D::X3DBBoxUpdater *_bboxupdater; X3D::MeshBuilder *_builder; MESH::MeshNormalUpdater *_normalUpdater; MESH::MeshDrawer *_drawer; X3DMemReleaser *_releaser; }; } #endif
#include "SimpleMeshGLScene.h" #include <X3DTK/x3dscenegraph.h> #include <X3DTK/bboxupdater.h> #include <X3DTK/meshnormalupdater.h> #include <X3DTK/memreleaser.h> #include <X3DTK/meshscenegraph.h> #include <iostream> #include <time.h> using namespace std; namespace X3DTK { SimpleMeshGLScene::SimpleMeshGLScene() : scene(0), meshScene(0) { _loader = new X3D::Loader(); _bboxupdater = new X3D::BBoxUpdater(); _builder = new X3D::MeshBuilder(); _drawer = new MESH::MeshDrawer(); _normalUpdater = new MESH::MeshNormalUpdater(); _releaser = new MemReleaser(); } SimpleMeshGLScene::~SimpleMeshGLScene() { _releaser->release(scene); //_releaser->release(meshScene); scene = 0; meshScene = 0; delete _loader; delete _bboxupdater; delete _builder; delete _drawer; delete _normalUpdater; delete _releaser; } void SimpleMeshGLScene::load(const char *file) { loadFile(file); computeBBox(); buildMeshScene(); } void SimpleMeshGLScene::drawMesh(bool selection) { _drawer->drawMesh(meshScene, selection); } void SimpleMeshGLScene::drawSelected() { _drawer->drawSelected(); } void SimpleMeshGLScene::release() { _releaser->release(scene); //_releaser->release(meshScene); scene = 0; meshScene = 0; } void SimpleMeshGLScene::loadFile(const char *file) { _releaser->release(scene); //_releaser->release(meshScene); scene = 0; meshScene = 0; scene = _loader->load(file); } void SimpleMeshGLScene::computeBBox() { _bboxupdater->update(scene, true); if (scene != 0) { SFVec3f center = scene->getBBoxCenter(); SFVec3f size = scene->getBBoxSize(); SFVec3f A = center + 0.5f*size; SFVec3f B = center - 0.5f*size; if (A.x < B.x) { min.x = A.x; max.x = B.x; } else { min.x = B.x; max.x = A.x; } if (A.y < B.y) { min.y = A.y; max.y = B.y; } else { min.y = B.y; max.y = A.y; } if (A.z < B.z) { min.z = A.z; max.z = B.z; } else { min.z = B.z; max.z = A.z; } } } void SimpleMeshGLScene::buildMeshScene() { meshScene = _builder->build(scene); _normalUpdater->updateNormals(meshScene); } }
#ifndef VIEWER_H #define VIEWER_H #include <QGLViewer/qglviewer.h> #include "SimpleMeshGLScene.h" class Viewer : public QGLViewer { public: Viewer(); ~Viewer(); protected : void loadFile(); void keyPressEvent(QKeyEvent *e); void init(); void draw(); void about(); QString helpString() const; void select(const QMouseEvent* e); void help() const; private: X3DTK::SimpleMeshGLScene scene; X3DTK::BBox BB; // Events dispatched to the scene. inline void toggleDrawPoints() {scene.changeDrawPoints();}; inline void toggleDrawEdges() {scene.changeDrawEdges();}; inline void toggleDrawFaces() {scene.changeDrawFaces();}; inline void toggleOneColorPerMesh() {scene.changeOneColorPerMesh();}; }; #endif
#include "Viewer.h" #include <math.h> #include <iostream> #include <qfiledialog.h> #include <qmessagebox.h> using namespace X3DTK; using namespace std; Viewer::Viewer() { } Viewer::~Viewer() { scene.release(); } void Viewer::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_L : loadFile(); updateGL(); break; case Qt::Key_V : toggleDrawPoints(); updateGL(); break; case Qt::Key_E : toggleDrawEdges(); updateGL(); break; case Qt::Key_F : toggleDrawFaces(); updateGL(); break; case Qt::Key_C : toggleOneColorPerMesh(); updateGL(); break; default : QGLViewer::keyPressEvent(e); } } void Viewer::loadFile() { QString name = QFileDialog::getOpenFileName("", "X3D files (*.x3d *.X3D);;All files (*)", this); // In case of Cancel if (name.isEmpty()) return; // Loads the file name. scene.load(name); setSceneBoundingBox(scene.getBBoxMin().f_data(), scene.getBBoxMax().f_data()); setSceneRadius(2.0f*sceneRadius()); showEntireScene(); } void Viewer::init() { glPolygonOffset(-2.0, -2.0); #ifdef GL_RESCALE_NORMAL glEnable(GL_RESCALE_NORMAL); #endif loadFile(); } void Viewer::draw() { scene.drawMesh(); scene.drawSelected(); } void Viewer::about() { QMessageBox::about(this, "about the simpleAnimationViewer", "this is an example showing how to animate a simple X3D scene.Type 'h' to display help"); } void Viewer::help() const { QMessageBox *mb = new QMessageBox("help", helpString(), QMessageBox::NoIcon,QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton,QMessageBox::NoButton, NULL, "Help", false,Qt::WStyle_DialogBorder | Qt::WType_Dialog | Qt::WDestructiveClose); mb->show(); } void Viewer::select(const QMouseEvent* e) { // Make openGL context current makeCurrent(); const int SENSITIVITY = 6; const int NB_HITS_MAX = 32768; // Prepare the selection mode static GLuint hits[NB_HITS_MAX]; glSelectBuffer(NB_HITS_MAX, hits); glRenderMode(GL_SELECT); glInitNames(); // Loads the matrices glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport); camera()->getViewport(viewport); gluPickMatrix(static_cast<GLdouble>(e->x()), static_cast<GLdouble>(e->y()), SENSITIVITY, SENSITIVITY, viewport); // Don't use loadProjectionMatrix() directly as it clears the GL_PROJECTION matrix with a glLoadIdentity. // The false flag indicates that no glLoadIdentity should be called, in order to combine the matrices. camera()->loadProjectionMatrix(false); camera()->loadModelViewMatrix(); // Render scene with objects ids scene.drawMesh(true); glFlush(); // Get the results GLint nb_hits = glRenderMode(GL_RENDER); // Too many elements in selection buffer if (nb_hits < 0) return; // No selection if (nb_hits == 0) { scene.setSelectedType(NOTHING); cout << "No selection" << endl; return; } // Interpret results unsigned int zMin = hits[1]; scene.setSelectedMesh(hits[3]); scene.setSelectedType(static_cast<SelectedType>(hits[4])); scene.setSelectedId(hits[5]); for (int i=1; i<nb_hits; ++i) // Prefer vertices over edges and edges over faces if (hits[i*6+1] < zMin+(((int)scene.getSelectedType() - hits[i*6+4])*200000)) { zMin = hits[i*6+1]; scene.setSelectedMesh(hits[i*6+3]); scene.setSelectedType(static_cast<SelectedType>(hits[i*6+4])); scene.setSelectedId(hits[i*6+5]); } switch (scene.getSelectedType()) { case NOTHING : break; case VERTICES :cout << "Vertex "; break; case EDGES : cout << "Edge "; break; case FACES : cout << "Face "; break; } cout << scene.getSelectedId() << " selected on mesh " << scene.getSelectedMesh() << endl; } QString Viewer::helpString() const { QString message("<b>L</b> loads a new file<br>"); message += "<b>F</b> toggles face display<br>"; message += "<b>E</b> toggles edge display<br>"; message += "<b>V</b> toggles vertex display<br>"; message += "<b>C</b> toggles one color per mesh<br>"; message += "<b>Shift+click</b> to select an element<br>"; message += "<hr>"; message += QGLViewer::helpString(); return message; }