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 | #ifndef QT3DRENDER_RENDER_OPENGL_QGRAPHICSUTILS_P_H |
41 | #define QT3DRENDER_RENDER_OPENGL_QGRAPHICSUTILS_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists for the convenience |
48 | // of other Qt classes. This header file may change from version to |
49 | // version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include <Qt3DRender/qt3drender_global.h> |
55 | #include <QMatrix2x2> |
56 | #include <QMatrix3x3> |
57 | #include <QMatrix4x4> |
58 | #include <QGenericMatrix> |
59 | #include <QVector2D> |
60 | #include <QVarLengthArray> |
61 | #include <QColor> |
62 | #include <shadervariables_p.h> |
63 | |
64 | QT_BEGIN_NAMESPACE |
65 | |
66 | namespace Qt3DRender { |
67 | |
68 | namespace Render { |
69 | |
70 | namespace OpenGL { |
71 | |
72 | namespace { |
73 | |
74 | const int QMatrix2x2Type = qMetaTypeId<QMatrix2x2>(); |
75 | const int QMatrix2x3Type = qMetaTypeId<QMatrix2x3>(); |
76 | const int QMatrix2x4Type = qMetaTypeId<QMatrix2x4>(); |
77 | const int QMatrix3x2Type = qMetaTypeId<QMatrix3x2>(); |
78 | const int QMatrix3x3Type = qMetaTypeId<QMatrix3x3>(); |
79 | const int QMatrix3x4Type = qMetaTypeId<QMatrix3x4>(); |
80 | const int QMatrix4x2Type = qMetaTypeId<QMatrix4x2>(); |
81 | const int QMatrix4x3Type = qMetaTypeId<QMatrix4x3>(); |
82 | |
83 | } |
84 | |
85 | class QGraphicsUtils |
86 | { |
87 | |
88 | public: |
89 | |
90 | template<typename T> |
91 | static const char *bytesFromVariant(const QVariant &v) |
92 | { |
93 | uint byteSize = sizeof(T); |
94 | // Max 16 float that we may want as doubles |
95 | // 64 should be best for most cases |
96 | static QVarLengthArray<char, 64> array(16 * byteSize); |
97 | memset(s: array.data(), c: 0, n: array.size()); |
98 | |
99 | switch (static_cast<QMetaType::Type>(v.type())) { |
100 | |
101 | // 1 byte |
102 | case QMetaType::Bool: { |
103 | T data = v.value<bool>(); |
104 | memcpy(array.data(), &data, byteSize); |
105 | break; |
106 | } |
107 | case QMetaType::Char: { |
108 | T data = v.value<char>(); |
109 | memcpy(array.data(), &data, byteSize); |
110 | break; |
111 | } |
112 | |
113 | // 4 bytes |
114 | case QMetaType::Float: { |
115 | T data = v.value<float>(); |
116 | memcpy(array.data(), &data, byteSize); |
117 | break; |
118 | } |
119 | case QMetaType::Int: { |
120 | T data = v.value<int>(); |
121 | memcpy(array.data(), &data, byteSize); |
122 | break; |
123 | |
124 | } |
125 | case QMetaType::UInt: { |
126 | qDebug() << "UINT" ; |
127 | T data = v.value<uint>(); |
128 | memcpy(array.data(), &data, byteSize); |
129 | break; |
130 | } |
131 | |
132 | // 8 bytes |
133 | case QMetaType::Double: { |
134 | T data = v.value<double>(); |
135 | memcpy(array.data(), &data, byteSize); |
136 | break; |
137 | } |
138 | |
139 | // 2 floats |
140 | case QMetaType::QPointF: { |
141 | QPointF vv = v.value<QPointF>(); |
142 | T data = vv.x(); |
143 | memcpy(array.data(), &data, byteSize); |
144 | data = vv.y(); |
145 | memcpy(array.data() + byteSize, &data, byteSize); |
146 | break; |
147 | } |
148 | case QMetaType::QSizeF: { |
149 | QSizeF vv = v.value<QSizeF>(); |
150 | T data = vv.width(); |
151 | memcpy(array.data(), &data, byteSize); |
152 | data = vv.height(); |
153 | memcpy(array.data() + byteSize, &data, byteSize); |
154 | break; |
155 | } |
156 | |
157 | case QMetaType::QVector2D: { |
158 | QVector2D vv = v.value<QVector2D>(); |
159 | T data = vv.x(); |
160 | memcpy(array.data(), &data, byteSize); |
161 | data = vv.y(); |
162 | memcpy(array.data() + byteSize, &data, byteSize); |
163 | break; |
164 | } |
165 | |
166 | // 2 ints |
167 | case QMetaType::QPoint: { |
168 | QPointF vv = v.value<QPoint>(); |
169 | T data = vv.x(); |
170 | memcpy(array.data(), &data, byteSize); |
171 | data = vv.y(); |
172 | memcpy(array.data() + byteSize, &data, byteSize); |
173 | break; |
174 | } |
175 | |
176 | case QMetaType::QSize: { |
177 | QSize vv = v.value<QSize>(); |
178 | T data = vv.width(); |
179 | memcpy(array.data(), &data, byteSize); |
180 | data = vv.height(); |
181 | memcpy(array.data() + byteSize, &data, byteSize); |
182 | break; |
183 | } |
184 | |
185 | // 3 floats |
186 | case QMetaType::QVector3D: { |
187 | QVector3D vv = v.value<QVector3D>(); |
188 | T data = vv.x(); |
189 | memcpy(array.data(), &data, byteSize); |
190 | data = vv.y(); |
191 | memcpy(array.data() + byteSize, &data, byteSize); |
192 | data = vv.z(); |
193 | memcpy(array.data() + 2 * byteSize, &data, byteSize); |
194 | break; |
195 | } |
196 | |
197 | // 4 floats |
198 | case QMetaType::QVector4D: { |
199 | QVector4D vv = v.value<QVector4D>(); |
200 | T data = vv.x(); |
201 | memcpy(array.data(), &data, byteSize); |
202 | data = vv.y(); |
203 | memcpy(array.data() + byteSize, &data, byteSize); |
204 | data = vv.z(); |
205 | memcpy(array.data() + 2 * byteSize, &data, byteSize); |
206 | data = vv.w(); |
207 | memcpy(array.data() + 3 * byteSize, &data, byteSize); |
208 | break; |
209 | } |
210 | |
211 | case QMetaType::QQuaternion: { |
212 | |
213 | break; |
214 | } |
215 | |
216 | case QMetaType::QRectF: { |
217 | QRectF vv = v.value<QRectF>(); |
218 | T data = vv.x(); |
219 | memcpy(array.data(), &data, byteSize); |
220 | data = vv.y(); |
221 | memcpy(array.data() + byteSize, &data, byteSize); |
222 | data = vv.width(); |
223 | memcpy(array.data() + 2 * byteSize, &data, byteSize); |
224 | data = vv.height(); |
225 | memcpy(array.data() + 3 * byteSize, &data, byteSize); |
226 | break; |
227 | } |
228 | |
229 | case QMetaType::QColor: { |
230 | QColor vv = v.value<QColor>(); |
231 | T data = vv.redF(); |
232 | memcpy(array.data(), &data, byteSize); |
233 | data = vv.greenF(); |
234 | memcpy(array.data() + byteSize, &data, byteSize); |
235 | data = vv.blueF(); |
236 | memcpy(array.data() + 2 * byteSize, &data, byteSize); |
237 | data = vv.alphaF(); |
238 | memcpy(array.data() + 3 * byteSize, &data, byteSize); |
239 | break; |
240 | } |
241 | |
242 | // 4 ints |
243 | case QMetaType::QRect: { |
244 | QRectF vv = v.value<QRect>(); |
245 | T data = vv.x(); |
246 | memcpy(array.data(), &data, byteSize); |
247 | data = vv.y(); |
248 | memcpy(array.data() + byteSize, &data, byteSize); |
249 | data = vv.width(); |
250 | memcpy(array.data() + 2 * byteSize, &data, byteSize); |
251 | data = vv.height(); |
252 | memcpy(array.data() + 3 * byteSize, &data, byteSize); |
253 | break; |
254 | } |
255 | |
256 | // 16 floats |
257 | case QMetaType::QMatrix4x4: { |
258 | QMatrix4x4 mat = v.value<QMatrix4x4>(); |
259 | float *data = mat.data(); |
260 | for (int i = 0; i < 16; i++) { |
261 | T d = data[i]; |
262 | memcpy(array.data() + i * byteSize, &d, byteSize); |
263 | } |
264 | break; |
265 | } |
266 | |
267 | default: { |
268 | |
269 | float *data = nullptr; |
270 | if (v.userType() == QMatrix3x3Type) { |
271 | QMatrix3x3 mat = v.value<QMatrix3x3>(); |
272 | data = mat.data(); |
273 | for (int i = 0; i < 9; i++) { |
274 | T d = data[i]; |
275 | memcpy(array.data() + i * byteSize, &d, byteSize); |
276 | } |
277 | } |
278 | else if (v.userType() == QMatrix2x2Type) { |
279 | QMatrix2x2 mat = v.value<QMatrix2x2>(); |
280 | data = mat.data(); |
281 | for (int i = 0; i < 4; i++) { |
282 | T d = data[i]; |
283 | memcpy(array.data() + i * byteSize, &d, byteSize); |
284 | } |
285 | } |
286 | else if (v.userType() == QMatrix2x3Type) { |
287 | QMatrix2x3 mat = v.value<QMatrix2x3>(); |
288 | data = mat.data(); |
289 | for (int i = 0; i < 6; i++) { |
290 | T d = data[i]; |
291 | memcpy(array.data() + i * byteSize, &d, byteSize); |
292 | } |
293 | } |
294 | else if (v.userType() == QMatrix3x2Type) { |
295 | QMatrix3x2 mat = v.value<QMatrix3x2>(); |
296 | data = mat.data(); |
297 | for (int i = 0; i < 6; i++) { |
298 | T d = data[i]; |
299 | memcpy(array.data() + i * byteSize, &d, byteSize); |
300 | } |
301 | } |
302 | else if (v.userType() == QMatrix2x4Type) { |
303 | QMatrix2x4 mat = v.value<QMatrix2x4>(); |
304 | data = mat.data(); |
305 | for (int i = 0; i < 8; i++) { |
306 | T d = data[i]; |
307 | memcpy(array.data() + i * byteSize, &d, byteSize); |
308 | } |
309 | } |
310 | else if (v.userType() == QMatrix4x2Type) { |
311 | QMatrix4x2 mat = v.value<QMatrix4x2>(); |
312 | data = mat.data(); |
313 | for (int i = 0; i < 8; i++) { |
314 | T d = data[i]; |
315 | memcpy(array.data() + i * byteSize, &d, byteSize); |
316 | } |
317 | } |
318 | else if (v.userType() == QMatrix3x4Type) { |
319 | QMatrix3x4 mat = v.value<QMatrix3x4>(); |
320 | data = mat.data(); |
321 | for (int i = 0; i < 12; i++) { |
322 | T d = data[i]; |
323 | memcpy(array.data() + i * byteSize, &d, byteSize); |
324 | } |
325 | } |
326 | else if (v.userType() == QMatrix4x3Type) { |
327 | QMatrix4x3 mat = v.value<QMatrix4x3>(); |
328 | data = mat.data(); |
329 | for (int i = 0; i < 12; i++) { |
330 | T d = data[i]; |
331 | memcpy(array.data() + i * byteSize, &d, byteSize); |
332 | } |
333 | } |
334 | else |
335 | qWarning() << Q_FUNC_INFO << "QVariant type conversion not handled for " << v.type(); |
336 | break; |
337 | } |
338 | |
339 | } |
340 | return array.constData(); |
341 | } |
342 | |
343 | |
344 | template<typename T> |
345 | static const T *valueArrayFromVariant(const QVariant &v, int count, int tupleSize) |
346 | { |
347 | uint byteSize = sizeof(T); |
348 | uint offset = byteSize * tupleSize; |
349 | static QVarLengthArray<char, 1024> uniformValuesArray(1024); |
350 | uniformValuesArray.resize(size: count * offset); |
351 | char *data = uniformValuesArray.data(); |
352 | memset(s: data, c: 0, n: uniformValuesArray.size()); |
353 | |
354 | QVariantList vList = v.toList(); |
355 | // Handles list of QVariant: usually arrays of float |
356 | if (!vList.isEmpty()) { |
357 | for (int i = 0; i < vList.length() && uint(i) * offset < uint(uniformValuesArray.size()); i++) { |
358 | const char *subBuffer = QGraphicsUtils::bytesFromVariant<T>(vList.at(i)); |
359 | memcpy(dest: data + i * offset, src: subBuffer, n: offset); |
360 | } |
361 | } |
362 | else { |
363 | memcpy(data, QGraphicsUtils::bytesFromVariant<T>(v), offset); |
364 | } |
365 | return reinterpret_cast<const T *>(uniformValuesArray.constData()); |
366 | } |
367 | |
368 | template<typename T> |
369 | static void fillDataArray(void *buffer, const T *data, const ShaderUniform &description, int tupleSize) |
370 | { |
371 | uint offset = description.m_offset / sizeof(T); |
372 | uint stride = description.m_arrayStride / sizeof(T); |
373 | T *bufferData = (T*)buffer; |
374 | |
375 | for (int i = 0; i < description.m_size; ++i) { |
376 | for (int j = 0; j < tupleSize; j++) { |
377 | int idx = i * tupleSize + j; |
378 | bufferData[offset + j] = data[idx]; |
379 | } |
380 | offset += stride; |
381 | } |
382 | } |
383 | |
384 | template<typename T> |
385 | static void fillDataMatrixArray(void *buffer, const T *data, const ShaderUniform &description, int cols, int rows) |
386 | { |
387 | uint offset = description.m_offset / sizeof(T); |
388 | uint arrayStride = description.m_arrayStride / sizeof(T); |
389 | uint matrixStride = description.m_matrixStride / sizeof(T); |
390 | T *bufferData = (T*)buffer; |
391 | |
392 | for (int i = 0; i < description.m_size; ++i) { |
393 | for (int col = 0; col < cols; ++col) { |
394 | for (int row = 0; row < rows; ++row) { |
395 | int idx = i * cols * rows + rows * col + row; |
396 | bufferData[offset + row] = data[idx]; |
397 | } |
398 | offset += matrixStride; |
399 | } |
400 | offset += arrayStride; |
401 | } |
402 | } |
403 | |
404 | }; |
405 | |
406 | } // namespace OpenGL |
407 | |
408 | } // namespace Render |
409 | |
410 | } // namespace Qt3DRender |
411 | |
412 | QT_END_NAMESPACE |
413 | |
414 | #endif // QT3DRENDER_RENDER_OPENGL_QGRAPHICSUTILS_P_H |
415 | |