From ae7d6cc65592966ede6b82354d9c4dc7b25b6df7 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 18 Apr 2024 14:16:04 +0200 Subject: [PATCH] Added QOpenGlwidget for testing --- demo/MainWindow.cpp | 33 +++- demo/MainWindow.h | 1 + demo/demo.pro | 13 +- demo/demo.qrc | 1 + demo/glwidget.cpp | 280 ++++++++++++++++++++++++++++++++++ demo/glwidget.h | 72 +++++++++ demo/images/deployed_code.svg | 5 + demo/logo.cpp | 103 +++++++++++++ demo/logo.h | 28 ++++ demo/main.cpp | 2 + 10 files changed, 529 insertions(+), 9 deletions(-) create mode 100644 demo/glwidget.cpp create mode 100644 demo/glwidget.h create mode 100644 demo/images/deployed_code.svg create mode 100644 demo/logo.cpp create mode 100644 demo/logo.h diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index cde5492..fa4cdfb 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -85,6 +85,7 @@ #include "StatusDialog.h" #include "DockSplitter.h" #include "ImageViewer.h" +#include "glwidget.h" @@ -658,6 +659,18 @@ void MainWindowPrivate::createActions() a = Menu->addAction("Pinned Image Viewer"); _this->connect(a, SIGNAL(triggered()), SLOT(createImageViewer())); + a = ui.toolBar->addAction("Create OpenGL Viewer"); + a->setToolTip("Creates a opengl widget for testing." ); + a->setIcon(svgIcon(":/adsdemo/images/deployed_code.svg")); + QObject::connect(a, &QAction::triggered, _this, &CMainWindow::createOpenGlWidget); + ui.menuTests->addAction(a); + + a = ui.toolBar->addAction("Apply VS Style"); + a->setToolTip("Applies a Visual Studio light style (visual_studio_light.css)." ); + a->setIcon(svgIcon(":/adsdemo/images/color_lens.svg")); + QObject::connect(a, &QAction::triggered, _this, &CMainWindow::applyVsStyle); + ui.menuTests->addAction(a); + ui.menuTests->addSeparator(); a = ui.menuTests->addAction("Show Status Dialog"); @@ -666,12 +679,6 @@ void MainWindowPrivate::createActions() a = ui.menuTests->addAction("Toggle Label 0 Window Title"); _this->connect(a, SIGNAL(triggered()), SLOT(toggleDockWidgetWindowTitle())); ui.menuTests->addSeparator(); - - a = ui.toolBar->addAction("Apply VS Style"); - a->setToolTip("Applies a Visual Studio light style (visual_studio_light.css)." ); - a->setIcon(svgIcon(":/adsdemo/images/color_lens.svg")); - QObject::connect(a, &QAction::triggered, _this, &CMainWindow::applyVsStyle); - ui.menuTests->addAction(a); } @@ -1055,3 +1062,17 @@ void CMainWindow::lockWorkspace(bool Value) } } + +//============================================================================ +void CMainWindow::createOpenGlWidget() +{ + qDebug() << ":createOpenGlWidget "; + static int OpenGlWidgetCount = 0; + + auto w = new GLWidget(); + auto DockWidget = new ads::CDockWidget(QString("OpenGL Viewer %1").arg(OpenGlWidgetCount++)); + DockWidget->setIcon(svgIcon(":/adsdemo/images/deployed_code.svg")); + DockWidget->setWidget(w, ads:: CDockWidget::ForceNoScrollArea); + d->DockManager->addDockWidget(ads::RightDockWidgetArea, DockWidget); +} + diff --git a/demo/MainWindow.h b/demo/MainWindow.h index dd12360..7beef1f 100644 --- a/demo/MainWindow.h +++ b/demo/MainWindow.h @@ -69,6 +69,7 @@ private slots: void applyVsStyle(); void createImageViewer(); void lockWorkspace(bool Value); + void createOpenGlWidget(); }; #endif // MAINWINDOW_H diff --git a/demo/demo.pro b/demo/demo.pro index 913b5be..b3feb22 100644 --- a/demo/demo.pro +++ b/demo/demo.pro @@ -2,7 +2,7 @@ ADS_OUT_ROOT = $${OUT_PWD}/.. TARGET = AdvancedDockingSystemDemo DESTDIR = $${ADS_OUT_ROOT}/lib -QT += core gui widgets quick quickwidgets +QT += core gui widgets quick quickwidgets opengl include(../ads.pri) @@ -10,6 +10,8 @@ lessThan(QT_MAJOR_VERSION, 6) { win32 { QT += axcontainer } +} else { + QT += openglwidgets } CONFIG += c++14 @@ -26,14 +28,19 @@ HEADERS += \ MainWindow.h \ StatusDialog.h \ ImageViewer.h \ - RenderWidget.h + RenderWidget.h \ + glwidget.h \ + logo.h + SOURCES += \ main.cpp \ MainWindow.cpp \ StatusDialog.cpp \ ImageViewer.cpp \ - RenderWidget.cpp + RenderWidget.cpp \ + glwidget.cpp \ + logo.cpp FORMS += \ mainwindow.ui \ diff --git a/demo/demo.qrc b/demo/demo.qrc index 8b35293..9ef0ff9 100644 --- a/demo/demo.qrc +++ b/demo/demo.qrc @@ -39,5 +39,6 @@ images/lock_outline.svg images/lock.svg images/lock_open.svg + images/deployed_code.svg diff --git a/demo/glwidget.cpp b/demo/glwidget.cpp new file mode 100644 index 0000000..3b01b3a --- /dev/null +++ b/demo/glwidget.cpp @@ -0,0 +1,280 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "glwidget.h" +#include +#include +#include +#include + +bool GLWidget::m_transparent = false; + +GLWidget::GLWidget(QWidget *parent) + : QOpenGLWidget(parent) +{ + m_core = QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile; + // --transparent causes the clear color to be transparent. Therefore, on systems that + // support it, the widget will become transparent apart from the logo. + if (m_transparent) { + QSurfaceFormat fmt = format(); + fmt.setAlphaBufferSize(8); + setFormat(fmt); + } +} + +GLWidget::~GLWidget() +{ + cleanup(); +} + +QSize GLWidget::minimumSizeHint() const +{ + return QSize(50, 50); +} + +QSize GLWidget::sizeHint() const +{ + return QSize(400, 400); +} + +static void qNormalizeAngle(int &angle) +{ + while (angle < 0) + angle += 360 * 16; + while (angle > 360 * 16) + angle -= 360 * 16; +} + +void GLWidget::setXRotation(int angle) +{ + qNormalizeAngle(angle); + if (angle != m_xRot) { + m_xRot = angle; + emit xRotationChanged(angle); + update(); + } +} + +void GLWidget::setYRotation(int angle) +{ + qNormalizeAngle(angle); + if (angle != m_yRot) { + m_yRot = angle; + emit yRotationChanged(angle); + update(); + } +} + +void GLWidget::setZRotation(int angle) +{ + qNormalizeAngle(angle); + if (angle != m_zRot) { + m_zRot = angle; + emit zRotationChanged(angle); + update(); + } +} + +void GLWidget::cleanup() +{ + if (m_program == nullptr) + return; + makeCurrent(); + m_logoVbo.destroy(); + delete m_program; + m_program = nullptr; + doneCurrent(); + QObject::disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup); + m_HiddenOnCleanup = isHidden(); + // Hiding here prevents the base class implementation to recreate + // the QOpenGlContext immediatelly allowing us to set the surface format again + hide(); +} + +static const char *vertexShaderSourceCore = + "#version 150\n" + "in vec4 vertex;\n" + "in vec3 normal;\n" + "out vec3 vert;\n" + "out vec3 vertNormal;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "uniform mat3 normalMatrix;\n" + "void main() {\n" + " vert = vertex.xyz;\n" + " vertNormal = normalMatrix * normal;\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSourceCore = + "#version 150\n" + "in highp vec3 vert;\n" + "in highp vec3 vertNormal;\n" + "out highp vec4 fragColor;\n" + "uniform highp vec3 lightPos;\n" + "void main() {\n" + " highp vec3 L = normalize(lightPos - vert);\n" + " highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n" + " highp vec3 color = vec3(0.39, 1.0, 0.0);\n" + " highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n" + " fragColor = vec4(col, 1.0);\n" + "}\n"; + +static const char *vertexShaderSource = + "attribute vec4 vertex;\n" + "attribute vec3 normal;\n" + "varying vec3 vert;\n" + "varying vec3 vertNormal;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 mvMatrix;\n" + "uniform mat3 normalMatrix;\n" + "void main() {\n" + " vert = vertex.xyz;\n" + " vertNormal = normalMatrix * normal;\n" + " gl_Position = projMatrix * mvMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSource = + "varying highp vec3 vert;\n" + "varying highp vec3 vertNormal;\n" + "uniform highp vec3 lightPos;\n" + "void main() {\n" + " highp vec3 L = normalize(lightPos - vert);\n" + " highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n" + " highp vec3 color = vec3(0.39, 1.0, 0.0);\n" + " highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n" + " gl_FragColor = vec4(col, 1.0);\n" + "}\n"; + +void GLWidget::initializeGL() +{ + // In this example the widget's corresponding top-level window can change + // several times during the widget's lifetime. Whenever this happens, the + // QOpenGLWidget's associated context is destroyed and a new one is created. + // Therefore we have to be prepared to clean up the resources on the + // aboutToBeDestroyed() signal, instead of the destructor. The emission of + // the signal will be followed by an invocation of initializeGL() where we + // can recreate all resources. + connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup); + + initializeOpenGLFunctions(); + glClearColor(0, 0, 0, m_transparent ? 0 : 1); + + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_core ? vertexShaderSourceCore : vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_core ? fragmentShaderSourceCore : fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->bindAttributeLocation("normal", 1); + m_program->link(); + + m_program->bind(); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_mvMatrixLoc = m_program->uniformLocation("mvMatrix"); + m_normalMatrixLoc = m_program->uniformLocation("normalMatrix"); + m_lightPosLoc = m_program->uniformLocation("lightPos"); + + // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x + // implementations this is optional and support may not be present + // at all. Nonetheless the below code works in all cases and makes + // sure there is a VAO when one is needed. + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + // Setup our vertex buffer object. + m_logoVbo.create(); + m_logoVbo.bind(); + m_logoVbo.allocate(m_logo.constData(), m_logo.count() * sizeof(GLfloat)); + + // Store the vertex attribute bindings for the program. + setupVertexAttribs(); + + // Our camera never changes in this example. + m_camera.setToIdentity(); + m_camera.translate(0, 0, -1); + + // Light position is fixed. + m_program->setUniformValue(m_lightPosLoc, QVector3D(0, 0, 70)); + + m_program->release(); +} + +void GLWidget::setupVertexAttribs() +{ + m_logoVbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glEnableVertexAttribArray(1); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), + nullptr); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), + reinterpret_cast(3 * sizeof(GLfloat))); + m_logoVbo.release(); +} + +void GLWidget::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + m_world.setToIdentity(); + m_world.rotate(180.0f - (m_xRot / 16.0f), 1, 0, 0); + m_world.rotate(m_yRot / 16.0f, 0, 1, 0); + m_world.rotate(m_zRot / 16.0f, 0, 0, 1); + + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + m_program->bind(); + m_program->setUniformValue(m_projMatrixLoc, m_proj); + m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world); + QMatrix3x3 normalMatrix = m_world.normalMatrix(); + m_program->setUniformValue(m_normalMatrixLoc, normalMatrix); + + glDrawArrays(GL_TRIANGLES, 0, m_logo.vertexCount()); + + m_program->release(); +} + +void GLWidget::resizeGL(int w, int h) +{ + m_proj.setToIdentity(); + m_proj.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f); +} + +void GLWidget::mousePressEvent(QMouseEvent *event) +{ + m_lastPos = event->position().toPoint(); +} + +void GLWidget::mouseMoveEvent(QMouseEvent *event) +{ + int dx = event->position().toPoint().x() - m_lastPos.x(); + int dy = event->position().toPoint().y() - m_lastPos.y(); + + if (event->buttons() & Qt::LeftButton) { + setXRotation(m_xRot + 8 * dy); + setYRotation(m_yRot + 8 * dx); + } else if (event->buttons() & Qt::RightButton) { + setXRotation(m_xRot + 8 * dy); + setZRotation(m_zRot + 8 * dx); + } + m_lastPos = event->position().toPoint(); +} + + +bool GLWidget::event(QEvent *event) +{ + auto Result = QOpenGLWidget::event(event); + if (event->type() == QEvent::WindowChangeInternal) + { + qDebug() << "QEvent::WindowChangeInternal"; + if (!context()) + { + setFormat(QSurfaceFormat::defaultFormat()); + if (!m_HiddenOnCleanup) + { + show(); + } + } + } + return Result; +} diff --git a/demo/glwidget.h b/demo/glwidget.h new file mode 100644 index 0000000..63045f2 --- /dev/null +++ b/demo/glwidget.h @@ -0,0 +1,72 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef GLWIDGET_H +#define GLWIDGET_H + +#include +#include +#include +#include +#include +#include "logo.h" + +QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram) + +class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT + +public: + GLWidget(QWidget *parent = nullptr); + ~GLWidget(); + + static bool isTransparent() { return m_transparent; } + static void setTransparent(bool t) { m_transparent = t; } + + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + +public slots: + void setXRotation(int angle); + void setYRotation(int angle); + void setZRotation(int angle); + void cleanup(); + +signals: + void xRotationChanged(int angle); + void yRotationChanged(int angle); + void zRotationChanged(int angle); + +protected: + void initializeGL() override; + void paintGL() override; + void resizeGL(int width, int height) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + virtual bool event(QEvent *event) override; + +private: + void setupVertexAttribs(); + + bool m_core; + int m_xRot = 0; + int m_yRot = 0; + int m_zRot = 0; + QPoint m_lastPos; + Logo m_logo; + QOpenGLVertexArrayObject m_vao; + QOpenGLBuffer m_logoVbo; + QOpenGLShaderProgram *m_program = nullptr; + int m_projMatrixLoc = 0; + int m_mvMatrixLoc = 0; + int m_normalMatrixLoc = 0; + int m_lightPosLoc = 0; + QMatrix4x4 m_proj; + QMatrix4x4 m_camera; + QMatrix4x4 m_world; + static bool m_transparent; + bool m_HiddenOnCleanup = false; +}; + +#endif diff --git a/demo/images/deployed_code.svg b/demo/images/deployed_code.svg new file mode 100644 index 0000000..6769954 --- /dev/null +++ b/demo/images/deployed_code.svg @@ -0,0 +1,5 @@ + + + lock_outline icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + diff --git a/demo/logo.cpp b/demo/logo.cpp new file mode 100644 index 0000000..b924ba0 --- /dev/null +++ b/demo/logo.cpp @@ -0,0 +1,103 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "logo.h" +#include + +Logo::Logo() +{ + m_data.resize(2500 * 6); + + const GLfloat x1 = +0.06f; + const GLfloat y1 = -0.14f; + const GLfloat x2 = +0.14f; + const GLfloat y2 = -0.06f; + const GLfloat x3 = +0.08f; + const GLfloat y3 = +0.00f; + const GLfloat x4 = +0.30f; + const GLfloat y4 = +0.22f; + + quad(x1, y1, x2, y2, y2, x2, y1, x1); + quad(x3, y3, x4, y4, y4, x4, y3, x3); + + extrude(x1, y1, x2, y2); + extrude(x2, y2, y2, x2); + extrude(y2, x2, y1, x1); + extrude(y1, x1, x1, y1); + extrude(x3, y3, x4, y4); + extrude(x4, y4, y4, x4); + extrude(y4, x4, y3, x3); + + const int NumSectors = 100; + + for (int i = 0; i < NumSectors; ++i) { + GLfloat angle = (i * 2 * M_PI) / NumSectors; + GLfloat angleSin = qSin(angle); + GLfloat angleCos = qCos(angle); + const GLfloat x5 = 0.30f * angleSin; + const GLfloat y5 = 0.30f * angleCos; + const GLfloat x6 = 0.20f * angleSin; + const GLfloat y6 = 0.20f * angleCos; + + angle = ((i + 1) * 2 * M_PI) / NumSectors; + angleSin = qSin(angle); + angleCos = qCos(angle); + const GLfloat x7 = 0.20f * angleSin; + const GLfloat y7 = 0.20f * angleCos; + const GLfloat x8 = 0.30f * angleSin; + const GLfloat y8 = 0.30f * angleCos; + + quad(x5, y5, x6, y6, x7, y7, x8, y8); + + extrude(x6, y6, x7, y7); + extrude(x8, y8, x5, y5); + } +} + +void Logo::add(const QVector3D &v, const QVector3D &n) +{ + GLfloat *p = m_data.data() + m_count; + *p++ = v.x(); + *p++ = v.y(); + *p++ = v.z(); + *p++ = n.x(); + *p++ = n.y(); + *p++ = n.z(); + m_count += 6; +} + +void Logo::quad(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4) +{ + QVector3D n = QVector3D::normal(QVector3D(x4 - x1, y4 - y1, 0.0f), QVector3D(x2 - x1, y2 - y1, 0.0f)); + + add(QVector3D(x1, y1, -0.05f), n); + add(QVector3D(x4, y4, -0.05f), n); + add(QVector3D(x2, y2, -0.05f), n); + + add(QVector3D(x3, y3, -0.05f), n); + add(QVector3D(x2, y2, -0.05f), n); + add(QVector3D(x4, y4, -0.05f), n); + + n = QVector3D::normal(QVector3D(x1 - x4, y1 - y4, 0.0f), QVector3D(x2 - x4, y2 - y4, 0.0f)); + + add(QVector3D(x4, y4, 0.05f), n); + add(QVector3D(x1, y1, 0.05f), n); + add(QVector3D(x2, y2, 0.05f), n); + + add(QVector3D(x2, y2, 0.05f), n); + add(QVector3D(x3, y3, 0.05f), n); + add(QVector3D(x4, y4, 0.05f), n); +} + +void Logo::extrude(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + QVector3D n = QVector3D::normal(QVector3D(0.0f, 0.0f, -0.1f), QVector3D(x2 - x1, y2 - y1, 0.0f)); + + add(QVector3D(x1, y1, +0.05f), n); + add(QVector3D(x1, y1, -0.05f), n); + add(QVector3D(x2, y2, +0.05f), n); + + add(QVector3D(x2, y2, -0.05f), n); + add(QVector3D(x2, y2, +0.05f), n); + add(QVector3D(x1, y1, -0.05f), n); +} diff --git a/demo/logo.h b/demo/logo.h new file mode 100644 index 0000000..0eed3f6 --- /dev/null +++ b/demo/logo.h @@ -0,0 +1,28 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef LOGO_H +#define LOGO_H + +#include +#include +#include + +class Logo +{ +public: + Logo(); + const GLfloat *constData() const { return m_data.constData(); } + int count() const { return m_count; } + int vertexCount() const { return m_count / 6; } + +private: + void quad(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4); + void extrude(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); + void add(const QVector3D &v, const QVector3D &n); + + QList m_data; + int m_count = 0; +}; + +#endif // LOGO_H diff --git a/demo/main.cpp b/demo/main.cpp index 750c983..feebeaf 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -41,6 +42,7 @@ int main(int argc, char *argv[]) QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif #endif + QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); std::shared_ptr b; QApplication a(argc, argv); a.setApplicationName("Advanced Docking System Demo");