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 "shaderdata_p.h" |
41 | #include "qshaderdata.h" |
42 | #include "qshaderdata_p.h" |
43 | #include <QMetaProperty> |
44 | #include <QMetaObject> |
45 | #include <Qt3DCore/qdynamicpropertyupdatedchange.h> |
46 | #include <Qt3DCore/qpropertyupdatedchange.h> |
47 | #include <private/qbackendnode_p.h> |
48 | #include <private/managers_p.h> |
49 | #include <private/nodemanagers_p.h> |
50 | |
51 | QT_BEGIN_NAMESPACE |
52 | |
53 | using namespace Qt3DCore; |
54 | |
55 | namespace Qt3DRender { |
56 | namespace Render { |
57 | |
58 | namespace { |
59 | |
60 | const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>(); |
61 | |
62 | } |
63 | |
64 | ShaderData::ShaderData() |
65 | : m_managers(nullptr) |
66 | { |
67 | } |
68 | |
69 | ShaderData::~ShaderData() |
70 | { |
71 | } |
72 | |
73 | void ShaderData::setManagers(NodeManagers *managers) |
74 | { |
75 | m_managers = managers; |
76 | } |
77 | |
78 | void ShaderData::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) |
79 | { |
80 | const QShaderData *node = qobject_cast<const QShaderData *>(object: frontEnd); |
81 | if (!node) |
82 | return; |
83 | BackendNode::syncFromFrontEnd(frontEnd, firstTime); |
84 | |
85 | if (firstTime) { |
86 | m_propertyReader = node->propertyReader(); |
87 | |
88 | const QMetaObject *metaObj = node->metaObject(); |
89 | const int propertyOffset = QShaderData::staticMetaObject.propertyOffset(); |
90 | const int propertyCount = metaObj->propertyCount(); |
91 | // Dynamic properties names |
92 | const auto dynamicPropertyNames = node->dynamicPropertyNames(); |
93 | |
94 | QVector<QString> propertyNames; |
95 | propertyNames.reserve(asize: propertyCount - propertyOffset + dynamicPropertyNames.size()); |
96 | |
97 | // Statiically defined properties |
98 | for (int i = propertyOffset; i < propertyCount; ++i) { |
99 | const QMetaProperty pro = metaObj->property(index: i); |
100 | if (pro.isWritable()) |
101 | propertyNames.push_back(t: QString::fromLatin1(str: pro.name())); |
102 | } |
103 | // Dynamic properties |
104 | for (const QByteArray &propertyName : dynamicPropertyNames) |
105 | propertyNames.push_back(t: QString::fromLatin1(str: propertyName)); |
106 | |
107 | for (const QString &propertyName : propertyNames) { |
108 | if (propertyName == QStringLiteral("data" ) || |
109 | propertyName == QStringLiteral("childNodes" )) // We don't handle default Node properties |
110 | continue; |
111 | |
112 | const QVariant &propertyValue = m_propertyReader->readProperty(v: node->property(name: propertyName.toLatin1())); |
113 | bool isNested = false; |
114 | bool isTransformed = false; |
115 | |
116 | // We check if the property is a QNodeId |
117 | isNested = (propertyValue.userType() == qNodeIdTypeId); |
118 | // We check if QVector<QNodeId> |
119 | if (propertyValue.userType() == QMetaType::QVariantList) { |
120 | QVariantList list = propertyValue.value<QVariantList>(); |
121 | if (list.count() > 0 && list.at(i: 0).userType() == qNodeIdTypeId) |
122 | isNested = true; |
123 | } |
124 | |
125 | // We check if property is a Transformed property |
126 | if (propertyValue.userType() == QVariant::Vector3D) { |
127 | // if there is a matching QShaderData::TransformType propertyTransformed |
128 | isTransformed = propertyNames.contains(t: propertyName + QLatin1String("Transformed" )); |
129 | } |
130 | m_originalProperties.insert(akey: propertyName, avalue: { .value: propertyValue, .isNested: isNested, .isTransformed: isTransformed }); |
131 | } |
132 | BackendNode::markDirty(changes: AbstractRenderer::ParameterDirty); |
133 | } else { |
134 | // Updates |
135 | if (!m_propertyReader.isNull()) { |
136 | auto it = m_originalProperties.begin(); |
137 | const auto end = m_originalProperties.end(); |
138 | |
139 | while (it != end) { |
140 | const QVariant newValue = m_propertyReader->readProperty(v: node->property(name: it.key().toLatin1())); |
141 | PropertyValue &propValue = it.value(); |
142 | if (propValue.value != newValue) { |
143 | // Note we aren't notified about nested QShaderData in this call |
144 | // only scalar / vec properties |
145 | propValue.value = newValue; |
146 | BackendNode::markDirty(changes: AbstractRenderer::ParameterDirty); |
147 | } |
148 | ++it; |
149 | } |
150 | } |
151 | } |
152 | } |
153 | |
154 | ShaderData *ShaderData::lookupResource(NodeManagers *managers, QNodeId id) |
155 | { |
156 | return managers->shaderDataManager()->lookupResource(id); |
157 | } |
158 | |
159 | ShaderData *ShaderData::lookupResource(QNodeId id) |
160 | { |
161 | return ShaderData::lookupResource(managers: m_managers, id); |
162 | } |
163 | |
164 | // RenderCommand updater jobs |
165 | QVariant ShaderData::getTransformedProperty(const QString &name, const Matrix4x4 &viewMatrix) const noexcept |
166 | { |
167 | // Note protecting m_worldMatrix at this point as we assume all world updates |
168 | // have been performed when reaching this point |
169 | const auto it = m_originalProperties.constFind(akey: name); |
170 | if (it != m_originalProperties.constEnd()) { |
171 | const PropertyValue &propertyValue = it.value(); |
172 | if (propertyValue.isTransformed) { |
173 | const auto transformedIt = m_originalProperties.constFind(akey: name + QLatin1String("Transformed" )); |
174 | if (transformedIt != m_originalProperties.constEnd()) { |
175 | const PropertyValue &transformedValue = transformedIt.value(); |
176 | const TransformType transformType = static_cast<TransformType>(transformedValue.value.toInt()); |
177 | switch (transformType) { |
178 | case ModelToEye: |
179 | return QVariant::fromValue(value: viewMatrix * m_worldMatrix * Vector3D(propertyValue.value.value<QVector3D>())); |
180 | case ModelToWorld: |
181 | return QVariant::fromValue(value: m_worldMatrix * Vector3D(propertyValue.value.value<QVector3D>())); |
182 | case ModelToWorldDirection: |
183 | return QVariant::fromValue(value: Vector3D(m_worldMatrix * Vector4D(propertyValue.value.value<QVector3D>(), 0.0f))); |
184 | case NoTransform: |
185 | break; |
186 | } |
187 | } |
188 | } |
189 | return propertyValue.value; |
190 | } |
191 | return QVariant(); |
192 | } |
193 | |
194 | // Unit tests only |
195 | ShaderData::TransformType ShaderData::propertyTransformType(const QString &name) const |
196 | { |
197 | const auto it = m_originalProperties.constFind(akey: name); |
198 | if (it != m_originalProperties.constEnd()) { |
199 | const PropertyValue &propertyValue = it.value(); |
200 | if (propertyValue.isTransformed) { |
201 | auto transformedIt = m_originalProperties.constFind(akey: name + QLatin1String("Transformed" )); |
202 | if (transformedIt != m_originalProperties.end()) |
203 | return static_cast<TransformType>(transformedIt.value().value.toInt()); |
204 | } |
205 | } |
206 | return NoTransform; |
207 | } |
208 | |
209 | // Called by FramePreparationJob or by RenderView when dealing with lights |
210 | void ShaderData::updateWorldTransform(const Matrix4x4 &worldMatrix) |
211 | { |
212 | if (m_worldMatrix != worldMatrix) { |
213 | m_worldMatrix = worldMatrix; |
214 | } |
215 | } |
216 | |
217 | RenderShaderDataFunctor::RenderShaderDataFunctor(AbstractRenderer *renderer, NodeManagers *managers) |
218 | : m_managers(managers) |
219 | , m_renderer(renderer) |
220 | { |
221 | } |
222 | |
223 | Qt3DCore::QBackendNode *RenderShaderDataFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const |
224 | { |
225 | ShaderData *backend = m_managers->shaderDataManager()->getOrCreateResource(id: change->subjectId()); |
226 | backend->setManagers(m_managers); |
227 | backend->setRenderer(m_renderer); |
228 | return backend; |
229 | } |
230 | |
231 | Qt3DCore::QBackendNode *RenderShaderDataFunctor::get(Qt3DCore::QNodeId id) const |
232 | { |
233 | return m_managers->shaderDataManager()->lookupResource(id); |
234 | } |
235 | |
236 | void RenderShaderDataFunctor::destroy(Qt3DCore::QNodeId id) const |
237 | { |
238 | m_managers->shaderDataManager()->releaseResource(id); |
239 | } |
240 | |
241 | } // namespace Render |
242 | } // namespace Qt3DRender |
243 | |
244 | QT_END_NAMESPACE |
245 | |