1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-04-25 05:17:44 +00:00

Add .clang-format and format mdlviewer

This commit is contained in:
Joshua Goins 2023-07-07 16:16:21 -04:00
parent 97dda3d091
commit d67a63710d
17 changed files with 326 additions and 351 deletions

33
.clang-format Normal file
View file

@ -0,0 +1,33 @@
---
AllowShortIfStatementsOnASingleLine: Never
CompactNamespaces: 'false'
DisableFormat: 'false'
IndentCaseLabels: 'true'
IndentPPDirectives: BeforeHash
IndentWidth: '4'
Language: Cpp
NamespaceIndentation: All
PointerAlignment: Left
ReflowComments: 'true'
SortIncludes: 'true'
SortUsingDeclarations: 'true'
SpacesInCStyleCastParentheses: 'false'
Standard: Cpp11
TabWidth: '0'
UseTab: Never
AllowShortEnumsOnASingleLine: false
BraceWrapping:
AfterEnum: true
AccessModifierOffset: -4
SpaceAfterTemplateKeyword: 'false'
AllowAllParametersOfDeclarationOnNextLine: false
AlignAfterOpenBracket: AlwaysBreak
BinPackArguments: false
BinPackParameters: false
ColumnLimit: 120
AllowShortBlocksOnASingleLine: 'false'
AllowShortCaseLabelsOnASingleLine: 'false'
AllowShortFunctionsOnASingleLine: 'Empty'
AllowShortLambdasOnASingleLine: 'Empty'
AllowShortLoopsOnASingleLine: 'false'
SeparateDefinitionBlocks: 'Always'

View file

@ -12,31 +12,31 @@
class GearView; class GearView;
class BoneEditor : public QWidget { class BoneEditor : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit BoneEditor(GearView *gearView, QWidget *parent = nullptr); explicit BoneEditor(GearView* gearView, QWidget* parent = nullptr);
private: private:
void treeItemClicked(QTreeWidgetItem *item, int column); void treeItemClicked(QTreeWidgetItem* item, int column);
GearView *gearView; GearView* gearView;
glm::vec3 currentPosition; glm::vec3 currentPosition;
glm::quat currentRotation; glm::quat currentRotation;
glm::vec3 currentScale; glm::vec3 currentScale;
glm::vec3 currentRacePosition; glm::vec3 currentRacePosition;
glm::quat currentRaceRotation; glm::quat currentRaceRotation;
glm::vec3 currentRaceScale; glm::vec3 currentRaceScale;
physis_Bone *currentEditedBone; physis_Bone* currentEditedBone;
Vector3Edit *posEdit; Vector3Edit* posEdit;
QuaternionEdit *rotationEdit; QuaternionEdit* rotationEdit;
Vector3Edit *scaleEdit; Vector3Edit* scaleEdit;
Vector3Edit *raceDeformPosEdit; Vector3Edit* raceDeformPosEdit;
QuaternionEdit *raceDeformRotationEdit; QuaternionEdit* raceDeformRotationEdit;
Vector3Edit *raceDeformScaleEdit; Vector3Edit* raceDeformScaleEdit;
}; };

