1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 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 "uniform_p.h" |
41 | #include "qabstracttexture.h" |
42 | |
43 | QT_BEGIN_NAMESPACE |
44 | |
45 | namespace Qt3DRender { |
46 | namespace Render { |
47 | |
48 | namespace { |
49 | |
50 | const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>(); |
51 | const int qVector3DTypeId = qMetaTypeId<Vector3D>(); |
52 | const int qVector4DTypeId = qMetaTypeId<Vector4D>(); |
53 | const int qMatrix4x4TypeId = qMetaTypeId<Matrix4x4>(); |
54 | |
55 | // glUniform*fv/glUniform*iv/glUniform*uiv -> only handles sizeof(float)/sizeof(int) |
56 | int byteSizeForMetaType(int type) |
57 | { |
58 | if (type == qMatrix4x4TypeId) |
59 | return sizeof(Matrix4x4); |
60 | if (type == qVector3DTypeId) |
61 | return sizeof(Vector3D); |
62 | if (type == qVector4DTypeId) |
63 | return sizeof(Vector4D); |
64 | if (type == qNodeIdTypeId) |
65 | return sizeof(Qt3DCore::QNodeId); |
66 | |
67 | switch (type) { |
68 | case QMetaType::Bool: |
69 | case QMetaType::Int: |
70 | case QMetaType::UInt: |
71 | case QMetaType::ULongLong: |
72 | case QMetaType::LongLong: |
73 | case QMetaType::Long: |
74 | case QMetaType::ULong: |
75 | case QMetaType::Short: |
76 | case QMetaType::UShort: |
77 | case QMetaType::Char: |
78 | case QMetaType::UChar: |
79 | return sizeof(int); |
80 | |
81 | case QMetaType::Float: |
82 | case QMetaType::Double: // Assumes conversion to float |
83 | return sizeof(float); |
84 | |
85 | case QMetaType::QPoint: |
86 | case QMetaType::QSize: |
87 | return 2 * sizeof(int); |
88 | |
89 | case QMetaType::QRect: |
90 | return 4 * sizeof(int); |
91 | |
92 | case QMetaType::QPointF: |
93 | case QMetaType::QSizeF: |
94 | case QMetaType::QVector2D: |
95 | return 2 * sizeof(float); |
96 | |
97 | case QMetaType::QVector3D: |
98 | return 3 * sizeof(float); |
99 | |
100 | case QMetaType::QRectF: |
101 | case QMetaType::QVector4D: |
102 | case QMetaType::QColor: |
103 | return 4 * sizeof(float); |
104 | case QMetaType::QMatrix4x4: |
105 | return 16 * sizeof(float); |
106 | |
107 | default: |
108 | Q_UNREACHABLE(); |
109 | return -1; |
110 | } |
111 | } |
112 | |
113 | } // anonymous |
114 | |
115 | UniformValue UniformValue::fromVariant(const QVariant &variant) |
116 | { |
117 | // Texture/Buffer case |
118 | const int type = variant.userType(); |
119 | |
120 | if (type == qNodeIdTypeId) |
121 | return UniformValue(variant.value<Qt3DCore::QNodeId>()); |
122 | |
123 | if (type == qMatrix4x4TypeId) |
124 | return UniformValue(variant.value<Matrix4x4>()); |
125 | |
126 | if (type == qVector3DTypeId) |
127 | return UniformValue(variant.value<Vector3D>()); |
128 | |
129 | if (type == qVector4DTypeId) |
130 | return UniformValue(variant.value<Vector4D>()); |
131 | |
132 | UniformValue v; |
133 | switch (type) { |
134 | case QMetaType::Bool: |
135 | v.data<bool>()[0] = variant.toBool(); |
136 | break; |
137 | case QMetaType::Int: |
138 | case QMetaType::UInt: |
139 | case QMetaType::Long: |
140 | case QMetaType::LongLong: |
141 | case QMetaType::Short: |
142 | case QMetaType::ULong: |
143 | case QMetaType::ULongLong: |
144 | case QMetaType::UShort: |
145 | case QMetaType::Char: |
146 | case QMetaType::UChar: |
147 | v.data<int>()[0] = variant.toInt(); |
148 | v.m_storedType = Int; |
149 | break; |
150 | case QMetaType::Float: |
151 | case QMetaType::Double: // Convert double to floats |
152 | v.m_data[0] = variant.toFloat(); |
153 | break; |
154 | case QMetaType::QPoint: { |
155 | const QPoint p = variant.toPoint(); |
156 | v.data<int>()[0] = p.x(); |
157 | v.data<int>()[1] = p.y(); |
158 | break; |
159 | } |
160 | case QMetaType::QSize: { |
161 | const QSize s = variant.toSize(); |
162 | v.data<int>()[0] = s.width(); |
163 | v.data<int>()[1] = s.height(); |
164 | break; |
165 | } |
166 | case QMetaType::QRect: { |
167 | const QRect r = variant.toRect(); |
168 | v.data<int>()[0] = r.x(); |
169 | v.data<int>()[1] = r.y(); |
170 | v.data<int>()[2] = r.width(); |
171 | v.data<int>()[3] = r.height(); |
172 | break; |
173 | } |
174 | case QMetaType::QSizeF: { |
175 | const QSizeF s = variant.toSize(); |
176 | v.m_data[0] = s.width(); |
177 | v.m_data[1] = s.height(); |
178 | break; |
179 | } |
180 | case QMetaType::QPointF: { |
181 | const QPointF p = variant.toPointF(); |
182 | v.m_data[0] = p.x(); |
183 | v.m_data[1] = p.y(); |
184 | break; |
185 | } |
186 | case QMetaType::QRectF: { |
187 | const QRectF r = variant.toRect(); |
188 | v.m_data[0] = r.x(); |
189 | v.m_data[1] = r.y(); |
190 | v.m_data[2] = r.width(); |
191 | v.m_data[3] = r.height(); |
192 | break; |
193 | } |
194 | case QMetaType::QVector2D: { |
195 | const QVector2D vec2 = variant.value<QVector2D>(); |
196 | v.m_data[0] = vec2.x(); |
197 | v.m_data[1] = vec2.y(); |
198 | break; |
199 | } |
200 | case QMetaType::QVector3D: { |
201 | const QVector3D vec3 = variant.value<QVector3D>(); |
202 | v.m_data[0] = vec3.x(); |
203 | v.m_data[1] = vec3.y(); |
204 | v.m_data[2] = vec3.z(); |
205 | break; |
206 | } |
207 | case QMetaType::QVector4D: { |
208 | const QVector4D vec4 = variant.value<QVector4D>(); |
209 | v.m_data[0] = vec4.x(); |
210 | v.m_data[1] = vec4.y(); |
211 | v.m_data[2] = vec4.z(); |
212 | v.m_data[3] = vec4.w(); |
213 | break; |
214 | } |
215 | case QMetaType::QColor: { |
216 | const QColor col = variant.value<QColor>(); |
217 | v.m_data[0] = col.redF(); |
218 | v.m_data[1] = col.greenF(); |
219 | v.m_data[2] = col.blueF(); |
220 | v.m_data[3] = col.alphaF(); |
221 | break; |
222 | } |
223 | case QMetaType::QMatrix4x4: { |
224 | const QMatrix4x4 mat44 = variant.value<QMatrix4x4>(); |
225 | // Use constData because we want column-major layout |
226 | v.m_data.resize(asize: 16); |
227 | memcpy(dest: v.data<float>(), src: mat44.constData(), n: 16 * sizeof(float)); |
228 | break; |
229 | } |
230 | case QMetaType::QVariantList: { |
231 | const QVariantList variants = variant.toList(); |
232 | if (variants.size() < 1) |
233 | break; |
234 | |
235 | const int listEntryType = variants.first().userType(); |
236 | |
237 | // array of textures |
238 | if (listEntryType == qNodeIdTypeId) |
239 | v.m_valueType = NodeId; |
240 | |
241 | const int stride = byteSizeForMetaType(type: listEntryType) / sizeof(float); |
242 | // Resize v.m_data |
243 | v.m_data.resize(asize: stride * variants.size()); |
244 | |
245 | int idx = 0; |
246 | for (const QVariant &variant : variants) { |
247 | Q_ASSERT_X(variant.userType() == listEntryType, |
248 | Q_FUNC_INFO, |
249 | "Uniform array doesn't contain elements of the same type" ); |
250 | UniformValue vi = UniformValue::fromVariant(variant); |
251 | memcpy(dest: v.data<float>() + idx, src: vi.data<float>(), n: stride * sizeof(float)); |
252 | idx += stride; |
253 | } |
254 | break; |
255 | } |
256 | |
257 | default: { |
258 | if (variant.userType() == qMetaTypeId<QMatrix3x3>()) { |
259 | const QMatrix3x3 mat33 = variant.value<QMatrix3x3>(); |
260 | // Use constData because we want column-major layout |
261 | v.m_data.resize(asize: 9); |
262 | memcpy(dest: v.data<float>(), src: mat33.constData(), n: 9 * sizeof(float)); |
263 | break; |
264 | } |
265 | if (variant.userType() == qMetaTypeId<Qt3DRender::QAbstractTexture *>()) { |
266 | // silently ignore null texture pointers as they are common while textures are loading |
267 | if (variant.value<Qt3DRender::QAbstractTexture *>() == nullptr) |
268 | break; |
269 | } |
270 | qWarning() << "Unknown uniform type or value:" << variant << "Please check your QParameters" ; |
271 | } |
272 | } |
273 | return v; |
274 | } |
275 | |
276 | template<> |
277 | void UniformValue::setData<QMatrix4x4>(const QVector<QMatrix4x4> &v) |
278 | { |
279 | m_data.resize(asize: 16 * v.size()); |
280 | m_valueType = ScalarValue; |
281 | int offset = 0; |
282 | const int byteSize = 16 * sizeof(float); |
283 | float *data = m_data.data(); |
284 | for (const auto &m : v) { |
285 | memcpy(dest: data + offset, src: m.constData(), n: byteSize); |
286 | offset += 16; |
287 | } |
288 | } |
289 | |
290 | } // namespace Render |
291 | } // namespace Qt3DRender |
292 | |
293 | QT_END_NAMESPACE |
294 | |