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 "qmaterial.h"
41#include "qmaterial_p.h"
42#include "qtexture.h"
43#include "qeffect.h"
44#include <Qt3DRender/private/renderlogging_p.h>
45#include "qparameter.h"
46#include <Qt3DCore/qpropertyupdatedchange.h>
47#include <Qt3DCore/qpropertynodeaddedchange.h>
48#include <Qt3DCore/qpropertynoderemovedchange.h>
49
50/*!
51 \qmltype Material
52 \instantiates Qt3DRender::QMaterial
53 \inqmlmodule Qt3D.Render
54 \brief Non-creatable abstract base for materials.
55 \since 5.5
56
57 Material provides a way to specify the rendering of an \l{Qt3D.Core::Entity}{entity}.
58 Any aspect can define its own subtype of Material so that a
59 Material can be used to describe a visual element; for example, the way
60 sound should reflect off an element, the temperature of a surface,
61 and so on.
62
63 In itself, a Material doesn't do anything. It's only when it references an
64 Effect node that a Material becomes useful.
65
66 In practice, it often happens that a single Effect is being referenced by
67 several Material components. This allows to only create the effect,
68 techniques, passes and shaders once while allowing to specify the material
69 by adding Parameter instances.
70
71 A Parameter defined on a Material is overridden by a Parameter (of the same
72 name) defined in a TechniqueFilter or a RenderPassFilter.
73
74 \code
75 Effect {
76 id: effect
77
78 technique: [
79 Technique {
80 id: gl3Technique
81 graphicsApiFilter {
82 api: GraphicsApiFilter.OpenGL
83 profile: GraphicsApiFilter.CoreProfile
84 majorVersion: 3
85 minorVersion: 1
86 }
87 renderPasses: [
88 RenderPass {
89 id: gl3Pass
90 shaderProgram: ShaderProgram {
91 ...
92 }
93 }
94 ]
95 }
96 ]
97 }
98
99 Material {
100 id: material1
101 parameters: [
102 Parameter { name: "color"; value: "green" }
103 ]
104 }
105
106 Material {
107 id: material2
108 parameters: [
109 Parameter { name: "color"; value: "white" }
110 ]
111 }
112 \endcode
113
114 \sa Effect, Technique, Parameter
115*/
116
117/*!
118 \class Qt3DRender::QMaterial
119 \inmodule Qt3DRender
120 \inherits Qt3DCore::QComponent
121 \brief Provides an abstract class that should be the base of all material component classes
122 in a scene.
123 \since 5.5
124
125 QMaterial provides a way to specify the rendering of an \l{Qt3DCore::QEntity}{entity}.
126 Any aspect can define its own subclass of QMaterial so that a
127 Material can be used to describe a visual element; for example, the way
128 sound should reflect off an element, the temperature of a surface,
129 and so on.
130
131 In itself, a QMaterial doesn't do anything. It's only when it references a
132 QEffect node that a QMaterial becomes useful.
133
134 In practice, it often happens that a single QEffect is being referenced by
135 several QMaterial components. This allows to only create the effect,
136 techniques, passes and shaders once while allowing to specify the material
137 by adding QParameter instances.
138
139 A QParameter defined on a QMaterial is overridden by a QParameter (of the same
140 name) defined in a QTechniqueFilter or a QRenderPassFilter.
141
142 \code
143 QMaterial *material1 = new QMaterial();
144 QMaterial *material2 = new QMaterial();
145
146 // Create effect, technique, render pass and shader
147 QEffect *effect = new QEffect();
148 QTechnique *gl3Technique = new QTechnique();
149 QRenderPass *gl3Pass = new QRenderPass();
150 QShaderProgram *glShader = new QShaderProgram();
151
152 // Set the shader on the render pass
153 gl3Pass->setShaderProgram(glShader);
154
155 // Add the pass to the technique
156 gl3Technique->addRenderPass(gl3Pass);
157
158 // Set the targeted GL version for the technique
159 gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
160 gl3Technique->graphicsApiFilter()->setMajorVersion(3);
161 gl3Technique->graphicsApiFilter()->setMinorVersion(1);
162 gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
163
164 // Add the technique to the effect
165 effect->addTechnique(gl3Technique);
166
167 // Set the effect on the materials
168 material1->setEffect(effect);
169 material2->setEffect(effect);
170
171 // Set different parameters on the materials
172 const QString parameterName = QStringLiteral("color");
173 material1->addParameter(new QParameter(parameterName, QColor::fromRgbF(0.0f, 1.0f, 0.0f, 1.0f);
174 material2->addParameter(new QParameter(parameterName, QColor::fromRgbF(1.0f, 1.0f, 1.0f, 1.0f);
175
176 \endcode
177
178 \sa QEffect, QTechnique, QParameter
179*/
180
181QT_BEGIN_NAMESPACE
182
183using namespace Qt3DCore;
184
185namespace Qt3DRender {
186
187QMaterialPrivate::QMaterialPrivate()
188 : QComponentPrivate()
189 , m_effect(nullptr)
190{
191}
192
193QMaterialPrivate::~QMaterialPrivate()
194{
195}
196
197QMaterial::QMaterial(QNode *parent)
198 : QComponent(*new QMaterialPrivate, parent)
199{
200}
201
202QMaterial::~QMaterial()
203{
204}
205
206/*! \internal */
207QMaterial::QMaterial(QMaterialPrivate &dd, QNode *parent)
208 : QComponent(dd, parent)
209{
210}
211
212/*!
213 \qmlproperty list<Parameter> Material::parameters
214
215 Holds the list of parameters used by the material.
216*/
217
218/*!
219 \qmlproperty Effect Material::effect
220
221 Specifies the effect to be used with the material.
222*/
223/*!
224 \property QMaterial::effect
225
226 Specifies the effect to be used with the material.
227 */
228void QMaterial::setEffect(QEffect *effect)
229{
230 Q_D(QMaterial);
231 if (effect != d->m_effect) {
232
233 if (d->m_effect)
234 d->unregisterDestructionHelper(d->m_effect);
235
236 // We need to add it as a child of the current node if it has been declared inline
237 // Or not previously added as a child of the current node so that
238 // 1) The backend gets notified about it's creation
239 // 2) When the current node is destroyed, it gets destroyed as well
240 if (effect && !effect->parent())
241 effect->setParent(this);
242 d->m_effect = effect;
243
244 // Ensures proper bookkeeping
245 if (d->m_effect)
246 d->registerDestructionHelper(d->m_effect, &QMaterial::setEffect, d->m_effect);
247
248 emit effectChanged(effect);
249 }
250}
251
252QEffect *QMaterial::effect() const
253{
254 Q_D(const QMaterial);
255 return d->m_effect;
256}
257
258/*!
259 * Add a \a parameter to the material's parameters.
260 */
261void QMaterial::addParameter(QParameter *parameter)
262{
263 Q_ASSERT(parameter);
264 Q_D(QMaterial);
265 if (!d->m_parameters.contains(parameter)) {
266 d->m_parameters.append(parameter);
267
268 // Ensures proper bookkeeping
269 d->registerDestructionHelper(parameter, &QMaterial::removeParameter, d->m_parameters);
270
271 // We need to add it as a child of the current node if it has been declared inline
272 // Or not previously added as a child of the current node so that
273 // 1) The backend gets notified about it's creation
274 // 2) When the current node is destroyed, it gets destroyed as well
275 if (!parameter->parent())
276 parameter->setParent(this);
277
278 if (d->m_changeArbiter != nullptr) {
279 const auto change = QPropertyNodeAddedChangePtr::create(id(), parameter);
280 change->setPropertyName("parameter");
281 d->notifyObservers(change);
282 }
283 }
284}
285
286/*!
287 * Remove a \a parameter from the material's parameters.
288 */
289void QMaterial::removeParameter(QParameter *parameter)
290{
291 Q_ASSERT(parameter);
292 Q_D(QMaterial);
293 if (d->m_changeArbiter != nullptr) {
294 const auto change = QPropertyNodeRemovedChangePtr::create(id(), parameter);
295 change->setPropertyName("parameter");
296 d->notifyObservers(change);
297 }
298 d->m_parameters.removeOne(parameter);
299}
300
301/*!
302 * Returns a vector of the material's current parameters
303 */
304QVector<QParameter *> QMaterial::parameters() const
305{
306 Q_D(const QMaterial);
307 return d->m_parameters;
308}
309
310Qt3DCore::QNodeCreatedChangeBasePtr QMaterial::createNodeCreationChange() const
311{
312 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QMaterialData>::create(this);
313 auto &data = creationChange->data;
314 Q_D(const QMaterial);
315 data.parameterIds = qIdsForNodes(d->m_parameters);
316 data.effectId = qIdForNode(d->m_effect);
317 return creationChange;
318}
319
320} // namespace Qt3DRender
321
322QT_END_NAMESPACE
323