/**************************************************************************** ** ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qjoint.h" #include "qjoint_p.h" #include QT_BEGIN_NAMESPACE namespace Qt3DCore { QJointPrivate::QJointPrivate() : QNodePrivate() , m_inverseBindMatrix() , m_rotation() , m_translation() , m_scale(1.0f, 1.0f, 1.0f) { } /*! \qmltype Joint \inqmlmodule Qt3D.Core \inherits Node \instantiates Qt3DCore::QJoint \since 5.10 \brief Used to transforms parts of skinned meshes. The Joint node is used to build skeletons as part of the skinned mesh support in Qt 3D. A joint can be transformed by way of its scale, rotation and translation properties. Any mesh vertices that are bound to the joint will have their transformations updated accordingly. */ /*! \qmlproperty vector3d Joint::scale Holds the uniform scale of the joint. */ /*! \qmlproperty quaternion Joint::rotation Holds the rotation of the joint as quaternion. */ /*! \qmlproperty vector3d Joint::translation Holds the translation of the joint as vector3d. */ /*! \qmlproperty real Joint::rotationX Holds the x rotation of the joint as an Euler angle. */ /*! \qmlproperty real Joint::rotationY Holds the y rotation of the joint as an Euler angle. */ /*! \qmlproperty real Joint::rotationZ Holds the z rotation of the joint as an Euler angle. */ /*! \qmlproperty matrix4x4 Joint::inverseBindMatrix Holds the inverse bind matrix of the joint. This is used to transform vertices from model space into the space of this joint so they can subsequently be multiplied by the joint's global transform to perform the skinning operation. */ /*! \class Qt3DCore::QJoint \inmodule Qt3DCore \inherits Qt3DCore::QNode \since 5.10 \brief Used to transforms parts of skinned meshes. The QJoint node is used to build skeletons as part of the skinned mesh support in Qt 3D. A joint can be transformed by way of its scale, rotation and translation properties. Any mesh vertices that are bound to the joint will have their transformations updated accordingly. */ /*! Constructs a new QJoint with \a parent. */ QJoint::QJoint(Qt3DCore::QNode *parent) : QNode(*new QJointPrivate, parent) { } /*! \internal */ QJoint::~QJoint() { } /*! \property Qt3DCore::QJoint::scale Holds the scale of the joint. */ QVector3D QJoint::scale() const { Q_D(const QJoint); return d->m_scale; } /*! \property Qt3DCore::QJoint::rotation Holds the rotation of the joint as QQuaternion. */ QQuaternion QJoint::rotation() const { Q_D(const QJoint); return d->m_rotation; } /*! \property Qt3DCore::QJoint::translation Holds the translation of the joint as QVector3D. */ QVector3D QJoint::translation() const { Q_D(const QJoint); return d->m_translation; } /*! \property Qt3DCore::QJoint::inverseBindMatrix Holds the inverse bind matrix of the joint. This is used to transform vertices from model space into the space of this joint so they can subsequently be multiplied by the joint's global transform to perform the skinning operation. */ QMatrix4x4 QJoint::inverseBindMatrix() const { Q_D(const QJoint); return d->m_inverseBindMatrix; } /*! \property Qt3DCore::QJoint::rotationX Holds the x rotation of the joint as an Euler angle. */ float QJoint::rotationX() const { Q_D(const QJoint); return d->m_eulerRotationAngles.x(); } /*! \property Qt3DCore::QJoint::rotationY Holds the y rotation of the joint as an Euler angle. */ float QJoint::rotationY() const { Q_D(const QJoint); return d->m_eulerRotationAngles.y(); } /*! \property Qt3DCore::QJoint::rotationZ Holds the z rotation of the joint as an Euler angle. */ float QJoint::rotationZ() const { Q_D(const QJoint); return d->m_eulerRotationAngles.z(); } void QJoint::setScale(const QVector3D &scale) { Q_D(QJoint); if (scale == d->m_scale) return; d->m_scale = scale; emit scaleChanged(scale); } void QJoint::setRotation(const QQuaternion &rotation) { Q_D(QJoint); if (rotation == d->m_rotation) return; d->m_rotation = rotation; const QVector3D oldRotation = d->m_eulerRotationAngles; d->m_eulerRotationAngles = d->m_rotation.toEulerAngles(); emit rotationChanged(rotation); const bool wasBlocked = blockNotifications(true); if (!qFuzzyCompare(d->m_eulerRotationAngles.x(), oldRotation.x())) emit rotationXChanged(d->m_eulerRotationAngles.x()); if (!qFuzzyCompare(d->m_eulerRotationAngles.y(), oldRotation.y())) emit rotationYChanged(d->m_eulerRotationAngles.y()); if (!qFuzzyCompare(d->m_eulerRotationAngles.z(), oldRotation.z())) emit rotationZChanged(d->m_eulerRotationAngles.z()); blockNotifications(wasBlocked); } void QJoint::setTranslation(const QVector3D &translation) { Q_D(QJoint); if (translation == d->m_translation) return; d->m_translation = translation; emit translationChanged(translation); } void QJoint::setInverseBindMatrix(const QMatrix4x4 &inverseBindMatrix) { Q_D(QJoint); if (d->m_inverseBindMatrix == inverseBindMatrix) return; d->m_inverseBindMatrix = inverseBindMatrix; emit inverseBindMatrixChanged(inverseBindMatrix); } void QJoint::setRotationX(float rotationX) { Q_D(QJoint); if (qFuzzyCompare(d->m_eulerRotationAngles.x(), rotationX)) return; const auto eulers = QVector3D(rotationX, d->m_eulerRotationAngles.y(), d->m_eulerRotationAngles.z()); const QQuaternion r = QQuaternion::fromEulerAngles(eulers); setRotation(r); } void QJoint::setRotationY(float rotationY) { Q_D(QJoint); if (qFuzzyCompare(d->m_eulerRotationAngles.y(), rotationY)) return; const auto eulers = QVector3D(d->m_eulerRotationAngles.x(), rotationY, d->m_eulerRotationAngles.z()); const QQuaternion r = QQuaternion::fromEulerAngles(eulers); setRotation(r); } void QJoint::setRotationZ(float rotationZ) { Q_D(QJoint); if (qFuzzyCompare(d->m_eulerRotationAngles.z(), rotationZ)) return; const auto eulers = QVector3D(d->m_eulerRotationAngles.x(), d->m_eulerRotationAngles.y(), rotationZ); const QQuaternion r = QQuaternion::fromEulerAngles(eulers); setRotation(r); } void QJoint::setName(const QString &name) { Q_D(QJoint); if (d->m_name == name) return; d->m_name = name; emit nameChanged(name); } /*! Sets the transform matrix for this joint to the identity matrix. */ void QJoint::setToIdentity() { setScale(QVector3D(1.0f, 1.0f, 1.0f)); setRotation(QQuaternion()); setTranslation(QVector3D()); } /*! Adds \a joint as a child of this joint. If \a joint has no parent, then this joint takes ownership of it. Child joints are in the coordinate system of their parent joint. */ void QJoint::addChildJoint(QJoint *joint) { Q_D(QJoint); if (!d->m_childJoints.contains(joint)) { d->m_childJoints.push_back(joint); // Force creation in backend by setting parent if (!joint->parent()) joint->setParent(this); // Ensures proper bookkeeping d->registerDestructionHelper(joint, &QJoint::removeChildJoint, d->m_childJoints); if (d->m_changeArbiter != nullptr) d->updateNode(joint, "childJoint", PropertyValueAdded); } } /*! Removes \a joint from this joint's list of children. The child joint is not destroyed. */ void QJoint::removeChildJoint(QJoint *joint) { Q_D(QJoint); if (d->m_childJoints.contains(joint)) { if (d->m_changeArbiter != nullptr) d->updateNode(joint, "childJoint", PropertyValueRemoved); d->m_childJoints.removeOne(joint); // Remove bookkeeping connection d->unregisterDestructionHelper(joint); } } /*! The vector of joints this joint has as children. */ QVector QJoint::childJoints() const { Q_D(const QJoint); return d->m_childJoints; } /*! Returns the name of the joint. */ QString QJoint::name() const { Q_D(const QJoint); return d->m_name; } /*! \internal */ Qt3DCore::QNodeCreatedChangeBasePtr QJoint::createNodeCreationChange() const { auto creationChange = Qt3DCore::QNodeCreatedChangePtr::create(this); auto &data = creationChange->data; Q_D(const QJoint); data.inverseBindMatrix = d->m_inverseBindMatrix; data.childJointIds = qIdsForNodes(d->m_childJoints); data.rotation = d->m_rotation; data.scale = d->m_scale; data.translation = d->m_translation; data.name = d->m_name; return creationChange; } } // namespace Qt3DCore QT_END_NAMESPACE