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 | |
57 | MainWidget::~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] |
68 | void MainWidget::mousePressEvent(QMouseEvent *e) |
69 | { |
70 | // Save mouse press position |
71 | mousePressPosition = QVector2D(e->position()); |
72 | } |
73 | |
74 | void 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] |
95 | void 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 | |
113 | void 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] |
137 | void 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] |
158 | void 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] |
176 | void 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 | |
192 | void 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 | |