#include "..\Header\OglViewerWidget.h" #include "..\Header\MainWindow.h" #include #include #include #include #include #define DEFAULT_Z_DISTANCE -4.0 ///////////////////////////////////////////////////////////////////////// // public constructor/destructor OglViewerWidget::OglViewerWidget(QWidget *parent) : QOpenGLWidget(parent), m_dataEngine(0) { setFocus(); m_translation.setZ(DEFAULT_Z_DISTANCE); setAcceptDrops(true); } OglViewerWidget::~OglViewerWidget() { // Make sure the context is current when deleting the texture // and the buffers. makeCurrent(); delete m_dataEngine; doneCurrent(); } ///////////////////////////////////////////////////////////////////////// // protected functions void OglViewerWidget::mousePressEvent(QMouseEvent *e) { // Save mouse press position m_mouse.position = QVector2D(e->localPos()); // Which button has been pressed? if (e->button() == Qt::LeftButton) m_mouse.left = true; else if (e->button() == Qt::RightButton) m_mouse.right = true; } void OglViewerWidget::mouseReleaseEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) m_mouse.left = false; else if (e->button() == Qt::RightButton) m_mouse.right = false; } void OglViewerWidget::mouseMoveEvent(QMouseEvent *e) { if (m_mouse.left) { // get the difference between last press and now QVector2D diff = QVector2D(e->localPos()) - m_mouse.position; // update the new position m_mouse.position = QVector2D(e->localPos()); // calculate the rotation axis and rotate if (m_rotDirections.x && m_rotDirections.y && m_rotDirections.z) { m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(diff.y(), diff.x(), 0.0).normalized(), diff.length() * 0.5) * m_rotation; } else if (m_rotDirections.x && m_rotDirections.y && !m_rotDirections.z) { float pitch, yaw, roll; m_rotation.getEulerAngles(&pitch, &yaw, &roll); pitch += diff.y() * 0.5; yaw += diff.x() * 0.5; if (pitch > 89) pitch = 89; else if (pitch < -89) pitch = -89; m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll); } else if (m_rotDirections.x && !m_rotDirections.y && !m_rotDirections.z) { m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(0.0, 1.0, 0.0).normalized(), diff.x() * 0.5) * m_rotation; } else if (!m_rotDirections.x && m_rotDirections.y && !m_rotDirections.z) { m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(1.0, 0.0, 0.0).normalized(), diff.y() * 0.5) * m_rotation; } else if (!m_rotDirections.x && !m_rotDirections.y && m_rotDirections.z) { m_rotation = QQuaternion::fromAxisAndAngle(QVector3D(0.0, 0.0, 1.0).normalized(), diff.x() * 0.5) * m_rotation; } else if (m_rotDirections.x && !m_rotDirections.y && m_rotDirections.z) { float pitch, yaw, roll; m_rotation.getEulerAngles(&pitch, &yaw, &roll); roll -= diff.y() * 0.5; yaw += diff.x() * 0.5; m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll); } else if (!m_rotDirections.x && m_rotDirections.y && m_rotDirections.z) { float pitch, yaw, roll; m_rotation.getEulerAngles(&pitch, &yaw, &roll); pitch += diff.y() * 0.5; roll += diff.x() * 0.5; if (pitch > 89) pitch = 89; else if (pitch < -89) pitch = -89; m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll); } // request an update update(); } else if (m_mouse.right) { // get the difference between last press and now QVector2D diff = QVector2D(e->localPos()) - m_mouse.position; // update the new position m_mouse.position = QVector2D(e->localPos()); // calculate the translation m_translation += {(float)(diff.x() * 0.01), (float)(diff.y() * -0.01), 0.0}; // request an update update(); } } void OglViewerWidget::wheelEvent(QWheelEvent *e) { m_translation += {0.0, 0.0, (float)e->angleDelta().y() / 240}; update(); } void OglViewerWidget::dragEnterEvent(QDragEnterEvent *e) { if (e->mimeData()->hasUrls()) if(e->mimeData()->urls().size() == 1) if(e->mimeData()->urls().first().toLocalFile().endsWith(".msh")) e->acceptProposedAction(); } void OglViewerWidget::dropEvent(QDropEvent * e) { emit loadFile(e->mimeData()->urls().first().toLocalFile()); } void OglViewerWidget::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Space) { resetView(); } else if (e->key() == Qt::Key_Escape) { parentWidget()->close(); } } void OglViewerWidget::initializeGL() { initializeOpenGLFunctions(); glClearColor(0.5000f, 0.8000f, 1.0000f, 0.0000f); initShaders(); // Enable depth buffer glEnable(GL_DEPTH_TEST); // Enable back face culling //glEnable(GL_CULL_FACE); // Enable transparency glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); m_dataEngine = new GeometryEngine(this); setConnections(); } void OglViewerWidget::resizeGL(int w, int h) { // Calculate aspect ratio qreal aspect = qreal(w) / qreal(h ? h : 1); // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees const qreal zNear = 0.1, zFar = 100.0, fov = 45.0; // Reset projection m_projection.setToIdentity(); // Set perspective projection m_projection.perspective(fov, aspect, zNear, zFar); } void OglViewerWidget::paintGL() { // Clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Calculate model view transformation QMatrix4x4 view; view.translate(m_translation); view.rotate(m_rotation); // Set view-projection matrix m_program.setUniformValue("vp_matrix", m_projection * view); // Draw cube geometry m_dataEngine->drawGeometry(&m_program, m_wireframe); } ///////////////////////////////////////////////////////////////////////// // private functions void OglViewerWidget::initShaders() { // Compile vertex shader if (!m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl")) close(); // Compile fragment shader if (!m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl")) close(); // Link shader pipeline if (!m_program.link()) close(); // Bind shader pipeline for use if (!m_program.bind()) close(); } void OglViewerWidget::setConnections() { connect(m_dataEngine, &GeometryEngine::requestResetView, this, &OglViewerWidget::resetView); connect(parentWidget(), SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString))); connect(this, SIGNAL(loadFile(QString)), m_dataEngine, SLOT(loadFile(QString))); connect(m_dataEngine, SIGNAL(sendMessage(QString, int)), parentWidget(), SLOT(printMessage(QString, int))); connect(m_dataEngine, SIGNAL(requestUpdate()), this, SLOT(update())); connect(m_dataEngine, SIGNAL(sendFileInfo(QString, QVector*, int, int)), parentWidget(), SLOT(setFileInfo(QString, QVector*, int, int))); } ///////////////////////////////////////////////////////////////////////// // private slots void OglViewerWidget::resetView() { m_rotation = QQuaternion(); m_translation = { 0.0, 0.0, DEFAULT_Z_DISTANCE }; update(); } ///////////////////////////////////////////////////////////////////////// // public slots void OglViewerWidget::changeDirection(int direction) { switch (direction) { case 1: m_rotDirections.x = !m_rotDirections.x; break; case 2: m_rotDirections.y = !m_rotDirections.y; break; case 3: m_rotDirections.z = !m_rotDirections.z; break; } } void OglViewerWidget::toggleWireframe() { m_wireframe = 1 - m_wireframe; update(); }