| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). |
| ** Contact: http://www.qt-project.org/legal |
| ** |
| ** This file is part of the Qt3D module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL3$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see http://www.qt.io/terms-conditions. For further |
| ** information use the contact form at http://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or later as published by the Free |
| ** Software Foundation and appearing in the file LICENSE.GPL included in |
| ** the packaging of this file. Please review the following information to |
| ** ensure the GNU General Public License version 2.0 requirements will be |
| ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qchannelmapping.h" |
| #include "qchannelmapping_p.h" |
| |
| #include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h> |
| |
| #include <QtCore/qmetaobject.h> |
| #include <QtCore/QMetaProperty> |
| |
| QT_BEGIN_NAMESPACE |
| |
| namespace Qt3DAnimation { |
| |
| namespace { |
| |
| template<typename T> |
| int componentCountForValue(const T &) |
| { |
| return 0; |
| } |
| |
| template<> |
| int componentCountForValue<QVector<float>>(const QVector<float> &v) |
| { |
| return v.size(); |
| } |
| |
| template<> |
| int componentCountForValue<QVariantList>(const QVariantList &v) |
| { |
| return v.size(); |
| } |
| |
| |
| int componentCountForType(int type, const QVariant &value) |
| { |
| const int vectorOfFloatTypeId = qMetaTypeId<QVector<float>>(); |
| |
| if (type == vectorOfFloatTypeId) |
| return componentCountForValue<QVector<float>>(value.value<QVector<float>>()); |
| |
| switch (type) { |
| case QMetaType::Float: |
| case QVariant::Double: |
| return 1; |
| |
| case QVariant::Vector2D: |
| return 2; |
| |
| case QVariant::Vector3D: |
| case QVariant::Color: |
| return 3; |
| |
| case QVariant::Vector4D: |
| case QVariant::Quaternion: |
| return 4; |
| |
| case QVariant::List: |
| return componentCountForValue<QVariantList>(value.toList()); |
| |
| default: |
| qWarning() << "Unhandled animation type"; |
| return 0; |
| } |
| } |
| |
| } // anonymous |
| |
| QChannelMappingPrivate::QChannelMappingPrivate() |
| : QAbstractChannelMappingPrivate() |
| , m_channelName() |
| , m_target(nullptr) |
| , m_property() |
| , m_propertyName(nullptr) |
| , m_type(static_cast<int>(QVariant::Invalid)) |
| , m_componentCount(0) |
| { |
| m_mappingType = QChannelMappingCreatedChangeBase::ChannelMapping; |
| } |
| |
| /*! |
| \internal |
| |
| Find the type of the property specified on the target node |
| */ |
| void QChannelMappingPrivate::updatePropertyNameTypeAndComponentCount() |
| { |
| int type; |
| int componentCount = 0; |
| const char *propertyName = nullptr; |
| |
| if (!m_target || m_property.isNull()) { |
| type = QVariant::Invalid; |
| } else { |
| const QMetaObject *mo = m_target->metaObject(); |
| const int propertyIndex = mo->indexOfProperty(m_property.toLocal8Bit()); |
| QMetaProperty mp = mo->property(propertyIndex); |
| propertyName = mp.name(); |
| type = mp.userType(); |
| const QVariant currentValue = m_target->property(mp.name()); |
| if (type == QMetaType::QVariant) { |
| if (currentValue.isValid()) { |
| type = currentValue.userType(); |
| } else { |
| qWarning("QChannelMapping: Attempted to target QVariant property with no value set. " |
| "Set a value first in order to be able to determine the type."); |
| } |
| } |
| componentCount = componentCountForType(type, currentValue); |
| } |
| |
| if (m_type != type) { |
| m_type = type; |
| update(); |
| } |
| |
| if (m_componentCount != componentCount) { |
| m_componentCount = componentCount; |
| update(); |
| } |
| |
| if (qstrcmp(m_propertyName, propertyName) != 0) { |
| m_propertyName = propertyName; |
| update(); |
| } |
| } |
| |
| /*! |
| \class Qt3DAnimation::QChannelMapping |
| \inherits Qt3DCore::QNode |
| \inmodule Qt3DAnimation |
| \brief Allows to map the channels within the clip onto properties of |
| objects in the application. |
| |
| */ |
| |
| QChannelMapping::QChannelMapping(Qt3DCore::QNode *parent) |
| : QAbstractChannelMapping(*new QChannelMappingPrivate, parent) |
| { |
| } |
| |
| QChannelMapping::QChannelMapping(QChannelMappingPrivate &dd, Qt3DCore::QNode *parent) |
| : QAbstractChannelMapping(dd, parent) |
| { |
| } |
| |
| QChannelMapping::~QChannelMapping() |
| { |
| } |
| |
| QString QChannelMapping::channelName() const |
| { |
| Q_D(const QChannelMapping); |
| return d->m_channelName; |
| } |
| |
| Qt3DCore::QNode *QChannelMapping::target() const |
| { |
| Q_D(const QChannelMapping); |
| return d->m_target; |
| } |
| |
| QString QChannelMapping::property() const |
| { |
| Q_D(const QChannelMapping); |
| return d->m_property; |
| } |
| |
| void QChannelMapping::setChannelName(const QString &channelName) |
| { |
| Q_D(QChannelMapping); |
| if (d->m_channelName == channelName) |
| return; |
| |
| d->m_channelName = channelName; |
| emit channelNameChanged(channelName); |
| } |
| |
| void QChannelMapping::setTarget(Qt3DCore::QNode *target) |
| { |
| Q_D(QChannelMapping); |
| if (d->m_target == target) |
| return; |
| |
| if (d->m_target) |
| d->unregisterDestructionHelper(d->m_target); |
| |
| if (target && !target->parent()) |
| target->setParent(this); |
| d->m_target = target; |
| |
| // Ensures proper bookkeeping |
| if (d->m_target) |
| d->registerDestructionHelper(d->m_target, &QChannelMapping::setTarget, d->m_target); |
| |
| emit targetChanged(target); |
| d->updatePropertyNameTypeAndComponentCount(); |
| } |
| |
| void QChannelMapping::setProperty(const QString &property) |
| { |
| Q_D(QChannelMapping); |
| if (d->m_property == property) |
| return; |
| |
| d->m_property = property; |
| |
| // The backend uses propertyName instead of property |
| const bool blocked = blockNotifications(true); |
| emit propertyChanged(property); |
| blockNotifications(blocked); |
| |
| d->updatePropertyNameTypeAndComponentCount(); |
| } |
| |
| Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() const |
| { |
| auto creationChange = QChannelMappingCreatedChangePtr<QChannelMappingData>::create(this); |
| auto &data = creationChange->data; |
| Q_D(const QChannelMapping); |
| data.channelName = d->m_channelName; |
| data.targetId = Qt3DCore::qIdForNode(d->m_target); |
| data.type = d->m_type; |
| data.componentCount = d->m_componentCount; |
| data.propertyName = d->m_propertyName; |
| return creationChange; |
| } |
| |
| } // namespace Qt3DAnimation |
| |
| QT_END_NAMESPACE |