2023-10-13 15:36:36 -04:00
|
|
|
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
#include "sklbpart.h"
|
|
|
|
|
2024-02-04 15:26:12 -05:00
|
|
|
#include <KLocalizedString>
|
2023-10-13 15:36:36 -04:00
|
|
|
#include <QFormLayout>
|
|
|
|
#include <QGroupBox>
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
2024-04-30 15:56:26 -04:00
|
|
|
#include <glm/gtx/matrix_decompose.hpp>
|
|
|
|
#include <glm/gtx/matrix_major_storage.hpp>
|
2023-10-13 15:36:36 -04:00
|
|
|
|
|
|
|
#include "quaternionedit.h"
|
|
|
|
#include "vec3edit.h"
|
|
|
|
|
|
|
|
void addItem(physis_Skeleton &skeleton, physis_Bone &bone, QTreeWidget *widget, QTreeWidgetItem *parent_item = nullptr)
|
|
|
|
{
|
|
|
|
auto item = new QTreeWidgetItem();
|
|
|
|
item->setText(0, QLatin1String(bone.name));
|
|
|
|
|
|
|
|
if (parent_item == nullptr) {
|
|
|
|
widget->addTopLevelItem(item);
|
|
|
|
} else {
|
|
|
|
parent_item->addChild(item);
|
|
|
|
}
|
|
|
|
|
2023-12-09 22:35:59 -05:00
|
|
|
for (uint32_t i = 0; i < skeleton.num_bones; i++) {
|
2023-10-13 15:36:36 -04:00
|
|
|
if (skeleton.bones[i].parent_bone != nullptr && strcmp(skeleton.bones[i].parent_bone->name, bone.name) == 0)
|
|
|
|
addItem(skeleton, skeleton.bones[i], widget, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-09 15:24:54 -05:00
|
|
|
SklbPart::SklbPart(QWidget *parent)
|
|
|
|
: QWidget(parent)
|
2023-10-13 15:36:36 -04:00
|
|
|
{
|
|
|
|
auto layout = new QHBoxLayout();
|
|
|
|
setLayout(layout);
|
|
|
|
|
|
|
|
boneListWidget = new QTreeWidget();
|
2024-02-04 15:26:12 -05:00
|
|
|
boneListWidget->setHeaderLabel(i18nc("@title:column", "Name"));
|
2023-10-13 15:36:36 -04:00
|
|
|
boneListWidget->setMaximumWidth(200);
|
|
|
|
|
|
|
|
layout->addWidget(boneListWidget);
|
|
|
|
|
2024-04-30 15:56:26 -04:00
|
|
|
transformLayout = new QVBoxLayout();
|
2023-10-13 15:36:36 -04:00
|
|
|
layout->addLayout(transformLayout);
|
|
|
|
|
2024-02-04 15:26:12 -05:00
|
|
|
auto transformGroup = new QGroupBox(i18nc("@title:group", "Bone Transform"));
|
2023-10-13 15:36:36 -04:00
|
|
|
transformLayout->addWidget(transformGroup);
|
|
|
|
auto transformGroupLayout = new QFormLayout();
|
|
|
|
transformGroup->setLayout(transformGroupLayout);
|
|
|
|
|
|
|
|
posEdit = new Vector3Edit(currentPosition);
|
2024-04-30 15:56:26 -04:00
|
|
|
posEdit->setEnabled(false);
|
2023-10-13 15:36:36 -04:00
|
|
|
connect(posEdit, &Vector3Edit::onValueChanged, [this] {
|
|
|
|
memcpy(currentEditedBone->position, glm::value_ptr(currentPosition), sizeof(float) * 3);
|
|
|
|
Q_EMIT valueChanged();
|
|
|
|
});
|
2024-02-04 15:26:12 -05:00
|
|
|
transformGroupLayout->addRow(i18nc("@label:spinbox", "Position"), posEdit);
|
2023-10-13 15:36:36 -04:00
|
|
|
|
|
|
|
rotationEdit = new QuaternionEdit(currentRotation);
|
2024-04-30 15:56:26 -04:00
|
|
|
rotationEdit->setEnabled(false);
|
2023-10-13 15:36:36 -04:00
|
|
|
connect(rotationEdit, &QuaternionEdit::onValueChanged, [this] {
|
|
|
|
memcpy(currentEditedBone->rotation, glm::value_ptr(currentRotation), sizeof(float) * 4);
|
|
|
|
Q_EMIT valueChanged();
|
|
|
|
});
|
2024-02-04 15:26:12 -05:00
|
|
|
transformGroupLayout->addRow(i18nc("@label:spinbox", "Rotation"), rotationEdit);
|
2023-10-13 15:36:36 -04:00
|
|
|
|
|
|
|
scaleEdit = new Vector3Edit(currentScale);
|
2024-04-30 15:56:26 -04:00
|
|
|
scaleEdit->setEnabled(false);
|
2023-10-13 15:36:36 -04:00
|
|
|
connect(scaleEdit, &Vector3Edit::onValueChanged, [this] {
|
|
|
|
memcpy(currentEditedBone->scale, glm::value_ptr(currentScale), sizeof(float) * 3);
|
|
|
|
Q_EMIT valueChanged();
|
|
|
|
});
|
2024-02-04 15:26:12 -05:00
|
|
|
transformGroupLayout->addRow(i18nc("@label:spinbox", "Scale"), scaleEdit);
|
2023-10-13 15:36:36 -04:00
|
|
|
|
|
|
|
connect(boneListWidget, &QTreeWidget::itemClicked, this, &SklbPart::treeItemClicked);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SklbPart::treeItemClicked(QTreeWidgetItem *item, int column)
|
|
|
|
{
|
2023-12-09 22:35:59 -05:00
|
|
|
for (uint32_t i = 0; i < skeleton.num_bones; i++) {
|
2023-10-13 15:36:36 -04:00
|
|
|
if (strcmp(skeleton.bones[i].name, item->text(column).toStdString().c_str()) == 0) {
|
|
|
|
currentPosition = glm::make_vec3(skeleton.bones[i].position);
|
|
|
|
currentRotation = glm::make_quat(skeleton.bones[i].rotation);
|
|
|
|
currentScale = glm::make_vec3(skeleton.bones[i].scale);
|
|
|
|
currentEditedBone = &skeleton.bones[i];
|
|
|
|
|
2024-04-30 15:56:26 -04:00
|
|
|
posEdit->setEnabled(true);
|
2023-10-13 15:36:36 -04:00
|
|
|
posEdit->setVector(currentPosition);
|
2024-04-30 15:56:26 -04:00
|
|
|
|
|
|
|
rotationEdit->setEnabled(true);
|
2023-10-13 15:36:36 -04:00
|
|
|
rotationEdit->setQuat(currentRotation);
|
2024-04-30 15:56:26 -04:00
|
|
|
|
|
|
|
scaleEdit->setEnabled(true);
|
2023-10-13 15:36:36 -04:00
|
|
|
scaleEdit->setVector(currentScale);
|
2024-04-30 15:56:26 -04:00
|
|
|
|
|
|
|
if (racePosEdit != nullptr && raceRotationEdit != nullptr && raceScaleEdit != nullptr) {
|
|
|
|
for (int j = 0; j < m_matrices.num_bones; j++) {
|
|
|
|
if (std::string_view{m_matrices.bones[j].name} == std::string_view{skeleton.bones[i].name}) {
|
|
|
|
auto deformBone = glm::rowMajor4(glm::vec4{m_matrices.bones[j].deform[0],
|
|
|
|
m_matrices.bones[j].deform[1],
|
|
|
|
m_matrices.bones[j].deform[2],
|
|
|
|
m_matrices.bones[j].deform[3]},
|
|
|
|
glm::vec4{m_matrices.bones[j].deform[4],
|
|
|
|
m_matrices.bones[j].deform[5],
|
|
|
|
m_matrices.bones[j].deform[6],
|
|
|
|
m_matrices.bones[j].deform[7]},
|
|
|
|
glm::vec4{m_matrices.bones[j].deform[8],
|
|
|
|
m_matrices.bones[j].deform[9],
|
|
|
|
m_matrices.bones[j].deform[10],
|
|
|
|
m_matrices.bones[j].deform[11]},
|
|
|
|
glm::vec4{0.0f, 0.0f, 0.0f, 1.0f});
|
|
|
|
|
|
|
|
glm::vec3 scale;
|
|
|
|
glm::quat rotation;
|
|
|
|
glm::vec3 translation;
|
|
|
|
glm::vec3 skew;
|
|
|
|
glm::vec4 perspective;
|
|
|
|
glm::decompose(deformBone, scale, rotation, translation, skew, perspective);
|
|
|
|
|
|
|
|
racePosEdit->setVector(translation);
|
|
|
|
raceRotationEdit->setQuat(rotation);
|
|
|
|
raceScaleEdit->setVector(scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-13 15:36:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SklbPart::clear()
|
|
|
|
{
|
|
|
|
boneListWidget->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SklbPart::load(physis_Skeleton file)
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
addItem(file, *file.root_bone, boneListWidget);
|
|
|
|
skeleton = file;
|
|
|
|
}
|
|
|
|
|
2024-04-30 15:56:26 -04:00
|
|
|
void SklbPart::load_pbd(physis_PBD deformer, int from_body_id, int to_body_id)
|
|
|
|
{
|
|
|
|
if (racePosEdit == nullptr && raceRotationEdit == nullptr && raceScaleEdit == nullptr) {
|
|
|
|
auto raceTransformGroup = new QGroupBox(i18nc("@title:group", "Race Transform"));
|
|
|
|
transformLayout->addWidget(raceTransformGroup);
|
|
|
|
auto raceTransformGroupLayout = new QFormLayout();
|
|
|
|
raceTransformGroup->setLayout(raceTransformGroupLayout);
|
|
|
|
|
|
|
|
racePosEdit = new Vector3Edit(currentPosition);
|
|
|
|
racePosEdit->setEnabled(false);
|
|
|
|
raceTransformGroupLayout->addRow(i18nc("@label:spinbox", "Position"), racePosEdit);
|
|
|
|
|
|
|
|
raceRotationEdit = new QuaternionEdit(currentRotation);
|
|
|
|
raceRotationEdit->setEnabled(false);
|
|
|
|
raceTransformGroupLayout->addRow(i18nc("@label:spinbox", "Rotation"), raceRotationEdit);
|
|
|
|
|
|
|
|
raceScaleEdit = new Vector3Edit(currentScale);
|
|
|
|
raceScaleEdit->setEnabled(false);
|
|
|
|
raceTransformGroupLayout->addRow(i18nc("@label:spinbox", "Scale"), raceScaleEdit);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_matrices = physis_pbd_get_deform_matrix(deformer, from_body_id, to_body_id);
|
|
|
|
}
|
|
|
|
|
2023-10-13 15:36:36 -04:00
|
|
|
#include "moc_sklbpart.cpp"
|