Skip to content
Snippets Groups Projects
Commit a995ad21 authored by Christophe Geuzaine's avatar Christophe Geuzaine
Browse files

move the selection code to drawContext, so we can use it as-is

with other toolkits than fltk
parent 3dea4b23
No related branches found
No related tags found
No related merge requests found
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "MElement.h" #include "MElement.h"
#include "Numeric.h" #include "Numeric.h"
#include "FlGui.h" #include "FlGui.h"
#include "VertexArray.h"
#include "Context.h" #include "Context.h"
static void lassoZoom(drawContext *ctx, mousePosition &click1, mousePosition &click2) static void lassoZoom(drawContext *ctx, mousePosition &click1, mousePosition &click2)
...@@ -108,9 +107,9 @@ void openglWindow::draw() ...@@ -108,9 +107,9 @@ void openglWindow::draw()
{ {
// some drawing routines can create data (STL triangulations, etc.): // some drawing routines can create data (STL triangulations, etc.):
// make sure that we don't fire draw() while we are already drawing, // make sure that we don't fire draw() while we are already drawing,
// e.g. due to an impromptu Fl::check(). The same lock is also used in // e.g. due to an impromptu Fl::check(). The same lock is also used
// _processSelectionBuffer to guarantee that we don't mix GL_RENDER and // in _select to guarantee that we don't mix GL_RENDER and GL_SELECT
// GL_SELECT rendering passes. // rendering passes.
if(_lock) return; if(_lock) return;
_lock = true; _lock = true;
...@@ -430,8 +429,7 @@ int openglWindow::handle(int event) ...@@ -430,8 +429,7 @@ int openglWindow::handle(int event)
std::vector<GFace*> faces; std::vector<GFace*> faces;
std::vector<GRegion*> regions; std::vector<GRegion*> regions;
std::vector<MElement*> elements; std::vector<MElement*> elements;
bool res = _processSelectionBuffer(_selection, false, bool res = _select(_selection, false, CTX::instance()->mouseHoverMeshes,
CTX::instance()->mouseHoverMeshes,
(int)_curr.win[0], (int)_curr.win[1], 5, 5, (int)_curr.win[0], (int)_curr.win[1], 5, 5,
vertices, edges, faces, regions, elements); vertices, edges, faces, regions, elements);
if((_selection == ENT_ALL && res) || if((_selection == ENT_ALL && res) ||
...@@ -461,220 +459,24 @@ int openglWindow::handle(int event) ...@@ -461,220 +459,24 @@ int openglWindow::handle(int event)
} }
} }
class hit{ bool openglWindow::_select(int type, bool multiple, bool mesh,
public: int x, int y, int w, int h,
GLuint type, ient, depth, type2, ient2;
hit(GLuint t, GLuint i, GLuint d, GLuint t2=0, GLuint i2=0)
: type(t), ient(i), depth(d), type2(t2), ient2(i2) {}
};
class hitDepthLessThan{
public:
bool operator()(const hit &h1, const hit &h2) const
{
return h1.depth < h2.depth;
}
};
// returns the element at a given position in a vertex array (element
// pointers are not always stored: returning 0 is not an error)
static MElement *getElement(GEntity *e, int va_type, int index)
{
switch(va_type){
case 2:
if(e->va_lines && index < e->va_lines->getNumElementPointers())
return *e->va_lines->getElementPointerArray(index);
break;
case 3:
if(e->va_triangles && index < e->va_triangles->getNumElementPointers())
return *e->va_triangles->getElementPointerArray(index);
break;
}
return 0;
}
bool openglWindow::_processSelectionBuffer(int type, bool multipleSelection,
bool meshSelection, int x, int y, int w, int h,
std::vector<GVertex*> &vertices, std::vector<GVertex*> &vertices,
std::vector<GEdge*> &edges, std::vector<GEdge*> &edges,
std::vector<GFace*> &faces, std::vector<GFace*> &faces,
std::vector<GRegion*> &regions, std::vector<GRegion*> &regions,
std::vector<MElement*> &elements) std::vector<MElement*> &elements)
{ {
vertices.clear();
edges.clear();
faces.clear();
regions.clear();
elements.clear();
// In our case the selection buffer size is equal to between 5 and 7
// times the maximum number of possible hits
GModel *m = GModel::current();
int eles = (meshSelection && CTX::instance()->pickElements) ?
4 * m->getNumMeshElements() : 0;
int size = 7 * (m->getNumVertices() + m->getNumEdges() + m->getNumFaces() +
m->getNumRegions() + eles);
if(!size) return false; // we won't get any hits: the model is empty!
size += 1000; // security
// same lock as in draw() to prevent firing up a GL_SELECT rendering pass // same lock as in draw() to prevent firing up a GL_SELECT rendering pass
// while a GL_RENDER pass is happening (due to the asynchronus nature of // while a GL_RENDER pass is happening (due to the asynchronus nature of
// Fl::check()s // Fl::check()s
if(_lock) return false; if(_lock) return false;
_lock = true; _lock = true;
make_current(); make_current();
GLuint *selectionBuffer = new GLuint[size]; bool ret = _ctx->select(type, multiple, mesh, x, y, w, h,
glSelectBuffer(size, selectionBuffer); vertices, edges, faces, regions, elements);
glRenderMode(GL_SELECT);
_ctx->render_mode = drawContext::GMSH_SELECT;
glInitNames();
glPushMatrix();
_ctx->initProjection(x, y, w, h);
_ctx->initPosition();
_ctx->drawGeom();
if(meshSelection) _ctx->drawMesh();
glPopMatrix();
GLint numhits = glRenderMode(GL_RENDER);
_ctx->render_mode = drawContext::GMSH_RENDER;
_lock = false; _lock = false;
return ret;
if(!numhits){ // no hits
delete [] selectionBuffer;
return false;
}
else if(numhits < 0){ // overflow
delete [] selectionBuffer;
Msg::Warning("Too many entities selected");
return false;
}
std::vector<hit> hits;
GLuint *ptr = selectionBuffer;
for(int i = 0; i < numhits; i++) {
// in Gmsh 'names' should always be 0, 2 or 4:
// * names == 0 means that there is nothing on the stack
// * if names == 2, the first name is the type of the entity
// (0 for point, 1 for edge, 2 for face or 3 for volume) and
// the second is the entity number;
// * if names == 4, the first name is the type of the entity,
// the second is the entity number, the third is the type
// of vertex array (2 for line, 3 for triangle, 4 for quad)
// and the fourth is the index of the element in the vertex
// array
GLuint names = *ptr++;
*ptr++; // mindepth
GLuint maxdepth = *ptr++;
if(names == 2){
GLuint depth = maxdepth;
GLuint type = *ptr++;
GLuint ient = *ptr++;
hits.push_back(hit(type, ient, depth));
}
else if(names == 4){
GLuint depth = maxdepth;
GLuint type = *ptr++;
GLuint ient = *ptr++;
GLuint type2 = *ptr++;
GLuint ient2 = *ptr++;
hits.push_back(hit(type, ient, depth, type2, ient2));
}
}
delete [] selectionBuffer;
if(!hits.size()){ // no entities
return false;
}
// sort hits to get closest entities first
std::sort(hits.begin(), hits.end(), hitDepthLessThan());
// filter result: if type == ENT_NONE, return the closest entity of
// "lowest dimension" (point < line < surface < volume). Otherwise,
// return the closest entity of type "type"
GLuint typmin = 10;
for(unsigned int i = 0; i < hits.size(); i++)
typmin = std::min(typmin, hits[i].type);
for(unsigned int i = 0; i < hits.size(); i++) {
if((type == ENT_ALL) ||
(type == ENT_NONE && hits[i].type == typmin) ||
(type == ENT_POINT && hits[i].type == 0) ||
(type == ENT_LINE && hits[i].type == 1) ||
(type == ENT_SURFACE && hits[i].type == 2) ||
(type == ENT_VOLUME && hits[i].type == 3)){
switch (hits[i].type) {
case 0:
{
GVertex *v = m->getVertexByTag(hits[i].ient);
if(!v){
Msg::Error("Problem in point selection processing");
return false;
}
vertices.push_back(v);
if(!multipleSelection) return true;
}
break;
case 1:
{
GEdge *e = m->getEdgeByTag(hits[i].ient);
if(!e){
Msg::Error("Problem in line selection processing");
return false;
}
if(hits[i].type2){
MElement *ele = getElement(e, hits[i].type2, hits[i].ient2);
if(ele) elements.push_back(ele);
}
edges.push_back(e);
if(!multipleSelection) return true;
}
break;
case 2:
{
GFace *f = m->getFaceByTag(hits[i].ient);
if(!f){
Msg::Error("Problem in surface selection processing");
return false;
}
if(hits[i].type2){
MElement *ele = getElement(f, hits[i].type2, hits[i].ient2);
if(ele) elements.push_back(ele);
}
faces.push_back(f);
if(!multipleSelection) return true;
}
break;
case 3:
{
GRegion *r = m->getRegionByTag(hits[i].ient);
if(!r){
Msg::Error("Problem in volume selection processing");
return false;
}
if(hits[i].type2){
MElement *ele = getElement(r, hits[i].type2, hits[i].ient2);
if(ele) elements.push_back(ele);
}
regions.push_back(r);
if(!multipleSelection) return true;
}
break;
}
}
}
if(vertices.size() || edges.size() || faces.size() ||
regions.size() || elements.size())
return true;
return false;
} }
char openglWindow::selectEntity(int type, char openglWindow::selectEntity(int type,
...@@ -730,7 +532,7 @@ char openglWindow::selectEntity(int type, ...@@ -730,7 +532,7 @@ char openglWindow::selectEntity(int type,
selectionMode = false; selectionMode = false;
return 'c'; return 'c';
} }
else if(_processSelectionBuffer(_selection, multi, true, _trySelectionXYWH[0], else if(_select(_selection, multi, true, _trySelectionXYWH[0],
_trySelectionXYWH[1], _trySelectionXYWH[2], _trySelectionXYWH[1], _trySelectionXYWH[2],
_trySelectionXYWH[3], vertices, edges, faces, _trySelectionXYWH[3], vertices, edges, faces,
regions, elements)){ regions, elements)){
......
...@@ -30,13 +30,9 @@ class openglWindow : public Fl_Gl_Window { ...@@ -30,13 +30,9 @@ class openglWindow : public Fl_Gl_Window {
double _lassoXY[2]; double _lassoXY[2];
void _drawScreenMessage(); void _drawScreenMessage();
void _drawBorder(); void _drawBorder();
bool _processSelectionBuffer(int type, bool _select(int type, bool multiple, bool mesh, int x, int y, int w, int h,
bool multipleSelection, bool meshSelection, std::vector<GVertex*> &vertices, std::vector<GEdge*> &edges,
int x, int y, int w, int h, std::vector<GFace*> &faces, std::vector<GRegion*> &regions,
std::vector<GVertex*> &vertices,
std::vector<GEdge*> &edges,
std::vector<GFace*> &faces,
std::vector<GRegion*> &regions,
std::vector<MElement*> &elements); std::vector<MElement*> &elements);
protected: protected:
void draw(); void draw();
......
...@@ -11,8 +11,10 @@ ...@@ -11,8 +11,10 @@
#include "Context.h" #include "Context.h"
#include "Numeric.h" #include "Numeric.h"
#include "GModel.h" #include "GModel.h"
#include "MElement.h"
#include "PView.h" #include "PView.h"
#include "PViewOptions.h" #include "PViewOptions.h"
#include "VertexArray.h"
#include "gl2ps.h" #include "gl2ps.h"
#if defined(HAVE_FLTK) #if defined(HAVE_FLTK)
...@@ -644,3 +646,209 @@ void drawContext::world2Viewport(double xyz[3], double win[3]) ...@@ -644,3 +646,209 @@ void drawContext::world2Viewport(double xyz[3], double win[3])
glGetDoublev(GL_MODELVIEW_MATRIX, model); glGetDoublev(GL_MODELVIEW_MATRIX, model);
gluProject(xyz[0], xyz[1], xyz[2], model, proj, viewport, &win[0], &win[1], &win[2]); gluProject(xyz[0], xyz[1], xyz[2], model, proj, viewport, &win[0], &win[1], &win[2]);
} }
class hit{
public:
GLuint type, ient, depth, type2, ient2;
hit(GLuint t, GLuint i, GLuint d, GLuint t2=0, GLuint i2=0)
: type(t), ient(i), depth(d), type2(t2), ient2(i2) {}
};
class hitDepthLessThan{
public:
bool operator()(const hit &h1, const hit &h2) const
{
return h1.depth < h2.depth;
}
};
// returns the element at a given position in a vertex array (element
// pointers are not always stored: returning 0 is not an error)
static MElement *getElement(GEntity *e, int va_type, int index)
{
switch(va_type){
case 2:
if(e->va_lines && index < e->va_lines->getNumElementPointers())
return *e->va_lines->getElementPointerArray(index);
break;
case 3:
if(e->va_triangles && index < e->va_triangles->getNumElementPointers())
return *e->va_triangles->getElementPointerArray(index);
break;
}
return 0;
}
bool drawContext::select(int type, bool multiple, bool mesh,
int x, int y, int w, int h,
std::vector<GVertex*> &vertices,
std::vector<GEdge*> &edges,
std::vector<GFace*> &faces,
std::vector<GRegion*> &regions,
std::vector<MElement*> &elements)
{
vertices.clear();
edges.clear();
faces.clear();
regions.clear();
elements.clear();
// in our case the selection buffer size is equal to between 5 and 7
// times the maximum number of possible hits
GModel *m = GModel::current();
int eles = (mesh && CTX::instance()->pickElements) ? 4 * m->getNumMeshElements() : 0;
int size = 7 * (m->getNumVertices() + m->getNumEdges() + m->getNumFaces() +
m->getNumRegions() + eles);
if(!size) return false; // the model is empty, don't bother!
// allocate selection buffer
size += 1000; // just to make sure
GLuint *selectionBuffer = new GLuint[size];
glSelectBuffer(size, selectionBuffer);
// do one rendering pass in select mode
render_mode = drawContext::GMSH_SELECT;
glRenderMode(GL_SELECT);
glInitNames();
glPushMatrix();
initProjection(x, y, w, h);
initPosition();
drawGeom();
if(mesh) drawMesh();
glPopMatrix();
GLint numhits = glRenderMode(GL_RENDER);
render_mode = drawContext::GMSH_RENDER;
if(!numhits){ // no hits
delete [] selectionBuffer;
return false;
}
else if(numhits < 0){ // overflow
delete [] selectionBuffer;
Msg::Warning("Too many entities selected");
return false;
}
// decode the hits
std::vector<hit> hits;
GLuint *ptr = selectionBuffer;
for(int i = 0; i < numhits; i++) {
// in Gmsh 'names' should always be 0, 2 or 4:
// * names == 0 means that there is nothing on the stack
// * if names == 2, the first name is the type of the entity
// (0 for point, 1 for edge, 2 for face or 3 for volume) and
// the second is the entity number;
// * if names == 4, the first name is the type of the entity,
// the second is the entity number, the third is the type
// of vertex array (2 for line, 3 for triangle, 4 for quad)
// and the fourth is the index of the element in the vertex
// array
GLuint names = *ptr++;
*ptr++; // mindepth
GLuint maxdepth = *ptr++;
if(names == 2){
GLuint depth = maxdepth;
GLuint type = *ptr++;
GLuint ient = *ptr++;
hits.push_back(hit(type, ient, depth));
}
else if(names == 4){
GLuint depth = maxdepth;
GLuint type = *ptr++;
GLuint ient = *ptr++;
GLuint type2 = *ptr++;
GLuint ient2 = *ptr++;
hits.push_back(hit(type, ient, depth, type2, ient2));
}
}
delete [] selectionBuffer;
if(!hits.size()){ // no entities
return false;
}
// sort hits to get closest entities first
std::sort(hits.begin(), hits.end(), hitDepthLessThan());
// filter result: if type == ENT_NONE, return the closest entity of
// "lowest dimension" (point < line < surface < volume). Otherwise,
// return the closest entity of type "type"
GLuint typmin = 10;
for(unsigned int i = 0; i < hits.size(); i++)
typmin = std::min(typmin, hits[i].type);
for(unsigned int i = 0; i < hits.size(); i++) {
if((type == ENT_ALL) ||
(type == ENT_NONE && hits[i].type == typmin) ||
(type == ENT_POINT && hits[i].type == 0) ||
(type == ENT_LINE && hits[i].type == 1) ||
(type == ENT_SURFACE && hits[i].type == 2) ||
(type == ENT_VOLUME && hits[i].type == 3)){
switch (hits[i].type) {
case 0:
{
GVertex *v = m->getVertexByTag(hits[i].ient);
if(!v){
Msg::Error("Problem in point selection processing");
return false;
}
vertices.push_back(v);
if(!multiple) return true;
}
break;
case 1:
{
GEdge *e = m->getEdgeByTag(hits[i].ient);
if(!e){
Msg::Error("Problem in line selection processing");
return false;
}
if(hits[i].type2){
MElement *ele = getElement(e, hits[i].type2, hits[i].ient2);
if(ele) elements.push_back(ele);
}
edges.push_back(e);
if(!multiple) return true;
}
break;
case 2:
{
GFace *f = m->getFaceByTag(hits[i].ient);
if(!f){
Msg::Error("Problem in surface selection processing");
return false;
}
if(hits[i].type2){
MElement *ele = getElement(f, hits[i].type2, hits[i].ient2);
if(ele) elements.push_back(ele);
}
faces.push_back(f);
if(!multiple) return true;
}
break;
case 3:
{
GRegion *r = m->getRegionByTag(hits[i].ient);
if(!r){
Msg::Error("Problem in volume selection processing");
return false;
}
if(hits[i].type2){
MElement *ele = getElement(r, hits[i].type2, hits[i].ient2);
if(ele) elements.push_back(ele);
}
regions.push_back(r);
if(!multiple) return true;
}
break;
}
}
}
if(vertices.size() || edges.size() || faces.size() ||
regions.size() || elements.size())
return true;
return false;
}
...@@ -27,6 +27,11 @@ ...@@ -27,6 +27,11 @@
class PView; class PView;
class GModel; class GModel;
class GVertex;
class GEdge;
class GFace;
class GRegion;
class MElement;
class drawTransform { class drawTransform {
public: public:
...@@ -164,6 +169,10 @@ class drawContext { ...@@ -164,6 +169,10 @@ class drawContext {
void unproject(double x, double y, double p[3], double d[3]); void unproject(double x, double y, double p[3], double d[3]);
void viewport2World(double win[3], double xyz[3]); void viewport2World(double win[3], double xyz[3]);
void world2Viewport(double xyz[3], double win[3]); void world2Viewport(double xyz[3], double win[3]);
bool select(int type, bool multiple, bool mesh, int x, int y, int w, int h,
std::vector<GVertex*> &vertices, std::vector<GEdge*> &edges,
std::vector<GFace*> &faces, std::vector<GRegion*> &regions,
std::vector<MElement*> &elements);
int fix2dCoordinates(double *x, double *y); int fix2dCoordinates(double *x, double *y);
void draw3d(); void draw3d();
void draw2d(); void draw2d();
......
...@@ -1217,11 +1217,11 @@ class AttractorField : public Field ...@@ -1217,11 +1217,11 @@ class AttractorField : public Field
dist = new ANNdist[1]; dist = new ANNdist[1];
n_nodes_by_edge = 20; n_nodes_by_edge = 20;
options["NodesList"] = new FieldOptionList options["NodesList"] = new FieldOptionList
(nodes_id, "Indices of nodes in the geomtric model", &update_needed); (nodes_id, "Indices of nodes in the geometric model", &update_needed);
options["EdgesList"] = new FieldOptionList options["EdgesList"] = new FieldOptionList
(edges_id, "Indices of curves in the geometric model", &update_needed); (edges_id, "Indices of curves in the geometric model", &update_needed);
options["NNodesByEdge"] = new FieldOptionInt options["NNodesByEdge"] = new FieldOptionInt
(n_nodes_by_edge, "Number of nodes used to discetized each curve", (n_nodes_by_edge, "Number of nodes used to discretized each curve",
&update_needed); &update_needed);
options["FacesList"] = new FieldOptionList options["FacesList"] = new FieldOptionList
(faces_id, "Indices of surfaces in the geometric model (Warning: might\n" (faces_id, "Indices of surfaces in the geometric model (Warning: might\n"
......
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
#include <gmsh/MElement.h> #include <gmsh/MElement.h>
#include <gmsh/drawContext.h> #include <gmsh/drawContext.h>
drawContext *ctx = 0; static drawContext *ctx = 0;
static mousePosition clickPos, prevPos;
static int specialKey = 0;
class drawContextTw : public drawContextGlobal{ class drawContextTw : public drawContextGlobal{
public: public:
...@@ -70,9 +72,6 @@ void keyboard(unsigned char key, int x, int y) ...@@ -70,9 +72,6 @@ void keyboard(unsigned char key, int x, int y)
glutPostRedisplay(); glutPostRedisplay();
} }
static mousePosition clickPos, prevPos;
static int specialKey = 0;
void mouseMotion(int x, int y) void mouseMotion(int x, int y)
{ {
if(TwEventMouseMotionGLUT(x, y)) return; if(TwEventMouseMotionGLUT(x, y)) return;
...@@ -108,6 +107,29 @@ void mouseMotion(int x, int y) ...@@ -108,6 +107,29 @@ void mouseMotion(int x, int y)
glutPostRedisplay(); glutPostRedisplay();
} }
void mousePassiveMotion(int x, int y)
{
if(TwEventMouseMotionGLUT(x, y)) return;
std::vector<GVertex*> vertices;
std::vector<GEdge*> edges;
std::vector<GFace*> faces;
std::vector<GRegion*> regions;
std::vector<MElement*> elements;
bool ret = ctx->select(ENT_ALL, false, false, x, y, 5, 5,
vertices, edges, faces, regions, elements);
if(ret){
GEntity *ge = 0;
if(vertices.size()) ge = vertices[0];
else if(edges.size()) ge = edges[0];
else if(faces.size()) ge = faces[0];
else if(regions.size()) ge = regions[0];
MElement *me = elements.size() ? elements[0] : 0;
printf("%s %s\n", ge ? ge->getInfoString().c_str() : "",
me ? me->getInfoString().c_str() : "");
}
}
void mouseButton(int button, int state, int x, int y) void mouseButton(int button, int state, int x, int y)
{ {
if(TwEventMouseButtonGLUT(button, state, x, y)) return; if(TwEventMouseButtonGLUT(button, state, x, y)) return;
...@@ -214,7 +236,7 @@ int main(int argc, char **argv) ...@@ -214,7 +236,7 @@ int main(int argc, char **argv)
glutReshapeFunc(reshape); glutReshapeFunc(reshape);
glutMouseFunc(mouseButton); glutMouseFunc(mouseButton);
glutMotionFunc(mouseMotion); glutMotionFunc(mouseMotion);
glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT); glutPassiveMotionFunc(mousePassiveMotion);
glutKeyboardFunc(keyboard); glutKeyboardFunc(keyboard);
glutSpecialFunc((GLUTspecialfun)TwEventSpecialGLUT); glutSpecialFunc((GLUTspecialfun)TwEventSpecialGLUT);
TwGLUTModifiersFunc(glutGetModifiers); TwGLUTModifiersFunc(glutGetModifiers);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment