qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,11 @@
QT += opengl
HEADERS = $$PWD/glwindow.h
SOURCES = $$PWD/glwindow.cpp \
$$PWD/main.cpp
RESOURCES += computegles31.qrc
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/computegles31
INSTALLS += target

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>Qt-logo-medium.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,372 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "glwindow.h"
#include <QImage>
#include <QOpenGLShaderProgram>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLExtraFunctions>
#include <QOpenGLVertexArrayObject>
#include <QtGui/qopengl.h>
#include <QDebug>
#include <QTimer>
#include <math.h>
#ifndef GL_READ_WRITE
#define GL_READ_WRITE 0x88BA
#endif
#ifndef GL_RGBA8
#define GL_RGBA8 0x8058
#endif
#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#endif
GLWindow::GLWindow()
{
const float animationStart = 0.0;
const float animationEnd = 10.0;
const float animationLength = 1000;
m_animationGroup = new QSequentialAnimationGroup(this);
m_animationGroup->setLoopCount(-1);
m_animationForward = new QPropertyAnimation(this, QByteArrayLiteral("blurRadius"));
m_animationForward->setStartValue(animationStart);
m_animationForward->setEndValue(animationEnd);
m_animationForward->setDuration(animationLength);
m_animationGroup->addAnimation(m_animationForward);
m_animationBackward = new QPropertyAnimation(this, QByteArrayLiteral("blurRadius"));
m_animationBackward->setStartValue(animationEnd);
m_animationBackward->setEndValue(animationStart);
m_animationBackward->setDuration(animationLength);
m_animationGroup->addAnimation(m_animationBackward);
m_animationGroup->start();
}
GLWindow::~GLWindow()
{
makeCurrent();
delete m_texImageInput;
delete m_texImageProcessed;
delete m_texImageTmp;
delete m_shaderDisplay;
delete m_shaderComputeH;
delete m_shaderComputeV;
delete m_animationGroup;
delete m_animationForward;
delete m_animationBackward;
delete m_vao;
}
void GLWindow::setBlurRadius(float blurRadius)
{
int radius = int(blurRadius);
if (radius != m_blurRadius) {
m_blurRadius = radius;
update();
}
}
void GLWindow::setAnimating(bool animate)
{
m_animate = animate;
if (animate)
m_animationGroup->start();
else
m_animationGroup->stop();
}
void GLWindow::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Space) { // pause
setAnimating(!m_animate);
}
update();
}
static const char *vsDisplaySource =
"const vec4 vertices[4] = vec4[4] (\n"
" vec4( -1.0, 1.0, 0.0, 1.0),\n"
" vec4( -1.0, -1.0, 0.0, 1.0),\n"
" vec4( 1.0, 1.0, 0.0, 1.0),\n"
" vec4( 1.0, -1.0, 0.0, 1.0)\n"
");\n"
"const vec2 texCoords[4] = vec2[4] (\n"
" vec2( 0.0, 1.0),\n"
" vec2( 0.0, 0.0),\n"
" vec2( 1.0, 1.0),\n"
" vec2( 1.0, 0.0)\n"
");\n"
"out vec2 texCoord;\n"
"uniform mat4 matProjection;\n"
"uniform vec2 imageRatio;\n"
"void main() {\n"
" gl_Position = matProjection * ( vertices[gl_VertexID] * vec4(imageRatio,0,1) );\n"
" texCoord = texCoords[gl_VertexID];\n"
"}\n";
static const char *fsDisplaySource =
"in lowp vec2 texCoord; \n"
"uniform sampler2D samImage; \n"
"layout(location = 0) out lowp vec4 color;\n"
"void main() {\n"
" lowp vec4 texColor = texture(samImage,texCoord);\n"
" color = vec4(texColor.rgb, 1.0);\n"
"}\n";
static const char *csComputeSourceV =
"#define COMPUTEPATCHSIZE 10 // Setting this to 10 to comply with MAX_COMPUTE_WORK_GROUP_INVOCATIONS for both OpenGL and OpenGLES - see QTBUG-79374 \n"
"#define IMGFMT rgba8 \n"
"layout (local_size_x = COMPUTEPATCHSIZE, local_size_y = COMPUTEPATCHSIZE) in;\n"
"layout(binding=0, IMGFMT) uniform readonly highp image2D inputImage; // Use a sampler to improve performance \n"
"layout(binding=1, IMGFMT) uniform writeonly highp image2D resultImage;\n"
"uniform int radius;\n"
"const float cutoff = 2.2;\n"
"float expFactor() { // a function, otherwise MESA produces error: initializer of global variable `expFactor' must be a constant expression\n"
" float sigma = clamp(float(radius) / cutoff,0.02,100.0);\n"
" return 1.0 / (2.0 * sigma * sigma);\n"
"}\n"
"float gaussian(float distance, float expfactor) {\n"
" return exp( -(distance * distance) * expfactor);\n"
"}\n"
"void main() {\n"
" ivec2 imgSize = imageSize(resultImage);\n"
" int x = int(gl_GlobalInvocationID.x);\n"
" int y = int(gl_GlobalInvocationID.y);\n"
" if ( (x >= imgSize.x) || (y >= imgSize.y) ) return;\n"
" vec4 sumPixels = vec4(0.0);\n"
" float sumWeights = 0.0;\n"
" int left = clamp(x - radius, 0, imgSize.x - 1);\n"
" int right = clamp(x + radius, 0, imgSize.x - 1);\n"
" int top = clamp(y - radius, 0, imgSize.y - 1);\n"
" int bottom = clamp(y + radius, 0, imgSize.y - 1);\n"
" float expfactor = expFactor();\n"
" for (int iY = top; iY <= bottom; iY++) {\n"
" float dy = float(abs(iY - y));\n"
" vec4 imgValue = imageLoad(inputImage, ivec2(x,iY));\n"
" float weight = gaussian(dy, expfactor);\n"
" sumWeights += weight;\n"
" sumPixels += (imgValue * weight);\n"
" }\n"
" sumPixels /= sumWeights;\n"
" imageStore(resultImage, ivec2(x,y), sumPixels);\n"
"}\n";
static const char *csComputeSourceH =
"#define COMPUTEPATCHSIZE 10 \n"
"#define IMGFMT rgba8 \n"
"layout (local_size_x = COMPUTEPATCHSIZE, local_size_y = COMPUTEPATCHSIZE) in;\n"
"layout(binding=0, IMGFMT) uniform readonly highp image2D inputImage; // Use a sampler to improve performance \n"
"layout(binding=1, IMGFMT) uniform writeonly highp image2D resultImage;\n"
"uniform int radius;\n"
"const float cutoff = 2.2;\n"
"float expFactor() { // a function, otherwise MESA produces error: initializer of global variable `expFactor' must be a constant expression\n"
" float sigma = clamp(float(radius) / cutoff,0.02,100.0);\n"
" return 1.0 / (2.0 * sigma * sigma);\n"
"}\n"
"float gaussian(float distance, float expfactor) {\n"
" return exp( -(distance * distance) * expfactor);\n"
"}\n"
"void main() {\n"
" ivec2 imgSize = imageSize(resultImage);\n"
" int x = int(gl_GlobalInvocationID.x);\n"
" int y = int(gl_GlobalInvocationID.y);\n"
" if ( (x >= imgSize.x) || (y >= imgSize.y) ) return;\n"
" vec4 sumPixels = vec4(0.0);\n"
" float sumWeights = 0.0;\n"
" int left = clamp(x - radius, 0, imgSize.x - 1);\n"
" int right = clamp(x + radius, 0, imgSize.x - 1);\n"
" int top = clamp(y - radius, 0, imgSize.y - 1);\n"
" int bottom = clamp(y + radius, 0, imgSize.y - 1);\n"
" float expfactor = expFactor();\n"
" for (int iX = left; iX <= right; iX++) {\n"
" float dx = float(abs(iX - x));\n"
" vec4 imgValue = imageLoad(inputImage, ivec2(iX,y));\n"
" float weight = gaussian(dx, expfactor);\n"
" sumWeights += weight;\n"
" sumPixels += (imgValue * weight);\n"
" }\n"
" sumPixels /= sumWeights;\n"
" imageStore(resultImage, ivec2(x,y), sumPixels);\n"
"}\n";
QByteArray versionedShaderCode(const char *src)
{
QByteArray versionedSrc;
if (QOpenGLContext::currentContext()->isOpenGLES())
versionedSrc.append(QByteArrayLiteral("#version 310 es\n"));
else
versionedSrc.append(QByteArrayLiteral("#version 430 core\n"));
versionedSrc.append(src);
return versionedSrc;
}
void computeProjection(int winWidth, int winHeight, int imgWidth, int imgHeight, QMatrix4x4 &outProjection, QSizeF &outQuadSize)
{
float ratioImg = float(imgWidth) / float(imgHeight);
float ratioCanvas = float(winWidth) / float(winHeight);
float correction = ratioImg / ratioCanvas;
float rescaleFactor = 1.0f;
float quadWidth = 1.0f;
float quadHeight = 1.0f;
if (correction < 1.0f) // canvas larger than image -- height = 1.0, vertical black bands
{
quadHeight = 1.0f;
quadWidth = 1.0f * ratioImg;
rescaleFactor = ratioCanvas;
correction = 1.0f / rescaleFactor;
}
else // image larger than canvas -- width = 1.0, horizontal black bands
{
quadWidth = 1.0f;
quadHeight = 1.0f / ratioImg;
correction = 1.0f / ratioCanvas;
}
const float frustumWidth = 1.0f * rescaleFactor;
const float frustumHeight = 1.0f * rescaleFactor * correction;
outProjection = QMatrix4x4();
outProjection.ortho(
-frustumWidth,
frustumWidth,
-frustumHeight,
frustumHeight,
-1.0f,
1.0f);
outQuadSize = QSizeF(quadWidth,quadHeight);
}
void GLWindow::initializeGL()
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
qDebug() << "Got a "
<< ctx->format().majorVersion()
<< "."
<< ctx->format().minorVersion()
<< ((ctx->format().renderableType() == QSurfaceFormat::OpenGLES) ? (" GLES") : (" GL"))
<< " context";
QImage img(":/Qt-logo-medium.png");
Q_ASSERT(!img.isNull());
delete m_texImageInput;
m_texImageInput = new QOpenGLTexture(img.convertToFormat(QImage::Format_RGBA8888).mirrored());
delete m_texImageTmp;
m_texImageTmp = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texImageTmp->setFormat(m_texImageInput->format());
m_texImageTmp->setSize(m_texImageInput->width(),m_texImageInput->height());
m_texImageTmp->allocateStorage(QOpenGLTexture::RGBA,QOpenGLTexture::UInt8); // WTF?
delete m_texImageProcessed;
m_texImageProcessed = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_texImageProcessed->setFormat(m_texImageInput->format());
m_texImageProcessed->setSize(m_texImageInput->width(),m_texImageInput->height());
m_texImageProcessed->allocateStorage(QOpenGLTexture::RGBA,QOpenGLTexture::UInt8);
m_texImageProcessed->setMagnificationFilter(QOpenGLTexture::Linear);
m_texImageProcessed->setMinificationFilter(QOpenGLTexture::Linear);
m_texImageProcessed->setWrapMode(QOpenGLTexture::ClampToEdge);
delete m_shaderDisplay;
m_shaderDisplay = new QOpenGLShaderProgram;
// Prepend the correct version directive to the sources. The rest is the
// same, thanks to the common GLSL syntax.
m_shaderDisplay->addShaderFromSourceCode(QOpenGLShader::Vertex, versionedShaderCode(vsDisplaySource));
m_shaderDisplay->addShaderFromSourceCode(QOpenGLShader::Fragment, versionedShaderCode(fsDisplaySource));
m_shaderDisplay->link();
delete m_shaderComputeV;
m_shaderComputeV = new QOpenGLShaderProgram;
m_shaderComputeV->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceV));
m_shaderComputeV->link();
delete m_shaderComputeH;
m_shaderComputeH = new QOpenGLShaderProgram;
m_shaderComputeH->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceH));
m_shaderComputeH->link();
// Create a VAO. Not strictly required for ES 3, but it is for plain OpenGL core context.
m_vao = new QOpenGLVertexArrayObject;
m_vao->create();
}
void GLWindow::resizeGL(int w, int h)
{
computeProjection(w,h,m_texImageInput->width(),m_texImageInput->height(),m_proj,m_quadSize);
}
QSize getWorkGroups(int workGroupSize, const QSize &imageSize)
{
int x = imageSize.width();
x = (x % workGroupSize) ? (x / workGroupSize) + 1 : (x / workGroupSize);
int y = imageSize.height();
y = (y % workGroupSize) ? (y / workGroupSize) + 1 : (y / workGroupSize);
return QSize(x,y);
}
void GLWindow::paintGL()
{
// Now use QOpenGLExtraFunctions instead of QOpenGLFunctions as we want to
// do more than what GL(ES) 2.0 offers.
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
// Process input image
QSize workGroups = getWorkGroups(10, QSize(m_texImageInput->width(), m_texImageInput->height()));
// Pass 1
f->glBindImageTexture(0, m_texImageInput->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8);
f->glBindImageTexture(1, m_texImageTmp->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8);
m_shaderComputeV->bind();
m_shaderComputeV->setUniformValue("radius",m_blurRadius);
f->glDispatchCompute(workGroups.width(),workGroups.height(),1);
f->glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
m_shaderComputeV->release();
// Pass 2
f->glBindImageTexture(0, m_texImageTmp->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8);
f->glBindImageTexture(1, m_texImageProcessed->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8);
m_shaderComputeH->bind();
m_shaderComputeH->setUniformValue("radius",m_blurRadius);
f->glDispatchCompute(workGroups.width(),workGroups.height(),1);
f->glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
m_shaderComputeH->release();
// Compute cleanup
f->glBindImageTexture(0, 0, 0, 0, 0, GL_READ_WRITE, GL_RGBA8);
f->glBindImageTexture(1, 0, 0, 0, 0, GL_READ_WRITE, GL_RGBA8);
// Display processed image
f->glClearColor(0, 0, 0, 1);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_texImageProcessed->bind(0);
m_shaderDisplay->bind();
m_shaderDisplay->setUniformValue("matProjection",m_proj);
m_shaderDisplay->setUniformValue("imageRatio",m_quadSize);
m_shaderDisplay->setUniformValue("samImage",0);
m_vao->bind();
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_vao->release();
m_shaderDisplay->release();
m_texImageProcessed->release(0);
}

