summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorKristoffer Skau <kristoffer.skau@qt.io>2022-10-27 15:38:53 +0200
committerKristoffer Skau <kristoffer.skau@qt.io>2022-11-28 19:12:27 +0100
commitee2dbcada81f5220a05414d7bf9d5eeebdda8972 (patch)
tree2bca1fc0c3569a98f26a0717d9e555a9b88f2364 /examples
parent8155bd54261688f333b2d68e2d76f0fc076a0fb4 (diff)
downloadqtbase-ee2dbcada81f5220a05414d7bf9d5eeebdda8972.tar.gz
Add support for stereoscopic content in QOpenGLWidget
Need to add the plumbing necessary to support two textures in QOpenGLWidget and use these in the backing store. The changes required on the RHI level is already done in an earlier patch. Then paintGL() needs to be called twice, once for each buffer. Also add overloads for the other functions of QOopenGLWidget where it makes sense to query for left or right buffer. Then finally create an example. [ChangeLog][Widgets][QOpenGLWidget] Added support for stereoscopic rendering. Fixes: QTBUG-64587 Change-Id: I5a5c53506dcf8a56442097290dceb7eb730d50ce Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'examples')
-rw-r--r--examples/opengl/CMakeLists.txt1
-rw-r--r--examples/opengl/doc/images/stereoexample-leftbuffer.pngbin0 -> 9987 bytes
-rw-r--r--examples/opengl/doc/images/stereoexample-rightbuffer.pngbin0 -> 10002 bytes
-rw-r--r--examples/opengl/doc/src/stereoqopenglwidget.qdoc41
-rw-r--r--examples/opengl/opengl.pro3
-rw-r--r--examples/opengl/stereoqopenglwidget/CMakeLists.txt41
-rw-r--r--examples/opengl/stereoqopenglwidget/glwidget.cpp277
-rw-r--r--examples/opengl/stereoqopenglwidget/glwidget.h53
-rw-r--r--examples/opengl/stereoqopenglwidget/main.cpp31
-rw-r--r--examples/opengl/stereoqopenglwidget/mainwindow.cpp25
-rw-r--r--examples/opengl/stereoqopenglwidget/mainwindow.h21
-rw-r--r--examples/opengl/stereoqopenglwidget/stereoqopenglwidget.pro11
12 files changed, 503 insertions, 1 deletions
diff --git a/examples/opengl/CMakeLists.txt b/examples/opengl/CMakeLists.txt
index 9c6768f324..d2c7ece2fd 100644
--- a/examples/opengl/CMakeLists.txt
+++ b/examples/opengl/CMakeLists.txt
@@ -15,4 +15,5 @@ if(TARGET Qt6::Widgets)
qt_internal_add_example(textures)
qt_internal_add_example(hellogles3)
qt_internal_add_example(computegles31)
+ qt_internal_add_example(stereoqopenglwidget)
endif()
diff --git a/examples/opengl/doc/images/stereoexample-leftbuffer.png b/examples/opengl/doc/images/stereoexample-leftbuffer.png
new file mode 100644
index 0000000000..6ae7d5118b
--- /dev/null
+++ b/examples/opengl/doc/images/stereoexample-leftbuffer.png
Binary files differ
diff --git a/examples/opengl/doc/images/stereoexample-rightbuffer.png b/examples/opengl/doc/images/stereoexample-rightbuffer.png
new file mode 100644
index 0000000000..3e2dc3c671
--- /dev/null
+++ b/examples/opengl/doc/images/stereoexample-rightbuffer.png
Binary files differ
diff --git a/examples/opengl/doc/src/stereoqopenglwidget.qdoc b/examples/opengl/doc/src/stereoqopenglwidget.qdoc
new file mode 100644
index 0000000000..c4e51f9cee
--- /dev/null
+++ b/examples/opengl/doc/src/stereoqopenglwidget.qdoc
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example stereoqopenglwidget
+ \title QOpenGLWidget Stereoscopic Rendering Example
+
+ \brief This example shows how to create a minimal QOpenGLWidget based application
+ with stereoscopic rendering support.
+
+ \image stereoexample-leftbuffer.png
+
+ The above image is what will be rendered to the left buffer.
+
+ \image stereoexample-rightbuffer.png
+
+ The above image is what will be rendered to the right buffer.
+
+ \note Support for stereoscopic rendering has certain hardware requirements, like
+ your graphics card needs stereo support.
+
+ \section1 Setting the correct surface flag
+ To enable stereoscopic rendering you need to set the flag
+ QSurfaceFormat::StereoBuffers globally. Just doing it on the widget is not enough
+ because of how the flag is handled internally. The safest is to do it on
+ QSurfaceFormat::SetDefaultFormat prior to starting the application.
+
+ \snippet stereoqopenglwidget/main.cpp 1
+
+ \section1 Rendering twice
+ After QSurfaceFormat::StereoBuffers is set, then paintGL() will be called twice,
+ once for each buffer. In paintGL() you can call currentTargetBuffer() to query
+ which TargetBuffer is currently active.
+
+ In the following snippet we slightly translate the matrix to not render the
+ vertices on top of each other. This is a simple example just too see that if the
+ necessary support is there, at runtime you should see two objects, one on the left
+ and one on the right.
+
+ \snippet stereoqopenglwidget/glwidget.cpp 1
+*/
diff --git a/examples/opengl/opengl.pro b/examples/opengl/opengl.pro
index 907930d7ac..24cda20f63 100644
--- a/examples/opengl/opengl.pro
+++ b/examples/opengl/opengl.pro
@@ -14,5 +14,6 @@ qtHaveModule(widgets) {
cube \
textures \
hellogles3 \
- computegles31
+ computegles31 \
+ stereoqopenglwidget
}
diff --git a/examples/opengl/stereoqopenglwidget/CMakeLists.txt b/examples/opengl/stereoqopenglwidget/CMakeLists.txt
new file mode 100644
index 0000000000..69fd304bb2
--- /dev/null
+++ b/examples/opengl/stereoqopenglwidget/CMakeLists.txt
@@ -0,0 +1,41 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(stereoqopenglwidget LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/opengl/stereoqopenglwidget")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL OpenGLWidgets Widgets)
+
+qt_add_executable(stereoqopenglwidget
+ glwidget.cpp glwidget.h
+ main.cpp
+ mainwindow.cpp mainwindow.h
+)
+
+set_target_properties(stereoqopenglwidget PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(stereoqopenglwidget PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::OpenGL
+ Qt::OpenGLWidgets
+ Qt::Widgets
+)
+
+
+install(TARGETS stereoqopenglwidget
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/opengl/stereoqopenglwidget/glwidget.cpp b/examples/opengl/stereoqopenglwidget/glwidget.cpp
new file mode 100644
index 0000000000..36a6300348
--- /dev/null
+++ b/examples/opengl/stereoqopenglwidget/glwidget.cpp
@@ -0,0 +1,277 @@
+// Copyright (C) 2022 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 <QFileDialog>
+#include <qmath.h>
+
+GLWidget::GLWidget(const QColor &background)
+ : m_background(background)
+{
+ setMinimumSize(300, 250);
+}
+
+GLWidget::~GLWidget()
+{
+ reset();
+}
+
+void GLWidget::saveImage(TargetBuffer targetBuffer)
+{
+ QImage img = grabFramebuffer(targetBuffer);
+ if (img.isNull()) {
+ qFatal("Failed to grab framebuffer");
+ }
+
+ const char *fn =
+ targetBuffer == TargetBuffer::LeftBuffer
+ ? "leftBuffer.png" : "rightBuffer.png";
+
+ QFileDialog fd(this);
+ fd.setAcceptMode(QFileDialog::AcceptSave);
+ fd.setDefaultSuffix("png");
+ fd.selectFile(fn);
+ if (fd.exec() == QDialog::Accepted)
+ img.save(fd.selectedFiles().first());
+}
+
+void GLWidget::reset()
+{
+ // And now release all OpenGL resources.
+ makeCurrent();
+ delete m_program;
+ m_program = nullptr;
+ delete m_vshader;
+ m_vshader = nullptr;
+ delete m_fshader;
+ m_fshader = nullptr;
+ m_vbo.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::initializeGL()
+{
+ initializeOpenGLFunctions();
+
+ m_vshader = 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_vshader->compileSourceCode(vsrc1);
+
+ m_fshader = new QOpenGLShader(QOpenGLShader::Fragment);
+ const char *fsrc1 =
+ "varying mediump vec4 color;\n"
+ "void main(void)\n"
+ "{\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+ m_fshader->compileSourceCode(fsrc1);
+
+ m_program = new QOpenGLShaderProgram;
+ m_program->addShader(m_vshader);
+ m_program->addShader(m_fshader);
+ m_program->link();
+
+
+ m_vertexAttr = m_program->attributeLocation("vertex");
+ m_normalAttr = m_program->attributeLocation("normal");
+ m_matrixUniform = m_program->uniformLocation("matrix");
+
+ createGeometry();
+
+ m_vbo.create();
+ m_vbo.bind();
+ 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_vbo.allocate(buf.constData(), (int)buf.count() * sizeof(GLfloat));
+ m_vbo.release();
+
+ m_contextWatchConnection = QObject::connect(context(), &QOpenGLContext::aboutToBeDestroyed, context(), [this] { reset(); });
+
+ glFrontFace(GL_CW);
+ glCullFace(GL_FRONT);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+}
+
+void GLWidget::paintGL()
+{
+ // When QSurfaceFormat::StereoBuffers is enabled, this function is called twice.
+ // Once where currentTargetBuffer() == QOpenGLWidget::LeftBuffer,
+ // and once where currentTargetBuffer() == QOpenGLWidget::RightBuffer.
+
+ glClearColor(m_background.redF(), m_background.greenF(), m_background.blueF(), 1.0f);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ //! [1]
+ // Slightly translate the model, so that there's a visible difference in each buffer.
+ QMatrix4x4 modelview;
+ if (currentTargetBuffer() == QOpenGLWidget::LeftBuffer)
+ modelview.translate(-0.4f, 0.0f, 0.0f);
+ else if (currentTargetBuffer() == QOpenGLWidget::RightBuffer)
+ modelview.translate(0.4f, 0.0f, 0.0f);
+ //! [1]
+
+ m_program->bind();
+ m_program->setUniformValue(m_matrixUniform, modelview);
+ m_program->enableAttributeArray(m_vertexAttr);
+ m_program->enableAttributeArray(m_normalAttr);
+
+ m_vbo.bind();
+ m_program->setAttributeBuffer(m_vertexAttr, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));
+ m_program->setAttributeBuffer(m_normalAttr, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
+ m_vbo.release();
+
+ glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
+
+ m_program->disableAttributeArray(m_normalAttr);
+ m_program->disableAttributeArray(m_vertexAttr);
+ m_program->release();
+ update();
+}
+
+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;
+}
diff --git a/examples/opengl/stereoqopenglwidget/glwidget.h b/examples/opengl/stereoqopenglwidget/glwidget.h
new file mode 100644
index 0000000000..0014ee37c1
--- /dev/null
+++ b/examples/opengl/stereoqopenglwidget/glwidget.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef GLWIDGET_H
+#define GLWIDGET_H
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions>
+#include <QOpenGLBuffer>
+#include <QVector3D>
+#include <QMatrix4x4>
+#include <QElapsedTimer>
+#include <QList>
+#include <QPushButton>
+
+
+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(const QColor &background);
+ ~GLWidget();
+
+ void saveImage(QOpenGLWidget::TargetBuffer targetBuffer);
+
+protected:
+ void paintGL() override;
+ void initializeGL() override;
+
+private:
+ void createGeometry();
+ void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4);
+ void extrude(qreal x1, qreal y1, qreal x2, qreal y2);
+ void reset();
+
+ QList<QVector3D> m_vertices;
+ QList<QVector3D> m_normals;
+ QOpenGLShader *m_vshader = nullptr;
+ QOpenGLShader *m_fshader = nullptr;
+ QOpenGLShaderProgram *m_program = nullptr;
+ QOpenGLBuffer m_vbo;
+ int m_vertexAttr;
+ int m_normalAttr;
+ int m_matrixUniform;
+ QColor m_background;
+ QMetaObject::Connection m_contextWatchConnection;
+};
+
+#endif
diff --git a/examples/opengl/stereoqopenglwidget/main.cpp b/examples/opengl/stereoqopenglwidget/main.cpp
new file mode 100644
index 0000000000..8aad756eca
--- /dev/null
+++ b/examples/opengl/stereoqopenglwidget/main.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+#include <QSurfaceFormat>
+#include "mainwindow.h"
+
+int main( int argc, char ** argv )
+{
+ QApplication a( argc, argv );
+
+ QCoreApplication::setApplicationName("Qt QOpenGLWidget Stereoscopic Rendering Example");
+ QCoreApplication::setOrganizationName("QtProject");
+ QCoreApplication::setApplicationVersion(QT_VERSION_STR);
+
+ //! [1]
+ QSurfaceFormat format;
+ format.setDepthBufferSize(24);
+ format.setStencilBufferSize(8);
+
+ // Enable stereoscopic rendering support
+ format.setStereo(true);
+
+ QSurfaceFormat::setDefaultFormat(format);
+ //! [1]
+
+ MainWindow mw;
+ mw.resize(1280, 720);
+ mw.show();
+ return a.exec();
+}
diff --git a/examples/opengl/stereoqopenglwidget/mainwindow.cpp b/examples/opengl/stereoqopenglwidget/mainwindow.cpp
new file mode 100644
index 0000000000..33f93ba7de
--- /dev/null
+++ b/examples/opengl/stereoqopenglwidget/mainwindow.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+#include <QApplication>
+#include <QMenuBar>
+#include "glwidget.h"
+
+MainWindow::MainWindow()
+{
+ GLWidget *glwidget = new GLWidget(qRgb(20, 20, 50));
+ setCentralWidget(glwidget);
+
+ QMenu *screenShotMenu = menuBar()->addMenu("&Screenshot");
+ screenShotMenu->addAction("Left buffer", this, [glwidget](){
+ glwidget->saveImage(QOpenGLWidget::LeftBuffer);
+ });
+
+ screenShotMenu->addAction("Right buffer", this, [glwidget](){
+ glwidget->saveImage(QOpenGLWidget::RightBuffer);
+ });
+
+ QMenu *helpMenu = menuBar()->addMenu("&Help");
+ helpMenu->addAction("About Qt", qApp, &QApplication::aboutQt);
+}
diff --git a/examples/opengl/stereoqopenglwidget/mainwindow.h b/examples/opengl/stereoqopenglwidget/mainwindow.h
new file mode 100644
index 0000000000..aa6f722e59
--- /dev/null
+++ b/examples/opengl/stereoqopenglwidget/mainwindow.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2022 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();
+};
+
+#endif
diff --git a/examples/opengl/stereoqopenglwidget/stereoqopenglwidget.pro b/examples/opengl/stereoqopenglwidget/stereoqopenglwidget.pro
new file mode 100644
index 0000000000..197afff571
--- /dev/null
+++ b/examples/opengl/stereoqopenglwidget/stereoqopenglwidget.pro
@@ -0,0 +1,11 @@
+QT += widgets opengl openglwidgets
+
+SOURCES += main.cpp \
+ glwidget.cpp \
+ mainwindow.cpp
+
+HEADERS += glwidget.h \
+ mainwindow.h
+
+target.path = $$[QT_INSTALL_EXAMPLES]/opengl/stereoqopenglwidget
+INSTALLS += target