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 <QOpenGLWindow> |
52 | #include <QScreen> |
53 | #include <QPainter> |
54 | #include <QPainterPath> |
55 | #include <QGuiApplication> |
56 | #include <QMatrix4x4> |
57 | #include <QStaticText> |
58 | #include <QKeyEvent> |
59 | |
60 | #include "background_renderer.h" |
61 | |
62 | static QPainterPath painterPathForTriangle() |
63 | { |
64 | static const QPointF bottomLeft(-1.0, -1.0); |
65 | static const QPointF top(0.0, 1.0); |
66 | static const QPointF bottomRight(1.0, -1.0); |
67 | |
68 | QPainterPath path(bottomLeft); |
69 | path.lineTo(p: top); |
70 | path.lineTo(p: bottomRight); |
71 | path.closeSubpath(); |
72 | return path; |
73 | } |
74 | |
75 | class OpenGLWindow : public QOpenGLWindow |
76 | { |
77 | Q_OBJECT |
78 | |
79 | public: |
80 | OpenGLWindow(); |
81 | |
82 | protected: |
83 | void paintGL() override; |
84 | void resizeGL(int w, int h) override; |
85 | void keyPressEvent(QKeyEvent *e) override; |
86 | |
87 | private: |
88 | void setAnimating(bool enabled); |
89 | |
90 | QMatrix4x4 m_window_normalised_matrix; |
91 | QMatrix4x4 m_window_painter_matrix; |
92 | QMatrix4x4 m_projection; |
93 | QMatrix4x4 m_view; |
94 | QMatrix4x4 m_model_triangle; |
95 | QMatrix4x4 m_model_text; |
96 | |
97 | FragmentToy m_fragment_toy; |
98 | QStaticText m_text_layout; |
99 | bool m_animate; |
100 | }; |
101 | |
102 | // Use NoPartialUpdate. This means that all the rendering goes directly to |
103 | // the window surface, no additional framebuffer object stands in the |
104 | // middle. This is fine since we will clear the entire framebuffer on each |
105 | // paint. Under the hood this means that the behavior is equivalent to the |
106 | // manual makeCurrent - perform OpenGL calls - swapBuffers loop that is |
107 | // typical in pure QWindow-based applications. |
108 | OpenGLWindow::OpenGLWindow() |
109 | : QOpenGLWindow(QOpenGLWindow::NoPartialUpdate) |
110 | , m_fragment_toy("./background.frag" ) |
111 | , m_text_layout("The triangle and this text is rendered with QPainter" ) |
112 | , m_animate(true) |
113 | { |
114 | setGeometry(posx: 300, posy: 300, w: 500, h: 500); |
115 | |
116 | m_view.lookAt(eye: QVector3D(3,1,1), |
117 | center: QVector3D(0,0,0), |
118 | up: QVector3D(0,1,0)); |
119 | |
120 | setAnimating(m_animate); |
121 | } |
122 | |
123 | void OpenGLWindow::paintGL() |
124 | { |
125 | m_fragment_toy.draw(windowSize: size()); |
126 | |
127 | QPainter p(this); |
128 | p.setWorldTransform(matrix: m_window_normalised_matrix.toTransform()); |
129 | |
130 | QMatrix4x4 mvp = m_projection * m_view * m_model_triangle; |
131 | p.setTransform(transform: mvp.toTransform(), combine: true); |
132 | |
133 | p.fillPath(path: painterPathForTriangle(), brush: QBrush(QGradient(QGradient::NightFade))); |
134 | |
135 | QTransform text_transform = (m_window_painter_matrix * m_view * m_model_text).toTransform(); |
136 | p.setTransform(transform: text_transform, combine: false); |
137 | p.setPen(QPen(Qt::black)); |
138 | m_text_layout.prepare(matrix: text_transform); |
139 | qreal x = - (m_text_layout.size().width() / 2); |
140 | qreal y = 0; |
141 | p.drawStaticText(x, y, staticText: m_text_layout); |
142 | |
143 | m_model_triangle.rotate(angle: -1, x: 0, y: 1, z: 0); |
144 | m_model_text.rotate(angle: 1, x: 0, y: 1, z: 0); |
145 | } |
146 | |
147 | void OpenGLWindow::resizeGL(int w, int h) |
148 | { |
149 | m_window_normalised_matrix.setToIdentity(); |
150 | m_window_normalised_matrix.translate(x: w / 2.0, y: h / 2.0); |
151 | m_window_normalised_matrix.scale(x: w / 2.0, y: -h / 2.0); |
152 | |
153 | m_window_painter_matrix.setToIdentity(); |
154 | m_window_painter_matrix.translate(x: w / 2.0, y: h / 2.0); |
155 | |
156 | m_text_layout.setTextWidth(std::max(a: w * 0.2, b: 80.0)); |
157 | |
158 | m_projection.setToIdentity(); |
159 | m_projection.perspective(verticalAngle: 45.f, aspectRatio: qreal(w) / qreal(h), nearPlane: 0.1f, farPlane: 100.f); |
160 | } |
161 | |
162 | void OpenGLWindow::keyPressEvent(QKeyEvent *e) |
163 | { |
164 | if (e->key() == Qt::Key_P) { // pause |
165 | m_animate = !m_animate; |
166 | setAnimating(m_animate); |
167 | } |
168 | } |
169 | |
170 | void OpenGLWindow::setAnimating(bool enabled) |
171 | { |
172 | if (enabled) { |
173 | // Animate continuously, throttled by the blocking swapBuffers() call the |
174 | // QOpenGLWindow internally executes after each paint. Once that is done |
175 | // (frameSwapped signal is emitted), we schedule a new update. This |
176 | // obviously assumes that the swap interval (see |
177 | // QSurfaceFormat::setSwapInterval()) is non-zero. |
178 | connect(sender: this, signal: &QOpenGLWindow::frameSwapped, |
179 | receiver: this, slot: QOverload<>::of(ptr: &QPaintDeviceWindow::update)); |
180 | update(); |
181 | } else { |
182 | disconnect(sender: this, signal: &QOpenGLWindow::frameSwapped, |
183 | receiver: this, slot: QOverload<>::of(ptr: &QPaintDeviceWindow::update)); |
184 | } |
185 | } |
186 | |
187 | int main(int argc, char **argv) |
188 | { |
189 | QGuiApplication app(argc, argv); |
190 | |
191 | OpenGLWindow window; |
192 | QSurfaceFormat fmt; |
193 | fmt.setDepthBufferSize(24); |
194 | fmt.setStencilBufferSize(8); |
195 | window.setFormat(fmt); |
196 | window.show(); |
197 | |
198 | return app.exec(); |
199 | } |
200 | |
201 | #include "main.moc" |
202 | |