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

source code of qt3d/src/render/materialsystem/qmaterial.cpp