Remove threadeqopenglwidget example
It is neither documented nor very useful, and it has platform-specific issues as reported over the years. Remove it now as part of the example revamp initiative. Task-number: QTBUG-50278 Task-number: QTBUG-110093 Task-number: QTBUG-76054 Task-number: QTBUG-43209 Pick-to: 6.5 Change-Id: I6dadaf4162b4c19411c544b9f204c19e37aa740d Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
This commit is contained in:
parent
86a517ac78
commit
6462a454e3
@ -7,7 +7,6 @@ qt_internal_add_example(openglwindow)
|
|||||||
qt_internal_add_example(qopenglwindow)
|
qt_internal_add_example(qopenglwindow)
|
||||||
if(TARGET Qt6::Widgets)
|
if(TARGET Qt6::Widgets)
|
||||||
qt_internal_add_example(contextinfo)
|
qt_internal_add_example(contextinfo)
|
||||||
qt_internal_add_example(threadedqopenglwidget)
|
|
||||||
qt_internal_add_example(2dpainting)
|
qt_internal_add_example(2dpainting)
|
||||||
qt_internal_add_example(hellogl2)
|
qt_internal_add_example(hellogl2)
|
||||||
qt_internal_add_example(qopenglwidget)
|
qt_internal_add_example(qopenglwidget)
|
||||||
|
@ -7,7 +7,6 @@ SUBDIRS = hellowindow \
|
|||||||
|
|
||||||
qtHaveModule(widgets) {
|
qtHaveModule(widgets) {
|
||||||
SUBDIRS += contextinfo \
|
SUBDIRS += contextinfo \
|
||||||
threadedqopenglwidget \
|
|
||||||
2dpainting \
|
2dpainting \
|
||||||
hellogl2 \
|
hellogl2 \
|
||||||
qopenglwidget \
|
qopenglwidget \
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
# Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
|
||||||
project(threadedqopenglwidget LANGUAGES CXX)
|
|
||||||
|
|
||||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
|
||||||
set(INSTALL_EXAMPLESDIR "examples")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/opengl/threadedqopenglwidget")
|
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL OpenGLWidgets Widgets)
|
|
||||||
|
|
||||||
qt_standard_project_setup()
|
|
||||||
|
|
||||||
qt_add_executable(threadedqopenglwidget
|
|
||||||
renderer.cpp renderer.h
|
|
||||||
glwidget.cpp glwidget.h
|
|
||||||
main.cpp
|
|
||||||
mainwindow.cpp mainwindow.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(threadedqopenglwidget PROPERTIES
|
|
||||||
WIN32_EXECUTABLE TRUE
|
|
||||||
MACOSX_BUNDLE TRUE
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(threadedqopenglwidget PRIVATE
|
|
||||||
Qt6::Core
|
|
||||||
Qt6::Gui
|
|
||||||
Qt6::OpenGL
|
|
||||||
Qt6::OpenGLWidgets
|
|
||||||
Qt6::Widgets
|
|
||||||
)
|
|
||||||
|
|
||||||
install(TARGETS threadedqopenglwidget
|
|
||||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
|
||||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
|
||||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
|
||||||
)
|
|
@ -1,71 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
||||||
|
|
||||||
#include "glwidget.h"
|
|
||||||
#include "renderer.h"
|
|
||||||
|
|
||||||
#include <qmath.h>
|
|
||||||
#include <QGuiApplication>
|
|
||||||
|
|
||||||
GLWidget::GLWidget(QWidget *parent)
|
|
||||||
: QOpenGLWidget(parent)
|
|
||||||
{
|
|
||||||
setMinimumSize(300, 250);
|
|
||||||
|
|
||||||
connect(this, &QOpenGLWidget::aboutToCompose, this, &GLWidget::onAboutToCompose);
|
|
||||||
connect(this, &QOpenGLWidget::frameSwapped, this, &GLWidget::onFrameSwapped);
|
|
||||||
connect(this, &QOpenGLWidget::aboutToResize, this, &GLWidget::onAboutToResize);
|
|
||||||
connect(this, &QOpenGLWidget::resized, this, &GLWidget::onResized);
|
|
||||||
|
|
||||||
m_thread = new QThread;
|
|
||||||
m_renderer = new Renderer(this);
|
|
||||||
m_renderer->moveToThread(m_thread);
|
|
||||||
connect(m_thread, &QThread::finished, m_renderer, &QObject::deleteLater);
|
|
||||||
|
|
||||||
connect(this, &GLWidget::renderRequested, m_renderer, &Renderer::render);
|
|
||||||
connect(m_renderer, &Renderer::contextWanted, this, &GLWidget::grabContext);
|
|
||||||
|
|
||||||
m_thread->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
GLWidget::~GLWidget()
|
|
||||||
{
|
|
||||||
m_renderer->prepareExit();
|
|
||||||
m_thread->quit();
|
|
||||||
m_thread->wait();
|
|
||||||
delete m_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLWidget::onAboutToCompose()
|
|
||||||
{
|
|
||||||
// We are on the gui thread here. Composition is about to
|
|
||||||
// begin. Wait until the render thread finishes.
|
|
||||||
m_renderer->lockRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLWidget::onFrameSwapped()
|
|
||||||
{
|
|
||||||
m_renderer->unlockRenderer();
|
|
||||||
// Assuming a blocking swap, our animation is driven purely by the
|
|
||||||
// vsync in this example.
|
|
||||||
emit renderRequested();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLWidget::onAboutToResize()
|
|
||||||
{
|
|
||||||
m_renderer->lockRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLWidget::onResized()
|
|
||||||
{
|
|
||||||
m_renderer->unlockRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLWidget::grabContext()
|
|
||||||
{
|
|
||||||
m_renderer->lockRenderer();
|
|
||||||
QMutexLocker lock(m_renderer->grabMutex());
|
|
||||||
context()->moveToThread(m_thread);
|
|
||||||
m_renderer->grabCond()->wakeAll();
|
|
||||||
m_renderer->unlockRenderer();
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
||||||
|
|
||||||
#ifndef GLWIDGET_H
|
|
||||||
#define GLWIDGET_H
|
|
||||||
|
|
||||||
#include <QOpenGLWidget>
|
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QThread)
|
|
||||||
|
|
||||||
class Renderer;
|
|
||||||
|
|
||||||
class GLWidget : public QOpenGLWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit GLWidget(QWidget *parent = nullptr);
|
|
||||||
~GLWidget();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *) override { }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void renderRequested();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void grabContext();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onAboutToCompose();
|
|
||||||
void onFrameSwapped();
|
|
||||||
void onAboutToResize();
|
|
||||||
void onResized();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QThread *m_thread;
|
|
||||||
Renderer *m_renderer;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // GLWIDGET_H
|
|
@ -1,88 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QScreen>
|
|
||||||
#include <QShortcut>
|
|
||||||
#include <QSurfaceFormat>
|
|
||||||
#include <QOpenGLContext>
|
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
#include <QCommandLineOption>
|
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "glwidget.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
static QString getGlString(QOpenGLFunctions *functions, GLenum name)
|
|
||||||
{
|
|
||||||
if (const GLubyte *p = functions->glGetString(name))
|
|
||||||
return QString::fromLatin1(reinterpret_cast<const char *>(p));
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main( int argc, char ** argv )
|
|
||||||
{
|
|
||||||
QApplication a( argc, argv );
|
|
||||||
|
|
||||||
QCoreApplication::setApplicationName("Qt Threaded QOpenGLWidget Example");
|
|
||||||
QCoreApplication::setOrganizationName("QtProject");
|
|
||||||
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
|
|
||||||
QCommandLineParser parser;
|
|
||||||
parser.setApplicationDescription(QCoreApplication::applicationName());
|
|
||||||
parser.addHelpOption();
|
|
||||||
parser.addVersionOption();
|
|
||||||
QCommandLineOption singleOption("single", "Single thread");
|
|
||||||
parser.addOption(singleOption);
|
|
||||||
parser.process(a);
|
|
||||||
|
|
||||||
QSurfaceFormat format;
|
|
||||||
format.setDepthBufferSize(16);
|
|
||||||
QSurfaceFormat::setDefaultFormat(format);
|
|
||||||
|
|
||||||
// Two top-level windows with two QOpenGLWidget children in each.
|
|
||||||
// The rendering for the four QOpenGLWidgets happens on four separate threads.
|
|
||||||
|
|
||||||
GLWidget topLevelGlWidget;
|
|
||||||
QPoint pos = topLevelGlWidget.screen()->availableGeometry().topLeft() + QPoint(200, 200);
|
|
||||||
topLevelGlWidget.setWindowTitle(QStringLiteral("Threaded QOpenGLWidget example top level"));
|
|
||||||
topLevelGlWidget.resize(200, 200);
|
|
||||||
topLevelGlWidget.move(pos);
|
|
||||||
topLevelGlWidget.show();
|
|
||||||
auto *closeShortcut = new QShortcut(Qt::CTRL | Qt::Key_Q, &a, QApplication::closeAllWindows);
|
|
||||||
closeShortcut->setContext(Qt::ApplicationShortcut);
|
|
||||||
|
|
||||||
const QString glInfo = getGlString(topLevelGlWidget.context()->functions(), GL_VENDOR)
|
|
||||||
+ QLatin1Char('/') + getGlString(topLevelGlWidget.context()->functions(), GL_RENDERER);
|
|
||||||
|
|
||||||
const bool supportsThreading = !glInfo.contains(QLatin1String("nouveau"), Qt::CaseInsensitive)
|
|
||||||
&& !glInfo.contains(QLatin1String("ANGLE"), Qt::CaseInsensitive)
|
|
||||||
&& !glInfo.contains(QLatin1String("llvmpipe"), Qt::CaseInsensitive);
|
|
||||||
|
|
||||||
const QString toolTip = supportsThreading ? glInfo : glInfo + QStringLiteral("\ndoes not support threaded OpenGL.");
|
|
||||||
topLevelGlWidget.setToolTip(toolTip);
|
|
||||||
|
|
||||||
std::unique_ptr<MainWindow> mw1;
|
|
||||||
std::unique_ptr<MainWindow> mw2;
|
|
||||||
if (!parser.isSet(singleOption)) {
|
|
||||||
if (supportsThreading) {
|
|
||||||
pos += QPoint(100, 100);
|
|
||||||
mw1.reset(new MainWindow);
|
|
||||||
mw1->setToolTip(toolTip);
|
|
||||||
mw1->move(pos);
|
|
||||||
mw1->setWindowTitle(QStringLiteral("Threaded QOpenGLWidget example #1"));
|
|
||||||
mw1->show();
|
|
||||||
pos += QPoint(100, 100);
|
|
||||||
mw2.reset(new MainWindow);
|
|
||||||
mw2->setToolTip(toolTip);
|
|
||||||
mw2->move(pos);
|
|
||||||
mw2->setWindowTitle(QStringLiteral("Threaded QOpenGLWidget example #2"));
|
|
||||||
mw2->show();
|
|
||||||
} else {
|
|
||||||
qWarning() << toolTip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.exec();
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
||||||
|
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "glwidget.h"
|
|
||||||
|
|
||||||
MainWindow::MainWindow()
|
|
||||||
{
|
|
||||||
setMinimumSize(800, 400);
|
|
||||||
GLWidget *glwidget1 = new GLWidget(this);
|
|
||||||
glwidget1->resize(400, 400);
|
|
||||||
|
|
||||||
GLWidget *glwidget2 = new GLWidget(this);
|
|
||||||
glwidget2->resize(400, 400);
|
|
||||||
glwidget2->move(400, 0);
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
||||||
|
|
||||||
#ifndef MAINWINDOW_H
|
|
||||||
#define MAINWINDOW_H
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
class MainWindow : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
MainWindow();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,267 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
||||||
|
|
||||||
#include "renderer.h"
|
|
||||||
#include <qmath.h>
|
|
||||||
#include <QOpenGLWidget>
|
|
||||||
#include <QGuiApplication>
|
|
||||||
|
|
||||||
static const char VERTEX_SHADER[] = R"(attribute highp vec4 vertex;
|
|
||||||
attribute mediump vec3 normal;
|
|
||||||
uniform mediump mat4 matrix;
|
|
||||||
varying mediump vec4 color;
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));
|
|
||||||
float angle = max(dot(normal, toLight), 0.0);
|
|
||||||
vec3 col = vec3(0.40, 1.0, 0.0);
|
|
||||||
color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);
|
|
||||||
color = clamp(color, 0.0, 1.0);
|
|
||||||
gl_Position = matrix * vertex;
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
static const char FRAGMENT_SHADER[] = R"(varying mediump vec4 color;
|
|
||||||
void main(void)
|
|
||||||
{
|
|
||||||
gl_FragColor = color;
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
Renderer::Renderer(QOpenGLWidget *w) :
|
|
||||||
m_glwidget(w)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::paintQtLogo()
|
|
||||||
{
|
|
||||||
vbo.bind();
|
|
||||||
program.setAttributeBuffer(vertexAttr, GL_FLOAT, 0, 3);
|
|
||||||
program.setAttributeBuffer(normalAttr, GL_FLOAT, vertices.count() * 3 * sizeof(GLfloat), 3);
|
|
||||||
vbo.release();
|
|
||||||
|
|
||||||
program.enableAttributeArray(vertexAttr);
|
|
||||||
program.enableAttributeArray(normalAttr);
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
|
|
||||||
|
|
||||||
program.disableAttributeArray(normalAttr);
|
|
||||||
program.disableAttributeArray(vertexAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some OpenGL implementations have serious issues with compiling and linking
|
|
||||||
// shaders on multiple threads concurrently. Avoid this.
|
|
||||||
Q_GLOBAL_STATIC(QMutex, initMutex)
|
|
||||||
|
|
||||||
void Renderer::render()
|
|
||||||
{
|
|
||||||
if (m_exiting)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QOpenGLContext *ctx = m_glwidget->context();
|
|
||||||
if (!ctx) // QOpenGLWidget not yet initialized
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Grab the context.
|
|
||||||
m_grabMutex.lock();
|
|
||||||
emit contextWanted();
|
|
||||||
m_grabCond.wait(&m_grabMutex);
|
|
||||||
QMutexLocker lock(&m_renderMutex);
|
|
||||||
m_grabMutex.unlock();
|
|
||||||
|
|
||||||
if (m_exiting)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Q_ASSERT(ctx->thread() == QThread::currentThread());
|
|
||||||
|
|
||||||
// Make the context (and an offscreen surface) current for this thread. The
|
|
||||||
// QOpenGLWidget's fbo is bound in the context.
|
|
||||||
m_glwidget->makeCurrent();
|
|
||||||
|
|
||||||
if (!m_inited) {
|
|
||||||
m_inited = true;
|
|
||||||
initializeOpenGLFunctions();
|
|
||||||
|
|
||||||
QMutexLocker initLock(initMutex());
|
|
||||||
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
|
|
||||||
vshader->compileSourceCode(VERTEX_SHADER);
|
|
||||||
|
|
||||||
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
|
|
||||||
fshader->compileSourceCode(FRAGMENT_SHADER);
|
|
||||||
|
|
||||||
program.addShader(vshader);
|
|
||||||
program.addShader(fshader);
|
|
||||||
program.link();
|
|
||||||
|
|
||||||
vertexAttr = program.attributeLocation("vertex");
|
|
||||||
normalAttr = program.attributeLocation("normal");
|
|
||||||
matrixUniform = program.uniformLocation("matrix");
|
|
||||||
|
|
||||||
m_fAngle = 0;
|
|
||||||
m_fScale = 1;
|
|
||||||
createGeometry();
|
|
||||||
|
|
||||||
vbo.create();
|
|
||||||
vbo.bind();
|
|
||||||
const int verticesSize = vertices.count() * 3 * sizeof(GLfloat);
|
|
||||||
vbo.allocate(verticesSize * 2);
|
|
||||||
vbo.write(0, vertices.constData(), verticesSize);
|
|
||||||
vbo.write(verticesSize, normals.constData(), verticesSize);
|
|
||||||
|
|
||||||
m_elapsed.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
//qDebug("%p elapsed %lld", QThread::currentThread(), m_elapsed.restart());
|
|
||||||
|
|
||||||
glClearColor(0.1f, 0.2f, 0.2f, 1.0f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
glFrontFace(GL_CW);
|
|
||||||
glCullFace(GL_FRONT);
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
|
|
||||||
QMatrix4x4 modelview;
|
|
||||||
modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
|
|
||||||
modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
|
|
||||||
modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
|
|
||||||
modelview.scale(m_fScale);
|
|
||||||
modelview.translate(0.0f, -0.2f, 0.0f);
|
|
||||||
|
|
||||||
program.bind();
|
|
||||||
program.setUniformValue(matrixUniform, modelview);
|
|
||||||
paintQtLogo();
|
|
||||||
program.release();
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
|
|
||||||
m_fAngle += 1.0f;
|
|
||||||
|
|
||||||
// Make no context current on this thread and move the QOpenGLWidget's
|
|
||||||
// context back to the gui thread.
|
|
||||||
m_glwidget->doneCurrent();
|
|
||||||
ctx->moveToThread(qGuiApp->thread());
|
|
||||||
|
|
||||||
// Schedule composition. Note that this will use QueuedConnection, meaning
|
|
||||||
// that update() will be invoked on the gui thread.
|
|
||||||
QMetaObject::invokeMethod(m_glwidget, "update");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::createGeometry()
|
|
||||||
{
|
|
||||||
vertices.clear();
|
|
||||||
normals.clear();
|
|
||||||
|
|
||||||
qreal x1 = +0.06f;
|
|
||||||
qreal y1 = -0.14f;
|
|
||||||
qreal x2 = +0.14f;
|
|
||||||
qreal y2 = -0.06f;
|
|
||||||
qreal x3 = +0.08f;
|
|
||||||
qreal y3 = +0.00f;
|
|
||||||
qreal x4 = +0.30f;
|
|
||||||
qreal 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;
|
|
||||||
const qreal sectorAngle = 2 * qreal(M_PI) / NumSectors;
|
|
||||||
|
|
||||||
for (int i = 0; i < NumSectors; ++i) {
|
|
||||||
qreal angle = i * sectorAngle;
|
|
||||||
qreal sinAngle = sin(angle);
|
|
||||||
qreal cosAngle = cos(angle);
|
|
||||||
qreal x5 = 0.30 * sinAngle;
|
|
||||||
qreal y5 = 0.30 * cosAngle;
|
|
||||||
qreal x6 = 0.20 * sinAngle;
|
|
||||||
qreal y6 = 0.20 * cosAngle;
|
|
||||||
|
|
||||||
angle += sectorAngle;
|
|
||||||
sinAngle = sin(angle);
|
|
||||||
cosAngle = cos(angle);
|
|
||||||
qreal x7 = 0.20 * sinAngle;
|
|
||||||
qreal y7 = 0.20 * cosAngle;
|
|
||||||
qreal x8 = 0.30 * sinAngle;
|
|
||||||
qreal y8 = 0.30 * cosAngle;
|
|
||||||
|
|
||||||
quad(x5, y5, x6, y6, x7, y7, x8, y8);
|
|
||||||
|
|
||||||
extrude(x6, y6, x7, y7);
|
|
||||||
extrude(x8, y8, x5, y5);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (qsizetype i = 0; i < vertices.size(); ++i)
|
|
||||||
vertices[i] *= 2.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4)
|
|
||||||
{
|
|
||||||
vertices << QVector3D(x1, y1, -0.05f);
|
|
||||||
vertices << QVector3D(x2, y2, -0.05f);
|
|
||||||
vertices << QVector3D(x4, y4, -0.05f);
|
|
||||||
|
|
||||||
vertices << QVector3D(x3, y3, -0.05f);
|
|
||||||
vertices << QVector3D(x4, y4, -0.05f);
|
|
||||||
vertices << QVector3D(x2, y2, -0.05f);
|
|
||||||
|
|
||||||
QVector3D n = QVector3D::normal
|
|
||||||
(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f));
|
|
||||||
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
|
|
||||||
vertices << QVector3D(x4, y4, 0.05f);
|
|
||||||
vertices << QVector3D(x2, y2, 0.05f);
|
|
||||||
vertices << QVector3D(x1, y1, 0.05f);
|
|
||||||
|
|
||||||
vertices << QVector3D(x2, y2, 0.05f);
|
|
||||||
vertices << QVector3D(x4, y4, 0.05f);
|
|
||||||
vertices << QVector3D(x3, y3, 0.05f);
|
|
||||||
|
|
||||||
n = QVector3D::normal
|
|
||||||
(QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f));
|
|
||||||
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2)
|
|
||||||
{
|
|
||||||
vertices << QVector3D(x1, y1, +0.05f);
|
|
||||||
vertices << QVector3D(x2, y2, +0.05f);
|
|
||||||
vertices << QVector3D(x1, y1, -0.05f);
|
|
||||||
|
|
||||||
vertices << QVector3D(x2, y2, -0.05f);
|
|
||||||
vertices << QVector3D(x1, y1, -0.05f);
|
|
||||||
vertices << QVector3D(x2, y2, +0.05f);
|
|
||||||
|
|
||||||
QVector3D n = QVector3D::normal
|
|
||||||
(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f));
|
|
||||||
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
normals << n;
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
||||||
|
|
||||||
#ifndef RENDERER_H
|
|
||||||
#define RENDERER_H
|
|
||||||
|
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
#include <QOpenGLBuffer>
|
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include <QVector3D>
|
|
||||||
#include <QMatrix4x4>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QWaitCondition>
|
|
||||||
#include <QElapsedTimer>
|
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QOpenGLWidget)
|
|
||||||
|
|
||||||
class Renderer : public QObject, protected QOpenGLFunctions
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Renderer(QOpenGLWidget *w);
|
|
||||||
void lockRenderer() { m_renderMutex.lock(); }
|
|
||||||
void unlockRenderer() { m_renderMutex.unlock(); }
|
|
||||||
QMutex *grabMutex() { return &m_grabMutex; }
|
|
||||||
QWaitCondition *grabCond() { return &m_grabCond; }
|
|
||||||
void prepareExit() { m_exiting = true; m_grabCond.wakeAll(); }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void contextWanted();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void render();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void paintQtLogo();
|
|
||||||
void createGeometry();
|
|
||||||
void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4);
|
|
||||||
void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
|
|
||||||
|
|
||||||
bool m_inited = false;
|
|
||||||
qreal m_fAngle = 0;
|
|
||||||
qreal m_fScale = 1;
|
|
||||||
QList<QVector3D> vertices;
|
|
||||||
QList<QVector3D> normals;
|
|
||||||
QOpenGLShaderProgram program;
|
|
||||||
QOpenGLBuffer vbo;
|
|
||||||
int vertexAttr = 0;
|
|
||||||
int normalAttr = 0;
|
|
||||||
int matrixUniform = 0;
|
|
||||||
QOpenGLWidget *m_glwidget = nullptr;
|
|
||||||
QMutex m_renderMutex;
|
|
||||||
QElapsedTimer m_elapsed;
|
|
||||||
QMutex m_grabMutex;
|
|
||||||
QWaitCondition m_grabCond;
|
|
||||||
bool m_exiting = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // RENDERER_H
|
|
@ -1,13 +0,0 @@
|
|||||||
QT += widgets opengl openglwidgets
|
|
||||||
|
|
||||||
SOURCES += main.cpp \
|
|
||||||
glwidget.cpp \
|
|
||||||
mainwindow.cpp \
|
|
||||||
renderer.cpp
|
|
||||||
|
|
||||||
HEADERS += glwidget.h \
|
|
||||||
mainwindow.h \
|
|
||||||
renderer.h
|
|
||||||
|
|
||||||
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/threadedqopenglwidget
|
|
||||||
INSTALLS += target
|
|
Loading…
Reference in New Issue
Block a user