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:GPL-EXCEPT$ |
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 General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtTest/QtTest> |
30 | #include <qgraphicsutils_p.h> |
31 | |
32 | class tst_QGraphicsUtils : public QObject |
33 | { |
34 | Q_OBJECT |
35 | private slots: |
36 | void fillScalarInDataArray(); |
37 | void fillArray(); |
38 | void fillScalarWithOffsets(); |
39 | void fillMatrix4x4(); |
40 | void fillMatrix3x4(); |
41 | void fillMatrix4x3(); |
42 | void fillMatrixArray(); |
43 | }; |
44 | |
45 | void tst_QGraphicsUtils::fillScalarInDataArray() |
46 | { |
47 | Qt3DRender::Render::OpenGL::ShaderUniform description; |
48 | |
49 | description.m_size = 1; |
50 | description.m_offset = 0; |
51 | description.m_arrayStride = 10; |
52 | |
53 | QVector4D testVector(8.0f, 8.0f, 3.0f, 1.0f); |
54 | const GLfloat *vectorData = Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: testVector, count: 1, tupleSize: 4); |
55 | |
56 | for (int i = 0; i < 4; i++) { |
57 | if (i == 0) |
58 | QVERIFY(vectorData[i] == testVector.x()); |
59 | else if (i == 1) |
60 | QVERIFY(vectorData[i] == testVector.y()); |
61 | else if (i == 2) |
62 | QVERIFY(vectorData[i] == testVector.z()); |
63 | else if (i == 3) |
64 | QVERIFY(vectorData[i] == testVector.w()); |
65 | } |
66 | |
67 | QByteArray data(description.m_size * 4 * sizeof(GLfloat), 0); |
68 | char *innerData = data.data(); |
69 | |
70 | // Checked that we are not overflowing |
71 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, data: vectorData, description, tupleSize: 2); |
72 | for (int i = 0; i < 4; ++i) { |
73 | if (i < 2) |
74 | QVERIFY(vectorData[i] == ((GLfloat*)innerData)[i]); |
75 | else |
76 | QVERIFY(((GLfloat*)innerData)[i] == 0.0f); |
77 | } |
78 | |
79 | // Check that all values are copied |
80 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, data: vectorData, description, tupleSize: 4); |
81 | for (int i = 0; i < 4; ++i) |
82 | QVERIFY(vectorData[i] == ((GLfloat*)innerData)[i]); |
83 | |
84 | // check that offsetting works |
85 | description.m_offset = 16; |
86 | data = QByteArray(description.m_size * 8 * sizeof(GLfloat), 0); |
87 | innerData = data.data(); |
88 | |
89 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, data: vectorData, description, tupleSize: 4); |
90 | for (int i = 0; i < 8; ++i) { |
91 | if (i < 4) |
92 | QVERIFY(((GLfloat*)innerData)[i] == 0.0f); |
93 | else |
94 | QVERIFY(vectorData[i - 4] == ((GLfloat*)innerData)[i]); |
95 | } |
96 | } |
97 | |
98 | void tst_QGraphicsUtils::fillArray() |
99 | { |
100 | QVector4D testVector(8.0f, 8.0f, 3.0f, 1.0f); |
101 | QVector4D testVector2(3.0f, 5.0f, 0.0f, 7.0f); |
102 | QVector4D testVector3(4.0f, 5.0f, 4.0f, 2.0f); |
103 | |
104 | QVariantList variantList = QVariantList() << testVector << testVector2 << testVector3; |
105 | const GLfloat *vectorData = Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: QVariant(variantList), count: 3, tupleSize: 4); |
106 | |
107 | Qt3DRender::Render::OpenGL::ShaderUniform description; |
108 | |
109 | description.m_size = 3; |
110 | description.m_offset = 16; |
111 | description.m_arrayStride = 16; |
112 | |
113 | QByteArray data(description.m_size * (4 + description.m_arrayStride) * sizeof(GLfloat) + description.m_offset, 0); |
114 | char *innerData = data.data(); |
115 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, data: vectorData, description, tupleSize: 4); |
116 | |
117 | int offset = description.m_offset / sizeof(GLfloat); |
118 | int stride = description.m_arrayStride / sizeof(GLfloat); |
119 | |
120 | GLfloat *innerDataFloat = (GLfloat*)innerData; |
121 | |
122 | for (int i = 0; i < 3; ++i) { |
123 | for (int j = 0; j < 4; ++j) { |
124 | int idx = i * 4 + j; |
125 | QVERIFY(innerDataFloat[offset + j] == vectorData[idx]); |
126 | } |
127 | offset += stride; |
128 | } |
129 | } |
130 | |
131 | void tst_QGraphicsUtils::fillScalarWithOffsets() |
132 | { |
133 | // Simulates Uniform Block |
134 | |
135 | // uniform Block { |
136 | // vec3 position; // Offset 0 - 12 bytes |
137 | // vec3 direction; // Offset 16 - 12 bytes |
138 | // vec4 color; // Offset 32 - 16 bytes |
139 | // float intensity; // Offset 48 - bytes |
140 | // } // total size 64 bytes |
141 | |
142 | QVector3D position(8.0f, 8.0f, 3.0f); |
143 | QVector3D direction(3.0f, 5.0f, 2.0f); |
144 | QVector4D color(4.0f, 5.0f, 4.0f, 1.0f); |
145 | float intensity = 1.0f; |
146 | |
147 | Qt3DRender::Render::OpenGL::ShaderUniform posUniform; |
148 | posUniform.m_size = 1; |
149 | posUniform.m_arrayStride = 0; |
150 | posUniform.m_matrixStride = 0; |
151 | posUniform.m_offset = 0; |
152 | |
153 | Qt3DRender::Render::OpenGL::ShaderUniform dirUniform; |
154 | dirUniform.m_size = 1; |
155 | dirUniform.m_arrayStride = 0; |
156 | dirUniform.m_matrixStride = 0; |
157 | dirUniform.m_offset = 16; |
158 | |
159 | Qt3DRender::Render::OpenGL::ShaderUniform colUniform; |
160 | colUniform.m_size = 1; |
161 | colUniform.m_arrayStride = 0; |
162 | colUniform.m_matrixStride = 0; |
163 | colUniform.m_offset = 32; |
164 | |
165 | Qt3DRender::Render::OpenGL::ShaderUniform intUniform; |
166 | intUniform.m_size = 1; |
167 | intUniform.m_arrayStride = 0; |
168 | intUniform.m_matrixStride = 0; |
169 | intUniform.m_offset = 48; |
170 | |
171 | QVector<GLfloat> data(16); |
172 | void *innerData = data.data(); |
173 | |
174 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, |
175 | data: Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: position, count: 1, tupleSize: 3), |
176 | description: posUniform, tupleSize: 3); |
177 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, |
178 | data: Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: direction, count: 1, tupleSize: 3), |
179 | description: dirUniform, tupleSize: 3); |
180 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, |
181 | data: Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: color, count: 1, tupleSize: 4), |
182 | description: colUniform, tupleSize: 4); |
183 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataArray(buffer: innerData, |
184 | data: Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: intensity, count: 1, tupleSize: 1), |
185 | description: intUniform, tupleSize: 1); |
186 | |
187 | GLfloat *floatData = (GLfloat*)innerData; |
188 | |
189 | // Check first 16 bytes - position |
190 | QVERIFY(floatData[0] == position.x()); |
191 | QVERIFY(floatData[1] == position.y()); |
192 | QVERIFY(floatData[2] == position.z()); |
193 | QVERIFY(floatData[3] == 0.0f); |
194 | // Check 16 - 32 bytes - direction |
195 | QVERIFY(floatData[4] == direction.x()); |
196 | QVERIFY(floatData[5] == direction.y()); |
197 | QVERIFY(floatData[6] == direction.z()); |
198 | QVERIFY(floatData[7] == 0.0f); |
199 | // Check 32 - 48 bytes - color |
200 | QVERIFY(floatData[8] == color.x()); |
201 | QVERIFY(floatData[9] == color.y()); |
202 | QVERIFY(floatData[10] == color.z()); |
203 | QVERIFY(floatData[11] == color.w()); |
204 | // Check 48 - 64 bytes - intensity |
205 | QVERIFY(floatData[12] == intensity); |
206 | QVERIFY(floatData[13] == 0.0f); |
207 | QVERIFY(floatData[14] == 0.0f); |
208 | QVERIFY(floatData[15] == 0.0f); |
209 | } |
210 | |
211 | void tst_QGraphicsUtils::fillMatrix4x4() |
212 | { |
213 | // row major |
214 | QMatrix4x4 mat(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f); |
215 | |
216 | // column major |
217 | const GLfloat *matData = Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: mat, count: 1, tupleSize: 16); |
218 | |
219 | Qt3DRender::Render::OpenGL::ShaderUniform description; |
220 | |
221 | description.m_size = 1; |
222 | description.m_offset = 0; |
223 | description.m_arrayStride = 0; |
224 | description.m_matrixStride = 16; |
225 | |
226 | |
227 | QByteArray data(description.m_size * 16 * sizeof(GLfloat), 0); |
228 | char *innerData = data.data(); |
229 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataMatrixArray(buffer: innerData, data: matData, description, cols: 4, rows: 4); |
230 | // Check for no offset/no stride |
231 | for (int i = 0; i < 16; ++i) |
232 | QVERIFY((((GLfloat *)innerData)[i]) == matData[i]); |
233 | |
234 | description.m_offset = 12; |
235 | data = QByteArray((description.m_size * 16 + description.m_offset) * sizeof(GLfloat), 0); |
236 | innerData = data.data(); |
237 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataMatrixArray(buffer: innerData, data: matData, description, cols: 4, rows: 4); |
238 | // Check with 12 offset/no stride |
239 | for (int i = 0; i < 16; ++i) |
240 | QVERIFY((((GLfloat *)innerData)[3 + i]) == matData[i]); |
241 | |
242 | description.m_matrixStride = 16; |
243 | data = QByteArray((description.m_size * 16 + 4 * description.m_matrixStride + description.m_offset) * sizeof(GLfloat), 0); |
244 | innerData = data.data(); |
245 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataMatrixArray(buffer: innerData, data: matData, description, cols: 4, rows: 4); |
246 | // Check with 10 offset/ 16 stride |
247 | int offset = description.m_offset / sizeof(GLfloat); |
248 | int matrixStride = description.m_matrixStride / sizeof(GLfloat); |
249 | |
250 | for (int col = 0; col < 4; ++col) { |
251 | for (int row = 0; row < 4; ++row) |
252 | QVERIFY((((GLfloat *)innerData)[offset + row]) == matData[col * 4 + row]); |
253 | offset += matrixStride; |
254 | } |
255 | } |
256 | |
257 | void tst_QGraphicsUtils::fillMatrix3x4() |
258 | { |
259 | QMatrix3x4 mat; |
260 | |
261 | mat.fill(value: 6.0f); |
262 | const GLfloat *matData = Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: QVariant::fromValue(value: mat), count: 1, tupleSize: 12); |
263 | |
264 | Qt3DRender::Render::OpenGL::ShaderUniform description; |
265 | |
266 | description.m_size = 1; |
267 | description.m_offset = 16; |
268 | description.m_arrayStride = 0; |
269 | description.m_matrixStride = 12; |
270 | |
271 | QByteArray data((description.m_size * 12 + 3 * description.m_matrixStride + description.m_offset) * sizeof(GLfloat), 0); |
272 | char *innerData = data.data(); |
273 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataMatrixArray(buffer: innerData, data: matData, description, cols: 3, rows: 4); |
274 | // Check with 16 offset/ 12 stride |
275 | int offset = description.m_offset / sizeof(GLfloat); |
276 | int matrixStride = description.m_matrixStride / sizeof(GLfloat); |
277 | |
278 | for (int col = 0; col < 3; ++col) { |
279 | for (int row = 0; row < 4; ++row) |
280 | QVERIFY((((GLfloat *)innerData)[offset + row]) == matData[col * 4 + row]); |
281 | offset += matrixStride; |
282 | } |
283 | } |
284 | |
285 | void tst_QGraphicsUtils::fillMatrix4x3() |
286 | { |
287 | QMatrix4x3 mat; |
288 | |
289 | mat.fill(value: 6.0f); |
290 | const GLfloat *matData = Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: QVariant::fromValue(value: mat), count: 1, tupleSize: 12); |
291 | |
292 | Qt3DRender::Render::OpenGL::ShaderUniform description; |
293 | |
294 | description.m_size = 1; |
295 | description.m_offset = 16; |
296 | description.m_arrayStride = 0; |
297 | description.m_matrixStride = 16; |
298 | |
299 | QByteArray data((description.m_size * 12 + 4 * description.m_matrixStride + description.m_offset) * sizeof(GLfloat), 0); |
300 | char *innerData = data.data(); |
301 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataMatrixArray(buffer: innerData, data: matData, description, cols: 4, rows: 3); |
302 | // Check with 16 offset/ 16 stride |
303 | int offset = description.m_offset / sizeof(GLfloat); |
304 | int matrixStride = description.m_matrixStride / sizeof(GLfloat); |
305 | |
306 | for (int col = 0; col < 4; ++col) { |
307 | for (int row = 0; row < 3; ++row) |
308 | QVERIFY((((GLfloat *)innerData)[offset + row]) == matData[col * 3 + row]); |
309 | offset += matrixStride; |
310 | } |
311 | } |
312 | |
313 | void tst_QGraphicsUtils::fillMatrixArray() |
314 | { |
315 | QMatrix4x3 mat1; |
316 | QMatrix4x3 mat2; |
317 | QMatrix4x3 mat3; |
318 | mat1.fill(value: 6.0f); |
319 | mat2.fill(value: 2.0f); |
320 | mat3.fill(value: 7.0f); |
321 | |
322 | QVariantList matrices = QVariantList() << QVariant::fromValue(value: mat1) << QVariant::fromValue(value: mat2) << QVariant::fromValue(value: mat3); |
323 | |
324 | const GLfloat *matData = Qt3DRender::Render::OpenGL::QGraphicsUtils::valueArrayFromVariant<GLfloat>(v: QVariant::fromValue(value: matrices), count: 3, tupleSize: 12); |
325 | |
326 | Qt3DRender::Render::OpenGL::ShaderUniform description; |
327 | |
328 | description.m_size = 3; |
329 | description.m_offset = 12; |
330 | description.m_arrayStride = 4; |
331 | description.m_matrixStride = 16; |
332 | |
333 | QByteArray data((description.m_size * (12 + 4 * description.m_matrixStride + description.m_arrayStride) + description.m_offset) * sizeof(GLfloat), 0); |
334 | char *innerData = data.data(); |
335 | Qt3DRender::Render::OpenGL::QGraphicsUtils::fillDataMatrixArray(buffer: innerData, data: matData, description, cols: 4, rows: 3); |
336 | // Check with 12 offset/ 4 array stride / 16 matrix stride |
337 | int offset = description.m_offset / sizeof(GLfloat); |
338 | int matrixStride = description.m_matrixStride / sizeof(GLfloat); |
339 | int arrayStride = description.m_arrayStride / sizeof(GLfloat); |
340 | |
341 | for (int i = 0; i < 3; ++i) { |
342 | for (int col = 0; col < 4; ++col) { |
343 | for (int row = 0; row < 3; ++row) { |
344 | int idx = i * 4 * 3 + col * 3 + row; |
345 | QVERIFY((((GLfloat *)innerData)[offset + row]) == matData[idx]); |
346 | } |
347 | offset += matrixStride; |
348 | } |
349 | offset += arrayStride; |
350 | } |
351 | } |
352 | |
353 | QTEST_APPLESS_MAIN(tst_QGraphicsUtils) |
354 | |
355 | #include "tst_qgraphicsutils.moc" |
356 | |