This repository has been archived on 2020-03-10. You can view files and clone it, but cannot push or open issues or pull requests.
mgm-tp1/meshviewerwidget.cpp
2020-03-04 10:41:03 +01:00

384 lines
12 KiB
C++

#include "meshviewerwidget.h"
MeshViewerWidget::MeshViewerWidget(QWidget*_parent) : QGLWidget(_parent)
{
triToDraw = 0;
linesToDraw = 0;
pointsToDraw = 0;
setMouseTracking(true);
setFocus();
}
MeshViewerWidget::MeshViewerWidget( QGLFormat& _fmt, QWidget* _parent ) : QGLWidget( _fmt, _parent )
{
setMouseTracking(true);
setFocus();
}
void MeshViewerWidget::initializeGL()
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glEnable( GL_DEPTH_TEST );
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_);
set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0);
glEnable( GL_MULTISAMPLE );
}
void MeshViewerWidget::translate( const OpenMesh::Vec3f& _trans )
{
glLoadIdentity();
glTranslated( _trans[0], _trans[1], _trans[2] );
glMultMatrixd( modelview_matrix_ );
glGetDoublev( GL_MODELVIEW_MATRIX, modelview_matrix_);
}
void MeshViewerWidget::resizeGL( int _w, int _h )
{
update_projection_matrix();
glViewport(0, 0, _w, _h);
updateGL();
}
void MeshViewerWidget::reloadPOV()
{
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_);
set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0);
updateGL();
}
void MeshViewerWidget::loadMesh(GLfloat* verts, GLfloat* colors, int nVerts, GLuint* triangles, int nTriangles)
{
GLfloat* vertsColsArray = new GLfloat[nVerts * 2];
for(int i = 0; i < nVerts; i = i + 3)
{
int j = 2 * i;
vertsColsArray[j] = colors[i] / 255.0;
vertsColsArray[j+1] = colors[i+1] / 255.0;
vertsColsArray[j+2] = colors[i+2] / 255.0;
vertsColsArray[j+3] = verts[i];
vertsColsArray[j+4] = verts[i+1];
vertsColsArray[j+5] = verts[i+2];
}
glGenBuffers( 2, TriDataBuffers );
glBindBuffer(GL_ARRAY_BUFFER, TriDataBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, nVerts * 2 * sizeof(GLfloat), vertsColsArray, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, TriDataBuffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nTriangles * sizeof(GLuint), triangles, GL_STATIC_DRAW);
triToDraw = nTriangles;
init = true;
delete[] vertsColsArray;
updateGL();
}
void MeshViewerWidget::loadLines(GLfloat* verts, GLfloat* colors, int nVerts, GLuint* lines, int nLines, QList<QPair<float, int> > es)
{
GLfloat* linesColsArray = new GLfloat[nVerts * 2];
for(int i = 0; i < nVerts; i = i + 3)
{
int j = 2 * i;
linesColsArray[j] = colors[i] / 255.0;
linesColsArray[j+1] = colors[i+1] / 255.0;
linesColsArray[j+2] = colors[i+2] / 255.0;
linesColsArray[j+3] = verts[i];
linesColsArray[j+4] = verts[i+1];
linesColsArray[j+5] = verts[i+2];
}
glGenBuffers( 2, LinesDataBuffers );
glBindBuffer(GL_ARRAY_BUFFER, LinesDataBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, nVerts * 2 * sizeof(GLfloat), linesColsArray, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, LinesDataBuffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nLines * sizeof(GLuint), lines, GL_STATIC_DRAW);
linesToDraw = nLines;
edgeSizes = es;
delete[] linesColsArray;
updateGL();
}
void MeshViewerWidget::loadPoints(GLfloat* verts, GLfloat* colors, int nVerts, GLuint* points, int nPoints, QList<QPair<float, int> > vs)
{
GLfloat* pointsColsArray = new GLfloat[nVerts * 2];
for(int i = 0; i < nVerts; i = i + 3)
{
int j = 2 * i;
pointsColsArray[j] = colors[i] / 255.0;
pointsColsArray[j+1] = colors[i+1] / 255.0;
pointsColsArray[j+2] = colors[i+2] / 255.0;
pointsColsArray[j+3] = verts[i];
pointsColsArray[j+4] = verts[i+1];
pointsColsArray[j+5] = verts[i+2];
}
glGenBuffers( 2, PointsDataBuffers );
glBindBuffer(GL_ARRAY_BUFFER, PointsDataBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, nVerts * 2 * sizeof(GLfloat), pointsColsArray, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, PointsDataBuffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nPoints * sizeof(GLuint), points, GL_STATIC_DRAW);
pointsToDraw = nPoints;
vertsSizes = vs;
delete[] pointsColsArray;
updateGL();
}
void MeshViewerWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadMatrixd( projection_matrix_ );
glMatrixMode( GL_MODELVIEW );
glLoadMatrixd( modelview_matrix_ );
if(triToDraw != 0)
{
glPolygonOffset(1.0, 2);
// on charge le buffer 0 : une liste de vertex [r, g, b, x, y, z] (6 float)
glBindBuffer(GL_ARRAY_BUFFER, TriDataBuffers[0]);
// on charge la partie [r, g, b]
glColorPointer( 3, GL_FLOAT, 6 * sizeof(float), 0 );
// on charge la partie [x, y, z]
glVertexPointer( 3, GL_FLOAT, 6 * sizeof(float), ((float*)NULL + (3)) );
// on charge le buffer 1 : une liste d'ID [v0, v1, v2] (3 int)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, TriDataBuffers[1]);
glEnableClientState( GL_VERTEX_ARRAY );
// affiche les faces en GL_COLOR_ARRAY
glEnableClientState( GL_COLOR_ARRAY );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glEnable(GL_POLYGON_OFFSET_FILL);
glDrawElements(GL_TRIANGLES, triToDraw, GL_UNSIGNED_INT, 0);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
}
if(linesToDraw != 0)
{
// on charge le buffer 0 : une liste de vertex [r, g, b, x, y, z] (6 float)
glBindBuffer(GL_ARRAY_BUFFER, LinesDataBuffers[0]);
// on charge la partie [r, g, b]
glColorPointer( 3, GL_FLOAT, 6 * sizeof(float), 0 );
// on charge la partie [x, y, z]
glVertexPointer( 3, GL_FLOAT, 6 * sizeof(float), ((float*)NULL + (3)) );
// on charge le buffer 1 : une liste d'ID [v0, v1] (2 int)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, LinesDataBuffers[1]);
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
int cur = 0;
for(int i = 0; i < edgeSizes.count(); i++)
{
glLineWidth(edgeSizes.at(i).first);
glDrawElements(GL_LINES, edgeSizes.at(i).second*2, GL_UNSIGNED_INT, (GLvoid*)(sizeof(GLfloat) * cur));
cur = cur + edgeSizes.at(i).second*2;
}
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
}
if(pointsToDraw != 0)
{
// on charge le buffer 0 : une liste de vertex [r, g, b, x, y, z] (6 float)
glBindBuffer(GL_ARRAY_BUFFER, PointsDataBuffers[0]);
// on charge la partie [r, g, b]
glColorPointer( 3, GL_FLOAT, 6 * sizeof(float), 0 );
// on charge la partie [x, y, z]
glVertexPointer( 3, GL_FLOAT, 6 * sizeof(float), ((float*)NULL + (3)) );
// on charge le buffer 1 : une liste d'ID [v0] (1 int)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, PointsDataBuffers[1]);
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
int cur = 0;
for(int i = 0; i < vertsSizes.count(); i++)
{
glPointSize(vertsSizes.at(i).first);
glDrawElements(GL_POINTS, vertsSizes.at(i).second, GL_UNSIGNED_INT, (GLvoid*)(sizeof(GLfloat) * cur));
cur = cur + vertsSizes.at(i).second;
}
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
}
}
void MeshViewerWidget::set_scene_pos( const OpenMesh::Vec3f& _cog, float _radius )
{
center_ = _cog;
radius_ = _radius;
update_projection_matrix();
view_all();
}
void MeshViewerWidget::update_projection_matrix()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(45.0, (GLfloat) width() / (GLfloat) height(), 0.01*radius_, 100.0*radius_);
glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix_);
glMatrixMode( GL_MODELVIEW );
}
void MeshViewerWidget::view_all()
{
translate( Vec3f( -(modelview_matrix_[0]*center_[0] + modelview_matrix_[4]*center_[1] + modelview_matrix_[8]*center_[2] + modelview_matrix_[12]), -(modelview_matrix_[1]*center_[0] + modelview_matrix_[5]*center_[1] + modelview_matrix_[9]*center_[2] + modelview_matrix_[13]), -(modelview_matrix_[2]*center_[0] + modelview_matrix_[6]*center_[1] + modelview_matrix_[10]*center_[2] + modelview_matrix_[14] + 3.0*radius_) ) );
}
void MeshViewerWidget::mousePressEvent( QMouseEvent* _event )
{
last_point_ok_ = map_to_sphere( last_point_2D_=_event->pos(), last_point_3D_ );
}
void MeshViewerWidget::mouseMoveEvent( QMouseEvent* _event )
{
QPoint newPoint2D = _event->pos();
Vec3f newPoint3D;
bool newPoint_hitSphere = map_to_sphere( newPoint2D, newPoint3D );
float dx = newPoint2D.x() - last_point_2D_.x();
float dy = newPoint2D.y() - last_point_2D_.y();
float w = width();
float h = height();
if ( (_event->buttons() == (Qt::LeftButton+Qt::MidButton)) || (_event->buttons() == Qt::LeftButton && _event->modifiers() == Qt::ControlModifier))
{
float value_y = radius_ * dy * 3.0 / h;
translate(Vec3f(0.0, 0.0, value_y));
}
else if ( (_event->buttons() == Qt::MidButton) || (_event->buttons() == Qt::LeftButton && _event->modifiers() == Qt::AltModifier) )
{
float z = - (modelview_matrix_[ 2]*center_[0] + modelview_matrix_[ 6]*center_[1] + modelview_matrix_[10]*center_[2] + modelview_matrix_[14]) / (modelview_matrix_[ 3]*center_[0] + modelview_matrix_[ 7]*center_[1] + modelview_matrix_[11]*center_[2] + modelview_matrix_[15]);
float aspect = w / h;
float near_plane = 0.01 * radius_;
float top = tan(45.0f/2.0f*M_PI/180.0f) * near_plane;
float right = aspect*top;
translate(Vec3f( 2.0*dx/w*right/near_plane*z, -2.0*dy/h*top/near_plane*z, 0.0f));
}
else if (_event->buttons() == Qt::LeftButton)
{
if (last_point_ok_)
{
if ((newPoint_hitSphere = map_to_sphere(newPoint2D, newPoint3D)))
{
Vec3f axis = last_point_3D_ % newPoint3D;
if (axis.sqrnorm() < 1e-7)
axis = Vec3f(1, 0, 0);
else
axis.normalize();
Vec3f d = last_point_3D_ - newPoint3D;
float t = 0.5 * d.norm() / TRACKBALL_RADIUS;
if (t < -1.0)
t = -1.0;
else if (t > 1.0)
t = 1.0;
float phi = 2.0 * asin(t);
float angle = phi * 180.0 / M_PI;
rotate(axis, angle);
}
}
}
last_point_2D_ = newPoint2D;
last_point_3D_ = newPoint3D;
last_point_ok_ = newPoint_hitSphere;
updateGL();
}
void MeshViewerWidget::mouseReleaseEvent( QMouseEvent* /* _event */ )
{
last_point_ok_ = false;
}
void MeshViewerWidget::wheelEvent(QWheelEvent* _event)
{
float d = -(float)_event->delta() / 120.0 * 0.2 * radius_;
translate(Vec3f(0.0, 0.0, d));
updateGL();
_event->accept();
}
bool MeshViewerWidget::map_to_sphere( const QPoint& _v2D, OpenMesh::Vec3f& _v3D )
{
double x = (2.0*_v2D.x() - width())/width();
double y = -(2.0*_v2D.y() - height())/height();
double xval = x;
double yval = y;
double x2y2 = xval*xval + yval*yval;
const double rsqr = TRACKBALL_RADIUS*TRACKBALL_RADIUS;
_v3D[0] = xval;
_v3D[1] = yval;
if (x2y2 < 0.5*rsqr)
_v3D[2] = sqrt(rsqr - x2y2);
else
_v3D[2] = 0.5*rsqr/sqrt(x2y2);
return true;
}
void MeshViewerWidget::rotate( const OpenMesh::Vec3f& _axis, float _angle )
{
Vec3f t( modelview_matrix_[0]*center_[0] + modelview_matrix_[4]*center_[1] + modelview_matrix_[8]*center_[2] + modelview_matrix_[12], modelview_matrix_[1]*center_[0] + modelview_matrix_[5]*center_[1] + modelview_matrix_[9]*center_[2] + modelview_matrix_[13], modelview_matrix_[2]*center_[0] + modelview_matrix_[6]*center_[1] + modelview_matrix_[10]*center_[2] + modelview_matrix_[14] );
glLoadIdentity();
glTranslatef(t[0], t[1], t[2]);
glRotated( _angle, _axis[0], _axis[1], _axis[2]);
glTranslatef(-t[0], -t[1], -t[2]);
glMultMatrixd(modelview_matrix_);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_);
}