6.5.3 clean

This commit is contained in:
kleuter
2023-11-01 18:02:52 +01:00
parent bbe896803b
commit 7018d9e6c8
2170 changed files with 57471 additions and 43550 deletions

View File

@ -7,7 +7,6 @@ if(TARGET Qt6::Widgets)
qt_internal_add_example(contextinfo)
qt_internal_add_example(2dpainting)
qt_internal_add_example(hellogl2)
qt_internal_add_example(qopenglwidget)
qt_internal_add_example(cube)
qt_internal_add_example(textures)
qt_internal_add_example(stereoqopenglwidget)

View File

@ -5,6 +5,7 @@
\example 2dpainting
\title 2D Painting Example
\ingroup examples-widgets-opengl
\examplecategory {Graphics & Multimedia}
\brief The 2D Painting example shows how QPainter and QOpenGLWidget can be
used together to display accelerated 2D graphics on supported hardware.

View File

@ -5,11 +5,14 @@
\example cube
\ingroup examples-widgets-opengl
\title Cube OpenGL ES 2.0 example
\examplecategory {Data Visualization & 3D}
\brief The Cube OpenGL ES 2.0 example shows how to write mouse rotatable
textured 3D cube using OpenGL ES 2.0 with Qt. It shows how to handle
polygon geometries efficiently and how to write simple vertex and
fragment shader for programmable graphics pipeline. In addition it
\brief Shows how to manually rotate a textured 3D cube with user input.
The Cube OpenGL ES 2.0 example shows how to manually rotate a textured 3D
cube with user input, using OpenGL ES 2.0 with Qt. It shows how to
handle polygon geometries efficiently and how to write a simple vertex and
fragment shader for a programmable graphics pipeline. In addition it
shows how to use quaternions for representing 3D object orientation.
This example has been written for OpenGL ES 2.0 but it works also on

View File

@ -5,6 +5,7 @@
\example hellogl2
\title Hello GL2 Example
\ingroup examples-widgets-opengl
\examplecategory {Data Visualization & 3D}
\brief The Hello GL2 example demonstrates the basic use of the OpenGL-related classes
provided with Qt.

View File

@ -5,24 +5,144 @@
\example hellogles3
\title Hello GLES3 Example
\ingroup examples-widgets-opengl
\examplecategory {Graphics & Multimedia}
\brief The Hello GLES3 example demonstrates easy, cross-platform usage of
OpenGL ES 3.0 functions via QOpenGLExtraFunctions in an application that
\brief Demonstrates OpenGL ES 3.0 functions via QOpenGLExtraFunctions.
\image hellogles3-example.png
\section1 Overview
This example demonstrates easy, cross-platform usage of OpenGL ES 3.0
functions via QOpenGLExtraFunctions in an application that
works identically on desktop platforms with OpenGL 3.3 and mobile/embedded
devices with OpenGL ES 3.0.
The code is always the same, with the exception of two places:
\list
\li The OpenGL context creation has to have a sufficiently high version
number for the features that are in use.
\li The shader code's version directive is different.
\endlist
This example has no QWidget dependencies. Instead, it uses QOpenGLWindow, a
This example has no QWidget dependencies, it uses QOpenGLWindow, a
convenience subclass of QWindow that allows easy implementation of windows
that contain OpenGL-rendered content. In this sense it complements the
\l{OpenGL Window Example}, which shows the implementation of an OpenGL-based
QWindow without using the convenience subclass.
\image hellogles3-example.png
The Qt logo shape implementation is included from the \l{Hello GL2 Example}.
In other aspects pertaining to using OpenGL there are the following
differences.
\list
\li The OpenGL context creation has to have a sufficiently high version
number for the features that are in use.
\li The shader's version directive is different.
\endlist
\section1 Setting up in main.cpp
Here we instantiate our QGuiApplication, QSurfaceformat and set its
\l{QSurfaceFormat::depthBufferSize()}{depth buffer size}:
\quotefromfile hellogles3/main.cpp
\skipto int main(int argc, char *argv[])
\printuntil fmt.setDepthBufferSize(24);
We request an OpenGL 3.3 core or OpenGL ES 3.0 context, depending on
QOpenGLContext::openGLModuleType():
\skipto if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
\printuntil QSurfaceFormat::setDefaultFormat(fmt);
We set the default surface format and instantiate our GLWindow \c glWindow.
\section1 Implementing GLWindow
This class delivers the features of the example application.
To start, \c GLWindow is declared by implementing a subclass of
QOpenGLWindow:
\quotefromfile hellogles3/glwindow.h
\skipto class GLWindow : public QOpenGLWindow
\printto {
The following properties are declared using Q_PROPERTY:
\printto public:
The following public functions are declared:
\printto private slots:
The following private objects are declared:
\printto };
On the implementation side, those functions that are not declared inline are
implemented (or re-implemented) in \c{glwindow.cpp}. The following selections
will cover implementation particulars pertaining to the use of OpenGL ES 3.0.
\section2 Animations
The following code pertains to the animations, and won't be explored here:
\quotefromfile hellogles3/glwindow.cpp
\skipto GLWindow::GLWindow()
\printto static const char *vertexShaderSource =
For more information see the documentation for \l QPropertyAnimation,
\l QSequentialAnimationGroup.
\section2 Shaders
The shaders are defined like so:
\printto QByteArray versionedShaderCode(const char *src)
\note These are OpenGL version agnostic. We take this and append
the version like so:
\printto void GLWindow::initializeGL()
\section2 Initializing OpenGL
Initializing the shader program in handled by \c initializeGL():
\printuntil m_program = new QOpenGLShaderProgram;
\skipto m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, versionedShaderCode(vertexShaderSource));
Now the OpenGL version is prepended and the various matrices and light
position is set:
\printuntil m_lightPosLoc = m_program->uniformLocation("lightPos");
While not strictly required for ES 3, a vertex array object is created.
\skipto delete m_vao;
\printuntil f->glEnable(GL_CULL_FACE);
\section2 Resizing the window
The perspective needs to be aligned with the new window size as so:
\skipto void GLWindow::resizeGL(int w, int h)
\printto void GLWindow::paintGL()
\section2 Painting
We use QOpenGLExtraFunctions instead of QOpenGLFunctions as we want to
do more than what GL(ES) 2.0 offers:
\printuntil QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
We clear the screen and buffers and bind our shader program and texture:
\printuntil m_texture->bind();
Logic for handling an initial \c paintGL() call or a call after a
\c resizeGL() call is implemented like so:
\printuntil }
Last, we demonstrate a function introduced in OpenGL 3.1 or OpenGL ES 3.0:
\skipto f->glDrawArraysInstanced(GL_TRIANGLES, 0, m_logo.vertexCount(), 32 * 36);
\printuntil }
This works because we earlier requested 3.3 or 3.0 context.
*/

