diff --git a/QtMeshViewer/Form Files/FileInfoWindow.ui b/QtMeshViewer/Form Files/FileInfoWindow.ui index 8c4793b..c7f45bf 100644 --- a/QtMeshViewer/Form Files/FileInfoWindow.ui +++ b/QtMeshViewer/Form Files/FileInfoWindow.ui @@ -47,6 +47,9 @@ Triangles: - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + diff --git a/QtMeshViewer/Header/FileInfoWindow.h b/QtMeshViewer/Header/FileInfoWindow.h index a48bad1..566accf 100644 --- a/QtMeshViewer/Header/FileInfoWindow.h +++ b/QtMeshViewer/Header/FileInfoWindow.h @@ -1,6 +1,5 @@ #pragma once #include -#include #include "ui_FileInfoWindow.h" class FileInfoWindow : public QWidget @@ -8,13 +7,21 @@ class FileInfoWindow : public QWidget Q_OBJECT public: - FileInfoWindow(QWidget *parent = Q_NULLPTR); - ~FileInfoWindow(); + FileInfoWindow(QWidget *parent = Q_NULLPTR) + : QWidget(parent) + , ui(new Ui::FileInfoWindow) + { + ui->setupUi(this); + setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint); + ui->scrollArea->widget()->setStyleSheet("background-color: #ffffff"); + }; + + ~FileInfoWindow() { delete ui; }; private: Ui::FileInfoWindow* ui; public: - void setBasicText(QString text); - void setDetailText(QString text); + void setBasicText(QString text) { ui->basic->setText(text); }; + void setDetailText(QString text) { ui->detail->setText(text); }; }; \ No newline at end of file diff --git a/QtMeshViewer/Header/FileInterface.h b/QtMeshViewer/Header/FileInterface.h index 3c040de..4dbed75 100644 --- a/QtMeshViewer/Header/FileInterface.h +++ b/QtMeshViewer/Header/FileInterface.h @@ -1,17 +1,13 @@ #pragma once +#include +#include #include #include #include -#include #include #include -#include -#include -#include -#include #include -#include <..\Header\MainWindow.h> - +#include "MainWindow.h" struct BoundingBox { QQuaternion rotation; diff --git a/QtMeshViewer/Header/GeometryEngine.h b/QtMeshViewer/Header/GeometryEngine.h index 9cd09b2..8542415 100644 --- a/QtMeshViewer/Header/GeometryEngine.h +++ b/QtMeshViewer/Header/GeometryEngine.h @@ -1,11 +1,11 @@ #pragma once -#include "..\Header\FileInterface.h" #include #include #include #include -#include #include +#include "FileInterface.h" + struct DrawInformation { unsigned int offset; @@ -22,20 +22,28 @@ public: GeometryEngine(QObject *parent = Q_NULLPTR); virtual ~GeometryEngine(); +// attributes private: QOpenGLBuffer m_arrayBuf; QOpenGLBuffer m_indexBuf; QVector* m_materials = Q_NULLPTR; - QVector m_drawList; - BoundingBox m_boundings; Material* m_defaultMaterial; + BoundingBox m_boundings; + QVector m_drawList; +// functions +private: void clearData(); -public slots: - void loadFile(QString filePath); +public: void drawGeometry(QOpenGLShaderProgram *program, bool wireframe); +// slots +public slots: + void loadFile(QString filePath); + + +// signals signals: void requestResetView(); void sendMessage(QString message, int severity); diff --git a/QtMeshViewer/Header/MainWindow.h b/QtMeshViewer/Header/MainWindow.h index bd86804..eba0e06 100644 --- a/QtMeshViewer/Header/MainWindow.h +++ b/QtMeshViewer/Header/MainWindow.h @@ -1,12 +1,11 @@ #pragma once - #include -#include -#include -#include -#include +#include #include "ui_MainWindow.h" -#include "..\Header\FileInfoWindow.h" +#include "FileInfoWindow.h" +#include +#include + struct Material; @@ -18,27 +17,32 @@ public: MainWindow(QWidget *parent = Q_NULLPTR); ~MainWindow(); +// attributes private: Ui::MainWindowClass* ui; - int m_curSeverity; - void setupWidgets(); + QByteArray m_fileInfo; QLabel* m_output; + int m_curSeverity; + FileInfoWindow* m_infoWindow; +// functions private: + void setupWidgets(); void openFile(); - void aboutFile(); - void aboutTool(); void takeScreenShot(); + void aboutTool(); protected: virtual void resizeEvent(QResizeEvent * e) Q_DECL_OVERRIDE; +// slots public slots: void printMessage(QString message, int severity); void setFileInfo(QString name, QVector* materials, int vertices, int triangle); +// signals signals: void loadFile(QString); }; diff --git a/QtMeshViewer/Header/OglViewerWidget.h b/QtMeshViewer/Header/OglViewerWidget.h index 3c84a3b..ed77ed1 100644 --- a/QtMeshViewer/Header/OglViewerWidget.h +++ b/QtMeshViewer/Header/OglViewerWidget.h @@ -1,14 +1,10 @@ #pragma once - -#include "geometryengine.h" -#include "..\Header\SettingsWindow.h" #include #include -#include -#include -#include -#include #include +#include +#include "GeometryEngine.h" +#include "SettingsWindow.h" class GeometryEngine; @@ -21,10 +17,26 @@ public: explicit OglViewerWidget(QWidget *parent = 0); ~OglViewerWidget(); -signals: - void loadFile(QString); - +// attributes private: + QOpenGLShaderProgram m_program; + GeometryEngine *m_dataEngine; + + QVector4D m_backgroundColorOn = { 0.02f, 0.02f, 0.02f, 1.0f }; + QVector4D m_backgroundColorOff = { 0.5f, 0.8f, 1.0f, 1.0f }; + + bool m_wireframe = false; + bool m_lightOn = false; + + struct { + QVector4D position = { 1,1,1,0 }; + QVector3D intensities = { 1.0,1.0,1.0 }; + float attenuationFactor = 0.0f; + float ambientCoefficient = 0.005f; + } m_light; + + SettingsWindow* m_settings; + struct { bool left = false; bool right = false; @@ -37,53 +49,37 @@ private: bool z = true; } m_rotDirections; - struct { - QVector4D position = { 1,1,1,0 }; - QVector3D intensities = { 1.0,1.0,1.0 }; - float attenuationFactor = 0.0f; - float ambientCoefficient = 0.005f; - } m_light; - - SettingsWindow* m_settings; - - QVector4D m_backgroundColorOn = {0.02f, 0.02f, 0.02f, 1.0f}; - QVector4D m_backgroundColorOff = { 0.5f, 0.8f, 1.0f, 1.0f }; - - QOpenGLShaderProgram m_program; - GeometryEngine *m_dataEngine; - QMatrix4x4 m_projection; QVector3D m_translation; QQuaternion m_rotation; - bool m_wireframe = false; - bool m_lightOn = false; - double m_zSpeed = 1.0; -protected: - void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; - void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; - void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE; - void wheelEvent(QWheelEvent *e) Q_DECL_OVERRIDE; - void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE; - void dropEvent(QDropEvent * event) Q_DECL_OVERRIDE; - void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE; +// functions +private: + void initShaders(); + void setConnections(); + void resetView(); + void updateLightPosition(); +protected: void initializeGL() Q_DECL_OVERRIDE; void resizeGL(int w, int h) Q_DECL_OVERRIDE; void paintGL() Q_DECL_OVERRIDE; -private: - void initShaders(); - void setConnections(); - void updateLightPosition(); + void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void wheelEvent(QWheelEvent *e) Q_DECL_OVERRIDE; + + void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE; -private slots: - void resetView(); + void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent * event) Q_DECL_OVERRIDE; +// slots public slots: - void changeDirection(int direction); + void toggleAxis(int axis); void toggleWireframe(); void toggleLight(); void showSettings(); @@ -93,7 +89,9 @@ public slots: void setAttFac(double value); void setAmbCoef(double value); +// signals signals: void sendMessage(QString message, int severity); + void loadFile(QString); }; diff --git a/QtMeshViewer/Header/SettingsWindow.h b/QtMeshViewer/Header/SettingsWindow.h index 30cd517..26a5963 100644 --- a/QtMeshViewer/Header/SettingsWindow.h +++ b/QtMeshViewer/Header/SettingsWindow.h @@ -3,6 +3,7 @@ #include "ui_SettingsWindow.h" #include + class SettingsWindow : public QWidget { Q_OBJECT diff --git a/QtMeshViewer/Header/tga.h b/QtMeshViewer/Header/tga.h index 0c560bd..c95e82c 100644 --- a/QtMeshViewer/Header/tga.h +++ b/QtMeshViewer/Header/tga.h @@ -3,7 +3,6 @@ #include #include -#include QImage loadTga(QString filePath, bool &success) { @@ -67,7 +66,7 @@ QImage loadTga(QString filePath, bool &success) int valb = vui8Pixels.at(y * ui32Width * ui32BpP / 8 + x * ui32BpP / 8); QColor value(valr, valg, valb); - img.setPixelColor(x, ui32Width - 1 - y, value); + img.setPixel(x, ui32Width - 1 - y, value.rgba()); } } } @@ -97,7 +96,7 @@ QImage loadTga(QString filePath, bool &success) else color.setRgb(qRgb(tempData[2], tempData[1], tempData[0])); - img.setPixelColor(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color); + img.setPixel(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color.rgba()); tmp_pixelIndex++; } } @@ -117,7 +116,7 @@ QImage loadTga(QString filePath, bool &success) else color.setRgb(qRgb(tempData[2], tempData[1], tempData[0])); - img.setPixelColor(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color); + img.setPixel(tmp_pixelIndex % ui32Width, ui32Height - 1 - (tmp_pixelIndex / ui32Width), color.rgba()); tmp_pixelIndex++; } } diff --git a/QtMeshViewer/Resources/StyleSheet.txt b/QtMeshViewer/Resources/StyleSheet.txt index b36e3a9..414040a 100644 --- a/QtMeshViewer/Resources/StyleSheet.txt +++ b/QtMeshViewer/Resources/StyleSheet.txt @@ -1,3 +1,9 @@ +QLabel#output { + color : white; + min-width: 400px; + min-height: 50px; +} + QToolButton { image: url(:/images/toolbar/placeholder.png); border-style: none; diff --git a/QtMeshViewer/Source/FileInfoWindow.cpp b/QtMeshViewer/Source/FileInfoWindow.cpp deleted file mode 100644 index 47e19af..0000000 --- a/QtMeshViewer/Source/FileInfoWindow.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "..\Header\FileInfoWindow.h" -#include - -FileInfoWindow::FileInfoWindow(QWidget *parent) - : QWidget(parent) - , ui(new Ui::FileInfoWindow) -{ - ui->setupUi(this); - - setWindowFlags(Qt::Tool | Qt::NoDropShadowWindowHint); - - ui->scrollArea->widget()->setStyleSheet("background-color: #ffffff"); - -} - -FileInfoWindow::~FileInfoWindow() -{ - delete ui; -} - -void FileInfoWindow::setBasicText(QString text) -{ - ui->basic->setText(text); -} - -void FileInfoWindow::setDetailText(QString text) -{ - ui->detail->setText(text); -} diff --git a/QtMeshViewer/Source/GeometryEngine.cpp b/QtMeshViewer/Source/GeometryEngine.cpp index 65bff18..80549ba 100644 --- a/QtMeshViewer/Source/GeometryEngine.cpp +++ b/QtMeshViewer/Source/GeometryEngine.cpp @@ -2,20 +2,18 @@ #include "..\Header\MshFile.h" #include "..\Header\OglViewerWidget.h" #include "..\Header\MainWindow.h" -#include #include ///////////////////////////////////////////////////////////////////////// -// public constructor/destructor +// constructor/destructor GeometryEngine::GeometryEngine(QObject *parent) : QObject(parent) , m_indexBuf(QOpenGLBuffer::IndexBuffer) + , m_defaultMaterial(FileInterface::getDefaultMaterial()) { initializeOpenGLFunctions(); - - m_defaultMaterial = FileInterface::getDefaultMaterial(); } GeometryEngine::~GeometryEngine() @@ -27,7 +25,7 @@ GeometryEngine::~GeometryEngine() ///////////////////////////////////////////////////////////////////////// -// private functions +// functions void GeometryEngine::clearData() { @@ -52,9 +50,100 @@ void GeometryEngine::clearData() m_drawList.clear(); } +void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program, bool wireframe) +{ + if (!m_arrayBuf.isCreated() || !m_indexBuf.isCreated()) + return; + + // Setup + // Tell OpenGL which VBOs to use + m_arrayBuf.bind(); + m_indexBuf.bind(); + + // Allways normalize by this + QMatrix4x4 normMatrix; + float maxExtent = std::max(std::max(m_boundings.extents[0], m_boundings.extents[1]), m_boundings.extents[2]); + normMatrix.scale(1 / maxExtent); + normMatrix.translate(-m_boundings.center[0], -m_boundings.center[1], -m_boundings.center[2]); + program->setUniformValue("norm_matrix", normMatrix); + + // Allways use texture unit 0 + program->setUniformValue("texture", 0); + + // Offset for position + quintptr offset = 0; + + // Tell OpenGL programmable pipeline how to locate vertex position data + int vertexLocation = program->attributeLocation("a_position"); + program->enableAttributeArray(vertexLocation); + program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); + + // Offset for texture coordinate + offset += sizeof(QVector3D); + + // Tell OpenGL programmable pipeline how to locate vertex texture coordinate data + int texcoordLocation = program->attributeLocation("a_texcoord"); + program->enableAttributeArray(texcoordLocation); + program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData)); + + //Offset for normal + offset += sizeof(QVector2D); + + // Tell OpenGL programmable pipeline how to locate vertex normal data + int normLocation = program->attributeLocation("a_normal"); + program->enableAttributeArray(normLocation); + program->setAttributeBuffer(normLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); + + // Paint + + for (auto& it : m_drawList) + { + bool tmp_transparent(false); + bool tmp_specular(false); + float shininess(0.0); + QVector3D specularColor; + + // bind the correct texture + if (it.textureIndex < (unsigned)m_materials->size() && m_materials->at(it.textureIndex).texture0 != Q_NULLPTR) + { + m_materials->at(it.textureIndex).texture0->bind(); + tmp_transparent = m_materials->at(it.textureIndex).transparent; + tmp_specular = m_materials->at(it.textureIndex).flags[7]; + shininess = m_materials->at(it.textureIndex).shininess; + specularColor = m_materials->at(it.textureIndex).specularColor.toVector3D(); + } + else + { + m_defaultMaterial->texture0->bind(); + tmp_transparent = m_defaultMaterial->transparent; + } + // Set model matrix + program->setUniformValue("m_matrix", it.modelMatrix); + + // Set normal matrix + program->setUniformValue("n_matrix", (normMatrix * it.modelMatrix).normalMatrix()); + + // set some more values + program->setUniformValue("b_transparent", tmp_transparent); + program->setUniformValue("b_specular", tmp_specular); + + // set some material attributes + program->setUniformValue("materialShininess", shininess); + program->setUniformValue("materialSpecularColor", specularColor); + + // Draw cube geometry using indices from VBO 1 + if (wireframe) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint))); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +} + ///////////////////////////////////////////////////////////////////////// -// public slots +// slots void GeometryEngine::loadFile(QString filePath) { @@ -134,94 +223,3 @@ void GeometryEngine::loadFile(QString filePath) } } -void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program, bool wireframe) -{ - if (!m_arrayBuf.isCreated() || !m_indexBuf.isCreated()) - return; - -// Setup - // Tell OpenGL which VBOs to use - m_arrayBuf.bind(); - m_indexBuf.bind(); - - // Allways normalize by this - QMatrix4x4 normMatrix; - float maxExtent = std::max(std::max(m_boundings.extents[0], m_boundings.extents[1]), m_boundings.extents[2]); - normMatrix.scale(1 / maxExtent); - normMatrix.translate(-m_boundings.center[0], -m_boundings.center[1], -m_boundings.center[2]); - program->setUniformValue("norm_matrix", normMatrix); - - // Allways use texture unit 0 - program->setUniformValue("texture", 0); - - // Offset for position - quintptr offset = 0; - - // Tell OpenGL programmable pipeline how to locate vertex position data - int vertexLocation = program->attributeLocation("a_position"); - program->enableAttributeArray(vertexLocation); - program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); - - // Offset for texture coordinate - offset += sizeof(QVector3D); - - // Tell OpenGL programmable pipeline how to locate vertex texture coordinate data - int texcoordLocation = program->attributeLocation("a_texcoord"); - program->enableAttributeArray(texcoordLocation); - program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData)); - - //Offset for normal - offset += sizeof(QVector2D); - - // Tell OpenGL programmable pipeline how to locate vertex normal data - int normLocation = program->attributeLocation("a_normal"); - program->enableAttributeArray(normLocation); - program->setAttributeBuffer(normLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); - -// Paint - - for (auto& it : m_drawList) - { - bool tmp_transparent(false); - bool tmp_specular(false); - float shininess(0.0); - QVector3D specularColor; - - // bind the correct texture - if (it.textureIndex < (unsigned) m_materials->size() && m_materials->at(it.textureIndex).texture0 != Q_NULLPTR) - { - m_materials->at(it.textureIndex).texture0->bind(); - tmp_transparent = m_materials->at(it.textureIndex).transparent; - tmp_specular = m_materials->at(it.textureIndex).flags[7]; - shininess = m_materials->at(it.textureIndex).shininess; - specularColor = m_materials->at(it.textureIndex).specularColor.toVector3D(); - } - else - { - m_defaultMaterial->texture0->bind(); - tmp_transparent = m_defaultMaterial->transparent; - } - // Set model matrix - program->setUniformValue("m_matrix", it.modelMatrix); - - // Set normal matrix - program->setUniformValue("n_matrix", (normMatrix * it.modelMatrix).normalMatrix()); - - // set some more values - program->setUniformValue("b_transparent", tmp_transparent); - program->setUniformValue("b_specular", tmp_specular); - - // set some material attributes - program->setUniformValue("materialShininess", shininess); - program->setUniformValue("materialSpecularColor", specularColor); - - // Draw cube geometry using indices from VBO 1 - if(wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint))); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -} - diff --git a/QtMeshViewer/Source/MainWindow.cpp b/QtMeshViewer/Source/MainWindow.cpp index 01b1f07..d09568e 100644 --- a/QtMeshViewer/Source/MainWindow.cpp +++ b/QtMeshViewer/Source/MainWindow.cpp @@ -1,32 +1,37 @@ #include "..\Header\MainWindow.h" #include "..\Header\OglViewerWidget.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "..\Header\FileInterface.h" +#include +#include +#include +#include +#include +#include +#include +#include #define WINDOW_NAME "Mesh Viewer" + +///////////////////////////////////////////////////////////////////////// +// constructor/destructor + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindowClass) - , m_curSeverity(0) , m_output(new QLabel(this)) + , m_curSeverity(0) , m_infoWindow(new FileInfoWindow(this)) { + // setup window ui->setupUi(this); setWindowTitle(WINDOW_NAME); setWindowIcon(QIcon(":/images/icon.ico")); + printMessage("MeshViewer by Anakin", 0); + + // setup opengl things QSurfaceFormat format; format.setDepthBufferSize(24); format.setMajorVersion(2); @@ -34,12 +39,13 @@ MainWindow::MainWindow(QWidget *parent) format.setProfile(QSurfaceFormat::NoProfile); QSurfaceFormat::setDefaultFormat(format); + // set default text to file info + m_fileInfo = "Filename: -\nMaterials: -\nVertices: -\nTriangle: -No file is open"; + + // add widgets to the window setupWidgets(); - printMessage("MeshViewer by Anakin", 0); - - m_fileInfo += "Filename: -\nMaterials: -\nVertices: -\nTriangle: -No file is open"; - + // load stylesheet QFile styleSheet(":/files/StyleSheet.txt"); styleSheet.open(QIODevice::ReadOnly); this->setStyleSheet(styleSheet.readAll()); @@ -52,35 +58,37 @@ MainWindow::~MainWindow() delete m_infoWindow; } -void MainWindow::openFile() -{ - QString fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Mesh (*.msh)"); - if(!fileName.isEmpty()) - emit loadFile(fileName); -} + +///////////////////////////////////////////////////////////////////////// +// functions void MainWindow::setupWidgets() { + // Ogl Viewer OglViewerWidget* viewer = new OglViewerWidget(this); setCentralWidget(viewer); connect(viewer, &OglViewerWidget::sendMessage, this, &MainWindow::printMessage); + // open file QToolButton *openFile = new QToolButton(this); openFile->setObjectName("openFile"); openFile->setToolTip("open file"); connect(openFile, &QToolButton::pressed, this, &MainWindow::openFile); ui->mainToolBar->addWidget(openFile); + // screenshot QToolButton *screenshot = new QToolButton(this); screenshot->setObjectName("screenshot"); screenshot->setToolTip("take screenshot"); connect(screenshot, &QToolButton::pressed, this, &MainWindow::takeScreenShot); ui->mainToolBar->addWidget(screenshot); + ////////////////////////////////////////////////// ui->mainToolBar->addSeparator(); QSignalMapper* signalMapper = new QSignalMapper(this); + // X QToolButton *x = new QToolButton(this); x->setObjectName("x"); x->setToolTip("x-direction"); @@ -88,6 +96,7 @@ void MainWindow::setupWidgets() x->setChecked(true); ui->mainToolBar->addWidget(x); + // Y QToolButton *y = new QToolButton(this); y->setObjectName("y"); y->setToolTip("y-direction"); @@ -95,6 +104,7 @@ void MainWindow::setupWidgets() y->setChecked(true); ui->mainToolBar->addWidget(y); + // Z QToolButton *z = new QToolButton(this); z->setObjectName("z"); z->setToolTip("z-direction"); @@ -110,10 +120,12 @@ void MainWindow::setupWidgets() signalMapper->setMapping(y, 2); signalMapper->setMapping(z, 3); - connect(signalMapper, SIGNAL(mapped(int)), viewer, SLOT(changeDirection(int))); + connect(signalMapper, SIGNAL(mapped(int)), viewer, SLOT(toggleAxis(int))); + ////////////////////////////////////////////////// ui->mainToolBar->addSeparator(); + // wireframe QToolButton *wireframe = new QToolButton(this); wireframe->setObjectName("wireframe"); wireframe->setToolTip("wireframe"); @@ -122,6 +134,7 @@ void MainWindow::setupWidgets() connect(wireframe, &QToolButton::pressed, viewer, &OglViewerWidget::toggleWireframe); ui->mainToolBar->addWidget(wireframe); + // light QToolButton *light = new QToolButton(this); light->setObjectName("light"); light->setToolTip("toggle light"); @@ -130,48 +143,52 @@ void MainWindow::setupWidgets() connect(light, &QToolButton::pressed, viewer, &OglViewerWidget::toggleLight); ui->mainToolBar->addWidget(light); + // settings QToolButton *settings = new QToolButton(this); settings->setObjectName("settings"); settings->setToolTip("settings"); connect(settings, &QToolButton::pressed, viewer, &OglViewerWidget::showSettings); ui->mainToolBar->addWidget(settings); + ////////////////////////////////////////////////// ui->mainToolBar->addSeparator(); + // fileinfo QToolButton *fileInfo = new QToolButton(this); fileInfo->setObjectName("fileInfo"); fileInfo->setToolTip("file info"); - connect(fileInfo, &QToolButton::pressed, this, &MainWindow::aboutFile); + connect(fileInfo, &QToolButton::pressed, m_infoWindow, &FileInfoWindow::show); ui->mainToolBar->addWidget(fileInfo); + // help QToolButton *help = new QToolButton(this); help->setObjectName("help"); help->setToolTip("help"); connect(help, &QToolButton::pressed, this, &MainWindow::aboutTool); ui->mainToolBar->addWidget(help); + // output on screen m_output->setObjectName("output"); - m_output->setStyleSheet("QLabel#output{color : white; min-width: 400px; min-height: 50px;}"); m_output->setAlignment(Qt::AlignTop); - m_output->setText("Name: -\nMaterials: -\nVertice: -\nTriangle: -"); + m_output->setText(m_fileInfo.left(m_fileInfo.indexOf(""))); m_output->raise(); } -void MainWindow::aboutFile() +void MainWindow::openFile() { - /*QMessageBox* dialog = new QMessageBox(QMessageBox::NoIcon, - WINDOW_NAME, - QString(m_fileInfo.left(m_fileInfo.indexOf(""))), - QMessageBox::StandardButton::Close, - this, - Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); + QString fileName = QFileDialog::getOpenFileName(this, "Open File", "", "Mesh (*.msh)"); + if(!fileName.isEmpty()) + emit loadFile(fileName); +} - dialog->setStyleSheet("QLabel{min-width: 200px;}"); - dialog->setDetailedText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("") - 8))); - dialog->exec(); - delete dialog;*/ - m_infoWindow->show(); +void MainWindow::takeScreenShot() +{ + QString destination = QFileDialog::getSaveFileName(this, "Save as...", "", "PNG (*.png);; BMP (*.bmp);;TIFF (*.tiff, *.tif);;JPEG (*.jpg *jpeg)"); + + OglViewerWidget* viewer = dynamic_cast(centralWidget()); + if (!destination.isEmpty() && viewer != NULL) + viewer->grab().save(destination); } void MainWindow::aboutTool() @@ -193,22 +210,48 @@ void MainWindow::aboutTool() delete dialog; } -void MainWindow::takeScreenShot() -{ - QString destination = QFileDialog::getSaveFileName(this, "Save as...", "", "PNG (*.png);; BMP (*.bmp);;TIFF (*.tiff, *.tif);;JPEG (*.jpg *jpeg)"); - - OglViewerWidget* viewer = dynamic_cast(centralWidget()); - if (!destination.isEmpty() && viewer != NULL) - viewer->grab().save(destination); -} - void MainWindow::resizeEvent(QResizeEvent * e) { m_output->move(40, e->size().height() - 80); } + +///////////////////////////////////////////////////////////////////////// +// slots + +void MainWindow::printMessage(QString message, int severity) +{ + if (!ui->statusBar->currentMessage().isEmpty() && severity < m_curSeverity) + return; + + m_curSeverity = severity; + int time(0); + QPalette palette; + + switch (severity) + { + case 1: + time = 3000; + palette.setColor(QPalette::WindowText, Qt::darkYellow); + break; + case 2: + time = 3000; + palette.setColor(QPalette::WindowText, Qt::red); + break; + case 0: + default: + time = 2000; + palette.setColor(QPalette::WindowText, Qt::black); + break; + } + + ui->statusBar->setPalette(palette); + ui->statusBar->showMessage(message, time); +} + void MainWindow::setFileInfo(QString name, QVector* materials, int vertices, int triangle) { + // save basic file information m_fileInfo = QByteArray("Filename: "); m_fileInfo += name; m_fileInfo += "\nMaterials: "; @@ -219,6 +262,7 @@ void MainWindow::setFileInfo(QString name, QVector* materials, int ver m_fileInfo += QByteArray::number(triangle); m_fileInfo += ""; + // add detailed information for (auto& it : *materials) { m_fileInfo += it.name; @@ -307,39 +351,11 @@ void MainWindow::setFileInfo(QString name, QVector* materials, int ver m_fileInfo += "-----------------------------------------------------------------\n"; } + // print basic information on screen m_output->setText(m_fileInfo.left(m_fileInfo.indexOf(""))); + // print basic and detailed information on info window m_infoWindow->setBasicText(QString(m_fileInfo.left(m_fileInfo.indexOf("")))); m_infoWindow->setDetailText(QString(m_fileInfo.right(m_fileInfo.size() - m_fileInfo.indexOf("") - 8))); } - -void MainWindow::printMessage(QString message, int severity) -{ - if (!ui->statusBar->currentMessage().isEmpty() && severity < m_curSeverity) - return; - - m_curSeverity = severity; - int time(0); - QPalette palette; - - switch (severity) - { - case 1: - time = 3000; - palette.setColor(QPalette::WindowText, Qt::darkYellow); - break; - case 2: - time = 3000; - palette.setColor(QPalette::WindowText, Qt::red); - break; - case 0: - default: - time = 2000; - palette.setColor(QPalette::WindowText, Qt::black); - break; - } - - ui->statusBar->setPalette(palette); - ui->statusBar->showMessage(message, time); -} \ No newline at end of file diff --git a/QtMeshViewer/Source/OglViewerWidget.cpp b/QtMeshViewer/Source/OglViewerWidget.cpp index b81da8a..705d7be 100644 --- a/QtMeshViewer/Source/OglViewerWidget.cpp +++ b/QtMeshViewer/Source/OglViewerWidget.cpp @@ -1,23 +1,20 @@ #include "..\Header\OglViewerWidget.h" -#include "..\Header\MainWindow.h" + #include #include #include -#include -#include #define DEFAULT_Z_DISTANCE -4.0 ///////////////////////////////////////////////////////////////////////// -// public constructor/destructor +// constructor/destructor OglViewerWidget::OglViewerWidget(QWidget *parent) : QOpenGLWidget(parent) , m_dataEngine(0) { setFocus(); - m_translation.setZ(DEFAULT_Z_DISTANCE); setAcceptDrops(true); m_settings = new SettingsWindow(m_backgroundColorOff.toVector3D() * 255, m_backgroundColorOn.toVector3D() * 255, m_light.intensities * 255, true, m_light.ambientCoefficient, m_light.attenuationFactor, 1, this); @@ -42,7 +39,135 @@ OglViewerWidget::~OglViewerWidget() ///////////////////////////////////////////////////////////////////////// -// protected functions +// 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))); +} + +void OglViewerWidget::resetView() +{ + m_rotation = QQuaternion(); + m_translation = { 0.0, 0.0, DEFAULT_Z_DISTANCE }; + m_zSpeed = 1; + update(); +} + +void OglViewerWidget::updateLightPosition() +{ + QMatrix4x4 rotateBack; + rotateBack.rotate(m_rotation.inverted()); + QVector3D cameraPosition = rotateBack * (-m_translation); + + m_light.position.setX(cameraPosition.x()); + m_light.position.setY(cameraPosition.y()); + m_light.position.setZ(cameraPosition.z()); +} + +// OpenGL /////////////////////////////////////////////////////////////// + +void OglViewerWidget::initializeGL() +{ + initializeOpenGLFunctions(); + initShaders(); + + // Enable depth buffer + glEnable(GL_DEPTH_TEST); + + //TODO: make this optional + // 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() +{ + // set background color, last value is dirtybit + if (m_lightOn && m_backgroundColorOn[3] == 1.0) + { + glClearColor(m_backgroundColorOn[0], m_backgroundColorOn[1], m_backgroundColorOn[2], 0.0000f); + m_backgroundColorOn[3] = 0.0; + } + else if (!m_lightOn && m_backgroundColorOff[3] == 1.0) + { + glClearColor(m_backgroundColorOff[0], m_backgroundColorOff[1], m_backgroundColorOff[2], 0.0000f); + m_backgroundColorOff[3] = 0.0; + } + + // Clear color and depth buffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Calculate view transformation + QMatrix4x4 view; + view.translate(m_translation); + view.rotate(m_rotation); + + // Set view-projection matrix + m_program.setUniformValue("vp_matrix", m_projection * view); + + // Set Light values + m_program.setUniformValue("b_light", m_lightOn); + m_program.setUniformValue("light.position", m_light.position); + m_program.setUniformValue("light.intensities", m_light.intensities); + m_program.setUniformValue("light.attenuationFactor", m_light.attenuationFactor); + m_program.setUniformValue("light.ambientCoefficient", m_light.ambientCoefficient); + + // Set camera position + QMatrix4x4 rotateBack; + rotateBack.rotate(m_rotation.inverted()); + m_program.setUniformValue("cameraPosition", rotateBack * (-m_translation)); + + // Draw cube geometry + m_dataEngine->drawGeometry(&m_program, m_wireframe); +} + +// Inputs /////////////////////////////////////////////////////////////// void OglViewerWidget::mousePressEvent(QMouseEvent *e) { @@ -74,11 +199,13 @@ void OglViewerWidget::mouseMoveEvent(QMouseEvent *e) // update the new position m_mouse.position = QVector2D(e->localPos()); - // calculate the rotation axis and rotate + // calculate the rotations depending on the active axis + // XYZ 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; } + // XY else if (m_rotDirections.x && m_rotDirections.y && !m_rotDirections.z) { @@ -96,18 +223,22 @@ void OglViewerWidget::mouseMoveEvent(QMouseEvent *e) m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll); } + // X 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; } + // Y 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; } + // Z 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; } + // XZ else if (m_rotDirections.x && !m_rotDirections.y && m_rotDirections.z) { float pitch, yaw, roll; @@ -117,6 +248,7 @@ void OglViewerWidget::mouseMoveEvent(QMouseEvent *e) m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll); } + // YZ else if (!m_rotDirections.x && m_rotDirections.y && m_rotDirections.z) { float pitch, yaw, roll; @@ -132,7 +264,6 @@ void OglViewerWidget::mouseMoveEvent(QMouseEvent *e) m_rotation = QQuaternion::fromEulerAngles(pitch, yaw, roll); } - // request an update update(); } @@ -158,20 +289,6 @@ void OglViewerWidget::wheelEvent(QWheelEvent *e) 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) @@ -200,147 +317,27 @@ void OglViewerWidget::keyPressEvent(QKeyEvent *e) } } -void OglViewerWidget::initializeGL() +void OglViewerWidget::dragEnterEvent(QDragEnterEvent *e) { - 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() -{ - if (m_lightOn && m_backgroundColorOn[3] == 1.0) - { - glClearColor(m_backgroundColorOn[0], m_backgroundColorOn[1], m_backgroundColorOn[2], 0.0000f); - m_backgroundColorOn[3] = 0.0; - } - else if(!m_lightOn && m_backgroundColorOff[3] == 1.0) - { - glClearColor(m_backgroundColorOff[0], m_backgroundColorOff[1], m_backgroundColorOff[2], 0.0000f); - m_backgroundColorOff[3] = 0.0; - } - - // 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); - - // Set Light values - m_program.setUniformValue("b_light", m_lightOn); - m_program.setUniformValue("light.position", m_light.position); - m_program.setUniformValue("light.intensities", m_light.intensities); - m_program.setUniformValue("light.attenuationFactor", m_light.attenuationFactor); - m_program.setUniformValue("light.ambientCoefficient", m_light.ambientCoefficient); - - // Set camera position - QMatrix4x4 rotateBack; - rotateBack.rotate(m_rotation.inverted()); - m_program.setUniformValue("cameraPosition", rotateBack * (-m_translation)); - - // 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))); + if (e->mimeData()->hasUrls()) + if(e->mimeData()->urls().size() == 1) + if(e->mimeData()->urls().first().toLocalFile().endsWith(".msh")) + e->acceptProposedAction(); } -void OglViewerWidget::updateLightPosition() +void OglViewerWidget::dropEvent(QDropEvent * e) { - QMatrix4x4 rotateBack; - rotateBack.rotate(m_rotation.inverted()); - QVector3D cameraPosition = rotateBack * (-m_translation); - - m_light.position.setX(cameraPosition.x()); - m_light.position.setY(cameraPosition.y()); - m_light.position.setZ(cameraPosition.z()); -} - - -///////////////////////////////////////////////////////////////////////// -// private slots - -void OglViewerWidget::resetView() -{ - m_rotation = QQuaternion(); - m_translation = { 0.0, 0.0, DEFAULT_Z_DISTANCE }; - m_zSpeed = 1; - update(); + emit loadFile(e->mimeData()->urls().first().toLocalFile()); } ///////////////////////////////////////////////////////////////////////// // public slots -void OglViewerWidget::changeDirection(int direction) +void OglViewerWidget::toggleAxis(int axis) { - switch (direction) + switch (axis) { case 1: m_rotDirections.x = !m_rotDirections.x; @@ -356,13 +353,13 @@ void OglViewerWidget::changeDirection(int direction) void OglViewerWidget::toggleWireframe() { - m_wireframe = 1 - m_wireframe; + m_wireframe = !m_wireframe; update(); } void OglViewerWidget::toggleLight() { - m_lightOn = 1 - m_lightOn; + m_lightOn = !m_lightOn; if (m_lightOn) { @@ -373,6 +370,7 @@ void OglViewerWidget::toggleLight() { m_backgroundColorOff[3] = 1.0; } + update(); } diff --git a/QtMeshViewer/Source/SettingsWindow.cpp b/QtMeshViewer/Source/SettingsWindow.cpp index de0c0b7..f440ccc 100644 --- a/QtMeshViewer/Source/SettingsWindow.cpp +++ b/QtMeshViewer/Source/SettingsWindow.cpp @@ -1,5 +1,8 @@ #include "..\Header\SettingsWindow.h" -#include + + +///////////////////////////////////////////////////////////////////////// +// constructor/destructor SettingsWindow::SettingsWindow(QVector3D bgOffColor, QVector3D bgOnColor, QVector3D lightColor, bool autoColor, double ambCoef, double attFac, int lightType, QWidget * parent) : QWidget(parent) @@ -38,6 +41,10 @@ SettingsWindow::~SettingsWindow() delete ui; } + +///////////////////////////////////////////////////////////////////////// +// functions + void SettingsWindow::setupConnections() { // light off @@ -87,8 +94,8 @@ void SettingsWindow::setupConnections() } -//////////////////////////////////////////////////////////////////////////////// -// connection slots +///////////////////////////////////////////////////////////////////////// +// slots void SettingsWindow::autoColorToggled() { diff --git a/QtMeshViewer/main.cpp b/QtMeshViewer/main.cpp index acd59df..a4a0ce0 100644 --- a/QtMeshViewer/main.cpp +++ b/QtMeshViewer/main.cpp @@ -1,8 +1,6 @@ #include "Header\MainWindow.h" #include -// TODO: add glow/emissive - int main(int argc, char *argv[]) { QApplication a(argc, argv);