5ebb9a8bf3
Old examples inherited from Qt 4 tend to set some state, such as enabling the depth test or culling, in initializeGL(). Newer examples tend not to do this; they rather set the necessary state in paintGL(). This mattered little (or not at all) in the past, but with WebAssembly and WebGL there are limitations in the GL context management in the wasm platform plugin. Under certain conditions, esp. when QOffscreenSurface is involved, it looks like the same native context gets reused, which means there is a chance of unexpected changes to the current state between calls to initializeGL() and paintGL(). (and also between paintGL() calls) See QWasmOpenGLContext for details. Update the textures example the same way we did for the cube one. Add a note to the QOpenGLWidget docs about this problem. Task-number: QTBUG-111304 Pick-to: 6.5 6.4 Change-Id: I29d2b2cdeb07bcecc5dc915d79c12b4323ca9ab3 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io> Reviewed-by: Inho Lee <inho.lee@qt.io>
174 lines
4.9 KiB
C++
174 lines
4.9 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
|
|
#include "glwidget.h"
|
|
#include <QOpenGLShaderProgram>
|
|
#include <QOpenGLTexture>
|
|
#include <QMouseEvent>
|
|
|
|
GLWidget::~GLWidget()
|
|
{
|
|
makeCurrent();
|
|
vbo.destroy();
|
|
for (int i = 0; i < 6; ++i)
|
|
delete textures[i];
|
|
delete program;
|
|
doneCurrent();
|
|
}
|
|
|
|
QSize GLWidget::minimumSizeHint() const
|
|
{
|
|
return QSize(50, 50);
|
|
}
|
|
|
|
QSize GLWidget::sizeHint() const
|
|
{
|
|
return QSize(200, 200);
|
|
}
|
|
|
|
void GLWidget::rotateBy(int xAngle, int yAngle, int zAngle)
|
|
{
|
|
xRot += xAngle;
|
|
yRot += yAngle;
|
|
zRot += zAngle;
|
|
update();
|
|
}
|
|
|
|
void GLWidget::setClearColor(const QColor &color)
|
|
{
|
|
clearColor = color;
|
|
update();
|
|
}
|
|
|
|
void GLWidget::initializeGL()
|
|
{
|
|
initializeOpenGLFunctions();
|
|
|
|
makeObject();
|
|
|
|
#define PROGRAM_VERTEX_ATTRIBUTE 0
|
|
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
|
|
|
|
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
|
|
const char *vsrc =
|
|
"attribute highp vec4 vertex;\n"
|
|
"attribute mediump vec4 texCoord;\n"
|
|
"varying mediump vec4 texc;\n"
|
|
"uniform mediump mat4 matrix;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" gl_Position = matrix * vertex;\n"
|
|
" texc = texCoord;\n"
|
|
"}\n";
|
|
vshader->compileSourceCode(vsrc);
|
|
|
|
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
|
|
const char *fsrc =
|
|
"uniform sampler2D texture;\n"
|
|
"varying mediump vec4 texc;\n"
|
|
"void main(void)\n"
|
|
"{\n"
|
|
" gl_FragColor = texture2D(texture, texc.st);\n"
|
|
"}\n";
|
|
fshader->compileSourceCode(fsrc);
|
|
|
|
program = new QOpenGLShaderProgram;
|
|
program->addShader(vshader);
|
|
program->addShader(fshader);
|
|
program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
|
|
program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
|
|
program->link();
|
|
|
|
program->bind();
|
|
program->setUniformValue("texture", 0);
|
|
}
|
|
|
|
void GLWidget::paintGL()
|
|
{
|
|
glClearColor(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF());
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
QMatrix4x4 m;
|
|
m.ortho(-0.5f, +0.5f, +0.5f, -0.5f, 4.0f, 15.0f);
|
|
m.translate(0.0f, 0.0f, -10.0f);
|
|
m.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);
|
|
m.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);
|
|
m.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
vbo.bind();
|
|
program->bind();
|
|
program->setUniformValue("matrix", m);
|
|
program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
|
|
program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
|
|
program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
|
|
program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
|
|
|
|
for (int i = 0; i < 6; ++i) {
|
|
textures[i]->bind();
|
|
glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
|
|
}
|
|
}
|
|
void GLWidget::resizeGL(int width, int height)
|
|
{
|
|
int side = qMin(width, height);
|
|
glViewport((width - side) / 2, (height - side) / 2, side, side);
|
|
}
|
|
|
|
void GLWidget::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
lastPos = event->position().toPoint();
|
|
}
|
|
|
|
void GLWidget::mouseMoveEvent(QMouseEvent *event)
|
|
{
|
|
int dx = event->position().toPoint().x() - lastPos.x();
|
|
int dy = event->position().toPoint().y() - lastPos.y();
|
|
|
|
if (event->buttons() & Qt::LeftButton) {
|
|
rotateBy(8 * dy, 8 * dx, 0);
|
|
} else if (event->buttons() & Qt::RightButton) {
|
|
rotateBy(8 * dy, 0, 8 * dx);
|
|
}
|
|
lastPos = event->position().toPoint();
|
|
}
|
|
|
|
void GLWidget::mouseReleaseEvent(QMouseEvent * /* event */)
|
|
{
|
|
emit clicked();
|
|
}
|
|
|
|
void GLWidget::makeObject()
|
|
{
|
|
static const int coords[6][4][3] = {
|
|
{ { +1, -1, -1 }, { -1, -1, -1 }, { -1, +1, -1 }, { +1, +1, -1 } },
|
|
{ { +1, +1, -1 }, { -1, +1, -1 }, { -1, +1, +1 }, { +1, +1, +1 } },
|
|
{ { +1, -1, +1 }, { +1, -1, -1 }, { +1, +1, -1 }, { +1, +1, +1 } },
|
|
{ { -1, -1, -1 }, { -1, -1, +1 }, { -1, +1, +1 }, { -1, +1, -1 } },
|
|
{ { +1, -1, +1 }, { -1, -1, +1 }, { -1, -1, -1 }, { +1, -1, -1 } },
|
|
{ { -1, -1, +1 }, { +1, -1, +1 }, { +1, +1, +1 }, { -1, +1, +1 } }
|
|
};
|
|
|
|
for (int j = 0; j < 6; ++j)
|
|
textures[j] = new QOpenGLTexture(QImage(QString(":/images/side%1.png").arg(j + 1)).mirrored());
|
|
|
|
QList<GLfloat> vertData;
|
|
for (int i = 0; i < 6; ++i) {
|
|
for (int j = 0; j < 4; ++j) {
|
|
// vertex position
|
|
vertData.append(0.2 * coords[i][j][0]);
|
|
vertData.append(0.2 * coords[i][j][1]);
|
|
vertData.append(0.2 * coords[i][j][2]);
|
|
// texture coordinate
|
|
vertData.append(j == 0 || j == 3);
|
|
vertData.append(j == 0 || j == 1);
|
|
}
|
|
}
|
|
|
|
vbo.create();
|
|
vbo.bind();
|
|
vbo.allocate(vertData.constData(), vertData.count() * sizeof(GLfloat));
|
|
}
|