1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "glwidget.h"
52#include <QOpenGLShaderProgram>
53#include <QOpenGLTexture>
54#include <QMouseEvent>
55
56GLWidget::~GLWidget()
57{
58 makeCurrent();
59 vbo.destroy();
60 for (int i = 0; i < 6; ++i)
61 delete textures[i];
62 delete program;
63 doneCurrent();
64}
65
66QSize GLWidget::minimumSizeHint() const
67{
68 return QSize(50, 50);
69}
70
71QSize GLWidget::sizeHint() const
72{
73 return QSize(200, 200);
74}
75
76void GLWidget::rotateBy(int xAngle, int yAngle, int zAngle)
77{
78 xRot += xAngle;
79 yRot += yAngle;
80 zRot += zAngle;
81 update();
82}
83
84void GLWidget::setClearColor(const QColor &color)
85{
86 clearColor = color;
87 update();
88}
89
90void GLWidget::initializeGL()
91{
92 initializeOpenGLFunctions();
93
94 makeObject();
95
96 glEnable(GL_DEPTH_TEST);
97 glEnable(GL_CULL_FACE);
98
99#define PROGRAM_VERTEX_ATTRIBUTE 0
100#define PROGRAM_TEXCOORD_ATTRIBUTE 1
101
102 QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
103 const char *vsrc =
104 "attribute highp vec4 vertex;\n"
105 "attribute mediump vec4 texCoord;\n"
106 "varying mediump vec4 texc;\n"
107 "uniform mediump mat4 matrix;\n"
108 "void main(void)\n"
109 "{\n"
110 " gl_Position = matrix * vertex;\n"
111 " texc = texCoord;\n"
112 "}\n";
113 vshader->compileSourceCode(vsrc);
114
115 QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
116 const char *fsrc =
117 "uniform sampler2D texture;\n"
118 "varying mediump vec4 texc;\n"
119 "void main(void)\n"
120 "{\n"
121 " gl_FragColor = texture2D(texture, texc.st);\n"
122 "}\n";
123 fshader->compileSourceCode(fsrc);
124
125 program = new QOpenGLShaderProgram;
126 program->addShader(vshader);
127 program->addShader(fshader);
128 program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
129 program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
130 program->link();
131
132 program->bind();
133 program->setUniformValue("texture", 0);
134}
135
136void GLWidget::paintGL()
137{
138 glClearColor(clearColor.redF(), clearColor.greenF(), clearColor.blueF(), clearColor.alphaF());
139 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
140
141 QMatrix4x4 m;
142 m.ortho(-0.5f, +0.5f, +0.5f, -0.5f, 4.0f, 15.0f);
143 m.translate(0.0f, 0.0f, -10.0f);
144 m.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);
145 m.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);
146 m.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);
147
148 program->setUniformValue("matrix", m);
149 program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
150 program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
151 program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
152 program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
153
154 for (int i = 0; i < 6; ++i) {
155 textures[i]->bind();
156 glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
157 }
158}
159void GLWidget::resizeGL(int width, int height)
160{
161 int side = qMin(width, height);
162 glViewport((width - side) / 2, (height - side) / 2, side, side);
163}
164
165void GLWidget::mousePressEvent(QMouseEvent *event)
166{
167 lastPos = event->position().toPoint();
168}
169
170void GLWidget::mouseMoveEvent(QMouseEvent *event)
171{
172 int dx = event->position().toPoint().x() - lastPos.x();
173 int dy = event->position().toPoint().y() - lastPos.y();
174
175 if (event->buttons() & Qt::LeftButton) {
176 rotateBy(8 * dy, 8 * dx, 0);
177 } else if (event->buttons() & Qt::RightButton) {
178 rotateBy(8 * dy, 0, 8 * dx);
179 }
180 lastPos = event->position().toPoint();
181}
182
183void GLWidget::mouseReleaseEvent(QMouseEvent * /* event */)
184{
185 emit clicked();
186}
187
188void GLWidget::makeObject()
189{
190 static const int coords[6][4][3] = {
191 { { +1, -1, -1 }, { -1, -1, -1 }, { -1, +1, -1 }, { +1, +1, -1 } },
192 { { +1, +1, -1 }, { -1, +1, -1 }, { -1, +1, +1 }, { +1, +1, +1 } },
193 { { +1, -1, +1 }, { +1, -1, -1 }, { +1, +1, -1 }, { +1, +1, +1 } },
194 { { -1, -1, -1 }, { -1, -1, +1 }, { -1, +1, +1 }, { -1, +1, -1 } },
195 { { +1, -1, +1 }, { -1, -1, +1 }, { -1, -1, -1 }, { +1, -1, -1 } },
196 { { -1, -1, +1 }, { +1, -1, +1 }, { +1, +1, +1 }, { -1, +1, +1 } }
197 };
198
199 for (int j = 0; j < 6; ++j)
200 textures[j] = new QOpenGLTexture(QImage(QString(":/images/side%1.png").arg(j + 1)).mirrored());
201
202 QList<GLfloat> vertData;
203 for (int i = 0; i < 6; ++i) {
204 for (int j = 0; j < 4; ++j) {
205 // vertex position
206 vertData.append(0.2 * coords[i][j][0]);
207 vertData.append(0.2 * coords[i][j][1]);
208 vertData.append(0.2 * coords[i][j][2]);
209 // texture coordinate
210 vertData.append(j == 0 || j == 3);
211 vertData.append(j == 0 || j == 1);
212 }
213 }
214
215 vbo.create();
216 vbo.bind();
217 vbo.allocate(vertData.constData(), vertData.count() * sizeof(GLfloat));
218}
219