Revision control
++ // Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++ #include "uniform_p.h"
++ #include "qabstracttexture.h"
++ #include <QVariant>
++
++ QT_BEGIN_NAMESPACE
++
++ namespace Qt3DRender {
++ namespace Render {
++
++ namespace {
++
++ const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>();
++ const int qVector3DTypeId = qMetaTypeId<Vector3D>();
++ const int qVector4DTypeId = qMetaTypeId<Vector4D>();
++ const int qMatrix4x4TypeId = qMetaTypeId<Matrix4x4>();
++
++ // glUniform*fv/glUniform*iv/glUniform*uiv -> only handles sizeof(float)/sizeof(int)
++ int byteSizeForMetaType(int type)
++ {
++ if (type == qMatrix4x4TypeId)
++ return sizeof(Matrix4x4);
++ if (type == qVector3DTypeId)
++ return sizeof(Vector3D);
++ if (type == qVector4DTypeId)
++ return sizeof(Vector4D);
++ if (type == qNodeIdTypeId)
++ return sizeof(Qt3DCore::QNodeId);
++
++ switch (type) {
++ case QMetaType::Bool:
++ case QMetaType::Int:
++ case QMetaType::UInt:
++ case QMetaType::ULongLong:
++ case QMetaType::LongLong:
++ case QMetaType::Long:
++ case QMetaType::ULong:
++ case QMetaType::Short:
++ case QMetaType::UShort:
++ case QMetaType::Char:
++ case QMetaType::UChar:
++ return sizeof(int);
++
++ case QMetaType::Float:
++ case QMetaType::Double: // Assumes conversion to float
++ return sizeof(float);
++
++ case QMetaType::QPoint:
++ case QMetaType::QSize:
++ return 2 * sizeof(int);
++
++ case QMetaType::QRect:
++ return 4 * sizeof(int);
++
++ case QMetaType::QPointF:
++ case QMetaType::QSizeF:
++ case QMetaType::QVector2D:
++ return 2 * sizeof(float);
++
++ case QMetaType::QVector3D:
++ return 3 * sizeof(float);
++
++ case QMetaType::QRectF:
++ case QMetaType::QVector4D:
++ case QMetaType::QColor:
++ return 4 * sizeof(float);
++ case QMetaType::QMatrix4x4:
++ return 16 * sizeof(float);
++
++ default:
++ Q_UNREACHABLE_RETURN(-1);
++ }
++ }
++
++ } // anonymous
++
++ UniformValue UniformValue::fromVariant(const QVariant &variant)
++ {
++ // Texture/Buffer case
++ const int type = variant.userType();
++
++ if (type == qNodeIdTypeId)
++ return UniformValue(variant.value<Qt3DCore::QNodeId>());
++
++ if (type == qMatrix4x4TypeId)
++ return UniformValue(variant.value<Matrix4x4>());
++
++ if (type == qVector3DTypeId)
++ return UniformValue(variant.value<Vector3D>());
++
++ if (type == qVector4DTypeId)
++ return UniformValue(variant.value<Vector4D>());
++
++ UniformValue v;
++ switch (type) {
++ case QMetaType::Bool:
++ v.data<bool>()[0] = variant.toBool();
++ break;
++ case QMetaType::Int:
++ case QMetaType::UInt:
++ case QMetaType::Long:
++ case QMetaType::LongLong:
++ case QMetaType::Short:
++ case QMetaType::ULong:
++ case QMetaType::ULongLong:
++ case QMetaType::UShort:
++ case QMetaType::Char:
++ case QMetaType::UChar:
++ v.data<int>()[0] = variant.toInt();
++ v.m_storedType = Int;
++ break;
++ case QMetaType::Float:
++ case QMetaType::Double: // Convert double to floats
++ v.m_data[0] = variant.toFloat();
++ break;
++ case QMetaType::QPoint: {
++ const QPoint p = variant.toPoint();
++ v.data<int>()[0] = p.x();
++ v.data<int>()[1] = p.y();
++ break;
++ }
++ case QMetaType::QSize: {
++ const QSize s = variant.toSize();
++ v.data<int>()[0] = s.width();
++ v.data<int>()[1] = s.height();
++ break;
++ }
++ case QMetaType::QRect: {
++ const QRect r = variant.toRect();
++ v.data<int>()[0] = r.x();
++ v.data<int>()[1] = r.y();
++ v.data<int>()[2] = r.width();
++ v.data<int>()[3] = r.height();
++ break;
++ }
++ case QMetaType::QSizeF: {
++ const QSizeF s = variant.toSize();
++ v.m_data[0] = s.width();
++ v.m_data[1] = s.height();
++ break;
++ }
++ case QMetaType::QPointF: {
++ const QPointF p = variant.toPointF();
++ v.m_data[0] = p.x();
++ v.m_data[1] = p.y();
++ break;
++ }
++ case QMetaType::QRectF: {
++ const QRectF r = variant.toRect();
++ v.m_data[0] = r.x();
++ v.m_data[1] = r.y();
++ v.m_data[2] = r.width();
++ v.m_data[3] = r.height();
++ break;
++ }
++ case QMetaType::QVector2D: {
++ const QVector2D vec2 = variant.value<QVector2D>();
++ v.m_data[0] = vec2.x();
++ v.m_data[1] = vec2.y();
++ break;
++ }
++ case QMetaType::QVector3D: {
++ const QVector3D vec3 = variant.value<QVector3D>();
++ v.m_data[0] = vec3.x();
++ v.m_data[1] = vec3.y();
++ v.m_data[2] = vec3.z();
++ break;
++ }
++ case QMetaType::QVector4D: {
++ const QVector4D vec4 = variant.value<QVector4D>();
++ v.m_data[0] = vec4.x();
++ v.m_data[1] = vec4.y();
++ v.m_data[2] = vec4.z();
++ v.m_data[3] = vec4.w();
++ break;
++ }
++ case QMetaType::QColor: {
++ const QColor col = variant.value<QColor>();
++ v.m_data[0] = col.redF();
++ v.m_data[1] = col.greenF();
++ v.m_data[2] = col.blueF();
++ v.m_data[3] = col.alphaF();
++ break;
++ }
++ case QMetaType::QMatrix4x4: {
++ const QMatrix4x4 mat44 = variant.value<QMatrix4x4>();
++ // Use constData because we want column-major layout
++ v.m_data.resize(16);
++ memcpy(v.data<float>(), mat44.constData(), 16 * sizeof(float));
++ break;
++ }
++ case QMetaType::QVariantList: {
++ const QVariantList variants = variant.toList();
++ if (variants.empty())
++ break;
++
++ const int listEntryType = variants.first().userType();
++
++ // array of textures
++ if (listEntryType == qNodeIdTypeId)
++ v.m_valueType = NodeId;
++
++ v.m_elementByteSize = byteSizeForMetaType(listEntryType);
++ const int stride = v.m_elementByteSize / sizeof(float);
++
++ // Resize v.m_data
++ v.m_data.resize(stride * variants.size());
++
++ int idx = 0;
++ for (const QVariant &variant : variants) {
++ Q_ASSERT_X(variant.userType() == listEntryType,
++ Q_FUNC_INFO,
++ "Uniform array doesn't contain elements of the same type");
++ UniformValue vi = UniformValue::fromVariant(variant);
++ memcpy(v.data<float>() + idx, vi.data<float>(), stride * sizeof(float));
++ idx += stride;
++ }
++ break;
++ }
++
++ default: {
++ if (variant.userType() == qMetaTypeId<QMatrix3x3>()) {
++ const QMatrix3x3 mat33 = variant.value<QMatrix3x3>();
++ // Use constData because we want column-major layout
++ v.m_data.resize(9);
++ memcpy(v.data<float>(), mat33.constData(), 9 * sizeof(float));
++ break;
++ }
++ if (variant.userType() == qMetaTypeId<Qt3DRender::QAbstractTexture *>()) {
++ // silently ignore null texture pointers as they are common while textures are loading
++ if (variant.value<Qt3DRender::QAbstractTexture *>() == nullptr)
++ break;
++ }
++ qWarning() << "Unknown uniform type or value:" << variant << "Please check your QParameters";
++ }
++ }
++ return v;
++ }
++
++ template<>
++ void UniformValue::setData<QMatrix4x4>(const QVector<QMatrix4x4> &v)
++ {
++ m_data.resize(16 * v.size());
++ m_valueType = ScalarValue;
++ int offset = 0;
++ const int byteSize = 16 * sizeof(float);
++ float *data = m_data.data();
++ for (const auto &m : v) {
++ memcpy(data + offset, m.constData(), byteSize);
++ offset += 16;
++ }
++ }
++
++ } // namespace Render
++ } // namespace Qt3DRender
++
++ QT_END_NAMESPACE