mod_geo-tp/src/mesh_viewer.cpp

182 lines
4.1 KiB
C++

#include "mesh_viewer.h"
#include <tgmath.h>
#include <QOpenGLShader>
#include <QOpenGLDebugLogger>
#include <QtGlobal>
MeshViewer::MeshViewer(QWidget *parent) : QOpenGLWidget(parent) {
setMouseTracking(true);
setFocus();
updateViewMatrix();
}
void MeshViewer::updateViewMatrix() {
view = zoom * rot * trans;
}
QSize MeshViewer::sizeHint() const {
return QSize(640, 480);
}
void MeshViewer::initializeGL() {
QOpenGLFunctions *glf = context()->functions();
#ifdef QT_DEBUG
const QSurfaceFormat &format = context()->format();
qDebug("MeshViewer: OpenGL %s%d.%d %s",
format.renderableType() == QSurfaceFormat::OpenGLES ? "ES " : "",
format.majorVersion(), format.minorVersion(),
format.profile() == QSurfaceFormat::CoreProfile ? "core profile"
: (format.profile() == QSurfaceFormat::CompatibilityProfile ? "compatibility profile"
: ""));
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
if (!logger->initialize()) {
qDebug("OpenGL debug output unavailable");
}
connect(logger, &QOpenGLDebugLogger::messageLogged,
[](const QOpenGLDebugMessage &message) {
qDebug() << "OpenGL:" << message.message();
});
logger->startLogging();
#endif
if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex,
":/shader.vert")) {
qFatal("%s", program.log().toUtf8().constData());
}
if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment,
":/shader.frag")) {
qFatal("%s", program.log().toUtf8().constData());
}
if (!program.link()) {
qFatal("%s", program.log().toUtf8().constData());
}
program.bind();
program.setUniformValue("alpha", (GLfloat) 1);
program.setUniformValue("wf_col", WIREFRAME_COLOR);
glf->glClearColor(1, 1, 1, 0);
glf->glEnable(GL_DEPTH_TEST);
glf->glEnable(GL_MULTISAMPLE);
qDebug("MeshViewer: initialization complete");
is_initialized = true;
emit initialized();
}
void MeshViewer::resizeGL(int w, int h) {
proj.setToIdentity();
proj.perspective(FOV, (float) w/h, .01, 100);
program.setUniformValue("proj", proj);
update();
}
void MeshViewer::paintGL() {
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 trans;
program.bind();
program.setUniformValue("view", view);
for (MeshView &m : meshes) {
m.paint(program);
}
}
void MeshViewer::addMesh(MyMesh &mesh) {
Q_ASSERT(isValid());
makeCurrent();
mesh.viewer_id = meshes.size();
meshes.emplace_back(mesh, program);
doneCurrent();
update();
}
void MeshViewer::removeMesh(const MyMesh &mesh) {
makeCurrent();
size_t i = 0;
for (auto it = meshes.begin(); it != meshes.end(); ++it) {
if (i == mesh.viewer_id) {
meshes.erase(it);
break;
}
i++;
}
doneCurrent();
update();
}
void MeshViewer::updateForReal() {
setEnabled(true);
setVisible(true);
update();
repaint();
makeCurrent();
paintGL();
doneCurrent();
}
void MeshViewer::mousePressEvent(QMouseEvent *e) {
if (e->button() & Qt::MiddleButton || e->button() & Qt::RightButton) {
mouse_pos = e->pos();
} else if (e->button() == Qt::LeftButton) {
float x = e->x();
float y = height() - e->y();
float depth;
makeCurrent();
QOpenGLFunctions *glf = context()->functions();
glf->glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
doneCurrent();
QVector3D position {x, y, depth};
position = position.unproject(view, proj, rect());
emit clicked(QVector3D(position));
} else {
e->ignore();
}
}
void MeshViewer::mouseReleaseEvent(QMouseEvent *e) {
(void) e;
}
void MeshViewer::mouseMoveEvent(QMouseEvent *e) {
QPoint delta = e->pos() - mouse_pos;
mouse_pos = e->pos();
if (e->buttons() & Qt::MiddleButton) {
rot.rotate(delta.x() / 5., 0, 1, 0);
rot.rotate(delta.y() / 5., QVector3D(1, 0, 0) * rot);
updateViewMatrix();
update();
}
if (e->buttons() & Qt::RightButton) {
QMatrix4x4 screen_trans;
screen_trans.translate(delta.x() / 1000., -delta.y() / 1000., 0);
trans = rot.inverted() * screen_trans * rot * trans;
// trans(0, 0) = 1;
// trans(0, 1) = 0;
// trans(1, 0) = 0;
// trans(1, 1) = 1;
updateViewMatrix();
update();
}
}
void MeshViewer::wheelEvent(QWheelEvent *e) {
zoom(2, 3) -= e->angleDelta().y() / 1000. * zoom(2, 3);
zoom.optimize();
updateViewMatrix();
update();
}