c450f6d21c
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>
210 lines
5.6 KiB
C++
210 lines
5.6 KiB
C++
// 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);
|
|
}
|