1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qtechnique.h"
41#include "qtechnique_p.h"
42#include "qparameter.h"
43#include "qgraphicsapifilter.h"
44#include <Qt3DCore/qpropertyupdatedchange.h>
45#include <Qt3DCore/qpropertynodeaddedchange.h>
46#include <Qt3DCore/qpropertynoderemovedchange.h>
47
48QT_BEGIN_NAMESPACE
49
50using namespace Qt3DCore;
51
52namespace Qt3DRender {
53
54QTechniquePrivate::QTechniquePrivate()
55 : QNodePrivate()
56{
57}
58
59QTechniquePrivate::~QTechniquePrivate()
60{
61}
62
63/*!
64 \qmltype Technique
65 \instantiates Qt3DRender::QTechnique
66 \inqmlmodule Qt3D.Render
67 \inherits Qt3DCore::QNode
68 \since 5.7
69 \brief Encapsulates a Technique.
70
71 A Technique specifies a set of RenderPass objects, FilterKey objects,
72 Parameter objects and a GraphicsApiFilter, which together define a
73 rendering technique the given graphics API can render. The filter keys are
74 used by TechniqueFilter to select specific techniques at specific parts of
75 the FrameGraph. If two Parameter instances with the same name are specified
76 in a Technique and a RenderPass, the one in Technique overrides the one
77 used in the RenderPass.
78
79 When creating an Effect that targets several versions of a graphics API, it
80 is useful to create several Technique nodes each with a graphicsApiFilter
81 set to match one of the targeted versions. At runtime, the Qt3D renderer
82 will select the most appropriate Technique based on which graphics API
83 versions are supported and (if specified) the FilterKey nodes that satisfy
84 a given TechniqueFilter in the FrameGraph.
85
86 \note When using OpenGL as the graphics API for rendering, Qt3D relies on
87 the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
88 to decide what is the most appropriate GL version available. If you need to
89 customize the QSurfaceFormat, do not forget to apply it with
90 QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
91 will likely have no effect on Qt3D related rendering.
92
93 \qml
94 Technique {
95 id: gl3Technique
96 parameters: [
97 Parameter { name: "color"; value: "orange" }
98 ]
99 filterKeys: [
100 FilterKey { name: "renderingStyle"; value: "forward" }
101 ]
102 graphicsApiFilter: {
103 api: GraphicsApiFilter.OpenGL
104 profile: GraphicsApiFilter.CoreProfile
105 majorVersion: 3
106 minorVersion: 1
107 }
108 renderPasses: [
109 RenderPass {
110 id: firstPass
111 shaderProgram: ShaderProgram {
112 // ...
113 }
114 },
115 RenderPass {
116 id: secondPass
117 shaderProgram: ShaderProgram {
118 // ...
119 }
120 }
121 ]
122 }
123 \endqml
124
125 \sa Effect, RenderPass, TechniqueFilter
126 */
127
128/*!
129 \class Qt3DRender::QTechnique
130 \inmodule Qt3DRender
131 \inherits Node
132 \since 5.7
133 \brief Encapsulates a Technique.
134
135 A Qt3DRender::QTechnique specifies a set of Qt3DRender::QRenderPass
136 objects, Qt3DRender::QFilterKey objects, Qt3DRender::QParameter objects and
137 a Qt3DRender::QGraphicsApiFilter, which together define a rendering
138 technique the given graphics API can render. The filter keys are used by
139 Qt3DRender::QTechniqueFilter to select specific techniques at specific
140 parts of the FrameGraph. If two QParameter instances with the same name are
141 specified in a QTechnique and a QRenderPass, the one in Technique overrides
142 the one used in the QRenderPass.
143
144 When creating an QEffect that targets several versions of a graphics API,
145 it is useful to create several QTechnique nodes each with a
146 graphicsApiFilter set to match one of the targeted GL versions. At runtime,
147 the Qt3D renderer will select the most appropriate QTechnique based on
148 which graphics API versions are supported and (if specified) the QFilterKey
149 nodes that satisfy a given QTechniqueFilter in the FrameGraph.
150
151 \note When using OpenGL as the graphics API for rendering, Qt3D relies on
152 the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
153 to decide what is the most appropriate GL version available. If you need to
154 customize the QSurfaceFormat, do not forget to apply it with
155 QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
156 will likely have no effect on Qt3D related rendering.
157
158 \code
159 QTechnique *gl3Technique = new QTechnique();
160
161 // Create the render passes
162 QRenderPass *firstPass = new QRenderPass();
163 QRenderPass *secondPass = new QRenderPass();
164
165 // Add the passes to the technique
166 gl3Technique->addRenderPass(firstPass);
167 gl3Technique->addRenderPass(secondPass);
168
169 // Set the targeted GL version for the technique
170 gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
171 gl3Technique->graphicsApiFilter()->setMajorVersion(3);
172 gl3Technique->graphicsApiFilter()->setMinorVersion(1);
173 gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
174
175 // Create a FilterKey
176 QFilterKey *filterKey = new QFilterKey();
177 filterKey->setName(QStringLiteral("name"));
178 fitlerKey->setValue(QStringLiteral("zFillPass"));
179
180 // Add the FilterKey to the Technique
181 gl3Technique->addFilterKey(filterKey);
182
183 // Create a QParameter
184 QParameter *colorParameter = new QParameter(QStringLiteral("color"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
185
186 // Add parameter to technique
187 gl3Technique->addParameter(colorParameter);
188 \endcode
189
190 \sa QEffect, QRenderPass, QTechniqueFilter
191 */
192
193/*!
194 \qmlproperty GraphicsApiFilter Qt3D.Render::Technique::graphicsApiFilter
195 Specifies the graphics API filter being used
196*/
197/*!
198 \qmlproperty list<FilterKey> Qt3D.Render::Technique::filterKeys
199 Specifies the list of filter keys enabling this technique
200*/
201/*!
202 \qmlproperty list<RenderPass> Qt3D.Render::Technique::renderPasses
203 Specifies the render passes used by the tehcnique
204*/
205/*!
206 \qmlproperty list<Parameter> Qt3D.Render::Technique::parameters
207 Specifies the parameters used by the technique
208*/
209/*!
210 \property Qt3DRender::QTechnique::graphicsApiFilter
211 Specifies the graphics API filter being used
212 */
213
214QTechnique::QTechnique(QNode *parent)
215 : QNode(*new QTechniquePrivate, parent)
216{
217 Q_D(QTechnique);
218 QObject::connect(&d->m_graphicsApiFilter, SIGNAL(graphicsApiFilterChanged()), this, SLOT(_q_graphicsApiFilterChanged()));
219}
220
221/*! \internal */
222QTechnique::~QTechnique()
223{
224}
225
226/*! \internal */
227QTechnique::QTechnique(QTechniquePrivate &dd, QNode *parent)
228 : QNode(dd, parent)
229{
230 Q_D(QTechnique);
231 QObject::connect(&d->m_graphicsApiFilter, SIGNAL(graphicsApiFilterChanged()), this, SLOT(_q_graphicsApiFilterChanged()));
232}
233
234/*! \internal */
235void QTechniquePrivate::_q_graphicsApiFilterChanged()
236{
237 if (m_changeArbiter != nullptr) {
238 auto change = QPropertyUpdatedChangePtr::create(m_id);
239 change->setPropertyName("graphicsApiFilterData");
240 change->setValue(QVariant::fromValue(QGraphicsApiFilterPrivate::get(const_cast<QGraphicsApiFilter *>(&m_graphicsApiFilter))->m_data));
241 notifyObservers(change);
242 }
243}
244
245/*!
246 Add \a filterKey to the Qt3DRender::QTechnique local filter keys.
247 */
248void QTechnique::addFilterKey(QFilterKey *filterKey)
249{
250 Q_ASSERT(filterKey);
251 Q_D(QTechnique);
252 if (!d->m_filterKeys.contains(filterKey)) {
253 d->m_filterKeys.append(filterKey);
254
255 // Ensures proper bookkeeping
256 d->registerDestructionHelper(filterKey, &QTechnique::removeFilterKey, d->m_filterKeys);
257
258 // We need to add it as a child of the current node if it has been declared inline
259 // Or not previously added as a child of the current node so that
260 // 1) The backend gets notified about it's creation
261 // 2) When the current node is destroyed, it gets destroyed as well
262 if (!filterKey->parent())
263 filterKey->setParent(this);
264
265 if (d->m_changeArbiter != nullptr) {
266 const auto change = QPropertyNodeAddedChangePtr::create(id(), filterKey);
267 change->setPropertyName("filterKeys");
268 d->notifyObservers(change);
269 }
270 }
271}
272
273/*!
274 Removes \a filterKey from the Qt3DRender::QTechnique local filter keys.
275 */
276void QTechnique::removeFilterKey(QFilterKey *filterKey)
277{
278 Q_ASSERT(filterKey);
279 Q_D(QTechnique);
280 if (d->m_changeArbiter != nullptr) {
281 const auto change = QPropertyNodeRemovedChangePtr::create(id(), filterKey);
282 change->setPropertyName("filterKeys");
283 d->notifyObservers(change);
284 }
285 d->m_filterKeys.removeOne(filterKey);
286 // Remove bookkeeping connection
287 d->unregisterDestructionHelper(filterKey);
288}
289
290/*!
291 Returns the list of Qt3DCore::QFilterKey key objects making up the filter keys
292 of the Qt3DRender::QTechnique.
293 */
294QVector<QFilterKey *> QTechnique::filterKeys() const
295{
296 Q_D(const QTechnique);
297 return d->m_filterKeys;
298}
299
300/*!
301 Add \a parameter to the technique's parameters.
302 */
303void QTechnique::addParameter(QParameter *parameter)
304{
305 Q_ASSERT(parameter);
306 Q_D(QTechnique);
307 if (!d->m_parameters.contains(parameter)) {
308 d->m_parameters.append(parameter);
309
310 // Ensures proper bookkeeping
311 d->registerDestructionHelper(parameter, &QTechnique::removeParameter, d->m_parameters);
312
313 // We need to add it as a child of the current node if it has been declared inline
314 // Or not previously added as a child of the current node so that
315 // 1) The backend gets notified about it's creation
316 // 2) When the current node is destroyed, the child parameters get destroyed as well
317 if (!parameter->parent())
318 parameter->setParent(this);
319
320 if (d->m_changeArbiter != nullptr) {
321 const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
322 change->setPropertyName("parameter");
323 d->notifyObservers(change);
324 }
325 }
326}
327
328/*!
329 Remove \a parameter from the technique's parameters.
330 */
331void QTechnique::removeParameter(QParameter *parameter)
332{
333 Q_ASSERT(parameter);
334 Q_D(QTechnique);
335 if (d->m_changeArbiter != nullptr) {
336 const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
337 change->setPropertyName("parameter");
338 d->notifyObservers(change);
339 }
340 d->m_parameters.removeOne(parameter);
341 // Remove bookkeeping connection
342 d->unregisterDestructionHelper(parameter);
343}
344
345/*!
346 Appends a \a pass to the technique.
347 */
348void QTechnique::addRenderPass(QRenderPass *pass)
349{
350 Q_ASSERT(pass);
351 Q_D(QTechnique);
352 if (!d->m_renderPasses.contains(pass)) {
353 d->m_renderPasses.append(pass);
354
355 // Ensures proper bookkeeping
356 d->registerDestructionHelper(pass, &QTechnique::removeRenderPass, d->m_renderPasses);
357
358 // We need to add it as a child of the current node if it has been declared inline
359 // Or not previously added as a child of the current node so that
360 // 1) The backend gets notified about it's creation
361 // 2) When the current node is destroyed, it gets destroyed as well
362 if (!pass->parent())
363 pass->setParent(this);
364
365 if (d->m_changeArbiter != nullptr) {
366 const auto change = QPropertyNodeAddedChangePtr::create(id(), pass);
367 change->setPropertyName("pass");
368 d->notifyObservers(change);
369 }
370 }
371}
372
373/*!
374 Removes a \a pass from the technique.
375 */
376void QTechnique::removeRenderPass(QRenderPass *pass)
377{
378 Q_ASSERT(pass);
379 Q_D(QTechnique);
380 if (d->m_changeArbiter) {
381 const auto change = QPropertyNodeRemovedChangePtr::create(id(), pass);
382 change->setPropertyName("pass");
383 d->notifyObservers(change);
384 }
385 d->m_renderPasses.removeOne(pass);
386 // Remove bookkeeping connection
387 d->unregisterDestructionHelper(pass);
388}
389
390/*!
391 Returns the list of render passes contained in the technique.
392 */
393QVector<QRenderPass *> QTechnique::renderPasses() const
394{
395 Q_D(const QTechnique);
396 return d->m_renderPasses;
397}
398
399/*!
400 Returns a vector of the techniques current parameters
401 */
402QVector<QParameter *> QTechnique::parameters() const
403{
404 Q_D(const QTechnique);
405 return d->m_parameters;
406}
407
408QGraphicsApiFilter *QTechnique::graphicsApiFilter()
409{
410 Q_D(QTechnique);
411 return &d->m_graphicsApiFilter;
412}
413
414Qt3DCore::QNodeCreatedChangeBasePtr QTechnique::createNodeCreationChange() const
415{
416 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QTechniqueData>::create(this);
417 QTechniqueData &data = creationChange->data;
418
419 Q_D(const QTechnique);
420 data.graphicsApiFilterData = QGraphicsApiFilterPrivate::get(const_cast<QGraphicsApiFilter *>(&d->m_graphicsApiFilter))->m_data;
421 data.filterKeyIds = qIdsForNodes(d->m_filterKeys);
422 data.parameterIds = qIdsForNodes(d->m_parameters);
423 data.renderPassIds = qIdsForNodes(d->m_renderPasses);
424
425 return creationChange;
426}
427
428} // of namespace Qt3DRender
429
430QT_END_NAMESPACE
431
432#include "moc_qtechnique.cpp"
433