View file

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <QDoubleSpinBox>
#include <QWidget> #include <QWidget>
#include <physis.hpp> #include <physis.hpp>
#include <QDoubleSpinBox>
class RaceTreeData : public QObject { class RaceTreeData : public QObject {
Q_OBJECT Q_OBJECT

View file

@ -14,14 +14,14 @@ public:
Q_SIGNALS: Q_SIGNALS:
void gearChanged(); void gearChanged();
public Q_SLOTS: public Q_SLOTS:
void clear(); void clear();
void addGear(GearInfo &info); void addGear(GearInfo& info);
private Q_SLOTS: private Q_SLOTS:
void reloadGear(); void reloadGear();
private: private:
void updateHeightScaling(float scale); void updateHeightScaling(float scale);
void updateBustScaling(float scale); void updateBustScaling(float scale);
void updateCharacterParameters(); void updateCharacterParameters();
@ -29,10 +29,10 @@ Q_SIGNALS:
std::optional<GearInfo> topSlot; std::optional<GearInfo> topSlot;
std::optional<GearInfo> bottomSlot; std::optional<GearInfo> bottomSlot;
GearView *gearView = nullptr; GearView* gearView = nullptr;
QComboBox *raceCombo, *genderCombo; QComboBox *raceCombo, *subraceCombo, *genderCombo;
GameData *data = nullptr; GameData* data = nullptr;
physis_CMP cmp; physis_CMP cmp;
float heightScale = 0.5f; float heightScale = 0.5f;

View file

@ -1,10 +1,10 @@
#pragma once #pragma once
#include <QWidget>
#include <physis.hpp>
#include <fmt/format.h>
#include <QComboBox>
#include "mdlpart.h" #include "mdlpart.h"
#include <QComboBox>
#include <QWidget>
#include <fmt/format.h>
#include <physis.hpp>
struct ModelInfo { struct ModelInfo {
int primaryID; int primaryID;
@ -17,11 +17,12 @@ struct GearInfo {
ModelInfo modelInfo; ModelInfo modelInfo;
std::string getMtrlPath(int raceID) { std::string getMtrlPath(int raceID) {
return fmt::format("chara/equipment/e{gearId:04d}/material/v{gearVersion:04d}/mt_c{raceId:04d}e{gearId:04d}_{slot}_a.mtrl", return fmt::format(
fmt::arg("gearId", modelInfo.primaryID), "chara/equipment/e{gearId:04d}/material/v{gearVersion:04d}/mt_c{raceId:04d}e{gearId:04d}_{slot}_a.mtrl",
fmt::arg("gearVersion", modelInfo.gearVersion), fmt::arg("gearId", modelInfo.primaryID),
fmt::arg("raceId", raceID), fmt::arg("gearVersion", modelInfo.gearVersion),
fmt::arg("slot", physis_get_slot_name(slot))); fmt::arg("raceId", raceID),
fmt::arg("slot", physis_get_slot_name(slot)));
} }
}; };
@ -41,15 +42,15 @@ public:
/// Returns an inclusive list of LoDs supported by the current gearset. /// Returns an inclusive list of LoDs supported by the current gearset.
int lodCount() const; int lodCount() const;
void exportModel(const QString &fileName); void exportModel(const QString& fileName);
MDLPart &part() const; MDLPart& part() const;
Race currentRace = Race::Hyur; Race currentRace = Race::Hyur;
Subrace currentSubrace = Subrace::Midlander; Subrace currentSubrace = Subrace::Midlander;
Gender currentGender = Gender::Male; Gender currentGender = Gender::Male;
Q_SIGNALS: Q_SIGNALS:
void gearChanged(); void gearChanged();
void modelReloaded(); void modelReloaded();
@ -58,7 +59,7 @@ public:
void genderChanged(); void genderChanged();
void levelOfDetailChanged(); void levelOfDetailChanged();
public Q_SLOTS: public Q_SLOTS:
void clear(); void clear();
void addGear(GearInfo& gear); void addGear(GearInfo& gear);
@ -70,7 +71,7 @@ public:
void reloadModel(); void reloadModel();
void reloadRaceDeforms(); void reloadRaceDeforms();
private: private:
int currentLod = 0; int currentLod = 0;
uint32_t maxLod = 0; uint32_t maxLod = 0;

View file

@ -6,8 +6,8 @@
#include <physis.hpp> #include <physis.hpp>
#include <unordered_map> #include <unordered_map>
#include "gearview.h"
#include "fullmodelviewer.h" #include "fullmodelviewer.h"
#include "gearview.h"
#include "singlegearview.h" #include "singlegearview.h"
struct GameData; struct GameData;

View file

@ -6,7 +6,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
class QuaternionEdit : public QWidget { class QuaternionEdit : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit QuaternionEdit(glm::quat& quat, QWidget* parent = nullptr); explicit QuaternionEdit(glm::quat& quat, QWidget* parent = nullptr);

View file

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <QWidget>
#include <QPushButton>
#include "gearview.h" #include "gearview.h"
#include <QPushButton>
#include <QWidget>
struct GameData; struct GameData;
@ -41,7 +41,7 @@ private:
Gender currentGender = Gender::Female; Gender currentGender = Gender::Female;
int currentLod = 0; int currentLod = 0;
GearView *gearView = nullptr; GearView* gearView = nullptr;
QComboBox *raceCombo, *subraceCombo, *genderCombo, *lodCombo; QComboBox *raceCombo, *subraceCombo, *genderCombo, *lodCombo;
QPushButton *addToFMVButton, *exportButton; QPushButton *addToFMVButton, *exportButton;

View file

@ -5,7 +5,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
class Vector3Edit : public QWidget { class Vector3Edit : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit Vector3Edit(glm::vec3& vec, QWidget* parent = nullptr); explicit Vector3Edit(glm::vec3& vec, QWidget* parent = nullptr);
~Vector3Edit(); ~Vector3Edit();

View file

@ -7,39 +7,40 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/matrix_decompose.hpp> #include <glm/gtx/matrix_decompose.hpp>
#include "vec3edit.h"
#include "quaternionedit.h"
#include "gearview.h" #include "gearview.h"
#include "quaternionedit.h"
#include "vec3edit.h"
void addItem(physis_Skeleton& skeleton, physis_Bone& bone, QTreeWidget* widget, QTreeWidgetItem* parent_item = nullptr) { void addItem(
physis_Skeleton& skeleton,
physis_Bone& bone,
QTreeWidget* widget,
QTreeWidgetItem* parent_item = nullptr) {
auto item = new QTreeWidgetItem(); auto item = new QTreeWidgetItem();
item->setText(0, bone.name); item->setText(0, bone.name);
if(parent_item == nullptr) { if (parent_item == nullptr) {
widget->addTopLevelItem(item); widget->addTopLevelItem(item);
} else { } else {
parent_item->addChild(item); parent_item->addChild(item);
} }
for(int i = 0; i < skeleton.num_bones; i++) { 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) if (skeleton.bones[i].parent_bone != nullptr && strcmp(skeleton.bones[i].parent_bone->name, bone.name) == 0)
addItem(skeleton, skeleton.bones[i], widget, item); addItem(skeleton, skeleton.bones[i], widget, item);
} }
} }
BoneEditor::BoneEditor(GearView *gearView, QWidget *parent) BoneEditor::BoneEditor(GearView* gearView, QWidget* parent) : gearView(gearView) {
: gearView(gearView) {
auto layout = new QHBoxLayout(); auto layout = new QHBoxLayout();
setLayout(layout); setLayout(layout);
auto boneListWidget = new QTreeWidget(); auto boneListWidget = new QTreeWidget();
connect(gearView, &GearView::modelReloaded, this, connect(gearView, &GearView::modelReloaded, this, [this, boneListWidget, gearView] {
[this, boneListWidget, gearView] { boneListWidget->clear();
boneListWidget->clear(); addItem(*gearView->part().skeleton, *gearView->part().skeleton->root_bone, boneListWidget);
addItem(*gearView->part().skeleton, });
*gearView->part().skeleton->root_bone, boneListWidget);
});
boneListWidget->setMaximumWidth(200); boneListWidget->setMaximumWidth(200);
@ -52,30 +53,26 @@ BoneEditor::BoneEditor(GearView *gearView, QWidget *parent)
posEdit = new Vector3Edit(currentPosition); posEdit = new Vector3Edit(currentPosition);
connect(posEdit, &Vector3Edit::onValueChanged, [this, gearView] { connect(posEdit, &Vector3Edit::onValueChanged, [this, gearView] {
memcpy(currentEditedBone->position, glm::value_ptr(currentPosition), memcpy(currentEditedBone->position, glm::value_ptr(currentPosition), sizeof(float) * 3);
sizeof(float) * 3); gearView->part().reloadRenderer();
gearView->part().reloadRenderer();
}); });
transformGroupLayout->addRow("Position", posEdit); transformGroupLayout->addRow("Position", posEdit);
rotationEdit = new QuaternionEdit(currentRotation); rotationEdit = new QuaternionEdit(currentRotation);
connect(rotationEdit, &QuaternionEdit::onValueChanged, [this, gearView] { connect(rotationEdit, &QuaternionEdit::onValueChanged, [this, gearView] {
memcpy(currentEditedBone->rotation, glm::value_ptr(currentRotation), memcpy(currentEditedBone->rotation, glm::value_ptr(currentRotation), sizeof(float) * 4);
sizeof(float) * 4); gearView->part().reloadRenderer();
gearView->part().reloadRenderer();
}); });
transformGroupLayout->addRow("Rotation", rotationEdit); transformGroupLayout->addRow("Rotation", rotationEdit);
scaleEdit = new Vector3Edit(currentScale); scaleEdit = new Vector3Edit(currentScale);
connect(scaleEdit, &Vector3Edit::onValueChanged, [this, gearView] { connect(scaleEdit, &Vector3Edit::onValueChanged, [this, gearView] {
memcpy(currentEditedBone->scale, glm::value_ptr(currentScale), memcpy(currentEditedBone->scale, glm::value_ptr(currentScale), sizeof(float) * 3);
sizeof(float) * 3); gearView->part().reloadRenderer();
gearView->part().reloadRenderer();
}); });
transformGroupLayout->addRow("Scale", scaleEdit); transformGroupLayout->addRow("Scale", scaleEdit);
connect(boneListWidget, &QTreeWidget::itemClicked, this, connect(boneListWidget, &QTreeWidget::itemClicked, this, &BoneEditor::treeItemClicked);
&BoneEditor::treeItemClicked);
auto raceDeformGroup = new QGroupBox("Race Deform"); auto raceDeformGroup = new QGroupBox("Race Deform");
layout->addWidget(raceDeformGroup); layout->addWidget(raceDeformGroup);
@ -92,11 +89,10 @@ BoneEditor::BoneEditor(GearView *gearView, QWidget *parent)
raceDeformGroupLayout->addRow("Scale", raceDeformScaleEdit); raceDeformGroupLayout->addRow("Scale", raceDeformScaleEdit);
} }
void BoneEditor::treeItemClicked(QTreeWidgetItem *item, int column) { void BoneEditor::treeItemClicked(QTreeWidgetItem* item, int column) {
auto &skeleton = *gearView->part().skeleton; auto& skeleton = *gearView->part().skeleton;
for (int i = 0; i < skeleton.num_bones; i++) { for (int i = 0; i < skeleton.num_bones; i++) {
if (strcmp(skeleton.bones[i].name, if (strcmp(skeleton.bones[i].name, item->text(column).toStdString().c_str()) == 0) {
item->text(column).toStdString().c_str()) == 0) {
currentPosition = glm::make_vec3(skeleton.bones[i].position); currentPosition = glm::make_vec3(skeleton.bones[i].position);
currentRotation = glm::make_quat(skeleton.bones[i].rotation); currentRotation = glm::make_quat(skeleton.bones[i].rotation);
currentScale = glm::make_vec3(skeleton.bones[i].scale); currentScale = glm::make_vec3(skeleton.bones[i].scale);
@ -112,8 +108,8 @@ void BoneEditor::treeItemClicked(QTreeWidgetItem *item, int column) {
glm::vec3 translation; glm::vec3 translation;
glm::vec3 skew; glm::vec3 skew;
glm::vec4 perspective; glm::vec4 perspective;
glm::decompose(gearView->part().boneData[i].deformRaceMatrix, scale, glm::decompose(
rotation, translation, skew, perspective); gearView->part().boneData[i].deformRaceMatrix, scale, rotation, translation, skew, perspective);
currentRacePosition = translation; currentRacePosition = translation;
currentRaceRotation = rotation; currentRaceRotation = rotation;

View file

@ -1,9 +1,9 @@
#include "cmpeditor.h" #include "cmpeditor.h"
#include <QTreeWidget>
#include <QHBoxLayout>
#include <QFormLayout> #include <QFormLayout>
#include <QGroupBox> #include <QGroupBox>
#include <QHBoxLayout>
#include <QTreeWidget>
#include "magic_enum.hpp" #include "magic_enum.hpp"
@ -14,63 +14,14 @@ struct RaceTree {
}; };
std::vector<RaceTree> raceTree = { std::vector<RaceTree> raceTree = {
{ {Race::Hyur, {Subrace::Midlander, Subrace::Highlander}},
Race::Hyur, {Race::Elezen, {Subrace::Wildwood, Subrace::Duskwight}},
{ {Race::Miqote, {Subrace::Seeker, Subrace::Keeper}},
Subrace::Midlander, {Race::Roegadyn, {Subrace::SeaWolf, Subrace::Hellion}},
Subrace::Highlander {Race::Lalafell, {Subrace::Plainsfolk, Subrace::Dunesfolk}},
} {Race::AuRa, {Subrace::Raen, Subrace::Xaela}},
}, {Race::Hrothgar, {Subrace::Hellion, Subrace::Lost}},
{ {Race::Viera, {Subrace::Rava, Subrace::Veena}}};
Race::Elezen,
{
Subrace::Wildwood,
Subrace::Duskwight
}
},
{
Race::Miqote,
{
Subrace::Seeker,
Subrace::Keeper
}
},
{
Race::Roegadyn,
{
Subrace::SeaWolf,
Subrace::Hellion
}
},
{
Race::Lalafell,
{
Subrace::Plainsfolk,
Subrace::Dunesfolk
}
},
{
Race::AuRa,
{
Subrace::Raen,
Subrace::Xaela
}
},
{
Race::Hrothgar,
{
Subrace::Hellion,
Subrace::Lost
}
},
{
Race::Viera,
{
Subrace::Rava,
Subrace::Veena
}
}
};
CmpEditor::CmpEditor(GameData* data) : data(data) { CmpEditor::CmpEditor(GameData* data) : data(data) {
auto layout = new QHBoxLayout(); auto layout = new QHBoxLayout();
@ -82,7 +33,7 @@ CmpEditor::CmpEditor(GameData* data) : data(data) {
raceListWidget->setMaximumWidth(200); raceListWidget->setMaximumWidth(200);
layout->addWidget(raceListWidget); layout->addWidget(raceListWidget);
for(auto race : raceTree) { for (auto race : raceTree) {
auto item = new QTreeWidgetItem(); auto item = new QTreeWidgetItem();
item->setText(0, magic_enum::enum_name(race.baseRace).data()); item->setText(0, magic_enum::enum_name(race.baseRace).data());
raceListWidget->addTopLevelItem(item); raceListWidget->addTopLevelItem(item);

View file

@ -6,63 +6,62 @@
#include <QGroupBox> #include <QGroupBox>
#include <QVBoxLayout> #include <QVBoxLayout>
FullModelViewer::FullModelViewer(GameData *data) : data(data) { FullModelViewer::FullModelViewer(GameData* data) : data(data) {
setWindowTitle("Full Model Viewer"); setWindowTitle("Full Model Viewer");
setMinimumWidth(640); setMinimumWidth(640);
setMinimumHeight(480); setMinimumHeight(480);
auto layout = new QVBoxLayout(); auto layout = new QVBoxLayout();
setLayout(layout); setLayout(layout);
cmp = physis_cmp_parse( cmp = physis_cmp_parse(physis_gamedata_extract_file(data, "chara/xls/charamake/human.cmp"));
physis_gamedata_extract_file(data, "chara/xls/charamake/human.cmp"));
gearView = new GearView(data); gearView = new GearView(data);
updateCharacterParameters(); updateCharacterParameters();
connect(gearView, &GearView::modelReloaded, this, connect(gearView, &GearView::modelReloaded, this, &FullModelViewer::updateCharacterParameters);
&FullModelViewer::updateCharacterParameters);
auto viewportLayout = new QHBoxLayout(); auto viewportLayout = new QHBoxLayout();
viewportLayout->addWidget(gearView, 1); viewportLayout->addWidget(gearView, 1);
layout->addLayout(viewportLayout); layout->addLayout(viewportLayout);
auto characterEditorWidget = new QWidget(); auto characterEditorWidget = new QWidget();
auto characterEditorLayout = new QFormLayout(); auto characterEditorLayout = new QFormLayout();
characterEditorWidget->setLayout(characterEditorLayout); characterEditorWidget->setLayout(characterEditorLayout);
auto characterHeight = new QSlider(); auto characterHeight = new QSlider();
characterHeight->setOrientation(Qt::Horizontal); characterHeight->setOrientation(Qt::Horizontal);
characterHeight->setSliderPosition(50); characterHeight->setSliderPosition(50);
connect(characterHeight, &QSlider::sliderMoved, this, [this](int position) { connect(characterHeight, &QSlider::sliderMoved, this, [this](int position) {
const float scale = (float)position / 100.0f; const float scale = (float)position / 100.0f;
updateHeightScaling(scale); updateHeightScaling(scale);
}); });
characterEditorLayout->addRow("Height", characterHeight); characterEditorLayout->addRow("Height", characterHeight);
auto bustSize = new QSlider(); auto bustSize = new QSlider();
bustSize->setOrientation(Qt::Horizontal); bustSize->setOrientation(Qt::Horizontal);
bustSize->setSliderPosition(50); bustSize->setSliderPosition(50);
connect(bustSize, &QSlider::sliderMoved, this, [this](int position) { connect(bustSize, &QSlider::sliderMoved, this, [this](int position) {
const float scale = (float)position / 100.0f; const float scale = (float)position / 100.0f;
updateBustScaling(scale); updateBustScaling(scale);
}); });
characterEditorLayout->addRow("Bust Size", bustSize); characterEditorLayout->addRow("Bust Size", bustSize);
auto tabWidget = new QTabWidget(); auto tabWidget = new QTabWidget();
tabWidget->addTab(new BoneEditor(gearView), "Bone Editor"); tabWidget->addTab(new BoneEditor(gearView), "Bone Editor");
tabWidget->addTab(characterEditorWidget, "Character Editor"); tabWidget->addTab(characterEditorWidget, "Character Editor");
viewportLayout->addWidget(tabWidget); viewportLayout->addWidget(tabWidget);
auto controlLayout = new QHBoxLayout(); auto controlLayout = new QHBoxLayout();
layout->addLayout(controlLayout); layout->addLayout(controlLayout);
raceCombo = new QComboBox(); raceCombo = new QComboBox();
connect(raceCombo, qOverload<int>(&QComboBox::currentIndexChanged), connect(raceCombo, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
[this](int index) { gearView->setRace((Race)index); }); gearView->setRace((Race)index);
controlLayout->addWidget(raceCombo); });
controlLayout->addWidget(raceCombo);
for (auto [race, race_name] : magic_enum::enum_entries<Race>()) { for (auto [race, race_name] : magic_enum::enum_entries<Race>()) {
raceCombo->addItem(race_name.data()); raceCombo->addItem(race_name.data());
} }
@ -88,8 +87,8 @@ void FullModelViewer::clear() {
Q_EMIT gearChanged(); Q_EMIT gearChanged();
} }
void FullModelViewer::addGear(GearInfo &info) { void FullModelViewer::addGear(GearInfo& info) {
switch(info.slot) { switch (info.slot) {
case Slot::Body: case Slot::Body:
topSlot = info; topSlot = info;
break; break;
@ -130,27 +129,25 @@ void FullModelViewer::reloadGear() {
} }
void FullModelViewer::updateHeightScaling(float scale) { void FullModelViewer::updateHeightScaling(float scale) {
auto &boneData = *gearView->part().skeleton; auto& boneData = *gearView->part().skeleton;
for (int i = 0; i < boneData.num_bones; i++) { for (int i = 0; i < boneData.num_bones; i++) {
const std::string_view name{boneData.bones[i].name}; const std::string_view name{boneData.bones[i].name};
if (name == "n_root") { if (name == "n_root") {
auto racialScaling = physis_cmp_get_racial_scaling_parameters( auto racialScaling =
cmp, gearView->currentRace, gearView->currentSubrace); physis_cmp_get_racial_scaling_parameters(cmp, gearView->currentRace, gearView->currentSubrace);
const float minSize = gearView->currentGender == Gender::Male const float minSize =
? racialScaling.male_min_size gearView->currentGender == Gender::Male ? racialScaling.male_min_size : racialScaling.female_min_size;
: racialScaling.female_min_size; const float maxSize =
const float maxSize = gearView->currentGender == Gender::Male gearView->currentGender == Gender::Male ? racialScaling.male_max_size : racialScaling.female_max_size;
? racialScaling.male_max_size
: racialScaling.female_max_size;
const float size = glm::mix(minSize, maxSize, scale); const float size = glm::mix(minSize, maxSize, scale);
boneData.bones[i].scale[0] = size; boneData.bones[i].scale[0] = size;
boneData.bones[i].scale[1] = size; boneData.bones[i].scale[1] = size;
boneData.bones[i].scale[2] = size; boneData.bones[i].scale[2] = size;
gearView->part().reloadRenderer(); gearView->part().reloadRenderer();
} }
} }
@ -158,25 +155,22 @@ void FullModelViewer::updateHeightScaling(float scale) {
} }
void FullModelViewer::updateBustScaling(float scale) { void FullModelViewer::updateBustScaling(float scale) {
auto &boneData = *gearView->part().skeleton; auto& boneData = *gearView->part().skeleton;
for (int i = 0; i < boneData.num_bones; i++) { for (int i = 0; i < boneData.num_bones; i++) {
const std::string_view name{boneData.bones[i].name}; const std::string_view name{boneData.bones[i].name};
if (name == "j_mune_l" || name == "j_mune_r") { if (name == "j_mune_l" || name == "j_mune_r") {
auto racialScaling = physis_cmp_get_racial_scaling_parameters( auto racialScaling =
cmp, gearView->currentRace, gearView->currentSubrace); physis_cmp_get_racial_scaling_parameters(cmp, gearView->currentRace, gearView->currentSubrace);
const float rangeX = glm::mix(racialScaling.bust_min_x, const float rangeX = glm::mix(racialScaling.bust_min_x, racialScaling.bust_max_x, scale);
racialScaling.bust_max_x, scale); const float rangeY = glm::mix(racialScaling.bust_min_y, racialScaling.bust_max_y, scale);
const float rangeY = glm::mix(racialScaling.bust_min_y, const float rangeZ = glm::mix(racialScaling.bust_min_z, racialScaling.bust_max_z, scale);
racialScaling.bust_max_y, scale);
const float rangeZ = glm::mix(racialScaling.bust_min_z,
racialScaling.bust_max_z, scale);
boneData.bones[i].scale[0] = rangeX; boneData.bones[i].scale[0] = rangeX;
boneData.bones[i].scale[1] = rangeY; boneData.bones[i].scale[1] = rangeY;
boneData.bones[i].scale[2] = rangeZ; boneData.bones[i].scale[2] = rangeZ;
gearView->part().reloadRenderer(); gearView->part().reloadRenderer();
} }
} }

View file

@ -1,44 +1,46 @@
#include "gearview.h" #include "gearview.h"
#include "magic_enum.hpp" #include "magic_enum.hpp"
#include <QVBoxLayout>
#include <QDebug> #include <QDebug>
#include <QVBoxLayout>
GearView::GearView(GameData *data) : data(data) { GearView::GearView(GameData* data) : data(data) {
mdlPart = new MDLPart(data); mdlPart = new MDLPart(data);
reloadRaceDeforms();
auto layout = new QVBoxLayout();
layout->addWidget(mdlPart);
setLayout(layout);
connect(this, &GearView::gearChanged, this, [=] { reloadModel(); });
connect(this, &GearView::raceChanged, this, [=] {
reloadRaceDeforms(); reloadRaceDeforms();
reloadModel();
}); auto layout = new QVBoxLayout();
connect(this, &GearView::genderChanged, this, [=] { layout->addWidget(mdlPart);
reloadRaceDeforms(); setLayout(layout);
reloadModel();
}); connect(this, &GearView::gearChanged, this, [=] {
connect(this, &GearView::levelOfDetailChanged, this, &GearView::reloadModel); reloadModel();
});
connect(this, &GearView::raceChanged, this, [=] {
reloadRaceDeforms();
reloadModel();
});
connect(this, &GearView::genderChanged, this, [=] {
reloadRaceDeforms();
reloadModel();
});
connect(this, &GearView::levelOfDetailChanged, this, &GearView::reloadModel);
} }
std::vector<std::pair<Race, Subrace>> GearView::supportedRaces() const { std::vector<std::pair<Race, Subrace>> GearView::supportedRaces() const {
std::vector<std::pair<Race, Subrace>> races; std::vector<std::pair<Race, Subrace>> races;
for (const auto &gear : gears) { for (const auto& gear : gears) {
for (auto [race, race_name] : magic_enum::enum_entries<Race>()) { for (auto [race, race_name] : magic_enum::enum_entries<Race>()) {
for (auto subrace : physis_get_supported_subraces(race).subraces) { for (auto subrace : physis_get_supported_subraces(race).subraces) {
auto equip_path = physis_build_equipment_path( auto equip_path =
gear.modelInfo.primaryID, race, subrace, currentGender, gear.slot); physis_build_equipment_path(gear.modelInfo.primaryID, race, subrace, currentGender, gear.slot);
if (physis_gamedata_exists(data, equip_path)) if (physis_gamedata_exists(data, equip_path))
races.emplace_back(race, subrace); races.emplace_back(race, subrace);
} }
}
} }
}
return races; return races;
} }
@ -46,10 +48,11 @@ std::vector<std::pair<Race, Subrace>> GearView::supportedRaces() const {
std::vector<Gender> GearView::supportedGenders() const { std::vector<Gender> GearView::supportedGenders() const {
std::vector<Gender> genders; std::vector<Gender> genders;
for (const auto& gear : gears) { for (const auto& gear : gears) {
for(auto [gender, gender_name] : magic_enum::enum_entries<Gender>()) { for (auto [gender, gender_name] : magic_enum::enum_entries<Gender>()) {
auto equip_path = physis_build_equipment_path(gear.modelInfo.primaryID, currentRace, Subrace::Midlander, currentGender, gear.slot); auto equip_path = physis_build_equipment_path(
gear.modelInfo.primaryID, currentRace, Subrace::Midlander, currentGender, gear.slot);
if(physis_gamedata_exists(data, equip_path)) if (physis_gamedata_exists(data, equip_path))
genders.push_back(gender); genders.push_back(gender);
} }
} }
@ -61,7 +64,7 @@ int GearView::lodCount() const {
return maxLod; return maxLod;
} }
void GearView::exportModel(const QString &fileName) { void GearView::exportModel(const QString& fileName) {
mdlPart->exportModel(fileName); mdlPart->exportModel(fileName);
} }
@ -87,8 +90,7 @@ void GearView::setRace(Race race) {
currentRace = race; currentRace = race;
auto supportedSubraces = physis_get_supported_subraces(race); auto supportedSubraces = physis_get_supported_subraces(race);
if (supportedSubraces.subraces[0] == currentSubrace || if (supportedSubraces.subraces[0] == currentSubrace || supportedSubraces.subraces[1] == currentSubrace) {
supportedSubraces.subraces[1] == currentSubrace) {
} else { } else {
setSubrace(supportedSubraces.subraces[0]); setSubrace(supportedSubraces.subraces[0]);
} }
@ -130,9 +132,9 @@ void GearView::reloadModel() {
for (const auto& gear : gears) { for (const auto& gear : gears) {
auto mdl_data = physis_gamedata_extract_file( auto mdl_data = physis_gamedata_extract_file(
data, physis_build_equipment_path(gear.modelInfo.primaryID, data,
currentRace, currentSubrace, physis_build_equipment_path(
currentGender, gear.slot)); gear.modelInfo.primaryID, currentRace, currentSubrace, currentGender, gear.slot));
// attempt to load the next best race // attempt to load the next best race
// currently hardcoded to hyur midlander // currently hardcoded to hyur midlander
@ -140,9 +142,9 @@ void GearView::reloadModel() {
Subrace fallbackSubrace = currentSubrace; Subrace fallbackSubrace = currentSubrace;
if (mdl_data.size == 0) { if (mdl_data.size == 0) {
mdl_data = physis_gamedata_extract_file( mdl_data = physis_gamedata_extract_file(
data, physis_build_equipment_path( data,
gear.modelInfo.primaryID, Race::Hyur, physis_build_equipment_path(
Subrace::Midlander, currentGender, gear.slot)); gear.modelInfo.primaryID, Race::Hyur, Subrace::Midlander, currentGender, gear.slot));
fallbackRace = Race::Hyur; fallbackRace = Race::Hyur;
fallbackSubrace = Subrace::Midlander; fallbackSubrace = Subrace::Midlander;
} }
@ -152,15 +154,16 @@ void GearView::reloadModel() {
std::vector<physis_Material> materials; std::vector<physis_Material> materials;
for (int i = 0; i < mdl.num_material_names; i++) { for (int i = 0; i < mdl.num_material_names; i++) {
const char *material_name = mdl.material_names[i]; const char* material_name = mdl.material_names[i];
// std::string mtrl_path = // std::string mtrl_path =
// loadedGear.gearInfo->getMtrlPath(201); // loadedGear.gearInfo->getMtrlPath(201);
std::string mtrl_path = fmt::format( std::string mtrl_path = fmt::format(
"chara/equipment/e{gearId:04d}/material/" "chara/equipment/e{gearId:04d}/material/"
"v{gearVersion:04d}{}", "v{gearVersion:04d}{}",
material_name, fmt::arg("gearId", gear.modelInfo.primaryID), material_name,
fmt::arg("gearVersion", gear.modelInfo.gearVersion)); fmt::arg("gearId", gear.modelInfo.primaryID),
fmt::arg("gearVersion", gear.modelInfo.gearVersion));
int bodyCode = 1; int bodyCode = 1;
@ -169,17 +172,15 @@ void GearView::reloadModel() {
"chara/human/c{raceCode:04d}/obj/body/b{bodyCode:04d}/" "chara/human/c{raceCode:04d}/obj/body/b{bodyCode:04d}/"
"material/v0001{}", "material/v0001{}",
material_name, material_name,
fmt::arg("raceCode", fmt::arg("raceCode", physis_get_race_code(fallbackRace, fallbackSubrace, currentGender)),
physis_get_race_code(fallbackRace, fallbackSubrace,
currentGender)),
fmt::arg("bodyCode", bodyCode)); fmt::arg("bodyCode", bodyCode));
if(physis_gamedata_exists(data, mtrl_path.c_str())) { if (physis_gamedata_exists(data, mtrl_path.c_str())) {
auto mat = physis_material_parse(physis_gamedata_extract_file(data, mtrl_path.c_str())); auto mat = physis_material_parse(physis_gamedata_extract_file(data, mtrl_path.c_str()));
materials.push_back(mat); materials.push_back(mat);
} }
if(physis_gamedata_exists(data, skinmtrl_path.c_str())) { if (physis_gamedata_exists(data, skinmtrl_path.c_str())) {
auto mat = physis_material_parse(physis_gamedata_extract_file(data, skinmtrl_path.c_str())); auto mat = physis_material_parse(physis_gamedata_extract_file(data, skinmtrl_path.c_str()));
materials.push_back(mat); materials.push_back(mat);
} }
@ -195,32 +196,27 @@ void GearView::reloadModel() {
} }
void GearView::reloadRaceDeforms() { void GearView::reloadRaceDeforms() {
qDebug() << "Loading race deform matrices for " qDebug() << "Loading race deform matrices for " << magic_enum::enum_name(currentRace).data()
<< magic_enum::enum_name(currentRace).data() << magic_enum::enum_name(currentSubrace).data() << magic_enum::enum_name(currentGender).data();
<< magic_enum::enum_name(currentSubrace).data() const int raceCode = physis_get_race_code(currentRace, currentSubrace, currentGender);
<< magic_enum::enum_name(currentGender).data();
const int raceCode =
physis_get_race_code(currentRace, currentSubrace, currentGender);
qDebug() << "Race code: " << raceCode; qDebug() << "Race code: " << raceCode;
QString skelName = QString skelName = QString{"c%1b0001.skel"}.arg(raceCode, 4, 10, QLatin1Char{'0'});
QString{"c%1b0001.skel"}.arg(raceCode, 4, 10, QLatin1Char{'0'}); mdlPart->setSkeleton(physis_skeleton_from_skel(physis_read_file(skelName.toStdString().c_str())));
mdlPart->setSkeleton(physis_skeleton_from_skel(
physis_read_file(skelName.toStdString().c_str())));
// racial deforms don't work on Hyur, not needed? TODO not sure // racial deforms don't work on Hyur, not needed? TODO not sure
if (currentRace != Race::Hyur) { if (currentRace != Race::Hyur) {
QString deformName = QString deformName = QString{"c%1_deform.json"}.arg(raceCode, 4, 10, QLatin1Char{'0'});
QString{"c%1_deform.json"}.arg(raceCode, 4, 10, QLatin1Char{'0'}); mdlPart->loadRaceDeformMatrices(physis_read_file(deformName.toStdString().c_str()));
mdlPart->loadRaceDeformMatrices(
physis_read_file(deformName.toStdString().c_str()));
} else { } else {
for (auto &data : mdlPart->boneData) { for (auto& data : mdlPart->boneData) {
data.deformRaceMatrix = glm::mat4(1.0f); data.deformRaceMatrix = glm::mat4(1.0f);
} }
} }
} }
MDLPart &GearView::part() const { return *mdlPart; } MDLPart& GearView::part() const {
return *mdlPart;
}
#include "moc_gearview.cpp" #include "moc_gearview.cpp"

View file

@ -1,18 +1,18 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QTableWidget>
#include <QListWidget>
#include <QLineEdit> #include <QLineEdit>
#include <QListWidget>
#include <QTableWidget>
#include <QTimer> #include <QTimer>
#include <QPushButton>
#include <QFileDialog>
#include <magic_enum.hpp>
#include <QMenuBar>
#include <QAction> #include <QAction>
#include <glm/gtc/type_ptr.hpp> #include <QFileDialog>
#include <QMenuBar>
#include <QPushButton>
#include <QTreeWidget> #include <QTreeWidget>
#include <glm/gtc/type_ptr.hpp>
#include <magic_enum.hpp>
#include <physis.hpp> #include <physis.hpp>
#include "cmpeditor.h" #include "cmpeditor.h"
@ -73,7 +73,7 @@ MainWindow::MainWindow(GameData* in_data) : data(*in_data) {
auto exh = physis_gamedata_read_excel_sheet_header(&data, "Item"); auto exh = physis_gamedata_read_excel_sheet_header(&data, "Item");
auto exd = physis_gamedata_read_excel_sheet(&data, "Item", exh, Language::English, 1); auto exd = physis_gamedata_read_excel_sheet(&data, "Item", exh, Language::English, 1);
for(int i = 0; i < exd.row_count; i++) { for (int i = 0; i < exd.row_count; i++) {
const auto row = exd.row_data[i]; const auto row = exd.row_data[i];
auto primaryModel = row.column_data[47].u_int64._0; auto primaryModel = row.column_data[47].u_int64._0;
auto secondaryModel = row.column_data[48].u_int64._0; auto secondaryModel = row.column_data[48].u_int64._0;
@ -90,7 +90,7 @@ MainWindow::MainWindow(GameData* in_data) : data(*in_data) {
} }
auto listWidget = new QListWidget(); auto listWidget = new QListWidget();
for(auto gear : gears) for (auto gear : gears)
listWidget->addItem(gear.name.c_str()); listWidget->addItem(gear.name.c_str());
listWidget->setMaximumWidth(200); listWidget->setMaximumWidth(200);
@ -104,8 +104,8 @@ MainWindow::MainWindow(GameData* in_data) : data(*in_data) {
layout->addWidget(gearView); layout->addWidget(gearView);
connect(listWidget, &QListWidget::itemClicked, [this](QListWidgetItem* item) { connect(listWidget, &QListWidget::itemClicked, [this](QListWidgetItem* item) {
for(auto& gear : gears) { for (auto& gear : gears) {
if(gear.name == item->text().toStdString()) { if (gear.name == item->text().toStdString()) {
gearView->setGear(gear); gearView->setGear(gear);
return; return;
} }

View file

@ -35,35 +35,35 @@ QuaternionEdit::QuaternionEdit(glm::quat& quat, QWidget* parent) : QWidget(paren
spinBoxes.z->setValue(euler.z); spinBoxes.z->setValue(euler.z);
connect( connect(
spinBoxes.x, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double d) { spinBoxes.x, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double d) {
auto euler = glm::eulerAngles(this->quat); auto euler = glm::eulerAngles(this->quat);
euler.x = glm::radians(d); euler.x = glm::radians(d);
this->quat = glm::quat(euler); this->quat = glm::quat(euler);
Q_EMIT onValueChanged(); Q_EMIT onValueChanged();
}); });
connect( connect(
spinBoxes.y, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double d) { spinBoxes.y, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double d) {
auto euler = glm::eulerAngles(this->quat); auto euler = glm::eulerAngles(this->quat);
euler.y = glm::radians(d); euler.y = glm::radians(d);
this->quat = glm::quat(euler); this->quat = glm::quat(euler);
Q_EMIT onValueChanged(); Q_EMIT onValueChanged();
}); });
connect( connect(
spinBoxes.z, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double d) { spinBoxes.z, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this](double d) {
auto euler = glm::eulerAngles(this->quat); auto euler = glm::eulerAngles(this->quat);
euler.z = glm::radians(d); euler.z = glm::radians(d);
this->quat = glm::quat(euler); this->quat = glm::quat(euler);
Q_EMIT onValueChanged(); Q_EMIT onValueChanged();
}); });
} }
void QuaternionEdit::setQuat(glm::quat &quat) { void QuaternionEdit::setQuat(glm::quat& quat) {
this->quat = quat; this->quat = quat;
auto euler = glm::eulerAngles(quat); auto euler = glm::eulerAngles(quat);
euler.x = glm::degrees(euler.x); euler.x = glm::degrees(euler.x);

View file

@ -1,8 +1,8 @@
#include "singlegearview.h" #include "singlegearview.h"
#include <QVBoxLayout>
#include <QPushButton>
#include <QFileDialog> #include <QFileDialog>
#include <QPushButton>
#include <QVBoxLayout>
#include "magic_enum.hpp" #include "magic_enum.hpp"
@ -17,38 +17,35 @@ SingleGearView::SingleGearView(GameData* data) : data(data) {
layout->addLayout(controlLayout); layout->addLayout(controlLayout);
raceCombo = new QComboBox(); raceCombo = new QComboBox();
connect(raceCombo, qOverload<int>(&QComboBox::currentIndexChanged), connect(raceCombo, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
[this](int index) { if (loadingComboData)
if (loadingComboData) return;
return;
setRace((Race)index); setRace((Race)index);
}); });
controlLayout->addWidget(raceCombo); controlLayout->addWidget(raceCombo);
subraceCombo = new QComboBox(); subraceCombo = new QComboBox();
connect(subraceCombo, qOverload<int>(&QComboBox::currentIndexChanged), connect(subraceCombo, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
[this](int index) { if (loadingComboData)
if (loadingComboData) return;
return;
setSubrace((Subrace)index); setSubrace((Subrace)index);
}); });
controlLayout->addWidget(subraceCombo); controlLayout->addWidget(subraceCombo);
genderCombo = new QComboBox(); genderCombo = new QComboBox();
connect(genderCombo, qOverload<int>(&QComboBox::currentIndexChanged), connect(genderCombo, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
[this](int index) { if (loadingComboData)
if (loadingComboData) return;
return;
setGender((Gender)index); setGender((Gender)index);
}); });
controlLayout->addWidget(genderCombo); controlLayout->addWidget(genderCombo);
lodCombo = new QComboBox(); lodCombo = new QComboBox();
connect(lodCombo, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) { connect(lodCombo, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
if(loadingComboData) if (loadingComboData)
return; return;
setLevelOfDetail(index); setLevelOfDetail(index);
@ -57,7 +54,7 @@ SingleGearView::SingleGearView(GameData* data) : data(data) {
addToFMVButton = new QPushButton("Add to FMV"); addToFMVButton = new QPushButton("Add to FMV");
connect(addToFMVButton, &QPushButton::clicked, this, [this](bool) { connect(addToFMVButton, &QPushButton::clicked, this, [this](bool) {
if(currentGear.has_value()) { if (currentGear.has_value()) {
Q_EMIT addToFullModelViewer(*currentGear); Q_EMIT addToFullModelViewer(*currentGear);
} }
}); });
@ -65,9 +62,7 @@ SingleGearView::SingleGearView(GameData* data) : data(data) {
exportButton = new QPushButton("Export..."); exportButton = new QPushButton("Export...");
connect(exportButton, &QPushButton::clicked, this, [this](bool) { connect(exportButton, &QPushButton::clicked, this, [this](bool) {
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Model"), QString fileName = QFileDialog::getSaveFileName(this, tr("Save Model"), "model.fbx", tr("FBX Files (*.fbx)"));
"model.fbx",
tr("FBX Files (*.fbx)"));
gearView->exportModel(fileName); gearView->exportModel(fileName);
}); });
@ -93,7 +88,7 @@ void SingleGearView::clear() {
Q_EMIT gearChanged(); Q_EMIT gearChanged();
} }
void SingleGearView::setGear(GearInfo &info) { void SingleGearView::setGear(GearInfo& info) {
currentGear = info; currentGear = info;
Q_EMIT gearChanged(); Q_EMIT gearChanged();
@ -101,7 +96,7 @@ void SingleGearView::setGear(GearInfo &info) {
void SingleGearView::setRace(Race race) { void SingleGearView::setRace(Race race) {
if (currentRace == race) { if (currentRace == race) {
return; return;
} }
currentRace = race; currentRace = race;
@ -110,7 +105,7 @@ void SingleGearView::setRace(Race race) {
void SingleGearView::setSubrace(Subrace subrace) { void SingleGearView::setSubrace(Subrace subrace) {
if (currentSubrace == subrace) { if (currentSubrace == subrace) {
return; return;
} }
currentSubrace = subrace; currentSubrace = subrace;
@ -119,7 +114,7 @@ void SingleGearView::setSubrace(Subrace subrace) {
void SingleGearView::setGender(Gender gender) { void SingleGearView::setGender(Gender gender) {
if (currentGender == gender) { if (currentGender == gender) {
return; return;
} }
currentGender = gender; currentGender = gender;
@ -152,17 +147,17 @@ void SingleGearView::reloadGear() {
raceCombo->clear(); raceCombo->clear();
subraceCombo->clear(); subraceCombo->clear();
for (auto [race, subrace] : gearView->supportedRaces()) { for (auto [race, subrace] : gearView->supportedRaces()) {
raceCombo->addItem(magic_enum::enum_name(race).data()); raceCombo->addItem(magic_enum::enum_name(race).data());
subraceCombo->addItem(magic_enum::enum_name(subrace).data()); subraceCombo->addItem(magic_enum::enum_name(subrace).data());
} }
genderCombo->clear(); genderCombo->clear();
for (auto gender : gearView->supportedGenders()) { for (auto gender : gearView->supportedGenders()) {
genderCombo->addItem(magic_enum::enum_name(gender).data()); genderCombo->addItem(magic_enum::enum_name(gender).data());
} }
lodCombo->clear(); lodCombo->clear();
for(int i = 0; i < gearView->lodCount(); i++) for (int i = 0; i < gearView->lodCount(); i++)
lodCombo->addItem(QString::number(i)); lodCombo->addItem(QString::number(i));
loadingComboData = false; loadingComboData = false;

View file

@ -27,25 +27,34 @@ Vector3Edit::Vector3Edit(glm::vec3& vec, QWidget* parent) : QWidget(parent), vec
spinBoxes.y->setValue(vec.y); spinBoxes.y->setValue(vec.y);
spinBoxes.z->setValue(vec.z); spinBoxes.z->setValue(vec.z);
connect(spinBoxes.x, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) { connect(
vec.x = d; spinBoxes.x,
emit onValueChanged(); static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
}); [this, &vec](double d) {
connect(spinBoxes.y, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) { vec.x = d;
vec.y = d; emit onValueChanged();
emit onValueChanged(); });
}); connect(
connect(spinBoxes.z, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) { spinBoxes.y,
vec.z = d; static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
emit onValueChanged(); [this, &vec](double d) {
}); vec.y = d;
emit onValueChanged();
});
connect(
spinBoxes.z,
static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
[this, &vec](double d) {
vec.z = d;
emit onValueChanged();
});
} }
Vector3Edit::~Vector3Edit() { Vector3Edit::~Vector3Edit() {
updateTimer->stop(); updateTimer->stop();
} }
void Vector3Edit::setVector(glm::vec3 &vec) { void Vector3Edit::setVector(glm::vec3& vec) {
this->vec = vec; this->vec = vec;
spinBoxes.x->setValue(vec.x); spinBoxes.x->setValue(vec.x);
spinBoxes.y->setValue(vec.y); spinBoxes.y->setValue(vec.y);