377 lines
11 KiB
C++
377 lines
11 KiB
C++
/****************************************************************************
|
|
* VCGLib o o *
|
|
* Visual and Computer Graphics Library o o *
|
|
* _ O _ *
|
|
* Copyright(C) 2004 \/)\/ *
|
|
* Visual Computing Lab /\/| *
|
|
* ISTI - Italian National Research Council | *
|
|
* \ *
|
|
* All rights reserved. *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
|
* for more details. *
|
|
* *
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
History
|
|
$Log: not supported by cvs2svn $
|
|
Revision 1.10 2006/12/07 00:39:22 cignoni
|
|
Added a class prototype for avoiding the inclusion of tetra.h
|
|
|
|
Revision 1.9 2006/12/04 09:27:13 cignoni
|
|
Removed useless include <tetra.h>
|
|
|
|
****************************************************************************/
|
|
#ifndef __PICK______H
|
|
#define __PICK______H
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
namespace vcg{
|
|
|
|
template <class MESH_TYPE>
|
|
class GLPickTri
|
|
{
|
|
typedef typename MESH_TYPE::FaceIterator FaceIterator;
|
|
typedef typename MESH_TYPE::FacePointer FacePointer;
|
|
typedef typename MESH_TYPE::VertexType VertexType;
|
|
|
|
public:
|
|
|
|
static bool PickNearestFace(int x, int y, MESH_TYPE &m, FacePointer &fi,int width=4, int height=4)
|
|
{
|
|
std::vector<FacePointer> result;
|
|
int val=PickFace(x,y,m,result,width,height);
|
|
if(val!=0)
|
|
{
|
|
fi=result[0];
|
|
return true;
|
|
}
|
|
fi=NULL;
|
|
return false;
|
|
}
|
|
|
|
static int PickFace(int x, int y, MESH_TYPE &m, std::vector<FacePointer> &result, int width=4, int height=4,bool sorted=true)
|
|
{
|
|
result.clear();
|
|
if(width==0 ||height==0) return 0;
|
|
long hits;
|
|
int sz=m.face.size()*5;
|
|
GLuint *selectBuf =new GLuint[sz];
|
|
// static unsigned int selectBuf[16384];
|
|
glSelectBuffer(sz, selectBuf);
|
|
glRenderMode(GL_SELECT);
|
|
glInitNames();
|
|
|
|
/* Because LoadName() won't work with no names on the stack */
|
|
glPushName(-1);
|
|
double mp[16];
|
|
|
|
GLint viewport[4];
|
|
glGetIntegerv(GL_VIEWPORT,viewport);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glGetDoublev(GL_PROJECTION_MATRIX ,mp);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
//gluPickMatrix(x, viewport[3]-y, 4, 4, viewport);
|
|
gluPickMatrix(x, y, width, height, viewport);
|
|
glMultMatrixd(mp);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
int fcnt=0;
|
|
FaceIterator fi;
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
{
|
|
if(!(*fi).IsD())
|
|
{
|
|
glLoadName(fcnt);
|
|
glBegin(GL_TRIANGLES);
|
|
glVertex( (*fi).V(0)->P() );
|
|
glVertex( (*fi).V(1)->P() );
|
|
glVertex( (*fi).V(2)->P() );
|
|
glEnd();
|
|
}
|
|
fcnt++; // the counter should advance even for deleted faces!
|
|
}
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
hits = glRenderMode(GL_RENDER);
|
|
//xstring buf;
|
|
//if (hits <= 0) return 0;
|
|
std::vector< std::pair<double,unsigned int> > H;
|
|
for(long ii=0;ii<hits;ii++){
|
|
//TRACE("%ui %ui %ui %ui\n",selectBuf[ii*4],selectBuf[ii*4+1],selectBuf[ii*4+2],selectBuf[ii*4+3]);
|
|
H.push_back( std::pair<double,unsigned int>(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3]));
|
|
}
|
|
if(sorted)
|
|
std::sort(H.begin(),H.end());
|
|
// if(H.size()>0) TRACE("\n Closest is %i\n",H[0].second);
|
|
result.resize(H.size());
|
|
for(long ii=0;ii<hits;ii++){
|
|
FaceIterator fi=m.face.begin();
|
|
advance(fi ,H[ii].second);
|
|
result[ii]=&*fi;
|
|
}
|
|
|
|
delete [] selectBuf;
|
|
return result.size();
|
|
}
|
|
|
|
// Same of above but it also assumes that you want only visible faces.
|
|
// Visibility is computed according to the current depth buffer.
|
|
static int PickFaceVisible(int x, int y, MESH_TYPE &m, std::vector<FacePointer> &resultZ, int width=4, int height=4, bool sorted=true)
|
|
{
|
|
// First step
|
|
|
|
double mm[16];
|
|
double mp[16];
|
|
GLint vp[4];
|
|
glGetIntegerv(GL_VIEWPORT,vp);
|
|
glGetDoublev(GL_MODELVIEW_MATRIX ,mm);
|
|
glGetDoublev(GL_PROJECTION_MATRIX ,mp);
|
|
int screenW = vp[2]-vp[0];
|
|
int screenH = vp[3]-vp[1];
|
|
|
|
GLfloat *buffer = new GLfloat[screenW*screenH];
|
|
glReadPixels(vp[0],vp[1],vp[2],vp[3],GL_DEPTH_COMPONENT,GL_FLOAT,buffer);
|
|
|
|
std::vector<FacePointer> result;
|
|
PickFace(x,y,m,result,width,height,sorted);
|
|
float LocalEpsilon = 0.001f;
|
|
for(int i =0;i<result.size();++i)
|
|
{
|
|
typename VertexType::CoordType v=Barycenter(*(result[i]));
|
|
GLdouble tx,ty,tz;
|
|
gluProject(v.X(),v.Y(),v.Z(), mm,mp,vp, &tx,&ty,&tz);
|
|
if(tx >=0 && tx<screenW && ty >=0 && ty<screenH)
|
|
{
|
|
float bufZ = buffer[int(tx)+int(ty)*screenW];
|
|
//qDebug("face %i txyz (%f %f %f) bufz %f",i,tx,ty,tz,bufZ);
|
|
if(bufZ + LocalEpsilon >= tz)
|
|
resultZ.push_back(result[i]);
|
|
}
|
|
}
|
|
|
|
delete [] buffer;
|
|
return resultZ.size();
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
template <class TETRA_MESH_TYPE>
|
|
class GLPickTetra
|
|
{
|
|
typedef typename TETRA_MESH_TYPE::TetraIterator TetraIterator;
|
|
typedef typename TETRA_MESH_TYPE::TetraPointer TetraPointer;
|
|
typedef typename TETRA_MESH_TYPE::VertexType VertexType;
|
|
|
|
public:
|
|
static bool PickNearestTetra(int x, int y,TETRA_MESH_TYPE &m, TetraIterator &ti,int width=4, int height=4)
|
|
{
|
|
std::vector<TetraPointer> result;
|
|
int val=PickTetra(x,y,m,result,width,height);
|
|
if(val!=0)
|
|
{
|
|
ti=result[0];
|
|
return true;
|
|
}
|
|
ti=0;
|
|
return false;
|
|
}
|
|
|
|
|
|
// class prototype needed for avoid the inclusion of tetra.h
|
|
class Tetra;
|
|
|
|
static int PickTetra(int x, int y, TETRA_MESH_TYPE &m, std::vector<TetraPointer> &result, int width=4, int height=4)
|
|
{
|
|
result.clear();
|
|
long hits;
|
|
int sz=m.tetra.size()*5;
|
|
unsigned int *selectBuf =new unsigned int[sz];
|
|
// static unsigned int selectBuf[16384];
|
|
glSelectBuffer(sz, selectBuf);
|
|
glRenderMode(GL_SELECT);
|
|
glInitNames();
|
|
|
|
/* Because LoadName() won't work with no names on the stack */
|
|
glPushName(-1);
|
|
double mp[16];
|
|
|
|
int viewport[4];
|
|
glGetIntegerv(GL_VIEWPORT,viewport);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glGetDoublev(GL_PROJECTION_MATRIX ,mp);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
//gluPickMatrix(x, viewport[3]-y, 4, 4, viewport);
|
|
gluPickMatrix(x, y, width, height, viewport);
|
|
glMultMatrixd(mp);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
int tetracnt=0;
|
|
TetraIterator ti;
|
|
for(ti=m.tetra.begin();ti!=m.tetra.end();++ti)
|
|
{
|
|
if(!(*ti).IsD())
|
|
{
|
|
glLoadName(tetracnt);
|
|
glBegin(GL_TRIANGLES);
|
|
for (int face=0;face<4;face++)
|
|
{
|
|
//glLoadName(tetracnt);
|
|
VertexType *v0=ti->V(Tetra::VofF(face,0));
|
|
VertexType *v1=ti->V(Tetra::VofF(face,1));
|
|
VertexType *v2=ti->V(Tetra::VofF(face,2));
|
|
glVertex(v0->P());
|
|
glVertex(v1->P());
|
|
glVertex(v2->P());
|
|
|
|
}
|
|
glEnd();
|
|
tetracnt++;
|
|
}
|
|
|
|
}
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
hits = glRenderMode(GL_RENDER);
|
|
//xstring buf;
|
|
//if (hits <= 0) return 0;
|
|
std::vector< std::pair<double,unsigned int> > H;
|
|
int ii;
|
|
for(ii=0;ii<hits;ii++){
|
|
//TRACE("%ui %ui %ui %ui\n",selectBuf[ii*4],selectBuf[ii*4+1],selectBuf[ii*4+2],selectBuf[ii*4+3]);
|
|
H.push_back( std::pair<double,unsigned int>(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3]));
|
|
}
|
|
std::sort(H.begin(),H.end());
|
|
// if(H.size()>0) TRACE("\n Closest is %i\n",H[0].second);
|
|
result.resize(H.size());
|
|
for(ii=0;ii<hits;ii++){
|
|
TetraIterator ti=m.tetra.begin();
|
|
advance(ti ,H[ii].second);
|
|
result[ii]=&*ti;
|
|
}
|
|
|
|
delete [] selectBuf;
|
|
return result.size();
|
|
}
|
|
|
|
static bool PickNearestTetraFace(int x, int y,TETRA_MESH_TYPE &m, TetraIterator &ti,int &face,int width=4, int height=4)
|
|
{
|
|
std::vector<std::pair<TetraPointer,int> > result;
|
|
int val=PickTetraFace(x,y,m,result,width,height);
|
|
if(val!=0)
|
|
{
|
|
ti=result[0].first;
|
|
face=result[0].second;
|
|
return true;
|
|
}
|
|
ti=0;
|
|
face=-1;
|
|
return false;
|
|
}
|
|
|
|
static int PickTetraFace(int x, int y, TETRA_MESH_TYPE &m, std::vector<std::pair<TetraPointer,int> > &result, int width=4, int height=4)
|
|
{
|
|
result.clear();
|
|
long hits;
|
|
int sz=(m.tetra.size()*4)*5;
|
|
unsigned int *selectBuf =new unsigned int[sz];
|
|
// static unsigned int selectBuf[16384];
|
|
glSelectBuffer(sz, selectBuf);
|
|
glRenderMode(GL_SELECT);
|
|
glInitNames();
|
|
|
|
/* Because LoadName() won't work with no names on the stack */
|
|
glPushName(-1);
|
|
double mp[16];
|
|
|
|
int viewport[4];
|
|
glGetIntegerv(GL_VIEWPORT,viewport);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glGetDoublev(GL_PROJECTION_MATRIX ,mp);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
//gluPickMatrix(x, viewport[3]-y, 4, 4, viewport);
|
|
gluPickMatrix(x, y, width, height, viewport);
|
|
glMultMatrixd(mp);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
int tetracnt=0;
|
|
TetraIterator ti;
|
|
VertexType *v0;
|
|
VertexType *v1;
|
|
VertexType *v2;
|
|
int face;
|
|
for(ti=m.tetra.begin();ti!=m.tetra.end();++ti)
|
|
{
|
|
if(!(*ti).IsD())
|
|
{
|
|
for (face=0;face<4;face++){
|
|
v0=ti->V(Tetra::VofF(face,0));
|
|
v1=ti->V(Tetra::VofF(face,1));
|
|
v2=ti->V(Tetra::VofF(face,2));
|
|
glLoadName(tetracnt);
|
|
glBegin(GL_TRIANGLES);
|
|
glVertex(v0->P());
|
|
glVertex(v1->P());
|
|
glVertex(v2->P());
|
|
glEnd();
|
|
tetracnt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
hits = glRenderMode(GL_RENDER);
|
|
//xstring buf;
|
|
//if (hits <= 0) return 0;
|
|
std::vector< std::pair<double,unsigned int> > H;
|
|
int ii;
|
|
for(ii=0;ii<hits;ii++){
|
|
//TRACE("%ui %ui %ui %ui\n",selectBuf[ii*4],selectBuf[ii*4+1],selectBuf[ii*4+2],selectBuf[ii*4+3]);
|
|
H.push_back( std::pair<double,unsigned int>(selectBuf[ii*4+1]/4294967295.0,selectBuf[ii*4+3]));
|
|
}
|
|
std::sort(H.begin(),H.end());
|
|
// if(H.size()>0) TRACE("\n Closest is %i\n",H[0].second);
|
|
result.resize(H.size());
|
|
for(ii=0;ii<hits;ii++){
|
|
TetraIterator ti=m.tetra.begin();
|
|
int index=H[ii].second;
|
|
advance(ti ,(int)(index/4));
|
|
result[ii]=std::pair<TetraPointer,int>(&*ti,index%4);
|
|
}
|
|
|
|
delete [] selectBuf;
|
|
return result.size();
|
|
}
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
#endif
|