From b0ccfbaf15a6195388b1ddac5d955859aa25bfe8 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Fri, 13 Oct 2023 15:36:36 -0400 Subject: [PATCH] Make armoury's bone editor a general-purpose part, add it to sagasu --- armoury/CMakeLists.txt | 7 +- armoury/include/boneeditor.h | 32 +---- armoury/src/boneeditor.cpp | 122 +------------------ common/CMakeLists.txt | 6 +- {armoury => common}/include/quaternionedit.h | 0 {armoury => common}/include/vec3edit.h | 0 {armoury => common}/src/quaternionedit.cpp | 0 {armoury => common}/src/vec3edit.cpp | 0 parts/CMakeLists.txt | 1 + parts/sklb/CMakeLists.txt | 9 ++ parts/sklb/sklbpart.cpp | 103 ++++++++++++++++ parts/sklb/sklbpart.h | 45 +++++++ sagasu/CMakeLists.txt | 2 +- sagasu/src/indexer.cpp | 4 +- sagasu/src/mainwindow.cpp | 5 + 15 files changed, 182 insertions(+), 154 deletions(-) rename {armoury => common}/include/quaternionedit.h (100%) rename {armoury => common}/include/vec3edit.h (100%) rename {armoury => common}/src/quaternionedit.cpp (100%) rename {armoury => common}/src/vec3edit.cpp (100%) create mode 100644 parts/sklb/CMakeLists.txt create mode 100644 parts/sklb/sklbpart.cpp create mode 100644 parts/sklb/sklbpart.h diff --git a/armoury/CMakeLists.txt b/armoury/CMakeLists.txt index efa0130..c27556e 100644 --- a/armoury/CMakeLists.txt +++ b/armoury/CMakeLists.txt @@ -10,9 +10,7 @@ target_sources(novus-armoury PRIVATE include/gearlistwidget.h include/gearview.h include/mainwindow.h - include/quaternionedit.h include/singlegearview.h - include/vec3edit.h src/boneeditor.cpp src/cmpeditor.cpp @@ -22,9 +20,7 @@ target_sources(novus-armoury PRIVATE src/gearview.cpp src/main.cpp src/mainwindow.cpp - src/quaternionedit.cpp - src/singlegearview.cpp - src/vec3edit.cpp) + src/singlegearview.cpp) target_include_directories(novus-armoury PUBLIC @@ -40,6 +36,7 @@ target_link_libraries(novus-armoury PUBLIC physis-logger mdlpart cmppart + sklbpart imgui novus-common) diff --git a/armoury/include/boneeditor.h b/armoury/include/boneeditor.h index e16e5d0..fec1e5e 100644 --- a/armoury/include/boneeditor.h +++ b/armoury/include/boneeditor.h @@ -3,19 +3,11 @@ #pragma once -#include -#include -#include -#include -#include -#include - -#include "quaternionedit.h" -#include "vec3edit.h" +#include "sklbpart.h" class GearView; -class BoneEditor : public QWidget +class BoneEditor : public SklbPart { Q_OBJECT @@ -23,25 +15,5 @@ public: explicit BoneEditor(GearView *gearView, QWidget *parent = nullptr); private: - void treeItemClicked(QTreeWidgetItem *item, int column); - GearView *gearView; - - glm::vec3 currentPosition; - glm::quat currentRotation; - glm::vec3 currentScale; - - glm::vec3 currentRacePosition; - glm::quat currentRaceRotation; - glm::vec3 currentRaceScale; - - physis_Bone *currentEditedBone = nullptr; - - Vector3Edit *posEdit = nullptr; - QuaternionEdit *rotationEdit = nullptr; - Vector3Edit *scaleEdit = nullptr; - - Vector3Edit *raceDeformPosEdit = nullptr; - QuaternionEdit *raceDeformRotationEdit = nullptr; - Vector3Edit *raceDeformScaleEdit = nullptr; }; diff --git a/armoury/src/boneeditor.cpp b/armoury/src/boneeditor.cpp index e10ab18..2419bd1 100644 --- a/armoury/src/boneeditor.cpp +++ b/armoury/src/boneeditor.cpp @@ -3,132 +3,22 @@ #include "boneeditor.h" -#include -#include -#include -#include -#include -#include - #include "gearview.h" -#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); - } - - for (int i = 0; i < skeleton.num_bones; i++) { - if (skeleton.bones[i].parent_bone != nullptr && strcmp(skeleton.bones[i].parent_bone->name, bone.name) == 0) - addItem(skeleton, skeleton.bones[i], widget, item); - } -} BoneEditor::BoneEditor(GearView *gearView, QWidget *parent) - : gearView(gearView) + : SklbPart() + , gearView(gearView) { - auto layout = new QHBoxLayout(); - setLayout(layout); - - auto boneListWidget = new QTreeWidget(); - boneListWidget->setHeaderLabel(QStringLiteral("Name")); - - connect(&gearView->part(), &MDLPart::skeletonChanged, this, [this, boneListWidget, gearView] { - boneListWidget->clear(); - addItem(*gearView->part().skeleton, *gearView->part().skeleton->root_bone, boneListWidget); + connect(&gearView->part(), &MDLPart::skeletonChanged, this, [this, gearView] { + load(*gearView->part().skeleton); }); - boneListWidget->setMaximumWidth(200); - - layout->addWidget(boneListWidget); - - auto transformLayout = new QVBoxLayout(); - layout->addLayout(transformLayout); - - auto transformGroup = new QGroupBox(QStringLiteral("Bone Transform")); - transformLayout->addWidget(transformGroup); - auto transformGroupLayout = new QFormLayout(); - transformGroup->setLayout(transformGroupLayout); - - posEdit = new Vector3Edit(currentPosition); - connect(posEdit, &Vector3Edit::onValueChanged, [this, gearView] { - memcpy(currentEditedBone->position, glm::value_ptr(currentPosition), sizeof(float) * 3); + connect(this, &SklbPart::valueChanged, this, [gearView] { gearView->part().reloadRenderer(); }); - transformGroupLayout->addRow(QStringLiteral("Position"), posEdit); - - rotationEdit = new QuaternionEdit(currentRotation); - connect(rotationEdit, &QuaternionEdit::onValueChanged, [this, gearView] { - memcpy(currentEditedBone->rotation, glm::value_ptr(currentRotation), sizeof(float) * 4); - gearView->part().reloadRenderer(); - }); - transformGroupLayout->addRow(QStringLiteral("Rotation"), rotationEdit); - - scaleEdit = new Vector3Edit(currentScale); - connect(scaleEdit, &Vector3Edit::onValueChanged, [this, gearView] { - memcpy(currentEditedBone->scale, glm::value_ptr(currentScale), sizeof(float) * 3); - gearView->part().reloadRenderer(); - }); - transformGroupLayout->addRow(QStringLiteral("Scale"), scaleEdit); - - connect(boneListWidget, &QTreeWidget::itemClicked, this, &BoneEditor::treeItemClicked); - - auto raceDeformGroup = new QGroupBox(QStringLiteral("Race Deform")); - transformLayout->addWidget(raceDeformGroup); - auto raceDeformGroupLayout = new QFormLayout(); - raceDeformGroup->setLayout(raceDeformGroupLayout); - - raceDeformPosEdit = new Vector3Edit(currentRacePosition); - raceDeformGroupLayout->addRow(QStringLiteral("Position"), raceDeformPosEdit); - - raceDeformRotationEdit = new QuaternionEdit(currentRaceRotation); - raceDeformGroupLayout->addRow(QStringLiteral("Rotation"), raceDeformRotationEdit); - - raceDeformScaleEdit = new Vector3Edit(currentRaceScale); - raceDeformGroupLayout->addRow(QStringLiteral("Scale"), raceDeformScaleEdit); if (gearView->part().skeleton) { - addItem(*gearView->part().skeleton, *gearView->part().skeleton->root_bone, boneListWidget); - } -} - -void BoneEditor::treeItemClicked(QTreeWidgetItem *item, int column) -{ - auto &skeleton = *gearView->part().skeleton; - for (int i = 0; i < skeleton.num_bones; i++) { - 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]; - - posEdit->setVector(currentPosition); - rotationEdit->setQuat(currentRotation); - scaleEdit->setVector(currentScale); - - glm::mat4 transformation; // your transformation matrix. - glm::vec3 scale; - glm::quat rotation; - glm::vec3 translation; - glm::vec3 skew; - glm::vec4 perspective; - /*glm::decompose(gearView->part().boneData[i].deformRaceMatrix, scale, rotation, translation, skew, perspective); - - currentRacePosition = translation; - currentRaceRotation = rotation; - currentRaceScale = scale; - - raceDeformPosEdit->setVector(currentRacePosition); - raceDeformRotationEdit->setQuat(currentRaceRotation); - raceDeformScaleEdit->setVector(currentRaceScale);*/ - } + load(*gearView->part().skeleton); } } diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 2c033ff..30cc611 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -6,13 +6,17 @@ target_sources(novus-common PRIVATE include/aboutdata.h include/filecache.h include/novusmainwindow.h + include/quaternionedit.h include/settings.h include/utility.h + include/vec3edit.h src/aboutdata.cpp src/filecache.cpp src/novusmainwindow.cpp + src/quaternionedit.cpp src/settings.cpp - src/utility.cpp) + src/utility.cpp + src/vec3edit.cpp) target_include_directories(novus-common PUBLIC include PRIVATE diff --git a/armoury/include/quaternionedit.h b/common/include/quaternionedit.h similarity index 100% rename from armoury/include/quaternionedit.h rename to common/include/quaternionedit.h diff --git a/armoury/include/vec3edit.h b/common/include/vec3edit.h similarity index 100% rename from armoury/include/vec3edit.h rename to common/include/vec3edit.h diff --git a/armoury/src/quaternionedit.cpp b/common/src/quaternionedit.cpp similarity index 100% rename from armoury/src/quaternionedit.cpp rename to common/src/quaternionedit.cpp diff --git a/armoury/src/vec3edit.cpp b/common/src/vec3edit.cpp similarity index 100% rename from armoury/src/vec3edit.cpp rename to common/src/vec3edit.cpp diff --git a/parts/CMakeLists.txt b/parts/CMakeLists.txt index 2bb4cad..c76962c 100644 --- a/parts/CMakeLists.txt +++ b/parts/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(exl) add_subdirectory(hex) add_subdirectory(mdl) add_subdirectory(shpk) +add_subdirectory(sklb) add_subdirectory(tex) \ No newline at end of file diff --git a/parts/sklb/CMakeLists.txt b/parts/sklb/CMakeLists.txt new file mode 100644 index 0000000..14342d4 --- /dev/null +++ b/parts/sklb/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2023 Joshua Goins +# SPDX-License-Identifier: CC0-1.0 + +add_library(sklbpart STATIC) +target_sources(sklbpart PRIVATE + sklbpart.cpp + sklbpart.h) +target_link_libraries(sklbpart PUBLIC novus-common physis z Qt6::Core Qt6::Widgets) +target_include_directories(sklbpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) \ No newline at end of file diff --git a/parts/sklb/sklbpart.cpp b/parts/sklb/sklbpart.cpp new file mode 100644 index 0000000..3873970 --- /dev/null +++ b/parts/sklb/sklbpart.cpp @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "sklbpart.h" + +#include +#include +#include +#include +#include + +#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); + } + + for (int i = 0; i < skeleton.num_bones; i++) { + if (skeleton.bones[i].parent_bone != nullptr && strcmp(skeleton.bones[i].parent_bone->name, bone.name) == 0) + addItem(skeleton, skeleton.bones[i], widget, item); + } +} + +SklbPart::SklbPart() +{ + auto layout = new QHBoxLayout(); + setLayout(layout); + + boneListWidget = new QTreeWidget(); + boneListWidget->setHeaderLabel(QStringLiteral("Name")); + boneListWidget->setMaximumWidth(200); + + layout->addWidget(boneListWidget); + + auto transformLayout = new QVBoxLayout(); + layout->addLayout(transformLayout); + + auto transformGroup = new QGroupBox(QStringLiteral("Bone Transform")); + transformLayout->addWidget(transformGroup); + auto transformGroupLayout = new QFormLayout(); + transformGroup->setLayout(transformGroupLayout); + + posEdit = new Vector3Edit(currentPosition); + connect(posEdit, &Vector3Edit::onValueChanged, [this] { + memcpy(currentEditedBone->position, glm::value_ptr(currentPosition), sizeof(float) * 3); + Q_EMIT valueChanged(); + }); + transformGroupLayout->addRow(QStringLiteral("Position"), posEdit); + + rotationEdit = new QuaternionEdit(currentRotation); + connect(rotationEdit, &QuaternionEdit::onValueChanged, [this] { + memcpy(currentEditedBone->rotation, glm::value_ptr(currentRotation), sizeof(float) * 4); + Q_EMIT valueChanged(); + }); + transformGroupLayout->addRow(QStringLiteral("Rotation"), rotationEdit); + + scaleEdit = new Vector3Edit(currentScale); + connect(scaleEdit, &Vector3Edit::onValueChanged, [this] { + memcpy(currentEditedBone->scale, glm::value_ptr(currentScale), sizeof(float) * 3); + Q_EMIT valueChanged(); + }); + transformGroupLayout->addRow(QStringLiteral("Scale"), scaleEdit); + + connect(boneListWidget, &QTreeWidget::itemClicked, this, &SklbPart::treeItemClicked); +} + +void SklbPart::treeItemClicked(QTreeWidgetItem *item, int column) +{ + for (int i = 0; i < skeleton.num_bones; i++) { + 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]; + + posEdit->setVector(currentPosition); + rotationEdit->setQuat(currentRotation); + scaleEdit->setVector(currentScale); + } + } +} + +void SklbPart::clear() +{ + boneListWidget->clear(); +} + +void SklbPart::load(physis_Skeleton file) +{ + clear(); + addItem(file, *file.root_bone, boneListWidget); + skeleton = file; +} + +#include "moc_sklbpart.cpp" \ No newline at end of file diff --git a/parts/sklb/sklbpart.h b/parts/sklb/sklbpart.h new file mode 100644 index 0000000..89d1153 --- /dev/null +++ b/parts/sklb/sklbpart.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "quaternionedit.h" +#include "vec3edit.h" + +class SklbPart : public QWidget +{ + Q_OBJECT + +public: + explicit SklbPart(); + + void clear(); + void load(physis_Skeleton file); + +Q_SIGNALS: + void valueChanged(); + +private: + void treeItemClicked(QTreeWidgetItem *item, int column); + + QTreeWidget *boneListWidget = nullptr; + + glm::vec3 currentPosition; + glm::quat currentRotation; + glm::vec3 currentScale; + + physis_Bone *currentEditedBone = nullptr; + + Vector3Edit *posEdit = nullptr; + QuaternionEdit *rotationEdit = nullptr; + Vector3Edit *scaleEdit = nullptr; + physis_Skeleton skeleton; +}; \ No newline at end of file diff --git a/sagasu/CMakeLists.txt b/sagasu/CMakeLists.txt index 455fb27..ebd3fe7 100644 --- a/sagasu/CMakeLists.txt +++ b/sagasu/CMakeLists.txt @@ -22,6 +22,6 @@ target_sources(novus-sagasu PRIVATE src/filepropertieswindow.cpp src/filetreemodel.cpp) target_include_directories(novus-sagasu PRIVATE include) -target_link_libraries(novus-sagasu PRIVATE Qt6::Concurrent cmppart shpkpart hexpart exlpart mdlpart exdpart texpart novus-sagasu-static) +target_link_libraries(novus-sagasu PRIVATE Qt6::Concurrent sklbpart cmppart shpkpart hexpart exlpart mdlpart exdpart texpart novus-sagasu-static) install(TARGETS novus-sagasu ${KF${QT_MAJOR_VERSION}_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/sagasu/src/indexer.cpp b/sagasu/src/indexer.cpp index e41cc78..31e3756 100644 --- a/sagasu/src/indexer.cpp +++ b/sagasu/src/indexer.cpp @@ -15,7 +15,8 @@ const std::array known_folders{"common", "chara/human/c0101/obj/face/f0001/model", "shader/sm5/shpk", "chara/xls/bonedeformer", - "chara/xls/charamake"}; + "chara/xls/charamake", + "chara/human/c0101/skeleton/base/b0001"}; const std::array common_font{"common/VulgarWordsFilter.dic", "common/VulgarWordsFilter_party.dic", @@ -167,6 +168,7 @@ int main(int argc, char *argv[]) database.addFile(QStringLiteral("shader/sm5/shpk/character.shpk")); database.addFile(QStringLiteral("chara/xls/bonedeformer/human.pbd")); database.addFile(QStringLiteral("chara/xls/charamake/human.cmp")); + database.addFile(QStringLiteral("chara/human/c0101/skeleton/base/b0001/skl_c0101b0001.sklb")); /*const QString gameDir{getGameDirectory()}; const std::string gameDirStd{gameDir.toStdString()}; diff --git a/sagasu/src/mainwindow.cpp b/sagasu/src/mainwindow.cpp index ebb70a1..bb9d0b0 100644 --- a/sagasu/src/mainwindow.cpp +++ b/sagasu/src/mainwindow.cpp @@ -18,6 +18,7 @@ #include "hexpart.h" #include "mdlpart.h" #include "shpkpart.h" +#include "sklbpart.h" #include "texpart.h" MainWindow::MainWindow(QString gamePath, GameData *data) @@ -102,6 +103,10 @@ void MainWindow::refreshParts(QString path) auto cmpWidget = new CmpPart(data); cmpWidget->load(file); partHolder->addTab(cmpWidget, QStringLiteral("Chara Make Params")); + } else if (info.completeSuffix() == QStringLiteral("sklb")) { + auto sklbWidget = new SklbPart(); + sklbWidget->load(physis_parse_skeleton(file)); + partHolder->addTab(sklbWidget, QStringLiteral("Skeleton")); } auto hexWidget = new HexPart();