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

source code of qt3d/src/render/backend/uniform.cpp