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 "qeffect.h"
41#include "qeffect_p.h"
42#include "qtechnique.h"
43#include "qparameter.h"
44
45#include <Qt3DCore/qpropertyupdatedchange.h>
46#include <Qt3DCore/qpropertynodeaddedchange.h>
47#include <Qt3DCore/qpropertynoderemovedchange.h>
48
49QT_BEGIN_NAMESPACE
50
51using namespace Qt3DCore;
52
53namespace Qt3DRender {
54
55QEffectPrivate::QEffectPrivate()
56 : QNodePrivate()
57{
58}
59
60/*!
61 \class Qt3DRender::QEffect
62 \inmodule Qt3DRender
63 \inherits Qt3DCore::QNode
64 \since 5.7
65 \brief The base class for effects in a Qt 3D scene.
66
67 The QEffect class combines a set of techniques and parameters used by those techniques to
68 produce a rendering effect for a material.
69
70 An QEffect instance should be shared among several QMaterial instances when possible.
71
72 \code
73 QEffect *effect = new QEffect();
74
75 // Create technique, render pass and shader
76 QTechnique *gl3Technique = new QTechnique();
77 QRenderPass *gl3Pass = new QRenderPass();
78 QShaderProgram *glShader = new QShaderProgram();
79
80 // Set the shader on the render pass
81 gl3Pass->setShaderProgram(glShader);
82
83 // Add the pass to the technique
84 gl3Technique->addRenderPass(gl3Pass);
85
86 // Set the targeted GL version for the technique
87 gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
88 gl3Technique->graphicsApiFilter()->setMajorVersion(3);
89 gl3Technique->graphicsApiFilter()->setMinorVersion(1);
90 gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
91
92 // Add the technique to the effect
93 effect->addTechnique(gl3Technique);
94 \endcode
95
96 A QParameter defined on an Effect is overridden by a QParameter (of the same
97 name) defined in a QMaterial, QTechniqueFilter, QRenderPassFilter.
98
99 \sa QMaterial, QTechnique, QParameter
100*/
101
102/*!
103 \qmltype Effect
104 \instantiates Qt3DRender::QEffect
105 \inherits Node
106 \inqmlmodule Qt3D.Render
107 \since 5.7
108 \brief The base class for effects in a Qt 3D scene.
109
110 The Effect type combines a set of techniques and parameters used by those techniques to
111 produce a rendering effect for a material.
112
113 An Effect instance should be shared among several Material instances when possible.
114
115 A Parameter defined on an Effect is overridden by a QParameter (of the same
116 name) defined in a Material, TechniqueFilter, RenderPassFilter.
117
118 \code
119 Effect {
120 id: effect
121
122 technique: [
123 Technique {
124 id: gl3Technique
125 graphicsApiFilter {
126 api: GraphicsApiFilter.OpenGL
127 profile: GraphicsApiFilter.CoreProfile
128 majorVersion: 3
129 minorVersion: 1
130 }
131 renderPasses: [
132 RenderPass {
133 id: gl3Pass
134 shaderProgram: ShaderProgram {
135 ...
136 }
137 }
138 ]
139 }
140 ]
141 }
142 \endcode
143
144 \sa Material, Technique, Parameter
145*/
146
147QEffect::QEffect(QNode *parent)
148 : QNode(*new QEffectPrivate, parent)
149{
150}
151
152QEffect::~QEffect()
153{
154}
155
156/*! \internal */
157QEffect::QEffect(QEffectPrivate &dd, QNode *parent)
158 : QNode(dd, parent)
159{
160}
161
162/*!
163 \qmlproperty list<Technique> Effect::techniques
164
165 Holds the list of techniques used by this effect.
166*/
167/*!
168 \qmlproperty list<Parameter> Effect::parameters
169
170 Holds the list of parameters used by this effect.
171 A parameter is used to set a corresponding uniform value in the shader used by this effect.
172*/
173
174/*!
175 * Adds \a parameter to the effect. It sends a QPropertyNodeAddedChange to the backend.
176 * The \a parameter will be used to set a corresponding uniform value in the shader used
177 * by this effect.
178 */
179void QEffect::addParameter(QParameter *parameter)
180{
181 Q_D(QEffect);
182 if (parameter && !d->m_parameters.contains(parameter)) {
183 d->m_parameters.append(parameter);
184
185 // Ensures proper bookkeeping
186 d->registerDestructionHelper(parameter, &QEffect::removeParameter, d->m_parameters);
187
188 // We need to add it as a child of the current node if it has been declared inline
189 // Or not previously added as a child of the current node so that
190 // 1) The backend gets notified about it's creation
191 // 2) When the current node is destroyed, it gets destroyed as well
192 if (!parameter->parent())
193 parameter->setParent(this);
194
195 if (d->m_changeArbiter != nullptr) {
196 const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
197 change->setPropertyName("parameter");
198 d->notifyObservers(change);
199 }
200 }
201}
202
203/*!
204 * Removes a parameter \a parameter from the effect.
205 */
206void QEffect::removeParameter(QParameter *parameter)
207{
208 Q_D(QEffect);
209
210 if (parameter && d->m_changeArbiter != nullptr) {
211 const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
212 change->setPropertyName("parameter");
213 d->notifyObservers(change);
214 }
215 d->m_parameters.removeOne(parameter);
216 // Remove bookkeeping connection
217 d->unregisterDestructionHelper(parameter);
218}
219
220/*!
221 * Returns the list of parameters used by the effect.
222 */
223QVector<QParameter *> QEffect::parameters() const
224{
225 Q_D(const QEffect);
226 return d->m_parameters;
227}
228
229/*!
230 * Adds a new technique \a t to the effect. It sends a QPropertyNodeAddedChange to the backend.
231 */
232void QEffect::addTechnique(QTechnique *t)
233{
234 Q_ASSERT(t);
235 Q_D(QEffect);
236 if (t && !d->m_techniques.contains(t)) {
237 d->m_techniques.append(t);
238
239 // Ensures proper bookkeeping
240 d->registerDestructionHelper(t, &QEffect::removeTechnique, d->m_techniques);
241
242 // We need to add it as a child of the current node if it has been declared inline
243 // Or not previously added as a child of the current node so that
244 // 1) The backend gets notified about it's creation
245 // 2) When the current node is destroyed, tit gets destroyed as well
246 if (!t->parent())
247 t->setParent(this);
248
249 if (d->m_changeArbiter != nullptr) {
250 const auto change = QPropertyNodeAddedChangePtr::create(id(), t);
251 change->setPropertyName("technique");
252 d->notifyObservers(change);
253 }
254 }
255}
256
257/*!
258 * Removes a technique \a t from the effect.
259 */
260void QEffect::removeTechnique(QTechnique *t)
261{
262 Q_D(QEffect);
263 if (t && d->m_changeArbiter != nullptr) {
264 const auto change = QPropertyNodeRemovedChangePtr::create(id(), t);
265 change->setPropertyName("technique");
266 d->notifyObservers(change);
267 }
268 d->m_techniques.removeOne(t);
269 // Remove bookkeeping connection
270 d->unregisterDestructionHelper(t);
271}
272
273/*!
274 * Returns the list of techniques used by the effect.
275 */
276QVector<QTechnique *> QEffect::techniques() const
277{
278 Q_D(const QEffect);
279 return d->m_techniques;
280}
281
282Qt3DCore::QNodeCreatedChangeBasePtr QEffect::createNodeCreationChange() const
283{
284 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QEffectData>::create(this);
285 auto &data = creationChange->data;
286 Q_D(const QEffect);
287 data.parameterIds = qIdsForNodes(d->m_parameters);
288 data.techniqueIds = qIdsForNodes(d->m_techniques);
289 return creationChange;
290}
291
292} // namespace Qt3DRender
293
294QT_END_NAMESPACE
295