summaryrefslogtreecommitdiffstats
path: root/tests/manual
diff options
context:
space:
mode:
authorKristoffer Skau <kristoffer.skau@qt.io>2022-11-24 14:31:09 +0100
committerKristoffer Skau <kristoffer.skau@qt.io>2022-12-01 13:42:07 +0100
commitc450f6d21c5153e05bd10afdd54767623cfbe7e8 (patch)
treee7ce6d73cda2f0f83673cad8b528bb67463e9cdd /tests/manual
parent9bc74d14f379ad58d7a80d5514a3db5be5012de0 (diff)
Support stereoscopic rendering with QGraphicsView
This patch adds a manual test and the required work in graphicsview and qwidget private apis to support stereoscopic rendeing. Basically it works by doing the drawing in QGraphicsView::paintEvent twice, once for each buffer. This way the scene items are rendered to both buffers. There's also an update to resolvement in QOpenGLWidgetPrivate so that multisampling works correctly. [ChangeLog][Widgets][QGraphicsView] Added support for stereoscopic rendering. Task-number: QTBUG-64587 Change-Id: I20650682daa805b64fe7f0d2ba086917d3f12229 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'tests/manual')
-rw-r--r--tests/manual/stereographicsview/CMakeLists.txt32
-rw-r--r--tests/manual/stereographicsview/main.cpp26
-rw-r--r--tests/manual/stereographicsview/mainwindow.cpp79
-rw-r--r--tests/manual/stereographicsview/mainwindow.h30
-rw-r--r--tests/manual/stereographicsview/mainwindow.ui101
-rw-r--r--tests/manual/stereographicsview/mygraphicsview.cpp209
-rw-r--r--tests/manual/stereographicsview/mygraphicsview.h47
-rw-r--r--tests/manual/stereographicsview/stereographicsview.pro13
8 files changed, 537 insertions, 0 deletions
diff --git a/tests/manual/stereographicsview/CMakeLists.txt b/tests/manual/stereographicsview/CMakeLists.txt
new file mode 100644
index 0000000000..937e10de91
--- /dev/null
+++ b/tests/manual/stereographicsview/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Generated from stereographicsview.pro.
+
+#####################################################################
+## stereographicsview Binary:
+#####################################################################
+
+set(CMAKE_AUTOUIC ON)
+
+qt_internal_add_manual_test(stereographicsview
+ GUI
+ SOURCES
+ main.cpp
+ mainwindow.cpp
+ mainwindow.h
+ mainwindow.ui
+ mygraphicsview.h
+ mygraphicsview.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::OpenGL
+ Qt::OpenGLWidgets
+ Qt::Widgets
+ Qt::WidgetsPrivate
+)
+
+#### Keys ignored in scope 1:.:.:stereographicsview.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/manual/stereographicsview/main.cpp b/tests/manual/stereographicsview/main.cpp
new file mode 100644
index 0000000000..6564e8efc4
--- /dev/null
+++ b/tests/manual/stereographicsview/main.cpp
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "mainwindow.h"
+
+#include <QApplication>
+#include <QSurfaceFormat>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+
+ QSurfaceFormat format;
+ format.setDepthBufferSize(24);
+ format.setStencilBufferSize(8);
+ format.setSamples(16);
+ format.setStereo(true);
+ QSurfaceFormat::setDefaultFormat(format);
+
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
+
+
+#include "main.moc"
diff --git a/tests/manual/stereographicsview/mainwindow.cpp b/tests/manual/stereographicsview/mainwindow.cpp
new file mode 100644
index 0000000000..003b4da8c3
--- /dev/null
+++ b/tests/manual/stereographicsview/mainwindow.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "mainwindow.h"
+#include "./ui_mainwindow.h"
+#include <QPushButton>
+#include <QSlider>
+#include <QLabel>
+#include <QGraphicsEllipseItem>
+#include <QRandomGenerator>
+#include <QOpenGLWidget>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ ui->graphicsView->setViewport(new QOpenGLWidget);
+ ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+
+ QRect rect = ui->graphicsView->rect();
+ QGraphicsScene *m_scene = new QGraphicsScene(rect);
+ ui->graphicsView->setScene(m_scene);
+
+ QSize initialSize(150, 150);
+ m_ellipse = m_scene->addEllipse(
+ rect.width() / 2 - initialSize.width() / 2,
+ rect.height() / 2 - initialSize.height() / 2,
+ initialSize.width(),
+ initialSize.height(),
+ QPen(Qt::magenta, 5),
+ Qt::blue);
+
+ QPushButton *button = new QPushButton();
+ button->setGeometry(QRect(rect.width() / 2 - 75, 100, 150, 50));
+ button->setText("Random ellipse color");
+ QObject::connect(button, &QPushButton::pressed, [&]() {
+ m_ellipse->setBrush(QColor::fromRgb(QRandomGenerator::global()->generate()));
+ m_ellipse->setPen(QPen(QColor::fromRgb(QRandomGenerator::global()->generate()), 5));
+ });
+ m_scene->addWidget(button);
+
+ m_label = new QLabel();
+ m_label->setGeometry(QRect(rect.width() / 2 - 50, rect.height() - 100, 100, 50));
+ m_label->setAlignment(Qt::AlignCenter);
+ m_scene->addWidget(m_label);
+
+ QSlider *slider = new QSlider(Qt::Horizontal);
+ slider->setGeometry(QRect(rect.width() / 2 - 100, rect.height() - 50, 200, 50));
+ slider->setMinimum(10);
+ slider->setMaximum(300);
+ slider->setValue(initialSize.width());
+ QObject::connect(slider, &QAbstractSlider::valueChanged, [this](int value){
+ QRectF rect = m_ellipse->rect();
+ rect.setWidth(value);
+ rect.setHeight(value);
+ m_ellipse->setRect(rect);
+ m_label->setText("Ellipse size: " + QString::number(value));
+ });
+ emit slider->valueChanged(initialSize.width());
+ m_scene->addWidget(slider);
+
+ QMenu *screenShotMenu = menuBar()->addMenu("&Screenshot");
+ screenShotMenu->addAction("Left buffer", this, [this](){
+ ui->graphicsView->saveImage(QOpenGLWidget::LeftBuffer);
+ });
+
+ screenShotMenu->addAction("Right buffer", this, [this](){
+ ui->graphicsView->saveImage(QOpenGLWidget::RightBuffer);
+ });
+
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
diff --git a/tests/manual/stereographicsview/mainwindow.h b/tests/manual/stereographicsview/mainwindow.h
new file mode 100644
index 0000000000..4a65dad68d
--- /dev/null
+++ b/tests/manual/stereographicsview/mainwindow.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+QT_END_NAMESPACE
+
+class QGraphicsEllipseItem;
+class QLabel;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+private:
+ QGraphicsEllipseItem *m_ellipse;
+ QLabel *m_label;
+
+ Ui::MainWindow *ui;
+};
+#endif // MAINWINDOW_H
diff --git a/tests/manual/stereographicsview/mainwindow.ui b/tests/manual/stereographicsview/mainwindow.ui
new file mode 100644
index 0000000000..2ebb6b8caa
--- /dev/null
+++ b/tests/manual/stereographicsview/mainwindow.ui
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1120</width>
+ <height>695</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="MyGraphicsView" name="graphicsView">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>QGraphicsView Stereoscopic Example</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1120</width>
+ <height>21</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>MyGraphicsView</class>
+ <extends>QGraphicsView</extends>
+ <header>mygraphicsview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/manual/stereographicsview/mygraphicsview.cpp b/tests/manual/stereographicsview/mygraphicsview.cpp
new file mode 100644
index 0000000000..dc6e39f4a0
--- /dev/null
+++ b/tests/manual/stereographicsview/mygraphicsview.cpp
@@ -0,0 +1,209 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "mygraphicsview.h"
+#include <QResizeEvent>
+#include <QFileDialog>
+
+Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
+
+MyGraphicsView::MyGraphicsView(QWidget *parent) :
+ QGraphicsView(parent),
+ m_indexBuf(QOpenGLBuffer::IndexBuffer)
+{
+
+}
+
+MyGraphicsView::MyGraphicsView(QGraphicsScene *scene, QWidget *parent) :
+ QGraphicsView(scene, parent)
+{
+
+}
+
+void MyGraphicsView::saveImage(QOpenGLWidget::TargetBuffer targetBuffer)
+{
+ QOpenGLWidget *w = static_cast<QOpenGLWidget*>(viewport());
+ Q_ASSERT(w);
+
+ w->makeCurrent(targetBuffer);
+ draw(targetBuffer);
+
+ QImage img = qt_gl_read_framebuffer(w->size() * w->devicePixelRatio(), true, true);
+
+ if (img.isNull()) {
+ qFatal("Failed to grab framebuffer");
+ }
+
+ const char *fn =
+ targetBuffer == QOpenGLWidget::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 MyGraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
+{
+ if (!m_initialized)
+ init();
+
+ QOpenGLWidget *w = static_cast<QOpenGLWidget*>(viewport());
+
+ painter->beginNativePainting();
+
+ draw(w->currentTargetBuffer());
+
+ painter->endNativePainting();
+
+
+ m_yaw += 0.5;
+ if (m_yaw > 360)
+ m_yaw = 0;
+}
+
+void MyGraphicsView::resizeEvent(QResizeEvent *event)
+{
+ QGraphicsView::resizeEvent(event);
+
+ resize(event->size().width(), event->size().height());
+}
+
+void MyGraphicsView::init()
+{
+ if (m_initialized)
+ return;
+
+ initializeOpenGLFunctions();
+
+ initShaders();
+ initCube();
+
+ resize(viewport()->width(), viewport()->height());
+
+ m_initialized = true;
+}
+
+void MyGraphicsView::initShaders()
+{
+ static const char *vertexShaderSource =
+ "#ifdef GL_ES\n"
+ "// Set default precision to medium\n"
+ "precision mediump int;\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "attribute vec4 a_position;\n"
+ "uniform mat4 u_mvp;\n"
+ "void main() {\n"
+ "gl_Position = u_mvp * a_position;\n"
+ "}\n";
+
+ static const char *fragmentShaderSource =
+ "#ifdef GL_ES\n"
+ "// Set default precision to medium\n"
+ "precision mediump int;\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "void main() {\n"
+ "gl_FragColor = vec4(0.7, 0.1, 0.0, 1.0);\n"
+ "}\n";
+
+ if (!m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource))
+ close();
+
+ if (!m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource))
+ close();
+
+ if (!m_program.link())
+ close();
+
+ if (!m_program.bind())
+ close();
+}
+
+void MyGraphicsView::initCube()
+{
+ m_arrayBuf.create();
+ m_indexBuf.create();
+
+ QVector3D vertices[] = {
+ QVector3D(-1.0f, -1.0f, 1.0f),
+ QVector3D( 1.0f, -1.0f, 1.0f),
+ QVector3D(-1.0f, 1.0f, 1.0f),
+ QVector3D( 1.0f, 1.0f, 1.0f),
+ QVector3D( 1.0f, -1.0f, 1.0f),
+ QVector3D( 1.0f, -1.0f, -1.0f),
+ QVector3D( 1.0f, 1.0f, 1.0f),
+ QVector3D( 1.0f, 1.0f, -1.0f),
+ QVector3D( 1.0f, -1.0f, -1.0f),
+ QVector3D(-1.0f, -1.0f, -1.0f),
+ QVector3D( 1.0f, 1.0f, -1.0f),
+ QVector3D(-1.0f, 1.0f, -1.0f),
+ QVector3D(-1.0f, -1.0f, -1.0f),
+ QVector3D(-1.0f, -1.0f, 1.0f),
+ QVector3D(-1.0f, 1.0f, -1.0f),
+ QVector3D(-1.0f, 1.0f, 1.0f),
+ QVector3D(-1.0f, -1.0f, -1.0f),
+ QVector3D( 1.0f, -1.0f, -1.0f),
+ QVector3D(-1.0f, -1.0f, 1.0f),
+ QVector3D( 1.0f, -1.0f, 1.0f),
+ QVector3D(-1.0f, 1.0f, 1.0f),
+ QVector3D( 1.0f, 1.0f, 1.0f),
+ QVector3D(-1.0f, 1.0f, -1.0f),
+ QVector3D( 1.0f, 1.0f, -1.0f)
+ };
+
+ GLushort indices[] = {
+ 0, 1, 2, 3, 3,
+ 4, 4, 5, 6, 7, 7,
+ 8, 8, 9, 10, 11, 11,
+ 12, 12, 13, 14, 15, 15,
+ 16, 16, 17, 18, 19, 19,
+ 20, 20, 21, 22, 23
+ };
+
+
+ m_arrayBuf.bind();
+ m_arrayBuf.allocate(vertices, 24 * sizeof(QVector3D));
+
+ m_indexBuf.bind();
+ m_indexBuf.allocate(indices, 34 * sizeof(GLushort));
+}
+
+void MyGraphicsView::draw(QOpenGLWidget::TargetBuffer targetBuffer)
+{
+ glClearColor(0.0f, 0.7f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ m_program.bind();
+ m_arrayBuf.bind();
+ m_indexBuf.bind();
+
+ QMatrix4x4 matrix;
+ matrix.translate(targetBuffer == QOpenGLWidget::LeftBuffer ? -2.0 : 2.0,
+ 0.0,
+ -10.0);
+ matrix.scale(2.0);
+ matrix.rotate(QQuaternion::fromEulerAngles(10, m_yaw, 0));
+ m_program.setUniformValue("u_mvp", m_projection * matrix);
+
+ int vertexLocation = m_program.attributeLocation("a_position");
+ m_program.enableAttributeArray(vertexLocation);
+ m_program.setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, sizeof(QVector3D));
+
+ glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, nullptr);
+}
+
+void MyGraphicsView::resize(int w, int h)
+{
+ qreal aspect = qreal(w) / qreal(h ? h : 1);
+ const qreal zNear = 0.0, zFar = 100.0, fov = 45.0;
+ m_projection.setToIdentity();
+ m_projection.perspective(fov, aspect, zNear, zFar);
+
+ if (m_initialized)
+ glViewport(0, 0, w, h);
+}
diff --git a/tests/manual/stereographicsview/mygraphicsview.h b/tests/manual/stereographicsview/mygraphicsview.h
new file mode 100644
index 0000000000..03204cb316
--- /dev/null
+++ b/tests/manual/stereographicsview/mygraphicsview.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef MYGRAPHICSVIEW_H
+#define MYGRAPHICSVIEW_H
+
+#include <QOpenGLFunctions>
+#include <QGraphicsView>
+#include <QOpenGLShaderProgram>
+#include <QOpenGLBuffer>
+#include <QMatrix4x4>
+#include <QOpenGLWidget>
+
+class MyGraphicsView : public QGraphicsView, protected QOpenGLFunctions
+{
+public:
+ MyGraphicsView(QWidget *parent = nullptr);
+ MyGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr);
+
+ void saveImage(QOpenGLWidget::TargetBuffer targetBuffer);
+
+protected:
+ void drawBackground(QPainter *painter, const QRectF &rect) override;
+
+ void resizeEvent(QResizeEvent *event) override;
+
+private:
+ void init();
+ void initShaders();
+ void initCube();
+
+ void draw(QOpenGLWidget::TargetBuffer targetBuffer);
+
+ void resize(int w, int h);
+
+
+ bool m_initialized = false;
+
+ QOpenGLShaderProgram m_program;
+ QMatrix4x4 m_projection;
+ QOpenGLBuffer m_arrayBuf;
+ QOpenGLBuffer m_indexBuf;
+
+ qreal m_yaw = 0;
+};
+
+#endif // MYGRAPHICSVIEW_H
diff --git a/tests/manual/stereographicsview/stereographicsview.pro b/tests/manual/stereographicsview/stereographicsview.pro
new file mode 100644
index 0000000000..597166367c
--- /dev/null
+++ b/tests/manual/stereographicsview/stereographicsview.pro
@@ -0,0 +1,13 @@
+QT += widgets widgets-private gui-private core-private
+
+TARGET = stereographicsview
+TEMPLATE = app
+
+SOURCES += main.cpp \
+ mainwindow.cpp \
+ mainwindow.h \
+ mainwindow.ui \
+ mygraphicsview.h \
+ mygraphicsview.cpp \
+
+HEADERS += openglwidget.h