mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-02 07:15:27 +08:00
6.5.3 clean
This commit is contained in:
53
tests/manual/examples/opengl/qopenglwidget/CMakeLists.txt
Normal file
53
tests/manual/examples/opengl/qopenglwidget/CMakeLists.txt
Normal file
@ -0,0 +1,53 @@
|
||||
# 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}"
|
||||
)
|
99
tests/manual/examples/opengl/qopenglwidget/bubble.cpp
Normal file
99
tests/manual/examples/opengl/qopenglwidget/bubble.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// 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);
|
||||
}
|
39
tests/manual/examples/opengl/qopenglwidget/bubble.h
Normal file
39
tests/manual/examples/opengl/qopenglwidget/bubble.h
Normal file
@ -0,0 +1,39 @@
|
||||
// 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
|
540
tests/manual/examples/opengl/qopenglwidget/glwidget.cpp
Normal file
540
tests/manual/examples/opengl/qopenglwidget/glwidget.cpp
Normal file
@ -0,0 +1,540 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
85
tests/manual/examples/opengl/qopenglwidget/glwidget.h
Normal file
85
tests/manual/examples/opengl/qopenglwidget/glwidget.h
Normal file
@ -0,0 +1,85 @@
|
||||
// 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
|
42
tests/manual/examples/opengl/qopenglwidget/main.cpp
Normal file
42
tests/manual/examples/opengl/qopenglwidget/main.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
// 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 )
|
||||
{
|
||||
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();
|
||||
}
|
188
tests/manual/examples/opengl/qopenglwidget/mainwindow.cpp
Normal file
188
tests/manual/examples/opengl/qopenglwidget/mainwindow.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
// 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();
|
||||
}
|
39
tests/manual/examples/opengl/qopenglwidget/mainwindow.h
Normal file
39
tests/manual/examples/opengl/qopenglwidget/mainwindow.h
Normal file
@ -0,0 +1,39 @@
|
||||
// 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
|
15
tests/manual/examples/opengl/qopenglwidget/qopenglwidget.pro
Normal file
15
tests/manual/examples/opengl/qopenglwidget/qopenglwidget.pro
Normal file
@ -0,0 +1,15 @@
|
||||
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
|
BIN
tests/manual/examples/opengl/qopenglwidget/qt.png
Normal file
BIN
tests/manual/examples/opengl/qopenglwidget/qt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
5
tests/manual/examples/opengl/qopenglwidget/texture.qrc
Normal file
5
tests/manual/examples/opengl/qopenglwidget/texture.qrc
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>qt.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
Reference in New Issue
Block a user