View File

@ -0,0 +1,63 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QOpenGLWindow>
#include <QOpenGLTexture>
#include <QMatrix4x4>
#include <QVector3D>
#include <QKeyEvent>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <QRectF>
QT_BEGIN_NAMESPACE
class QOpenGLTexture;
class QOpenGLShaderProgram;
class QOpenGLBuffer;
class QOpenGLVertexArrayObject;
QT_END_NAMESPACE
class GLWindow : public QOpenGLWindow
{
Q_OBJECT
Q_PROPERTY(float blurRadius READ blurRadius WRITE setBlurRadius)
public:
GLWindow();
~GLWindow();
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
float blurRadius() const { return m_blurRadius; }
void setBlurRadius(float blurRadius);
protected:
void keyPressEvent(QKeyEvent *e) override;
void setAnimating(bool animate);
private:
QPropertyAnimation *m_animationForward = nullptr;
QPropertyAnimation *m_animationBackward = nullptr;
QSequentialAnimationGroup *m_animationGroup;
QOpenGLTexture *m_texImageInput = nullptr;
QOpenGLTexture *m_texImageTmp = nullptr;
QOpenGLTexture *m_texImageProcessed = nullptr;
QOpenGLShaderProgram *m_shaderDisplay = nullptr;
QOpenGLShaderProgram *m_shaderComputeV = nullptr;
QOpenGLShaderProgram *m_shaderComputeH = nullptr;
QMatrix4x4 m_proj;
QSizeF m_quadSize;
int m_blurRadius = 0;
bool m_animate = true;
QOpenGLVertexArrayObject *m_vao = nullptr;
};
#endif

