diff --git a/QtMeshViewer/Form Files/MainWindow.ui b/QtMeshViewer/Form Files/MainWindow.ui new file mode 100644 index 0000000..01cc077 --- /dev/null +++ b/QtMeshViewer/Form Files/MainWindow.ui @@ -0,0 +1,32 @@ + + + MainWindowClass + + + + 0 + 0 + 600 + 400 + + + + MainWindow + + + + + TopToolBarArea + + + false + + + + + + + + + + diff --git a/QtMeshViewer/Header/GeometryEngine.h b/QtMeshViewer/Header/GeometryEngine.h new file mode 100644 index 0000000..36f7797 --- /dev/null +++ b/QtMeshViewer/Header/GeometryEngine.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GEOMETRYENGINE_H +#define GEOMETRYENGINE_H + +#include +#include +#include + +class GeometryEngine : protected QOpenGLFunctions +{ +public: + GeometryEngine(); + virtual ~GeometryEngine(); + + void drawCubeGeometry(QOpenGLShaderProgram *program); + +private: + void initCubeGeometry(); + + QOpenGLBuffer arrayBuf; + QOpenGLBuffer indexBuf; +}; + +#endif // GEOMETRYENGINE_H diff --git a/QtMeshViewer/Header/MainWindow.h b/QtMeshViewer/Header/MainWindow.h new file mode 100644 index 0000000..49e2d43 --- /dev/null +++ b/QtMeshViewer/Header/MainWindow.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "ui_MainWindow.h" + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = Q_NULLPTR); + ~MainWindow(); + +private: + Ui::MainWindowClass* ui; +}; diff --git a/QtMeshViewer/Header/OglViewerWidget.h b/QtMeshViewer/Header/OglViewerWidget.h new file mode 100644 index 0000000..7cb8bfc --- /dev/null +++ b/QtMeshViewer/Header/OglViewerWidget.h @@ -0,0 +1,50 @@ +#pragma once + +#include "geometryengine.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +class GeometryEngine; + +class OglViewerWidget : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + explicit OglViewerWidget(QWidget *parent = 0); + ~OglViewerWidget(); + +protected: + void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE; + + void initializeGL() Q_DECL_OVERRIDE; + void resizeGL(int w, int h) Q_DECL_OVERRIDE; + void paintGL() Q_DECL_OVERRIDE; + + void initShaders(); + void initTextures(); + +private: + QBasicTimer timer; + QOpenGLShaderProgram program; + GeometryEngine *geometries; + + QOpenGLTexture *texture; + + QMatrix4x4 projection; + + QVector2D mousePressPosition; + QVector3D rotationAxis; + qreal angularSpeed; + QQuaternion rotation; +}; + diff --git a/QtMeshViewer/Resources/Resources.qrc b/QtMeshViewer/Resources/Resources.qrc new file mode 100644 index 0000000..bdb879b --- /dev/null +++ b/QtMeshViewer/Resources/Resources.qrc @@ -0,0 +1,9 @@ + + + fshader.glsl + vshader.glsl + + + cube.png + + diff --git a/QtMeshViewer/Resources/cube.png b/QtMeshViewer/Resources/cube.png new file mode 100644 index 0000000..42c8c51 Binary files /dev/null and b/QtMeshViewer/Resources/cube.png differ diff --git a/QtMeshViewer/Resources/fshader.glsl b/QtMeshViewer/Resources/fshader.glsl new file mode 100644 index 0000000..18068cf --- /dev/null +++ b/QtMeshViewer/Resources/fshader.glsl @@ -0,0 +1,18 @@ +#ifdef GL_ES +// Set default precision to medium +precision mediump int; +precision mediump float; +#endif + +uniform sampler2D texture; + +varying vec2 v_texcoord; + +//! [0] +void main() +{ + // Set fragment color from texture + gl_FragColor = texture2D(texture, v_texcoord); +} +//! [0] + diff --git a/QtMeshViewer/Resources/icon.ico b/QtMeshViewer/Resources/icon.ico new file mode 100644 index 0000000..3a2186f Binary files /dev/null and b/QtMeshViewer/Resources/icon.ico differ diff --git a/QtMeshViewer/Resources/vshader.glsl b/QtMeshViewer/Resources/vshader.glsl new file mode 100644 index 0000000..cfdc061 --- /dev/null +++ b/QtMeshViewer/Resources/vshader.glsl @@ -0,0 +1,24 @@ +#ifdef GL_ES +// Set default precision to medium +precision mediump int; +precision mediump float; +#endif + +uniform mat4 mvp_matrix; + +attribute vec4 a_position; +attribute vec2 a_texcoord; + +varying vec2 v_texcoord; + +//! [0] +void main() +{ + // Calculate vertex position in screen space + gl_Position = mvp_matrix * a_position; + + // Pass texture coordinate to fragment shader + // Value will be automatically interpolated to fragments inside polygon faces + v_texcoord = a_texcoord; +} +//! [0] diff --git a/QtMeshViewer/Source/GeometryEngine.cpp b/QtMeshViewer/Source/GeometryEngine.cpp new file mode 100644 index 0000000..21e1703 --- /dev/null +++ b/QtMeshViewer/Source/GeometryEngine.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "..\Header\GeometryEngine.h" + +#include +#include + +struct VertexData +{ + QVector3D position; + QVector2D texCoord; +}; + +//! [0] +GeometryEngine::GeometryEngine() + : indexBuf(QOpenGLBuffer::IndexBuffer) +{ + initializeOpenGLFunctions(); + + // Generate 2 VBOs + arrayBuf.create(); + indexBuf.create(); + + // Initializes cube geometry and transfers it to VBOs + initCubeGeometry(); +} + +GeometryEngine::~GeometryEngine() +{ + arrayBuf.destroy(); + indexBuf.destroy(); +} +//! [0] + +void GeometryEngine::initCubeGeometry() +{ + // For cube we would need only 8 vertices but we have to + // duplicate vertex for each face because texture coordinate + // is different. + VertexData vertices[] = { + // Vertex data for face 0 + {QVector3D(-1.0f, -1.0f, 1.0f), QVector2D(0.0f, 0.0f)}, // v0 + {QVector3D( 1.0f, -1.0f, 1.0f), QVector2D(0.33f, 0.0f)}, // v1 + {QVector3D(-1.0f, 1.0f, 1.0f), QVector2D(0.0f, 0.5f)}, // v2 + {QVector3D( 1.0f, 1.0f, 1.0f), QVector2D(0.33f, 0.5f)}, // v3 + + // Vertex data for face 1 + {QVector3D( 1.0f, -1.0f, 1.0f), QVector2D( 0.0f, 0.5f)}, // v4 + {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.5f)}, // v5 + {QVector3D( 1.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)}, // v6 + {QVector3D( 1.0f, 1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v7 + + // Vertex data for face 2 + {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.5f)}, // v8 + {QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(1.0f, 0.5f)}, // v9 + {QVector3D( 1.0f, 1.0f, -1.0f), QVector2D(0.66f, 1.0f)}, // v10 + {QVector3D(-1.0f, 1.0f, -1.0f), QVector2D(1.0f, 1.0f)}, // v11 + + // Vertex data for face 3 + {QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.0f)}, // v12 + {QVector3D(-1.0f, -1.0f, 1.0f), QVector2D(1.0f, 0.0f)}, // v13 + {QVector3D(-1.0f, 1.0f, -1.0f), QVector2D(0.66f, 0.5f)}, // v14 + {QVector3D(-1.0f, 1.0f, 1.0f), QVector2D(1.0f, 0.5f)}, // v15 + + // Vertex data for face 4 + {QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.0f)}, // v16 + {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.0f)}, // v17 + {QVector3D(-1.0f, -1.0f, 1.0f), QVector2D(0.33f, 0.5f)}, // v18 + {QVector3D( 1.0f, -1.0f, 1.0f), QVector2D(0.66f, 0.5f)}, // v19 + + // Vertex data for face 5 + {QVector3D(-1.0f, 1.0f, 1.0f), QVector2D(0.33f, 0.5f)}, // v20 + {QVector3D( 1.0f, 1.0f, 1.0f), QVector2D(0.66f, 0.5f)}, // v21 + {QVector3D(-1.0f, 1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v22 + {QVector3D( 1.0f, 1.0f, -1.0f), QVector2D(0.66f, 1.0f)} // v23 + }; + + // Indices for drawing cube faces using triangle strips. + // Triangle strips can be connected by duplicating indices + // between the strips. If connecting strips have opposite + // vertex order then last index of the first strip and first + // index of the second strip needs to be duplicated. If + // connecting strips have same vertex order then only last + // index of the first strip needs to be duplicated. + GLushort indices[] = { + 0, 1, 2, 3, 3, // Face 0 - triangle strip ( v0, v1, v2, v3) + 4, 4, 5, 6, 7, 7, // Face 1 - triangle strip ( v4, v5, v6, v7) + 8, 8, 9, 10, 11, 11, // Face 2 - triangle strip ( v8, v9, v10, v11) + 12, 12, 13, 14, 15, 15, // Face 3 - triangle strip (v12, v13, v14, v15) + 16, 16, 17, 18, 19, 19, // Face 4 - triangle strip (v16, v17, v18, v19) + 20, 20, 21, 22, 23 // Face 5 - triangle strip (v20, v21, v22, v23) + }; + +//! [1] + // Transfer vertex data to VBO 0 + arrayBuf.bind(); + arrayBuf.allocate(vertices, 24 * sizeof(VertexData)); + + // Transfer index data to VBO 1 + indexBuf.bind(); + indexBuf.allocate(indices, 34 * sizeof(GLushort)); +//! [1] +} + +//! [2] +void GeometryEngine::drawCubeGeometry(QOpenGLShaderProgram *program) +{ + // Tell OpenGL which VBOs to use + arrayBuf.bind(); + indexBuf.bind(); + + // 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)); + + // Draw cube geometry using indices from VBO 1 + glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, 0); +} +//! [2] diff --git a/QtMeshViewer/Source/MainWindow.cpp b/QtMeshViewer/Source/MainWindow.cpp new file mode 100644 index 0000000..57860fd --- /dev/null +++ b/QtMeshViewer/Source/MainWindow.cpp @@ -0,0 +1,24 @@ +#include "..\Header\MainWindow.h" +#include "..\Header\OglViewerWidget.h" +#include + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindowClass) +{ + ui->setupUi(this); + + QSurfaceFormat format; + format.setDepthBufferSize(24); + QSurfaceFormat::setDefaultFormat(format); + + this->setCentralWidget(new OglViewerWidget(this)); + + ui->statusBar->showMessage("haha vbgf"); +} + + +MainWindow::~MainWindow() +{ + delete ui; +} \ No newline at end of file diff --git a/QtMeshViewer/Source/OglViewerWidget.cpp b/QtMeshViewer/Source/OglViewerWidget.cpp new file mode 100644 index 0000000..e83c85f --- /dev/null +++ b/QtMeshViewer/Source/OglViewerWidget.cpp @@ -0,0 +1,157 @@ +#include "..\Header\OglViewerWidget.h" + +#include +#include + +OglViewerWidget::OglViewerWidget(QWidget *parent) : + QOpenGLWidget(parent), + geometries(0), + texture(0), + angularSpeed(0) +{ +} + +OglViewerWidget::~OglViewerWidget() +{ + // Make sure the context is current when deleting the texture + // and the buffers. + makeCurrent(); + delete texture; + delete geometries; + doneCurrent(); +} + +void OglViewerWidget::mousePressEvent(QMouseEvent *e) +{ + // Save mouse press position + mousePressPosition = QVector2D(e->localPos()); +} + +void OglViewerWidget::mouseReleaseEvent(QMouseEvent *e) +{ + // Mouse release position - mouse press position + QVector2D diff = QVector2D(e->localPos()) - mousePressPosition; + + // Rotation axis is perpendicular to the mouse position difference + // vector + QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized(); + + // Accelerate angular speed relative to the length of the mouse sweep + qreal acc = diff.length() / 100.0; + + // Calculate new rotation axis as weighted sum + rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized(); + + // Increase angular speed + angularSpeed += acc; +} + +void OglViewerWidget::timerEvent(QTimerEvent *) +{ + // Decrease angular speed (friction) + angularSpeed *= 0.99; + + // Stop rotation when speed goes below threshold + if (angularSpeed < 0.01) { + angularSpeed = 0.0; + } else { + // Update rotation + rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation; + + // Request an update + update(); + } +} + +void OglViewerWidget::initializeGL() +{ + initializeOpenGLFunctions(); + + glClearColor(0, 0, 0, 1); + + initShaders(); + initTextures(); + + // Enable depth buffer + glEnable(GL_DEPTH_TEST); + + // Enable back face culling + glEnable(GL_CULL_FACE); + + geometries = new GeometryEngine; + + // Use QBasicTimer because its faster than QTimer + timer.start(12, this); +} + +void OglViewerWidget::initShaders() +{ + // Compile vertex shader + if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl")) + close(); + + // Compile fragment shader + if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl")) + close(); + + // Link shader pipeline + if (!program.link()) + close(); + + // Bind shader pipeline for use + if (!program.bind()) + close(); +} + +void OglViewerWidget::initTextures() +{ + // Load cube.png image + texture = new QOpenGLTexture(QImage(":images/cube.png").mirrored()); + + // Set nearest filtering mode for texture minification + texture->setMinificationFilter(QOpenGLTexture::Nearest); + + // Set bilinear filtering mode for texture magnification + texture->setMagnificationFilter(QOpenGLTexture::Linear); + + // Wrap texture coordinates by repeating + // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2) + texture->setWrapMode(QOpenGLTexture::Repeat); +} + +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 = 3.0, zFar = 7.0, fov = 45.0; + + // Reset projection + projection.setToIdentity(); + + // Set perspective projection + projection.perspective(fov, aspect, zNear, zFar); +} + +void OglViewerWidget::paintGL() +{ + // Clear color and depth buffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + texture->bind(); + + // Calculate model view transformation + QMatrix4x4 matrix; + matrix.translate(0.0, 0.0, -5.0); + matrix.rotate(rotation); + + // Set modelview-projection matrix + program.setUniformValue("mvp_matrix", projection * matrix); + + // Use texture unit 0 which contains cube.png + program.setUniformValue("texture", 0); + + // Draw cube geometry + geometries->drawCubeGeometry(&program); +} diff --git a/QtMeshViewer/main.cpp b/QtMeshViewer/main.cpp new file mode 100644 index 0000000..f4ddde4 --- /dev/null +++ b/QtMeshViewer/main.cpp @@ -0,0 +1,12 @@ +#include "Header\MainWindow.h" +#include + + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + MainWindow w; + w.show(); + return a.exec(); +}