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 QtCore module 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 "mainwidget.h"
52
53#include <QMouseEvent>
54
55#include <cmath>
56
57MainWidget::~MainWidget()
58{
59 // Make sure the context is current when deleting the texture
60 // and the buffers.
61 makeCurrent();
62 delete texture;
63 delete geometries;
64 doneCurrent();
65}
66
67//! [0]
68void MainWidget::mousePressEvent(QMouseEvent *e)
69{
70 // Save mouse press position
71 mousePressPosition = QVector2D(e->position());
72}
73
74void MainWidget::mouseReleaseEvent(QMouseEvent *e)
75{
76 // Mouse release position - mouse press position
77 QVector2D diff = QVector2D(e->position()) - mousePressPosition;
78
79 // Rotation axis is perpendicular to the mouse position difference
80 // vector
81 QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
82
83 // Accelerate angular speed relative to the length of the mouse sweep
84 qreal acc = diff.length() / 100.0;
85
86 // Calculate new rotation axis as weighted sum
87 rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();
88
89 // Increase angular speed
90 angularSpeed += acc;
91}
92//! [0]
93
94//! [1]
95void MainWidget::timerEvent(QTimerEvent *)
96{
97 // Decrease angular speed (friction)
98 angularSpeed *= 0.99;
99
100 // Stop rotation when speed goes below threshold
101 if (angularSpeed < 0.01) {
102 angularSpeed = 0.0;
103 } else {
104 // Update rotation
105 rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation;
106
107 // Request an update
108 update();
109 }
110}
111//! [1]
112
113void MainWidget::initializeGL()
114{
115 initializeOpenGLFunctions();
116
117 glClearColor(0, 0, 0, 1);
118
119 initShaders();
120 initTextures();
121
122//! [2]
123 // Enable depth buffer
124 glEnable(GL_DEPTH_TEST);
125
126 // Enable back face culling
127 glEnable(GL_CULL_FACE);
128//! [2]
129
130 geometries = new GeometryEngine;
131
132 // Use QBasicTimer because its faster than QTimer
133 timer.start(12, this);
134}
135
136//! [3]
137void MainWidget::initShaders()
138{
139 // Compile vertex shader
140 if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vshader.glsl"))
141 close();
142
143 // Compile fragment shader
144 if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fshader.glsl"))
145 close();
146
147 // Link shader pipeline
148 if (!program.link())
149 close();
150
151 // Bind shader pipeline for use
152 if (!program.bind())
153 close();
154}
155//! [3]
156
157//! [4]
158void MainWidget::initTextures()
159{
160 // Load cube.png image
161 texture = new QOpenGLTexture(QImage(":/cube.png").mirrored());
162
163 // Set nearest filtering mode for texture minification
164 texture->setMinificationFilter(QOpenGLTexture::Nearest);
165
166 // Set bilinear filtering mode for texture magnification
167 texture->setMagnificationFilter(QOpenGLTexture::Linear);
168
169 // Wrap texture coordinates by repeating
170 // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
171 texture->setWrapMode(QOpenGLTexture::Repeat);
172}
173//! [4]
174
175//! [5]
176void MainWidget::resizeGL(int w, int h)
177{
178 // Calculate aspect ratio
179 qreal aspect = qreal(w) / qreal(h ? h : 1);
180
181 // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
182 const qreal zNear = 3.0, zFar = 7.0, fov = 45.0;
183
184 // Reset projection
185 projection.setToIdentity();
186
187 // Set perspective projection
188 projection.perspective(fov, aspect, zNear, zFar);
189}
190//! [5]
191
192void MainWidget::paintGL()
193{
194 // Clear color and depth buffer
195 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
196
197 texture->bind();
198
199//! [6]
200 // Calculate model view transformation
201 QMatrix4x4 matrix;
202 matrix.translate(0.0, 0.0, -5.0);
203 matrix.rotate(rotation);
204
205 // Set modelview-projection matrix
206 program.setUniformValue("mvp_matrix", projection * matrix);
207//! [6]
208
209 // Use texture unit 0 which contains cube.png
210 program.setUniformValue("texture", 0);
211
212 // Draw cube geometry
213 geometries->drawCubeGeometry(&program);
214}
215