View File

@ -4,6 +4,8 @@
/*!
\example openglwindow
\title OpenGL Window Example
\ingroup examples-widgets-opengl
\examplecategory {Graphics & Multimedia}
\brief This example shows how to create a minimal QWindow based application
for the purpose of using OpenGL.

View File

@ -4,7 +4,7 @@
/*!
\example stereoqopenglwidget
\title QOpenGLWidget Stereoscopic Rendering Example
\examplecategory {Graphics & Multimedia}
\brief This example shows how to create a minimal QOpenGLWidget based application
with stereoscopic rendering support.

View File

@ -6,10 +6,8 @@
#include <QWidget>
QT_BEGIN_NAMESPACE
class QSlider;
class QPushButton;
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QSlider)
QT_FORWARD_DECLARE_CLASS(QPushButton)
class GLWidget;
class MainWindow;

View File

@ -9,14 +9,10 @@
#include <QVector3D>
#include "../hellogl2/logo.h"
QT_BEGIN_NAMESPACE
class QOpenGLTexture;
class QOpenGLShaderProgram;
class QOpenGLBuffer;
class QOpenGLVertexArrayObject;
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
QT_FORWARD_DECLARE_CLASS(QOpenGLBuffer)
QT_FORWARD_DECLARE_CLASS(QOpenGLVertexArrayObject)
class GLWindow : public QOpenGLWindow
{

View File

@ -7,7 +7,6 @@ qtHaveModule(widgets) {
SUBDIRS += contextinfo \
2dpainting \
hellogl2 \
qopenglwidget \
cube \
textures \
stereoqopenglwidget

View File

@ -7,11 +7,9 @@
#include <QWindow>
#include <QOpenGLFunctions>
QT_BEGIN_NAMESPACE
class QPainter;
class QOpenGLContext;
class QOpenGLPaintDevice;
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QPainter)
QT_FORWARD_DECLARE_CLASS(QOpenGLContext)
QT_FORWARD_DECLARE_CLASS(QOpenGLPaintDevice)
//! [1]
class OpenGLWindow : public QWindow, protected QOpenGLFunctions

View File

@ -1,53 +0,0 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(qopenglwidget LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/opengl/qopenglwidget")
find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL OpenGLWidgets Widgets)
qt_standard_project_setup()
qt_add_executable(qopenglwidget
bubble.cpp bubble.h
glwidget.cpp glwidget.h
main.cpp
mainwindow.cpp mainwindow.h
)
set_target_properties(qopenglwidget PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(qopenglwidget PRIVATE
Qt6::Core
Qt6::Gui
Qt6::OpenGL
Qt6::OpenGLWidgets
Qt6::Widgets
)
# Resources:
set(texture_resource_files
"qt.png"
)
qt6_add_resources(qopenglwidget "texture"
PREFIX
"/"
FILES
${texture_resource_files}
)
install(TARGETS qopenglwidget
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -1,99 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "bubble.h"
Bubble::Bubble(const QPointF &position, qreal radius, const QPointF &velocity)
: position(position), vel(velocity), radius(radius)
{
innerColor = randomColor();
outerColor = randomColor();
updateBrush();
}
//! [0]
void Bubble::updateCache()
{
delete cache;
cache = new QImage(qRound(radius * 2 + 2), qRound(radius * 2 + 2), QImage::Format_ARGB32_Premultiplied);
cache->fill(0x00000000);
QPainter p(cache);
p.setRenderHint(QPainter::Antialiasing);
QPen pen(Qt::white);
pen.setWidth(2);
p.setPen(pen);
p.setBrush(brush);
p.drawEllipse(1, 1, int(2*radius), int(2*radius));
}
//! [0]
Bubble::~Bubble()
{
delete cache;
}
void Bubble::updateBrush()
{
QRadialGradient gradient(QPointF(radius, radius), radius,
QPointF(radius*0.5, radius*0.5));
gradient.setColorAt(0, QColor(255, 255, 255, 255));
gradient.setColorAt(0.25, innerColor);
gradient.setColorAt(1, outerColor);
brush = QBrush(gradient);
updateCache();
}
//! [1]
void Bubble::drawBubble(QPainter *painter)
{
painter->save();
painter->translate(position.x() - radius, position.y() - radius);
painter->setOpacity(0.8);
painter->drawImage(0, 0, *cache);
painter->restore();
}
//! [1]
QColor Bubble::randomColor()
{
int red = int(185 + QRandomGenerator::global()->bounded(70));
int green = int(185 + QRandomGenerator::global()->bounded(70));
int blue = int(205 + QRandomGenerator::global()->bounded(50));
int alpha = int(91 + QRandomGenerator::global()->bounded(100));
return QColor(red, green, blue, alpha);
}
void Bubble::move(const QRect &bbox)
{
position += vel;
qreal leftOverflow = position.x() - radius - bbox.left();
qreal rightOverflow = position.x() + radius - bbox.right();
qreal topOverflow = position.y() - radius - bbox.top();
qreal bottomOverflow = position.y() + radius - bbox.bottom();
if (leftOverflow < 0.0) {
position.setX(position.x() - 2 * leftOverflow);
vel.setX(-vel.x());
} else if (rightOverflow > 0.0) {
position.setX(position.x() - 2 * rightOverflow);
vel.setX(-vel.x());
}
if (topOverflow < 0.0) {
position.setY(position.y() - 2 * topOverflow);
vel.setY(-vel.y());
} else if (bottomOverflow > 0.0) {
position.setY(position.y() - 2 * bottomOverflow);
vel.setY(-vel.y());
}
}
QRectF Bubble::rect()
{
return QRectF(position.x() - radius, position.y() - radius,
2 * radius, 2 * radius);
}

View File

@ -1,39 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef BUBBLE_H
#define BUBBLE_H
#include <QBrush>
#include <QColor>
#include <QPointF>
#include <QRect>
#include <QRectF>
QT_FORWARD_DECLARE_CLASS(QPainter)
class Bubble
{
public:
Bubble(const QPointF &position, qreal radius, const QPointF &velocity);
~Bubble();
void drawBubble(QPainter *painter);
void updateBrush();
void move(const QRect &bbox);
void updateCache();
QRectF rect();
private:
QColor randomColor();
QBrush brush;
QPointF position;
QPointF vel;
qreal radius;
QColor innerColor;
QColor outerColor;
QImage *cache = nullptr;
};
#endif

View File

@ -1,540 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "glwidget.h"
#include <QPainter>
#include <QPaintEngine>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QRandomGenerator>
#include <QCoreApplication>
#include <qmath.h>
#include "mainwindow.h"
#include "bubble.h"
const int bubbleNum = 8;
#ifndef GL_SRGB8_ALPHA8
#define GL_SRGB8_ALPHA8 0x8C43
#endif
GLWidget::GLWidget(MainWindow *maybeMainWindow, const QColor &background)
: m_mainWindow(maybeMainWindow),
m_background(background)
{
setMinimumSize(300, 250);
if (QCoreApplication::arguments().contains(QStringLiteral("--srgb")))
setTextureFormat(GL_SRGB8_ALPHA8);
}
GLWidget::~GLWidget()
{
reset();
}
void GLWidget::reset()
{
qDeleteAll(m_bubbles);
// Leave everything in a state suitable for a subsequent call to
// initialize(). This matters when coming from the context's
// aboutToBeDestroyed signal, would not matter when invoked from the
// destructor.
m_bubbles.clear();
// And now release all OpenGL resources.
makeCurrent();
delete m_texture;
m_texture = nullptr;
delete m_program1;
m_program1 = nullptr;
delete m_program2;
m_program2 = nullptr;
delete m_vshader1;
m_vshader1 = nullptr;
delete m_fshader1;
m_fshader1 = nullptr;
delete m_vshader2;
m_vshader2 = nullptr;
delete m_fshader2;
m_fshader2 = nullptr;
m_vbo1.destroy();
m_vbo2.destroy();
doneCurrent();
// We are done with the current QOpenGLContext, forget it. If there is a
// subsequent initialize(), that will then connect to the new context.
QObject::disconnect(m_contextWatchConnection);
}
void GLWidget::setScaling(int scale)
{
if (scale > 30)
m_fScale = 1 + qreal(scale - 30) / 30 * 0.25;
else if (scale < 30)
m_fScale = 1 - (qreal(30 - scale) / 30 * 0.25);
else
m_fScale = 1;
}
void GLWidget::setLogo()
{
m_qtLogo = true;
}
void GLWidget::setTexture()
{
m_qtLogo = false;
}
void GLWidget::setShowBubbles(bool bubbles)
{
m_showBubbles = bubbles;
}
void GLWidget::paintQtLogo()
{
m_program1->enableAttributeArray(m_vertexAttr1);
m_program1->enableAttributeArray(m_normalAttr1);
m_vbo1.bind();
// The data in the buffer is placed like this:
// vertex1.x, vertex1.y, vertex1.z, normal1.x, normal1.y, normal1.z, vertex2.x, ...
m_program1->setAttributeBuffer(m_vertexAttr1, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));
m_program1->setAttributeBuffer(m_normalAttr1, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
m_vbo1.release();
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
m_program1->disableAttributeArray(m_normalAttr1);
m_program1->disableAttributeArray(m_vertexAttr1);
}
void GLWidget::paintTexturedCube()
{
m_texture->bind();
if (!m_vbo2.isCreated()) {
static GLfloat afVertices[] = {
-0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5,
0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5,
-0.5, -0.5, -0.5, 0.5,-0.5,-0.5,-0.5,0.5,-0.5,
0.5, 0.5, -0.5, -0.5,0.5,-0.5,0.5,-0.5,-0.5,
0.5, -0.5, -0.5, 0.5,-0.5,0.5,0.5,0.5,-0.5,
0.5, 0.5, 0.5, 0.5,0.5,-0.5,0.5,-0.5,0.5,
-0.5, 0.5, -0.5, -0.5,-0.5,0.5,-0.5,-0.5,-0.5,
-0.5, -0.5, 0.5, -0.5,0.5,-0.5,-0.5,0.5,0.5,
0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
-0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5,
-0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5
};
static GLfloat afTexCoord[] = {
0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f,
1.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f,
1.0f,0.0f, 1.0f,1.0f, 0.0f,0.0f,
0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f
};
GLfloat afNormals[] = {
0,0,-1, 0,0,-1, 0,0,-1,
0,0,-1, 0,0,-1, 0,0,-1,
0,0,1, 0,0,1, 0,0,1,
0,0,1, 0,0,1, 0,0,1,
-1,0,0, -1,0,0, -1,0,0,
-1,0,0, -1,0,0, -1,0,0,
1,0,0, 1,0,0, 1,0,0,
1,0,0, 1,0,0, 1,0,0,
0,-1,0, 0,-1,0, 0,-1,0,
0,-1,0, 0,-1,0, 0,-1,0,
0,1,0, 0,1,0, 0,1,0,
0,1,0, 0,1,0, 0,1,0
};
m_vbo2.create();
m_vbo2.bind();
m_vbo2.allocate(36 * 8 * sizeof(GLfloat));
m_vbo2.write(0, afVertices, sizeof(afVertices));
m_vbo2.write(sizeof(afVertices), afTexCoord, sizeof(afTexCoord));
m_vbo2.write(sizeof(afVertices) + sizeof(afTexCoord), afNormals, sizeof(afNormals));
m_vbo2.release();
}
m_program2->setUniformValue(m_textureUniform2, 0); // use texture unit 0
m_program2->enableAttributeArray(m_vertexAttr2);
m_program2->enableAttributeArray(m_normalAttr2);
m_program2->enableAttributeArray(m_texCoordAttr2);
m_vbo2.bind();
// In the buffer we first have 36 vertices (3 floats for each), then 36 texture
// coordinates (2 floats for each), then 36 normals (3 floats for each).
m_program2->setAttributeBuffer(m_vertexAttr2, GL_FLOAT, 0, 3);
m_program2->setAttributeBuffer(m_texCoordAttr2, GL_FLOAT, 36 * 3 * sizeof(GLfloat), 2);
m_program2->setAttributeBuffer(m_normalAttr2, GL_FLOAT, 36 * 5 * sizeof(GLfloat), 3);
m_vbo2.release();
glDrawArrays(GL_TRIANGLES, 0, 36);
m_program2->disableAttributeArray(m_vertexAttr2);
m_program2->disableAttributeArray(m_normalAttr2);
m_program2->disableAttributeArray(m_texCoordAttr2);
}
void GLWidget::initializeGL()
{
initializeOpenGLFunctions();
m_texture = new QOpenGLTexture(QImage(":/qt.png"));
m_vshader1 = new QOpenGLShader(QOpenGLShader::Vertex);
const char *vsrc1 =
"attribute highp vec4 vertex;\n"
"attribute mediump vec3 normal;\n"
"uniform mediump mat4 matrix;\n"
"varying mediump vec4 color;\n"
"void main(void)\n"
"{\n"
" vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n"
" float angle = max(dot(normal, toLight), 0.0);\n"
" vec3 col = vec3(0.40, 1.0, 0.0);\n"
" color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n"
" color = clamp(color, 0.0, 1.0);\n"
" gl_Position = matrix * vertex;\n"
"}\n";
m_vshader1->compileSourceCode(vsrc1);
m_fshader1 = new QOpenGLShader(QOpenGLShader::Fragment);
const char *fsrc1 =
"varying mediump vec4 color;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = color;\n"
"}\n";
m_fshader1->compileSourceCode(fsrc1);
m_program1 = new QOpenGLShaderProgram;
m_program1->addShader(m_vshader1);
m_program1->addShader(m_fshader1);
m_program1->link();
m_vertexAttr1 = m_program1->attributeLocation("vertex");
m_normalAttr1 = m_program1->attributeLocation("normal");
m_matrixUniform1 = m_program1->uniformLocation("matrix");
m_vshader2 = new QOpenGLShader(QOpenGLShader::Vertex);
const char *vsrc2 =
"attribute highp vec4 vertex;\n"
"attribute highp vec4 texCoord;\n"
"attribute mediump vec3 normal;\n"
"uniform mediump mat4 matrix;\n"
"varying highp vec4 texc;\n"
"varying mediump float angle;\n"
"void main(void)\n"
"{\n"
" vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n"
" angle = max(dot(normal, toLight), 0.0);\n"
" gl_Position = matrix * vertex;\n"
" texc = texCoord;\n"
"}\n";
m_vshader2->compileSourceCode(vsrc2);
m_fshader2 = new QOpenGLShader(QOpenGLShader::Fragment);
const char *fsrc2 =
"varying highp vec4 texc;\n"
"uniform sampler2D tex;\n"
"varying mediump float angle;\n"
"void main(void)\n"
"{\n"
" highp vec3 color = texture2D(tex, texc.st).rgb;\n"
" color = color * 0.2 + color * 0.8 * angle;\n"
" gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);\n"
"}\n";
m_fshader2->compileSourceCode(fsrc2);
m_program2 = new QOpenGLShaderProgram;
m_program2->addShader(m_vshader2);
m_program2->addShader(m_fshader2);
m_program2->link();
m_vertexAttr2 = m_program2->attributeLocation("vertex");
m_normalAttr2 = m_program2->attributeLocation("normal");
m_texCoordAttr2 = m_program2->attributeLocation("texCoord");
m_matrixUniform2 = m_program2->uniformLocation("matrix");
m_textureUniform2 = m_program2->uniformLocation("tex");
m_fAngle = 0;
m_fScale = 1;
createGeometry();
// Use a vertex buffer object. Client-side pointers are old-school and should be avoided.
m_vbo1.create();
m_vbo1.bind();
// For the cube all the data belonging to the texture coordinates and
// normals is placed separately, after the vertices. Here, for the Qt logo,
// let's do something different and potentially more efficient: create a
// properly interleaved data set.
const int vertexCount = m_vertices.count();
QList<GLfloat> buf;
buf.resize(vertexCount * 3 * 2);
GLfloat *p = buf.data();
for (int i = 0; i < vertexCount; ++i) {
*p++ = m_vertices[i].x();
*p++ = m_vertices[i].y();
*p++ = m_vertices[i].z();
*p++ = m_normals[i].x();
*p++ = m_normals[i].y();
*p++ = m_normals[i].z();
}
m_vbo1.allocate(buf.constData(), buf.count() * sizeof(GLfloat));
m_vbo1.release();
createBubbles(bubbleNum - m_bubbles.count());
// A well-behaved QOpenGLWidget releases OpenGL resources not only upon
// destruction, but also when the associated OpenGL context disappears. If
// the widget continues to exist, the context's destruction will be
// followed by a call to initialize(). This is not strictly mandatory in
// widgets that never change their parents.
m_contextWatchConnection = QObject::connect(context(), &QOpenGLContext::aboutToBeDestroyed, context(), [this] { reset(); });
}
void GLWidget::paintGL()
{
createBubbles(bubbleNum - m_bubbles.count());
QPainter painter;
painter.begin(this);
painter.beginNativePainting();
glClearColor(m_background.redF(), m_background.greenF(), m_background.blueF(), m_transparent ? 0.0f : 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);
if (m_qtLogo) {
m_program1->bind();
m_program1->setUniformValue(m_matrixUniform1, modelview);
paintQtLogo();
m_program1->release();
} else {
m_program2->bind();
m_program2->setUniformValue(m_matrixUniform2, modelview);
paintTexturedCube();
m_program2->release();
}
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
painter.endNativePainting();
if (m_showBubbles) {
for (Bubble *bubble : std::as_const(m_bubbles))
bubble->drawBubble(&painter);
}
if (const int elapsed = m_time.elapsed()) {
QString framesPerSecond;
framesPerSecond.setNum(m_frames /(elapsed / 1000.0), 'f', 2);
painter.setPen(m_transparent ? Qt::black : Qt::white);
painter.drawText(20, 40, framesPerSecond + " paintGL calls / s");
}
painter.end();
for (Bubble *bubble : std::as_const(m_bubbles))
bubble->move(rect());
if (!(m_frames % 100)) {
m_time.start();
m_frames = 0;
}
m_fAngle += 1.0f;
++m_frames;
// When requested, follow the ideal way to animate: Rely on
// blocking swap and just schedule updates continuously.
if (!m_mainWindow || !m_mainWindow->timerEnabled())
update();
}
void GLWidget::createBubbles(int number)
{
for (int i = 0; i < number; ++i) {
QPointF position(width()*(0.1 + QRandomGenerator::global()->bounded(0.8)),
height()*(0.1 + QRandomGenerator::global()->bounded(0.8)));
qreal radius = qMin(width(), height())*(0.0175 + QRandomGenerator::global()->bounded(0.0875));
QPointF velocity(width()*0.0175*(-0.5 + QRandomGenerator::global()->bounded(1.0)),
height()*0.0175*(-0.5 + QRandomGenerator::global()->bounded(1.0)));
m_bubbles.append(new Bubble(position, radius, velocity));
}
}
void GLWidget::createGeometry()
{
m_vertices.clear();
m_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 x5 = 0.30 * sin(angle);
qreal y5 = 0.30 * cos(angle);
qreal x6 = 0.20 * sin(angle);
qreal y6 = 0.20 * cos(angle);
angle += sectorAngle;
qreal x7 = 0.20 * sin(angle);
qreal y7 = 0.20 * cos(angle);
qreal x8 = 0.30 * sin(angle);
qreal y8 = 0.30 * cos(angle);
quad(x5, y5, x6, y6, x7, y7, x8, y8);
extrude(x6, y6, x7, y7);
extrude(x8, y8, x5, y5);
}
for (int i = 0;i < m_vertices.size();i++)
m_vertices[i] *= 2.0f;
}
void GLWidget::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4)
{
m_vertices << QVector3D(x1, y1, -0.05f);
m_vertices << QVector3D(x2, y2, -0.05f);
m_vertices << QVector3D(x4, y4, -0.05f);
m_vertices << QVector3D(x3, y3, -0.05f);
m_vertices << QVector3D(x4, y4, -0.05f);
m_vertices << QVector3D(x2, y2, -0.05f);
QVector3D n = QVector3D::normal
(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f));
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
m_vertices << QVector3D(x4, y4, 0.05f);
m_vertices << QVector3D(x2, y2, 0.05f);
m_vertices << QVector3D(x1, y1, 0.05f);
m_vertices << QVector3D(x2, y2, 0.05f);
m_vertices << QVector3D(x4, y4, 0.05f);
m_vertices << QVector3D(x3, y3, 0.05f);
n = QVector3D::normal
(QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f));
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
}
void GLWidget::extrude(qreal x1, qreal y1, qreal x2, qreal y2)
{
m_vertices << QVector3D(x1, y1, +0.05f);
m_vertices << QVector3D(x2, y2, +0.05f);
m_vertices << QVector3D(x1, y1, -0.05f);
m_vertices << QVector3D(x2, y2, -0.05f);
m_vertices << QVector3D(x1, y1, -0.05f);
m_vertices << QVector3D(x2, y2, +0.05f);
QVector3D n = QVector3D::normal
(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f));
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
m_normals << n;
}
void GLWidget::setTransparent(bool transparent)
{
setAttribute(Qt::WA_AlwaysStackOnTop, transparent);
m_transparent = transparent;
// Call update() on the top-level window after toggling AlwayStackOnTop to make sure
// the entire backingstore is updated accordingly.
window()->update();
}
void GLWidget::resizeGL(int, int)
{
if (m_mainWindow) {
if (!m_btn) {
m_btn = new QPushButton("\nAdd widget\n", this);
connect(m_btn, &QPushButton::clicked, this, [this] { m_mainWindow->addNew(); });
}
m_btn->move(20, 80);
if (!m_btn2) {
m_btn2 = new QPushButton("\nI prefer tabbed widgets\n", this);
connect(m_btn2, &QPushButton::clicked, this, [this] { m_mainWindow->showNewWindow(); });
}
m_btn2->move(20, 160);
}
}

View File

@ -1,85 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QVector3D>
#include <QMatrix4x4>
#include <QElapsedTimer>
#include <QList>
#include <QPushButton>
class Bubble;
class MainWindow;
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)
QT_FORWARD_DECLARE_CLASS(QOpenGLShader)
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
GLWidget(MainWindow *maybeMainWindow, const QColor &background);
~GLWidget();
public slots:
void setScaling(int scale);
void setLogo();
void setTexture();
void setShowBubbles(bool);
void setTransparent(bool transparent);
protected:
void resizeGL(int w, int h) override;
void paintGL() override;
void initializeGL() override;
private:
void paintTexturedCube();
void paintQtLogo();
void createGeometry();
void createBubbles(int number);
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);
void reset();
MainWindow *m_mainWindow;
qreal m_fAngle = 0;
qreal m_fScale = 1;
bool m_showBubbles = true;
QList<QVector3D> m_vertices;
QList<QVector3D> m_normals;
bool m_qtLogo = true;
QList<Bubble *> m_bubbles;
int m_frames = 0;
QElapsedTimer m_time;
QOpenGLShader *m_vshader1 = nullptr;
QOpenGLShader *m_fshader1 = nullptr;
QOpenGLShader *m_vshader2 = nullptr;
QOpenGLShader *m_fshader2 = nullptr;
QOpenGLShaderProgram *m_program1 = nullptr;
QOpenGLShaderProgram *m_program2 = nullptr;
QOpenGLTexture *m_texture = nullptr;
QOpenGLBuffer m_vbo1;
QOpenGLBuffer m_vbo2;
int m_vertexAttr1 = 0;
int m_normalAttr1 = 0;
int m_matrixUniform1 = 0;
int m_vertexAttr2 = 0;
int m_normalAttr2 = 0;
int m_texCoordAttr2 = 0;
int m_matrixUniform2 = 0;
int m_textureUniform2 = 0;
bool m_transparent = false;
QPushButton *m_btn = nullptr;
QPushButton *m_btn2 = nullptr;
QColor m_background;
QMetaObject::Connection m_contextWatchConnection;
};
#endif

View File

@ -1,43 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QApplication>
#include <QMainWindow>
#include <QColorSpace>
#include <QSurfaceFormat>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include "mainwindow.h"
int main( int argc, char ** argv )
{
Q_INIT_RESOURCE(texture);
QApplication a( argc, argv );
QCoreApplication::setApplicationName("Qt QOpenGLWidget Example");
QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption multipleSampleOption("multisample", "Multisampling");
parser.addOption(multipleSampleOption);
QCommandLineOption srgbOption("srgb", "Use sRGB Color Space");
parser.addOption(srgbOption);
parser.process(a);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
if (parser.isSet(srgbOption))
format.setColorSpace(QColorSpace::SRgb);
if (parser.isSet(multipleSampleOption))
format.setSamples(4);
QSurfaceFormat::setDefaultFormat(format);
MainWindow mw;
mw.resize(1280, 720);
mw.show();
return a.exec();
}

View File

@ -1,188 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "mainwindow.h"
#include <QApplication>
#include <QMenuBar>
#include <QGroupBox>
#include <QSlider>
#include <QLabel>
#include <QCheckBox>
#include <QRandomGenerator>
#include <QSpinBox>
#include <QScrollArea>
#include <QTabWidget>
#include <QTabBar>
#include <QToolButton>
#include "glwidget.h"
MainWindow::MainWindow()
: m_nextX(1), m_nextY(1)
{
GLWidget *glwidget = new GLWidget(this, qRgb(20, 20, 50));
m_glWidgets << glwidget;
QLabel *label = new QLabel(this);
m_timer = new QTimer(this);
QSlider *slider = new QSlider(this);
slider->setOrientation(Qt::Horizontal);
QLabel *updateLabel = new QLabel("Update interval");
QSpinBox *updateInterval = new QSpinBox(this);
updateInterval->setSuffix(" ms");
updateInterval->setValue(10);
updateInterval->setToolTip("Interval for the timer that calls update().\n"
"Note that on most systems the swap will block to wait for vsync\n"
"and therefore an interval < 16 ms will likely lead to a 60 FPS update rate.");
QGroupBox *updateGroupBox = new QGroupBox(this);
QCheckBox *timerBased = new QCheckBox("Use timer", this);
timerBased->setChecked(false);
timerBased->setToolTip("Toggles using a timer to trigger update().\n"
"When not set, each paintGL() schedules the next update immediately,\n"
"expecting the blocking swap to throttle the thread.\n"
"This shows how unnecessary the timer is in most cases.");
QCheckBox *transparent = new QCheckBox("Transparent background", this);
transparent->setToolTip("Toggles Qt::WA_AlwaysStackOnTop and transparent clear color for glClear().\n"
"Note how the button on top stacks incorrectly when enabling this.");
QHBoxLayout *updateLayout = new QHBoxLayout;
updateLayout->addWidget(updateLabel);
updateLayout->addWidget(updateInterval);
updateLayout->addWidget(timerBased);
updateLayout->addWidget(transparent);
updateGroupBox->setLayout(updateLayout);
slider->setRange(0, 50);
slider->setSliderPosition(30);
m_timer->setInterval(10);
label->setText("A scrollable QOpenGLWidget");
label->setAlignment(Qt::AlignHCenter);
QGroupBox * groupBox = new QGroupBox(this);
setCentralWidget(groupBox);
groupBox->setTitle("QOpenGLWidget Example");
m_layout = new QGridLayout(groupBox);
QScrollArea *scrollArea = new QScrollArea;
scrollArea->setWidget(glwidget);
m_layout->addWidget(scrollArea,1,0,8,1);
m_layout->addWidget(label,9,0,1,1);
m_layout->addWidget(updateGroupBox, 10, 0, 1, 1);
m_layout->addWidget(slider, 11,0,1,1);
groupBox->setLayout(m_layout);
QMenu *fileMenu = menuBar()->addMenu("&File");
fileMenu->addAction("E&xit", this, &QWidget::close);
QMenu *showMenu = menuBar()->addMenu("&Show");
showMenu->addAction("Show 3D Logo", glwidget, &GLWidget::setLogo);
showMenu->addAction("Show 2D Texture", glwidget, &GLWidget::setTexture);
QAction *showBubbles = showMenu->addAction("Show bubbles", glwidget, &GLWidget::setShowBubbles);
showBubbles->setCheckable(true);
showBubbles->setChecked(true);
showMenu->addAction("Open tab window", this, &MainWindow::showNewWindow);
QMenu *helpMenu = menuBar()->addMenu("&Help");
helpMenu->addAction("About Qt", qApp, &QApplication::aboutQt);
connect(m_timer, &QTimer::timeout, glwidget, QOverload<>::of(&QWidget::update));
connect(slider, &QAbstractSlider::valueChanged, glwidget, &GLWidget::setScaling);
connect(transparent, &QCheckBox::toggled, glwidget, &GLWidget::setTransparent);
connect(updateInterval, &QSpinBox::valueChanged,
this, &MainWindow::updateIntervalChanged);
connect(timerBased, &QCheckBox::toggled, this, &MainWindow::timerUsageChanged);
connect(timerBased, &QCheckBox::toggled, updateInterval, &QWidget::setEnabled);
if (timerBased->isChecked())
m_timer->start();
else
updateInterval->setEnabled(false);
}
void MainWindow::updateIntervalChanged(int value)
{
m_timer->setInterval(value);
if (m_timer->isActive())
m_timer->start();
}
void MainWindow::addNew()
{
if (m_nextY == 4)
return;
GLWidget *w = new GLWidget(nullptr, qRgb(QRandomGenerator::global()->bounded(256),
QRandomGenerator::global()->bounded(256),
QRandomGenerator::global()->bounded(256)));
m_glWidgets << w;
connect(m_timer, &QTimer::timeout, w, QOverload<>::of(&QWidget::update));
m_layout->addWidget(w, m_nextY, m_nextX, 1, 1);
if (m_nextX == 3) {
m_nextX = 1;
++m_nextY;
} else {
++m_nextX;
}
}
void MainWindow::timerUsageChanged(bool enabled)
{
if (enabled) {
m_timer->start();
} else {
m_timer->stop();
for (QOpenGLWidget *w : std::as_const(m_glWidgets))
w->update();
}
}
void MainWindow::resizeEvent(QResizeEvent *)
{
m_glWidgets[0]->setMinimumSize(size() + QSize(128, 128));
}
void MainWindow::showNewWindow()
{
QTabWidget *tabs = new QTabWidget;
tabs->resize(800, 600);
QToolButton *tb = new QToolButton;
tb->setText(QLatin1String("+"));
tabs->addTab(new QLabel(QLatin1String("Add OpenGL widgets with +")), QString());
tabs->setTabEnabled(0, false);
tabs->tabBar()->setTabButton(0, QTabBar::RightSide, tb);
tabs->tabBar()->setTabsClosable(true);
QObject::connect(tabs->tabBar(), &QTabBar::tabCloseRequested, tabs, [tabs](int index) {
tabs->widget(index)->deleteLater();
});
const QString msgToTopLevel = QLatin1String("Break out to top-level window");
const QString msgFromTopLevel = QLatin1String("Move back under tab widget");
QObject::connect(tb, &QAbstractButton::clicked, tabs, [=] {
GLWidget *glwidget = new GLWidget(nullptr, Qt::blue);
glwidget->resize(tabs->size());
glwidget->setWindowTitle(QString::asprintf("QOpenGLWidget %p", glwidget));
QPushButton *btn = new QPushButton(msgToTopLevel, glwidget);
connect(btn, &QPushButton::clicked, glwidget, [=] {
if (glwidget->parent()) {
glwidget->setAttribute(Qt::WA_DeleteOnClose, true);
glwidget->setParent(nullptr);
glwidget->show();
btn->setText(msgFromTopLevel);
} else {
glwidget->setAttribute(Qt::WA_DeleteOnClose, false);
tabs->addTab(glwidget, glwidget->windowTitle());
btn->setText(msgToTopLevel);
}
});
tabs->setCurrentIndex(tabs->addTab(glwidget, glwidget->windowTitle()));
});
tabs->setAttribute(Qt::WA_DeleteOnClose);
tabs->show();
}

View File

@ -1,39 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include <QGridLayout>
QT_FORWARD_DECLARE_CLASS(QOpenGLWidget)
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
void addNew();
bool timerEnabled() const { return m_timer->isActive(); }
void resizeEvent(QResizeEvent *);
public slots:
void showNewWindow();
private slots:
void updateIntervalChanged(int value);
void timerUsageChanged(bool enabled);
private:
QTimer *m_timer;
QGridLayout *m_layout;
int m_nextX;
int m_nextY;
QList<QOpenGLWidget *> m_glWidgets;
};
#endif

View File

@ -1,15 +0,0 @@
QT += widgets opengl openglwidgets
SOURCES += main.cpp \
glwidget.cpp \
mainwindow.cpp \
bubble.cpp
HEADERS += glwidget.h \
mainwindow.h \
bubble.h
RESOURCES += texture.qrc
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/qopenglwidget
INSTALLS += target

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,5 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>qt.png</file>
</qresource>
</RCC>

View File

@ -26,11 +26,11 @@ set_target_properties(stereoqopenglwidget PROPERTIES
)
target_link_libraries(stereoqopenglwidget PUBLIC
Qt::Core
Qt::Gui
Qt::OpenGL
Qt::OpenGLWidgets
Qt::Widgets
Qt6::Core
Qt6::Gui
Qt6::OpenGL
Qt6::OpenGLWidgets
Qt6::Widgets
)

View File

@ -8,8 +8,6 @@
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(textures);
QApplication app(argc, argv);
QSurfaceFormat format;