View File

@ -0,0 +1,101 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QSurfaceFormat>
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QDebug>
#include <QPair>
#include "glwindow.h"
bool OGLSupports(int major, int minor, bool gles = false, QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile)
{
QOpenGLContext ctx;
QSurfaceFormat fmt;
fmt.setVersion(major, minor);
if (gles) {
fmt.setRenderableType(QSurfaceFormat::OpenGLES);
} else {
fmt.setRenderableType(QSurfaceFormat::OpenGL);
fmt.setProfile(profile);
}
ctx.setFormat(fmt);
ctx.create();
if (!ctx.isValid())
return false;
int ctxMajor = ctx.format().majorVersion();
int ctxMinor = ctx.format().minorVersion();
bool isGles = (ctx.format().renderableType() == QSurfaceFormat::OpenGLES);
if (isGles != gles) return false;
if (ctxMajor < major) return false;
if (ctxMajor == major && ctxMinor < minor)
return false;
if (!gles && ctx.format().profile() != profile)
return false;
return true;
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qDebug() << "Support for GL 2.0 noprof "<<( OGLSupports(2,0,false) ? "yes" : "no");
qDebug() << "Support for GL 2.0 core "<<( OGLSupports(2,0,false, QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 2.0 compat "<<( OGLSupports(2,0,false, QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 2.1 noprof "<<( OGLSupports(2,1,false) ? "yes" : "no");
qDebug() << "Support for GL 2.1 core "<<( OGLSupports(2,1,false, QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 2.1 compat "<<( OGLSupports(2,1,false, QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.0 noprof "<<( OGLSupports(3,0,false) ? "yes" : "no");
qDebug() << "Support for GL 3.0 core "<<( OGLSupports(3,0,false, QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.0 compat "<<( OGLSupports(3,0,false, QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.1 noprof "<<( OGLSupports(3,1,false) ? "yes" : "no");
qDebug() << "Support for GL 3.1 core "<<( OGLSupports(3,1,false, QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.1 compat "<<( OGLSupports(3,1,false, QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.2 core "<<( OGLSupports(3,2,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.2 compat "<<( OGLSupports(3,2,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.3 core "<<( OGLSupports(3,3,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 3.3 compat "<<( OGLSupports(3,3,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.0 core "<<( OGLSupports(4,0,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.0 compat "<<( OGLSupports(4,0,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.1 core "<<( OGLSupports(4,1,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.1 compat "<<( OGLSupports(4,1,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.2 core "<<( OGLSupports(4,2,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.2 compat "<<( OGLSupports(4,2,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.3 core "<<( OGLSupports(4,3,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.3 compat "<<( OGLSupports(4,3,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.4 core "<<( OGLSupports(4,4,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.4 compat "<<( OGLSupports(4,4,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.5 core "<<( OGLSupports(4,5,false,QSurfaceFormat::CoreProfile) ? "yes" : "no");
qDebug() << "Support for GL 4.5 compat "<<( OGLSupports(4,5,false,QSurfaceFormat::CompatibilityProfile) ? "yes" : "no");
qDebug() << "Support for GLES 2.0 "<<( OGLSupports(2,0,true) ? "yes" : "no");
qDebug() << "Support for GLES 3.0 "<<( OGLSupports(3,0,true) ? "yes" : "no");
qDebug() << "Support for GLES 3.1 "<<( OGLSupports(3,1,true) ? "yes" : "no");
qDebug() << "Support for GLES 3.2 "<<( OGLSupports(3,2,true) ? "yes" : "no");
QSurfaceFormat fmt;
fmt.setDepthBufferSize(24);
// Request OpenGL ES 3.1 context, as this is a GLES example. If not available, go for OpenGL 4.3 core.
if (OGLSupports(3,1,true)) {
qDebug("Requesting 3.1 GLES context");
fmt.setVersion(3, 1);
fmt.setRenderableType(QSurfaceFormat::OpenGLES);
} else if (OGLSupports(4,3,false,QSurfaceFormat::CoreProfile)) {
qDebug("Requesting 4.3 core context");
fmt.setVersion(4, 3);
fmt.setRenderableType(QSurfaceFormat::OpenGL);
fmt.setProfile(QSurfaceFormat::CoreProfile);
} else {
qWarning("Error: This system does not support OpenGL Compute Shaders! Exiting.");
return -1;
}
QSurfaceFormat::setDefaultFormat(fmt);
GLWindow glWindow;
glWindow.showMaximized();
return app.exec();
}

View File

@ -0,0 +1,39 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(hellowindow LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/opengl/hellowindow")
find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL)
qt_standard_project_setup()
qt_add_executable(hellowindow
hellowindow.cpp hellowindow.h
main.cpp
)
set_target_properties(hellowindow PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(hellowindow PRIVATE
Qt6::Core
Qt6::CorePrivate
Qt6::Gui
Qt6::GuiPrivate
Qt6::OpenGL
)
install(TARGETS hellowindow
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,305 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "hellowindow.h"
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QRandomGenerator>
#include <qmath.h>
#include <QElapsedTimer>
Renderer::Renderer(const QSurfaceFormat &format, Renderer *share, QScreen *screen)
: m_initialized(false)
, m_format(format)
{
m_context = new QOpenGLContext(this);
if (screen)
m_context->setScreen(screen);
m_context->setFormat(format);
if (share)
m_context->setShareContext(share->m_context);
m_context->create();
m_backgroundColor = QColor::fromRgbF(0.1f, 0.1f, 0.2f, 1.0f);
m_backgroundColor.setRed(QRandomGenerator::global()->bounded(64));
m_backgroundColor.setGreen(QRandomGenerator::global()->bounded(128));
m_backgroundColor.setBlue(QRandomGenerator::global()->bounded(256));
}
HelloWindow::HelloWindow(const QSharedPointer<Renderer> &renderer, QScreen *screen)
: m_colorIndex(0), m_renderer(renderer)
{
setSurfaceType(QWindow::OpenGLSurface);
setFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
setGeometry(QRect(10, 10, 640, 480));
setFormat(renderer->format());
if (screen)
setScreen(screen);
create();
updateColor();
connect(renderer.data(), &Renderer::requestUpdate, this, &QWindow::requestUpdate);
}
void HelloWindow::exposeEvent(QExposeEvent *)
{
if (isExposed())
render();
}
bool HelloWindow::event(QEvent *ev)
{
if (ev->type() == QEvent::UpdateRequest && isExposed())
render();
return QWindow::event(ev);
}
void HelloWindow::render()
{
static QElapsedTimer timer;
if (!timer.isValid())
timer.start();
qreal a = (qreal)(((timer.elapsed() * 3) % 36000) / 100.0);
auto call = [this, r = m_renderer.data(), a, c = color()]() { r->render(this, a, c); };
QMetaObject::invokeMethod(m_renderer.data(), call);
}
void HelloWindow::mousePressEvent(QMouseEvent *)
{
updateColor();
}
QColor HelloWindow::color() const
{
return m_color;
}
void HelloWindow::updateColor()
{
QColor colors[] =
{
QColor(100, 255, 0),
QColor(0, 100, 255)
};
m_color = colors[m_colorIndex];
m_colorIndex = 1 - m_colorIndex;
}
void Renderer::render(HelloWindow *surface, qreal angle, const QColor &color)
{
if (!m_context->makeCurrent(surface))
return;
QSize viewSize = surface->size();
if (!m_initialized) {
initialize();
m_initialized = true;
}
QOpenGLFunctions *f = m_context->functions();
f->glViewport(0, 0, viewSize.width() * surface->devicePixelRatio(), viewSize.height() * surface->devicePixelRatio());
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
f->glClearColor(m_backgroundColor.redF(), m_backgroundColor.greenF(), m_backgroundColor.blueF(), m_backgroundColor.alphaF());
f->glFrontFace(GL_CW);
f->glCullFace(GL_FRONT);
f->glEnable(GL_CULL_FACE);
f->glEnable(GL_DEPTH_TEST);
m_program->bind();
m_vbo.bind();
m_program->enableAttributeArray(vertexAttr);
m_program->enableAttributeArray(normalAttr);
m_program->setAttributeBuffer(vertexAttr, GL_FLOAT, 0, 3);
const int verticesSize = vertices.count() * 3 * sizeof(GLfloat);
m_program->setAttributeBuffer(normalAttr, GL_FLOAT, verticesSize, 3);
QMatrix4x4 modelview;
modelview.rotate(angle, 0.0f, 1.0f, 0.0f);
modelview.rotate(angle, 1.0f, 0.0f, 0.0f);
modelview.rotate(angle, 0.0f, 0.0f, 1.0f);
modelview.translate(0.0f, -0.2f, 0.0f);
m_program->setUniformValue(matrixUniform, modelview);
m_program->setUniformValue(colorUniform, color);
m_context->functions()->glDrawArrays(GL_TRIANGLES, 0, vertices.size());
m_context->swapBuffers(surface);
emit requestUpdate();
}
Q_GLOBAL_STATIC(QMutex, initMutex)
void Renderer::initialize()
{
// Threaded shader compilation can confuse some drivers. Avoid it.
QMutexLocker lock(initMutex());
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
vshader->compileSourceCode(
"attribute highp vec4 vertex;"
"attribute mediump vec3 normal;"
"uniform mediump mat4 matrix;"
"uniform lowp vec4 sourceColor;"
"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 = sourceColor.rgb;"
" color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);"
" color = clamp(color, 0.0, 1.0);"
" gl_Position = matrix * vertex;"
"}");
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
fshader->compileSourceCode(
"varying mediump vec4 color;"
"void main(void)"
"{"
" gl_FragColor = color;"
"}");
m_program = new QOpenGLShaderProgram(this);
m_program->addShader(vshader);
m_program->addShader(fshader);
m_program->link();
m_program->bind();
vertexAttr = m_program->attributeLocation("vertex");
normalAttr = m_program->attributeLocation("normal");
matrixUniform = m_program->uniformLocation("matrix");
colorUniform = m_program->uniformLocation("sourceColor");
createGeometry();
m_vbo.create();
m_vbo.bind();
const int verticesSize = vertices.count() * 3 * sizeof(GLfloat);
m_vbo.allocate(verticesSize * 2);
m_vbo.write(0, vertices.constData(), verticesSize);
m_vbo.write(verticesSize, normals.constData(), verticesSize);
}
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 x5 = 0.30 * qSin(angle);
qreal y5 = 0.30 * qCos(angle);
qreal x6 = 0.20 * qSin(angle);
qreal y6 = 0.20 * qCos(angle);
angle += sectorAngle;
qreal x7 = 0.20 * qSin(angle);
qreal y7 = 0.20 * qCos(angle);
qreal x8 = 0.30 * qSin(angle);
qreal y8 = 0.30 * qCos(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 < 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;
}

View File

@ -0,0 +1,77 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef HELLOWINDOW_H
#define HELLOWINDOW_H
#include <QWindow>
#include <QColor>
#include <QMutex>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QSharedPointer>
#include <QTimer>
class HelloWindow;
class Renderer : public QObject
{
Q_OBJECT
public:
explicit Renderer(const QSurfaceFormat &format, Renderer *share = nullptr,
QScreen *screen = nullptr);
QSurfaceFormat format() const { return m_format; }
public slots:
void render(HelloWindow *surface, qreal angle, const QColor &color);
signals:
void requestUpdate();
private:
void initialize();
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);
QList<QVector3D> vertices;
QList<QVector3D> normals;
int vertexAttr;
int normalAttr;
int matrixUniform;
int colorUniform;
bool m_initialized;
QSurfaceFormat m_format;
QOpenGLContext *m_context;
QOpenGLShaderProgram *m_program;
QOpenGLBuffer m_vbo;
QColor m_backgroundColor;
};
class HelloWindow : public QWindow
{
public:
explicit HelloWindow(const QSharedPointer<Renderer> &renderer, QScreen *screen = nullptr);
QColor color() const;
void updateColor();
protected:
bool event(QEvent *ev) override;
void exposeEvent(QExposeEvent *event) override;
void mousePressEvent(QMouseEvent *) override;
void render();
private:
int m_colorIndex;
QColor m_color;
const QSharedPointer<Renderer> m_renderer;
};
#endif // HELLOWINDOW_H

View File

@ -0,0 +1,9 @@
QT += gui-private core-private opengl
HEADERS += hellowindow.h
SOURCES += hellowindow.cpp main.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/hellowindow
INSTALLS += target

View File

@ -0,0 +1,125 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "hellowindow.h"
#include <qpa/qplatformintegration.h>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QGuiApplication>
#include <QScreen>
#include <QThread>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QCoreApplication::setApplicationName("Qt HelloWindow GL Example");
QCoreApplication::setOrganizationName("QtProject");
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption multipleOption("multiple", "Create multiple windows");
parser.addOption(multipleOption);
QCommandLineOption multipleSampleOption("multisample", "Multisampling");
parser.addOption(multipleSampleOption);
QCommandLineOption multipleScreenOption("multiscreen", "Run on multiple screens");
parser.addOption(multipleScreenOption);
QCommandLineOption timeoutOption("timeout", "Close after 10s");
parser.addOption(timeoutOption);
parser.process(app);
// Some platforms can only have one window per screen. Therefore we need to differentiate.
const bool multipleWindows = parser.isSet(multipleOption);
const bool multipleScreens = parser.isSet(multipleScreenOption);
QScreen *screen = QGuiApplication::primaryScreen();
QRect screenGeometry = screen->availableGeometry();
QSurfaceFormat format;
format.setDepthBufferSize(16);
if (parser.isSet(multipleSampleOption))
format.setSamples(4);
QPoint center = QPoint(screenGeometry.center().x(), screenGeometry.top() + 80);
QSize windowSize(400, 320);
int delta = 40;
QList<QWindow *> windows;
QSharedPointer<Renderer> rendererA(new Renderer(format));
HelloWindow *windowA = new HelloWindow(rendererA);
windowA->setGeometry(QRect(center, windowSize).translated(-windowSize.width() - delta / 2, 0));
windowA->setTitle(QStringLiteral("Thread A - Context A"));
windowA->setVisible(true);
windows.prepend(windowA);
QList<QThread *> renderThreads;
if (multipleWindows) {
QSharedPointer<Renderer> rendererB(new Renderer(format, rendererA.data()));
QThread *renderThread = new QThread;
rendererB->moveToThread(renderThread);
renderThreads << renderThread;
HelloWindow *windowB = new HelloWindow(rendererA);
windowB->setGeometry(QRect(center, windowSize).translated(delta / 2, 0));
windowB->setTitle(QStringLiteral("Thread A - Context A"));
windowB->setVisible(true);
windows.prepend(windowB);
HelloWindow *windowC = new HelloWindow(rendererB);
windowC->setGeometry(QRect(center, windowSize).translated(-windowSize.width() / 2, windowSize.height() + delta));
windowC->setTitle(QStringLiteral("Thread B - Context B"));
windowC->setVisible(true);
windows.prepend(windowC);
}
if (multipleScreens) {
for (int i = 1; i < QGuiApplication::screens().size(); ++i) {
QScreen *screen = QGuiApplication::screens().at(i);
QSharedPointer<Renderer> renderer(new Renderer(format, rendererA.data(), screen));
QThread *renderThread = new QThread;
renderer->moveToThread(renderThread);
renderThreads.prepend(renderThread);
QRect screenGeometry = screen->availableGeometry();
QPoint center = screenGeometry.center();
QSize windowSize = screenGeometry.size() * 0.8;
HelloWindow *window = new HelloWindow(renderer, screen);
window->setGeometry(QRect(center, windowSize).translated(-windowSize.width() / 2, -windowSize.height() / 2));
QChar id = QChar('B' + i);
window->setTitle(QStringLiteral("Thread ") + id + QStringLiteral(" - Context ") + id);
window->setVisible(true);
windows.prepend(window);
}
}
for (int i = 0; i < renderThreads.size(); ++i) {
QObject::connect(qGuiApp, &QGuiApplication::lastWindowClosed, renderThreads.at(i), &QThread::quit);
renderThreads.at(i)->start();
}
// Quit after 10 seconds. For platforms that do not have windows that are closeable.
if (parser.isSet(timeoutOption))
QTimer::singleShot(10000, qGuiApp, &QCoreApplication::quit);
const int exitValue = app.exec();
for (int i = 0; i < renderThreads.size(); ++i) {
renderThreads.at(i)->quit(); // some platforms may not have windows to close so ensure quit()
renderThreads.at(i)->wait();
}
qDeleteAll(windows);
qDeleteAll(renderThreads);
return exitValue;
}

View File

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

View File

@ -0,0 +1,18 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QRect>
#include "paintedwindow.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
PaintedWindow window;
window.show();
return app.exec();
}

View File

@ -0,0 +1,185 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "paintedwindow.h"
#include <QGuiApplication>
#include <QOpenGLContext>
#include <QOpenGLPaintDevice>
#include <QPainter>
#include <QPainterPath>
#include <QScreen>
#include <QTimer>
#include <qmath.h>
PaintedWindow::PaintedWindow()
{
QSurfaceFormat format;
format.setStencilBufferSize(8);
format.setSamples(4);
setSurfaceType(QWindow::OpenGLSurface);
setFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
setFormat(format);
create();
m_context = new QOpenGLContext(this);
m_context->setFormat(format);
m_context->create();
m_animation = new QPropertyAnimation(this, "rotation");
m_animation->setStartValue(qreal(0));
m_animation->setEndValue(qreal(1));
m_animation->setDuration(500);
QRect screenGeometry = screen()->availableGeometry();
QPoint center = screenGeometry.center();
QRect windowRect = screen()->isLandscape(screen()->orientation()) ? QRect(0, 0, 640, 480) : QRect(0, 0, 480, 640);
setGeometry(QRect(center - windowRect.center(), windowRect.size()));
m_rotation = 0;
reportContentOrientationChange(screen()->orientation());
m_targetOrientation = contentOrientation();
m_nextTargetOrientation = Qt::PrimaryOrientation;
connect(screen(), &QScreen::orientationChanged, this, &PaintedWindow::orientationChanged);
connect(m_animation, &QAbstractAnimation::finished, this, &PaintedWindow::rotationDone);
connect(this, &PaintedWindow::rotationChanged, this, QOverload<>::of(&PaintedWindow::paint));
}
void PaintedWindow::exposeEvent(QExposeEvent *)
{
if (isExposed())
paint();
}
void PaintedWindow::mousePressEvent(QMouseEvent *)
{
Qt::ScreenOrientation o = contentOrientation();
switch (o) {
case Qt::LandscapeOrientation:
orientationChanged(Qt::PortraitOrientation);
break;
case Qt::PortraitOrientation:
orientationChanged(Qt::InvertedLandscapeOrientation);
break;
case Qt::InvertedLandscapeOrientation:
orientationChanged(Qt::InvertedPortraitOrientation);
break;
case Qt::InvertedPortraitOrientation:
orientationChanged(Qt::LandscapeOrientation);
break;
default:
Q_ASSERT(false);
}
paint();
}
void PaintedWindow::orientationChanged(Qt::ScreenOrientation newOrientation)
{
if (contentOrientation() == newOrientation)
return;
if (m_animation->state() == QAbstractAnimation::Running) {
m_nextTargetOrientation = newOrientation;
return;
}
QRect rect(0, 0, width(), height());
m_prevImage = QImage(width(), height(), QImage::Format_ARGB32_Premultiplied);
m_nextImage = QImage(width(), height(), QImage::Format_ARGB32_Premultiplied);
m_prevImage.fill(0);
m_nextImage.fill(0);
QPainter p;
p.begin(&m_prevImage);
p.setTransform(screen()->transformBetween(contentOrientation(), screen()->orientation(), rect));
paint(&p, screen()->mapBetween(contentOrientation(), screen()->orientation(), rect));
p.end();
p.begin(&m_nextImage);
p.setTransform(screen()->transformBetween(newOrientation, screen()->orientation(), rect));
paint(&p, screen()->mapBetween(newOrientation, screen()->orientation(), rect));
p.end();
m_deltaRotation = screen()->angleBetween(newOrientation, contentOrientation());
if (m_deltaRotation > 180)
m_deltaRotation = 180 - m_deltaRotation;
m_targetOrientation = newOrientation;
m_animation->start();
}
void PaintedWindow::rotationDone()
{
reportContentOrientationChange(m_targetOrientation);
if (m_nextTargetOrientation != Qt::PrimaryOrientation) {
Q_ASSERT(m_animation->state() != QAbstractAnimation::Running);
orientationChanged(m_nextTargetOrientation);
m_nextTargetOrientation = Qt::PrimaryOrientation;
}
}
void PaintedWindow::setRotation(qreal r)
{
if (r != m_rotation) {
m_rotation = r;
emit rotationChanged(r);
}
}
void PaintedWindow::paint()
{
m_context->makeCurrent(this);
QRect rect(0, 0, width() * devicePixelRatio(), height() * devicePixelRatio());
QOpenGLPaintDevice device(size() * devicePixelRatio());
QPainter painter(&device);
QPainterPath path;
path.addEllipse(rect);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.fillRect(rect, Qt::transparent);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.fillPath(path, Qt::blue);
if (contentOrientation() != m_targetOrientation) {
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.save();
painter.translate(width() / 2, height() / 2);
painter.rotate(m_deltaRotation * m_rotation);
painter.translate(-width() / 2, -height() / 2);
painter.drawImage(0, 0, m_prevImage);
painter.restore();
painter.translate(width() / 2, height() / 2);
painter.rotate(m_deltaRotation * m_rotation - m_deltaRotation);
painter.translate(-width() / 2, -height() / 2);
painter.setOpacity(m_rotation);
painter.drawImage(0, 0, m_nextImage);
} else {
QRect mapped = screen()->mapBetween(contentOrientation(), screen()->orientation(), rect);
painter.setTransform(screen()->transformBetween(contentOrientation(), screen()->orientation(), rect));
paint(&painter, mapped);
painter.end();
}
m_context->swapBuffers(this);
}
void PaintedWindow::paint(QPainter *painter, const QRect &rect)
{
painter->setRenderHint(QPainter::Antialiasing);
QFont font;
font.setPixelSize(64);
painter->setFont(font);
painter->drawText(rect, Qt::AlignCenter, "Hello");
}

View File

@ -0,0 +1,62 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef PAINTEDWINDOW_H
#define PAINTEDWINDOW_H
#include <QWindow>
#include <QtGui/qopengl.h>
#include <QtOpenGL/qopenglshaderprogram.h>
#include <QtOpenGL/qopenglframebufferobject.h>
#include <QPropertyAnimation>
#include <QColor>
#include <QImage>
#include <QTime>
QT_BEGIN_NAMESPACE
class QOpenGLContext;
QT_END_NAMESPACE
class PaintedWindow : public QWindow
{
Q_OBJECT
Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
public:
PaintedWindow();
qreal rotation() const { return m_rotation; }
signals:
void rotationChanged(qreal rotation);
private slots:
void paint();
void setRotation(qreal r);
void orientationChanged(Qt::ScreenOrientation newOrientation);
void rotationDone();
private:
void exposeEvent(QExposeEvent *) override;
void mousePressEvent(QMouseEvent *) override;
void paint(QPainter *painter, const QRect &rect);
QOpenGLContext *m_context;
qreal m_rotation;
QImage m_prevImage;
QImage m_nextImage;
qreal m_deltaRotation;
Qt::ScreenOrientation m_targetOrientation;
Qt::ScreenOrientation m_nextTargetOrientation;
QPropertyAnimation *m_animation;
QTimer *m_paintTimer;
};
#endif // PAINTEDWINDOW_H

View File

@ -0,0 +1,8 @@
QT += opengl
HEADERS += paintedwindow.h
SOURCES += paintedwindow.cpp main.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/paintedwindow
INSTALLS += target

View File

@ -0,0 +1,49 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(qopenglwindow LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/opengl/qopenglwindow")
find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL)
qt_standard_project_setup()
qt_add_executable(qopenglwindow
background_renderer.cpp background_renderer.h
main.cpp
)
set_target_properties(qopenglwindow PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(qopenglwindow PRIVATE
Qt6::Core
Qt6::Gui
Qt6::OpenGL
)
# Resources:
set(shaders_resource_files
"background.frag"
)
qt_add_resources(qopenglwindow "shaders"
PREFIX
"/"
FILES
${shaders_resource_files}
)
install(TARGETS qopenglwindow
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,30 @@
#define M_PI 3.14159265358979323846
#define SPEED 10000.0
uniform int currentTime;
uniform highp vec2 windowSize;
highp float noise(highp vec2 co)
{
return 0.5 * fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
}
highp float curvSpeed()
{
return (mod(float(currentTime), SPEED) / SPEED) * (2.0 * M_PI);
}
highp float curv(int curvCount)
{
highp float curv_y = 0.1 *(cos((gl_FragCoord.x / windowSize.x) * (float(curvCount * 2) * M_PI) - curvSpeed())) + 0.5;
highp float frag_y = gl_FragCoord.y / windowSize.y;
return 1.0 - abs(curv_y - frag_y);
}
void main()
{
highp float coordNoise = noise(gl_FragCoord.xy);
highp float proximity = smoothstep(0.85, 1.0, (curv(6) + 1.0) * (coordNoise ));
highp vec3 color = vec3(coordNoise) * proximity;
gl_FragColor = vec4(color, 1.0);
}

View File

@ -0,0 +1,167 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "background_renderer.h"
#include <qmath.h>
#include <QFileInfo>
#include <QTime>
#include <QOpenGLShaderProgram>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <math.h>
static const char vertex_shader[] =
"attribute highp vec3 vertexCoord;"
"void main() {"
" gl_Position = vec4(vertexCoord,1.0);"
"}";
static const char fragment_shader[] =
"void main() {"
" gl_FragColor = vec4(0.0,1.0,0.0,1.0);"
"}";
static const float vertices[] = { -1, -1, 0,
-1, 1, 0,
1, -1, 0,
1, 1, 0 };
FragmentToy::FragmentToy(const QString &fragmentSource, QObject *parent)
: QObject(parent)
, m_recompile_shaders(true)
{
if (QFile::exists(fragmentSource)) {
QFileInfo info(fragmentSource);
m_fragment_file_last_modified = info.lastModified();
m_fragment_file = fragmentSource;
#if QT_CONFIG(filesystemwatcher)
m_watcher.addPath(info.canonicalPath());
QObject::connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &FragmentToy::fileChanged);
#endif
}
}
FragmentToy::~FragmentToy()
= default;
void FragmentToy::draw(const QSize &windowSize)
{
if (!m_program)
initializeOpenGLFunctions();
glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
if (!m_vao.isCreated())
m_vao.create();
QOpenGLVertexArrayObject::Binder binder(&m_vao);
if (!m_vertex_buffer.isCreated()) {
m_vertex_buffer.create();
m_vertex_buffer.bind();
m_vertex_buffer.allocate(vertices, sizeof(vertices));
m_vertex_buffer.release();
}
if (!m_program) {
m_program.reset(new QOpenGLShaderProgram);
m_program->create();
m_vertex_shader.reset(new QOpenGLShader(QOpenGLShader::Vertex));
if (!m_vertex_shader->compileSourceCode(vertex_shader)) {
qWarning() << "Failed to compile the vertex shader:" << m_vertex_shader->log();
}
if (!m_program->addShader(m_vertex_shader.get())) {
qWarning() << "Failed to add vertex shader to program:" << m_program->log();
}
}
if (!m_fragment_shader && m_recompile_shaders) {
QByteArray data;
if (m_fragment_file.size()) {
QFile file(m_fragment_file);
if (file.open(QIODevice::ReadOnly)) {
data = file.readAll();
} else {
qWarning() << "Failed to load input file, falling back to default";
data = QByteArray::fromRawData(fragment_shader, sizeof(fragment_shader));
}
} else {
QFile qrcFile(":/background.frag");
if (qrcFile.open(QIODevice::ReadOnly))
data = qrcFile.readAll();
else
data = QByteArray::fromRawData(fragment_shader, sizeof(fragment_shader));
}
if (data.size()) {
m_fragment_shader.reset(new QOpenGLShader(QOpenGLShader::Fragment));
if (!m_fragment_shader->compileSourceCode(data)) {
qWarning() << "Failed to compile fragment shader:" << m_fragment_shader->log();
m_fragment_shader.reset(nullptr);
}
} else {
qWarning() << "Unknown error, no fragment shader";
}
if (m_fragment_shader) {
if (!m_program->addShader(m_fragment_shader.get())) {
qWarning() << "Failed to add fragment shader to program:" << m_program->log();
}
}
}
if (m_recompile_shaders) {
m_recompile_shaders = false;
if (m_program->link()) {
m_vertex_coord_pos = m_program->attributeLocation("vertexCoord");
} else {
qWarning() << "Failed to link shader program" << m_program->log();
}
}
if (!m_program->isLinked())
return;
m_program->bind();
m_vertex_buffer.bind();
m_program->setAttributeBuffer("vertexCoord", GL_FLOAT, 0, 3, 0);
m_program->enableAttributeArray("vertexCoord");
m_vertex_buffer.release();
m_program->setUniformValue("currentTime", (uint) QDateTime::currentMSecsSinceEpoch());
m_program->setUniformValue("windowSize", windowSize);
QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_program->release();
}
void FragmentToy::fileChanged(const QString &path)
{
Q_UNUSED(path);
if (QFile::exists(m_fragment_file)) {
QFileInfo fragment_source(m_fragment_file);
if (fragment_source.lastModified() > m_fragment_file_last_modified) {
m_fragment_file_last_modified = fragment_source.lastModified();
m_recompile_shaders = true;
if (m_program) {
m_program->removeShader(m_fragment_shader.get());
m_fragment_shader.reset(nullptr);
}
}
} else {
m_recompile_shaders = true;
if (m_program) {
m_program->removeShader(m_fragment_shader.get());
m_fragment_shader.reset(nullptr);
}
}
}

View File

@ -0,0 +1,46 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef FRAGMENT_TOY_H
#define FRAGMENT_TOY_H
#include <QObject>
#include <QFile>
#include <QDateTime>
#if QT_CONFIG(filesystemwatcher)
#include <QFileSystemWatcher>
#endif
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include <memory>
class FragmentToy : public QObject, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit FragmentToy(const QString &fragmentSource, QObject *parent = nullptr);
~FragmentToy();
void draw(const QSize &windowSize);
private:
void fileChanged(const QString &path);
bool m_recompile_shaders;
#if QT_CONFIG(filesystemwatcher)
QFileSystemWatcher m_watcher;
#endif
QString m_fragment_file;
QDateTime m_fragment_file_last_modified;
std::unique_ptr<QOpenGLShaderProgram> m_program;
std::unique_ptr<QOpenGLShader> m_vertex_shader;
std::unique_ptr<QOpenGLShader> m_fragment_shader;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vertex_buffer;
GLuint m_vertex_coord_pos;
};
#endif //FRAGMENT_TOY_H

View File

@ -0,0 +1,154 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QOpenGLWindow>
#include <QScreen>
#include <QPainter>
#include <QPainterPath>
#include <QGuiApplication>
#include <QMatrix4x4>
#include <QStaticText>
#include <QKeyEvent>
#include "background_renderer.h"
static QPainterPath painterPathForTriangle()
{
static const QPointF bottomLeft(-1.0, -1.0);
static const QPointF top(0.0, 1.0);
static const QPointF bottomRight(1.0, -1.0);
QPainterPath path(bottomLeft);
path.lineTo(top);
path.lineTo(bottomRight);
path.closeSubpath();
return path;
}
class OpenGLWindow : public QOpenGLWindow
{
Q_OBJECT
public:
OpenGLWindow();
protected:
void paintGL() override;
void resizeGL(int w, int h) override;
void keyPressEvent(QKeyEvent *e) override;
private:
void setAnimating(bool enabled);
QMatrix4x4 m_window_normalised_matrix;
QMatrix4x4 m_window_painter_matrix;
QMatrix4x4 m_projection;
QMatrix4x4 m_view;
QMatrix4x4 m_model_triangle;
QMatrix4x4 m_model_text;
FragmentToy m_fragment_toy;
QStaticText m_text_layout;
bool m_animate;
};
// Use NoPartialUpdate. This means that all the rendering goes directly to
// the window surface, no additional framebuffer object stands in the
// middle. This is fine since we will clear the entire framebuffer on each
// paint. Under the hood this means that the behavior is equivalent to the
// manual makeCurrent - perform OpenGL calls - swapBuffers loop that is
// typical in pure QWindow-based applications.
OpenGLWindow::OpenGLWindow()
: QOpenGLWindow(QOpenGLWindow::NoPartialUpdate)
, m_fragment_toy("./background.frag")
, m_text_layout("The triangle and this text is rendered with QPainter")
, m_animate(true)
{
setGeometry(300, 300, 500, 500);
m_view.lookAt(QVector3D(3,1,1),
QVector3D(0,0,0),
QVector3D(0,1,0));
setAnimating(m_animate);
}
void OpenGLWindow::paintGL()
{
m_fragment_toy.draw(size());
QPainter p(this);
p.setWorldTransform(m_window_normalised_matrix.toTransform());
QMatrix4x4 mvp = m_projection * m_view * m_model_triangle;
p.setTransform(mvp.toTransform(), true);
p.fillPath(painterPathForTriangle(), QBrush(QGradient(QGradient::NightFade)));
QTransform text_transform = (m_window_painter_matrix * m_view * m_model_text).toTransform();
p.setTransform(text_transform, false);
p.setPen(QPen(Qt::black));
m_text_layout.prepare(text_transform);
qreal x = - (m_text_layout.size().width() / 2);
qreal y = 0;
p.drawStaticText(x, y, m_text_layout);
m_model_triangle.rotate(-1, 0, 1, 0);
m_model_text.rotate(1, 0, 1, 0);
}
void OpenGLWindow::resizeGL(int w, int h)
{
m_window_normalised_matrix.setToIdentity();
m_window_normalised_matrix.translate(w / 2.0, h / 2.0);
m_window_normalised_matrix.scale(w / 2.0, -h / 2.0);
m_window_painter_matrix.setToIdentity();
m_window_painter_matrix.translate(w / 2.0, h / 2.0);
m_text_layout.setTextWidth(std::max(w * 0.2, 80.0));
m_projection.setToIdentity();
m_projection.perspective(45.f, qreal(w) / qreal(h), 0.1f, 100.f);
}
void OpenGLWindow::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_P) { // pause
m_animate = !m_animate;
setAnimating(m_animate);
}
}
void OpenGLWindow::setAnimating(bool enabled)
{
if (enabled) {
// Animate continuously, throttled by the blocking swapBuffers() call the
// QOpenGLWindow internally executes after each paint. Once that is done
// (frameSwapped signal is emitted), we schedule a new update. This
// obviously assumes that the swap interval (see
// QSurfaceFormat::setSwapInterval()) is non-zero.
connect(this, &QOpenGLWindow::frameSwapped,
this, QOverload<>::of(&QPaintDeviceWindow::update));
update();
} else {
disconnect(this, &QOpenGLWindow::frameSwapped,
this, QOverload<>::of(&QPaintDeviceWindow::update));
}
}
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
OpenGLWindow window;
QSurfaceFormat fmt;
fmt.setDepthBufferSize(24);
fmt.setStencilBufferSize(8);
window.setFormat(fmt);
window.show();
return app.exec();
}
#include "main.moc"

View File

@ -0,0 +1,16 @@
TEMPLATE = app
TARGET = qopenglwindow
INCLUDEPATH += .
QT += opengl
RESOURCES += shaders.qrc
SOURCES += \
main.cpp \
background_renderer.cpp
HEADERS += \
background_renderer.h
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/qopenglwindow
INSTALLS += target

View File

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