// Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "skingeometry.h" #include struct Vertex { QVector3D position; qint32 joints[4]; float weights[4]; float pad; }; static const int s_vertexSize = sizeof(Vertex); Q_STATIC_ASSERT(s_vertexSize == 48); SkinGeometry::SkinGeometry(QQuick3DObject *parent) : QQuick3DGeometry(parent) { addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::F32Type); addAttribute(QQuick3DGeometry::Attribute::IndexSemantic, 0, QQuick3DGeometry::Attribute::ComponentType::U32Type); addAttribute(QQuick3DGeometry::Attribute::JointSemantic, offsetof(Vertex, joints[0]), QQuick3DGeometry::Attribute::ComponentType::I32Type); addAttribute(QQuick3DGeometry::Attribute::WeightSemantic, offsetof(Vertex, weights[0]), QQuick3DGeometry::Attribute::ComponentType::F32Type); } QList SkinGeometry::positions() const { return m_positions; } QList SkinGeometry::joints() const { return m_joints; } QList SkinGeometry::weights() const { return m_weights; } QList SkinGeometry::indexes() const { return m_indexes; } void SkinGeometry::setPositions(const QList &positions) { if (positions == m_positions) return; m_positions = positions; emit positionsChanged(); m_vertexDirty = true; } void SkinGeometry::setJoints(const QList &joints) { if (joints == m_joints) return; m_joints = joints; emit jointsChanged(); m_vertexDirty = true; } void SkinGeometry::setWeights(const QList &weights) { if (weights == m_weights) return; m_weights = weights; emit weightsChanged(); m_vertexDirty = true; } void SkinGeometry::setIndexes(const QList &indexes) { if (indexes == m_indexes) return; m_indexes = indexes; emit indexesChanged(); m_indexDirty = true; } QSSGRenderGraphObject *SkinGeometry::updateSpatialNode(QSSGRenderGraphObject *node) { if (m_vertexDirty) { m_vertexDirty = false; const int numVertexes = m_positions.size(); m_vertexBuffer.resize(numVertexes * s_vertexSize); Vertex *vert = reinterpret_cast(m_vertexBuffer.data()); for (int i = 0; i < numVertexes; ++i) { Vertex &v = vert[i]; v.position = m_positions[i]; if (m_joints.size() >= 4 * (i + 1)) memcpy(v.joints, m_joints.constData() + 4 * i, 4 * sizeof(qint32)); else v.joints[0] = v.joints[1] = v.joints[2] = v.joints[3] = 0; if (m_weights.size() >= 4 * (i + 1)) memcpy(v.weights, m_weights.constData() + 4 * i, 4 * sizeof(float)); else v.weights[0] = v.weights[1] = v.weights[2] = v.weights[3] = 0.0f; } setStride(s_vertexSize); setVertexData(m_vertexBuffer); setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles); } if (m_indexDirty) { m_indexDirty = false; m_indexBuffer = QByteArray(reinterpret_cast(m_indexes.data()), m_indexes.size() * sizeof(quint32)); setIndexData(m_indexBuffer); } node = QQuick3DGeometry::updateSpatialNode(node); return node; }