mirror of
https://github.com/redstrate/Novus.git
synced 2025-04-30 15:37:46 +00:00
Port to Qt6
This commit is contained in:
parent
d8d890bfbb
commit
4cd6f17439
40 changed files with 294 additions and 292 deletions
|
@ -14,7 +14,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(QT_MIN_VERSION 5.15)
|
set(QT_MIN_VERSION 5.15)
|
||||||
set(KF_MIN_VERSION 5.100)
|
set(KF_MIN_VERSION 5.100)
|
||||||
|
|
||||||
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
|
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
|
||||||
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ ecm_setup_version(${PROJECT_VERSION}
|
||||||
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/novus-version.h
|
VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/novus-version.h
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Qt5 ${QT_MIN_VERSION} COMPONENTS Core Widgets Concurrent CONFIG REQUIRED)
|
find_package(Qt6 ${QT_MIN_VERSION} COMPONENTS Core Widgets Concurrent Core5Compat CONFIG REQUIRED)
|
||||||
find_package(KF5 ${KF_MIN_VERSION} REQUIRED COMPONENTS Config XmlGui)
|
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS CoreAddons Config XmlGui)
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
find_package(glm REQUIRED)
|
find_package(glm REQUIRED)
|
||||||
if (NOT TARGET glm::glm)
|
if (NOT TARGET glm::glm)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
add_executable(argcracker src/main.cpp src/tickcount.cpp)
|
add_executable(argcracker src/main.cpp src/tickcount.cpp)
|
||||||
target_link_libraries(argcracker PUBLIC Qt5::Core ${LIBRARIES} physis z)
|
target_link_libraries(argcracker PUBLIC Qt6::Core Qt6::Core5Compat ${LIBRARIES} physis z)
|
||||||
target_include_directories(argcracker PUBLIC include)
|
target_include_directories(argcracker PUBLIC include)
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringRef>
|
||||||
|
|
||||||
#include <physis.hpp>
|
#include <physis.hpp>
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ inline QString encryptGameArg(QString arg) {
|
||||||
uint8_t* out_data = nullptr;
|
uint8_t* out_data = nullptr;
|
||||||
uint32_t out_size = 0;
|
uint32_t out_size = 0;
|
||||||
|
|
||||||
QByteArray toEncrypt = (QString(" /T =%1").arg(ticks) + arg).toUtf8();
|
QByteArray toEncrypt = (QStringLiteral(" /T =%1").arg(ticks) + arg).toUtf8();
|
||||||
|
|
||||||
physis_blowfish_encrypt(session,
|
physis_blowfish_encrypt(session,
|
||||||
reinterpret_cast<uint8_t*>(toEncrypt.data()), toEncrypt.size(), &out_data, &out_size);
|
reinterpret_cast<uint8_t*>(toEncrypt.data()), toEncrypt.size(), &out_data, &out_size);
|
||||||
|
@ -37,10 +38,10 @@ inline QString encryptGameArg(QString arg) {
|
||||||
QByteArray encryptedArg = QByteArray::fromRawData(
|
QByteArray encryptedArg = QByteArray::fromRawData(
|
||||||
reinterpret_cast<const char*>(out_data), out_size);
|
reinterpret_cast<const char*>(out_data), out_size);
|
||||||
|
|
||||||
QString base64 = encryptedArg.toBase64(QByteArray::Base64Option::Base64UrlEncoding | QByteArray::Base64Option::OmitTrailingEquals);
|
QString base64 = QString::fromUtf8(encryptedArg.toBase64(QByteArray::Base64Option::Base64UrlEncoding | QByteArray::Base64Option::OmitTrailingEquals));
|
||||||
char checksum = GetChecksum(key);
|
char checksum = GetChecksum(key);
|
||||||
|
|
||||||
return QString("//**sqex0003%1%2**//").arg(base64, QString(checksum));
|
return QStringLiteral("//**sqex0003%1%2**//").arg(base64, QLatin1String(&checksum, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QString decryptGameArg(uint32_t tickCount, QString sqexString) {
|
inline QString decryptGameArg(uint32_t tickCount, QString sqexString) {
|
||||||
|
@ -64,7 +65,7 @@ inline QString decryptGameArg(uint32_t tickCount, QString sqexString) {
|
||||||
QByteArray decrypted = QByteArray::fromRawData(
|
QByteArray decrypted = QByteArray::fromRawData(
|
||||||
reinterpret_cast<const char*>(out_data), out_size).trimmed();
|
reinterpret_cast<const char*>(out_data), out_size).trimmed();
|
||||||
|
|
||||||
return decrypted;
|
return QString::fromUtf8(decrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
@ -77,9 +78,9 @@ int main(int argc, char* argv[]) {
|
||||||
qInfo() << "Beginning to crack" << toCrack << "...";
|
qInfo() << "Beginning to crack" << toCrack << "...";
|
||||||
|
|
||||||
for(uint32_t i = bottom; i < TickCount(); i++) {
|
for(uint32_t i = bottom; i < TickCount(); i++) {
|
||||||
QString decrypted = decryptGameArg(i, toCrack);
|
const QString decrypted = decryptGameArg(i, QLatin1String(toCrack));
|
||||||
|
|
||||||
if(decrypted.contains(knownArg)) {
|
if (decrypted.contains(QLatin1String(knownArg))) {
|
||||||
qInfo() << "Decrypted successfully:" << decrypted;
|
qInfo() << "Decrypted successfully:" << decrypted;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@ target_include_directories(armoury
|
||||||
${CMAKE_BINARY_DIR})
|
${CMAKE_BINARY_DIR})
|
||||||
target_link_libraries(armoury PUBLIC
|
target_link_libraries(armoury PUBLIC
|
||||||
${LIBRARIES}
|
${LIBRARIES}
|
||||||
Qt5::Core
|
Qt6::Core
|
||||||
Qt5::Widgets
|
Qt6::Widgets
|
||||||
Qt5::Concurrent
|
Qt6::Concurrent
|
||||||
magic_enum
|
magic_enum
|
||||||
physis z
|
physis z
|
||||||
mdlpart
|
mdlpart
|
||||||
|
|
|
@ -15,7 +15,7 @@ public:
|
||||||
|
|
||||||
void setVector(glm::vec3& vec);
|
void setVector(glm::vec3& vec);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void onValueChanged();
|
void onValueChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -20,7 +20,7 @@ void addItem(
|
||||||
QTreeWidget* widget,
|
QTreeWidget* widget,
|
||||||
QTreeWidgetItem* parent_item = nullptr) {
|
QTreeWidgetItem* parent_item = nullptr) {
|
||||||
auto item = new QTreeWidgetItem();
|
auto item = new QTreeWidgetItem();
|
||||||
item->setText(0, bone.name);
|
item->setText(0, QLatin1String(bone.name));
|
||||||
|
|
||||||
if (parent_item == nullptr) {
|
if (parent_item == nullptr) {
|
||||||
widget->addTopLevelItem(item);
|
widget->addTopLevelItem(item);
|
||||||
|
@ -39,7 +39,7 @@ BoneEditor::BoneEditor(GearView* gearView, QWidget* parent) : gearView(gearView)
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
auto boneListWidget = new QTreeWidget();
|
auto boneListWidget = new QTreeWidget();
|
||||||
boneListWidget->setHeaderLabel("Name");
|
boneListWidget->setHeaderLabel(QStringLiteral("Name"));
|
||||||
|
|
||||||
connect(gearView, &GearView::modelReloaded, this, [this, boneListWidget, gearView] {
|
connect(gearView, &GearView::modelReloaded, this, [this, boneListWidget, gearView] {
|
||||||
boneListWidget->clear();
|
boneListWidget->clear();
|
||||||
|
@ -53,7 +53,7 @@ BoneEditor::BoneEditor(GearView* gearView, QWidget* parent) : gearView(gearView)
|
||||||
auto transformLayout = new QVBoxLayout();
|
auto transformLayout = new QVBoxLayout();
|
||||||
layout->addLayout(transformLayout);
|
layout->addLayout(transformLayout);
|
||||||
|
|
||||||
auto transformGroup = new QGroupBox("Bone Transform");
|
auto transformGroup = new QGroupBox(QStringLiteral("Bone Transform"));
|
||||||
transformLayout->addWidget(transformGroup);
|
transformLayout->addWidget(transformGroup);
|
||||||
auto transformGroupLayout = new QFormLayout();
|
auto transformGroupLayout = new QFormLayout();
|
||||||
transformGroup->setLayout(transformGroupLayout);
|
transformGroup->setLayout(transformGroupLayout);
|
||||||
|
@ -63,37 +63,37 @@ BoneEditor::BoneEditor(GearView* gearView, QWidget* parent) : gearView(gearView)
|
||||||
memcpy(currentEditedBone->position, glm::value_ptr(currentPosition), sizeof(float) * 3);
|
memcpy(currentEditedBone->position, glm::value_ptr(currentPosition), sizeof(float) * 3);
|
||||||
gearView->part().reloadRenderer();
|
gearView->part().reloadRenderer();
|
||||||
});
|
});
|
||||||
transformGroupLayout->addRow("Position", posEdit);
|
transformGroupLayout->addRow(QStringLiteral("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), sizeof(float) * 4);
|
memcpy(currentEditedBone->rotation, glm::value_ptr(currentRotation), sizeof(float) * 4);
|
||||||
gearView->part().reloadRenderer();
|
gearView->part().reloadRenderer();
|
||||||
});
|
});
|
||||||
transformGroupLayout->addRow("Rotation", rotationEdit);
|
transformGroupLayout->addRow(QStringLiteral("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), sizeof(float) * 3);
|
memcpy(currentEditedBone->scale, glm::value_ptr(currentScale), sizeof(float) * 3);
|
||||||
gearView->part().reloadRenderer();
|
gearView->part().reloadRenderer();
|
||||||
});
|
});
|
||||||
transformGroupLayout->addRow("Scale", scaleEdit);
|
transformGroupLayout->addRow(QStringLiteral("Scale"), scaleEdit);
|
||||||
|
|
||||||
connect(boneListWidget, &QTreeWidget::itemClicked, this, &BoneEditor::treeItemClicked);
|
connect(boneListWidget, &QTreeWidget::itemClicked, this, &BoneEditor::treeItemClicked);
|
||||||
|
|
||||||
auto raceDeformGroup = new QGroupBox("Race Deform");
|
auto raceDeformGroup = new QGroupBox(QStringLiteral("Race Deform"));
|
||||||
transformLayout->addWidget(raceDeformGroup);
|
transformLayout->addWidget(raceDeformGroup);
|
||||||
auto raceDeformGroupLayout = new QFormLayout();
|
auto raceDeformGroupLayout = new QFormLayout();
|
||||||
raceDeformGroup->setLayout(raceDeformGroupLayout);
|
raceDeformGroup->setLayout(raceDeformGroupLayout);
|
||||||
|
|
||||||
raceDeformPosEdit = new Vector3Edit(currentRacePosition);
|
raceDeformPosEdit = new Vector3Edit(currentRacePosition);
|
||||||
raceDeformGroupLayout->addRow("Position", raceDeformPosEdit);
|
raceDeformGroupLayout->addRow(QStringLiteral("Position"), raceDeformPosEdit);
|
||||||
|
|
||||||
raceDeformRotationEdit = new QuaternionEdit(currentRaceRotation);
|
raceDeformRotationEdit = new QuaternionEdit(currentRaceRotation);
|
||||||
raceDeformGroupLayout->addRow("Rotation", raceDeformRotationEdit);
|
raceDeformGroupLayout->addRow(QStringLiteral("Rotation"), raceDeformRotationEdit);
|
||||||
|
|
||||||
raceDeformScaleEdit = new Vector3Edit(currentRaceScale);
|
raceDeformScaleEdit = new Vector3Edit(currentRaceScale);
|
||||||
raceDeformGroupLayout->addRow("Scale", raceDeformScaleEdit);
|
raceDeformGroupLayout->addRow(QStringLiteral("Scale"), raceDeformScaleEdit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BoneEditor::treeItemClicked(QTreeWidgetItem* item, int column) {
|
void BoneEditor::treeItemClicked(QTreeWidgetItem* item, int column) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ std::vector<RaceTree> raceTree = {
|
||||||
{Race::Viera, {Subrace::Rava, Subrace::Veena}}};
|
{Race::Viera, {Subrace::Rava, Subrace::Veena}}};
|
||||||
|
|
||||||
CmpEditor::CmpEditor(GameData* data) : data(data) {
|
CmpEditor::CmpEditor(GameData* data) : data(data) {
|
||||||
setWindowTitle("CMP Editor");
|
setWindowTitle(QStringLiteral("CMP Editor"));
|
||||||
|
|
||||||
auto layout = new QHBoxLayout();
|
auto layout = new QHBoxLayout();
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
@ -40,12 +40,12 @@ CmpEditor::CmpEditor(GameData* data) : data(data) {
|
||||||
|
|
||||||
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, QLatin1String(magic_enum::enum_name(race.baseRace).data()));
|
||||||
raceListWidget->addTopLevelItem(item);
|
raceListWidget->addTopLevelItem(item);
|
||||||
|
|
||||||
for (auto subrace : race.subRaces) {
|
for (auto subrace : race.subRaces) {
|
||||||
auto subItem = new QTreeWidgetItem();
|
auto subItem = new QTreeWidgetItem();
|
||||||
subItem->setText(0, magic_enum::enum_name(subrace).data());
|
subItem->setText(0, QLatin1String(magic_enum::enum_name(subrace).data()));
|
||||||
subItem->setData(0, Qt::UserRole, QVariant::fromValue(new RaceTreeData(race.baseRace, subrace)));
|
subItem->setData(0, Qt::UserRole, QVariant::fromValue(new RaceTreeData(race.baseRace, subrace)));
|
||||||
item->addChild(subItem);
|
item->addChild(subItem);
|
||||||
}
|
}
|
||||||
|
@ -65,46 +65,46 @@ CmpEditor::CmpEditor(GameData* data) : data(data) {
|
||||||
detailBox->setLayout(detailBoxLayout);
|
detailBox->setLayout(detailBoxLayout);
|
||||||
|
|
||||||
maleMinSize = new QDoubleSpinBox();
|
maleMinSize = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Male Min Size", maleMinSize);
|
detailBoxLayout->addRow(QStringLiteral("Male Min Size"), maleMinSize);
|
||||||
|
|
||||||
maleMaxSize = new QDoubleSpinBox();
|
maleMaxSize = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Male Max Size", maleMaxSize);
|
detailBoxLayout->addRow(QStringLiteral("Male Max Size"), maleMaxSize);
|
||||||
|
|
||||||
maleMinTail = new QDoubleSpinBox();
|
maleMinTail = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Male Min Tail", maleMinTail);
|
detailBoxLayout->addRow(QStringLiteral("Male Min Tail"), maleMinTail);
|
||||||
|
|
||||||
maleMaxTail = new QDoubleSpinBox();
|
maleMaxTail = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Male Max Tail", maleMaxTail);
|
detailBoxLayout->addRow(QStringLiteral("Male Max Tail"), maleMaxTail);
|
||||||
|
|
||||||
femaleMinSize = new QDoubleSpinBox();
|
femaleMinSize = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Female Min Size", femaleMinSize);
|
detailBoxLayout->addRow(QStringLiteral("Female Min Size"), femaleMinSize);
|
||||||
|
|
||||||
femaleMaxSize = new QDoubleSpinBox();
|
femaleMaxSize = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Female Max Size", femaleMaxSize);
|
detailBoxLayout->addRow(QStringLiteral("Female Max Size"), femaleMaxSize);
|
||||||
|
|
||||||
femaleMinTail = new QDoubleSpinBox();
|
femaleMinTail = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Female Min Tail", femaleMinTail);
|
detailBoxLayout->addRow(QStringLiteral("Female Min Tail"), femaleMinTail);
|
||||||
|
|
||||||
femaleMaxTail = new QDoubleSpinBox();
|
femaleMaxTail = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Female Max Tail", femaleMaxTail);
|
detailBoxLayout->addRow(QStringLiteral("Female Max Tail"), femaleMaxTail);
|
||||||
|
|
||||||
bustMinX = new QDoubleSpinBox();
|
bustMinX = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Bust Min X", bustMinX);
|
detailBoxLayout->addRow(QStringLiteral("Bust Min X"), bustMinX);
|
||||||
|
|
||||||
bustMinY = new QDoubleSpinBox();
|
bustMinY = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Bust Min Y", bustMinY);
|
detailBoxLayout->addRow(QStringLiteral("Bust Min Y"), bustMinY);
|
||||||
|
|
||||||
bustMinZ = new QDoubleSpinBox();
|
bustMinZ = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Bust Min Z", bustMinZ);
|
detailBoxLayout->addRow(QStringLiteral("Bust Min Z"), bustMinZ);
|
||||||
|
|
||||||
bustMaxX = new QDoubleSpinBox();
|
bustMaxX = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Bust Max X", bustMaxX);
|
detailBoxLayout->addRow(QStringLiteral("Bust Max X"), bustMaxX);
|
||||||
|
|
||||||
bustMaxY = new QDoubleSpinBox();
|
bustMaxY = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Bust Max Y", bustMaxY);
|
detailBoxLayout->addRow(QStringLiteral("Bust Max Y"), bustMaxY);
|
||||||
|
|
||||||
bustMaxZ = new QDoubleSpinBox();
|
bustMaxZ = new QDoubleSpinBox();
|
||||||
detailBoxLayout->addRow("Bust Max Z", bustMaxZ);
|
detailBoxLayout->addRow(QStringLiteral("Bust Max Z"), bustMaxZ);
|
||||||
|
|
||||||
loadRaceData(Race::Hyur, Subrace::Midlander);
|
loadRaceData(Race::Hyur, Subrace::Midlander);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data) {
|
FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data) {
|
||||||
setWindowTitle("Full Model Viewer");
|
setWindowTitle(QStringLiteral("Full Model Viewer"));
|
||||||
setMinimumWidth(1280);
|
setMinimumWidth(1280);
|
||||||
setMinimumHeight(720);
|
setMinimumHeight(720);
|
||||||
|
|
||||||
|
@ -23,15 +23,13 @@ FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data)
|
||||||
auto layout = new QVBoxLayout();
|
auto layout = new QVBoxLayout();
|
||||||
dummyWidget->setLayout(layout);
|
dummyWidget->setLayout(layout);
|
||||||
|
|
||||||
auto fileMenu = menuBar()->addMenu("File");
|
auto fileMenu = menuBar()->addMenu(QStringLiteral("File"));
|
||||||
|
|
||||||
auto datOpenAction = fileMenu->addAction("Load character DAT...");
|
auto datOpenAction = fileMenu->addAction(QStringLiteral("Load character DAT..."));
|
||||||
datOpenAction->setIcon(QIcon::fromTheme("document-open"));
|
datOpenAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
|
||||||
connect(datOpenAction, &QAction::triggered, [=] {
|
connect(datOpenAction, &QAction::triggered, [=] {
|
||||||
auto fileName = QFileDialog::getOpenFileName(nullptr,
|
auto fileName =
|
||||||
"Open DAT File",
|
QFileDialog::getOpenFileName(nullptr, QStringLiteral("Open DAT File"), QStringLiteral("~"), QStringLiteral("FFXIV Character DAT File (*.dat)"));
|
||||||
"~",
|
|
||||||
"FFXIV Character DAT File (*.dat)");
|
|
||||||
|
|
||||||
auto buffer = physis_read_file(fileName.toStdString().c_str());
|
auto buffer = physis_read_file(fileName.toStdString().c_str());
|
||||||
|
|
||||||
|
@ -69,7 +67,7 @@ FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data)
|
||||||
const float scale = (float)position / 100.0f;
|
const float scale = (float)position / 100.0f;
|
||||||
updateHeightScaling(scale);
|
updateHeightScaling(scale);
|
||||||
});
|
});
|
||||||
characterEditorLayout->addRow("Height", characterHeight);
|
characterEditorLayout->addRow(QStringLiteral("Height"), characterHeight);
|
||||||
|
|
||||||
auto bustSize = new QSlider();
|
auto bustSize = new QSlider();
|
||||||
bustSize->setOrientation(Qt::Horizontal);
|
bustSize->setOrientation(Qt::Horizontal);
|
||||||
|
@ -78,7 +76,7 @@ FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data)
|
||||||
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(QStringLiteral("Bust Size"), bustSize);
|
||||||
|
|
||||||
characterEditorLayout->addWidget(addFaceGroup());
|
characterEditorLayout->addWidget(addFaceGroup());
|
||||||
characterEditorLayout->addWidget(addHairGroup());
|
characterEditorLayout->addWidget(addHairGroup());
|
||||||
|
@ -86,8 +84,8 @@ FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data)
|
||||||
characterEditorLayout->addWidget(addTailGroup());
|
characterEditorLayout->addWidget(addTailGroup());
|
||||||
|
|
||||||
auto tabWidget = new QTabWidget();
|
auto tabWidget = new QTabWidget();
|
||||||
tabWidget->addTab(new BoneEditor(gearView), "Bone Editor");
|
tabWidget->addTab(new BoneEditor(gearView), QStringLiteral("Bone Editor"));
|
||||||
tabWidget->addTab(characterEditorWidget, "Character Editor");
|
tabWidget->addTab(characterEditorWidget, QStringLiteral("Character Editor"));
|
||||||
viewportLayout->addWidget(tabWidget);
|
viewportLayout->addWidget(tabWidget);
|
||||||
|
|
||||||
auto controlLayout = new QHBoxLayout();
|
auto controlLayout = new QHBoxLayout();
|
||||||
|
@ -97,7 +95,7 @@ FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data)
|
||||||
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(), (int)race);
|
raceCombo->addItem(QLatin1String(race_name.data()), (int)race);
|
||||||
}
|
}
|
||||||
|
|
||||||
subraceCombo = new QComboBox();
|
subraceCombo = new QComboBox();
|
||||||
|
@ -120,7 +118,7 @@ FullModelViewer::FullModelViewer(GameData* data, FileCache& cache) : data(data)
|
||||||
controlLayout->addWidget(genderCombo);
|
controlLayout->addWidget(genderCombo);
|
||||||
|
|
||||||
for (auto [gender, gender_name] : magic_enum::enum_entries<Gender>()) {
|
for (auto [gender, gender_name] : magic_enum::enum_entries<Gender>()) {
|
||||||
genderCombo->addItem(gender_name.data(), (int)gender);
|
genderCombo->addItem(QLatin1String(gender_name.data()), (int)gender);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(this, &FullModelViewer::gearChanged, this, &FullModelViewer::reloadGear);
|
connect(this, &FullModelViewer::gearChanged, this, &FullModelViewer::reloadGear);
|
||||||
|
@ -261,28 +259,28 @@ void FullModelViewer::updateCharacterParameters() {
|
||||||
void FullModelViewer::updateSupportedSubraces() {
|
void FullModelViewer::updateSupportedSubraces() {
|
||||||
subraceCombo->clear();
|
subraceCombo->clear();
|
||||||
for (auto subrace : physis_get_supported_subraces(gearView->currentRace).subraces) {
|
for (auto subrace : physis_get_supported_subraces(gearView->currentRace).subraces) {
|
||||||
subraceCombo->addItem(magic_enum::enum_name(subrace).data(), (int)subrace);
|
subraceCombo->addItem(QLatin1String(magic_enum::enum_name(subrace).data()), (int)subrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QGroupBox* FullModelViewer::addFaceGroup() {
|
QGroupBox* FullModelViewer::addFaceGroup() {
|
||||||
auto faceGroup = new QGroupBox("Face");
|
auto faceGroup = new QGroupBox(QStringLiteral("Face"));
|
||||||
auto faceGroupLayout = new QVBoxLayout();
|
auto faceGroupLayout = new QVBoxLayout();
|
||||||
faceGroup->setLayout(faceGroupLayout);
|
faceGroup->setLayout(faceGroupLayout);
|
||||||
|
|
||||||
auto faceRadio1 = new QRadioButton("Face 1");
|
auto faceRadio1 = new QRadioButton(QStringLiteral("Face 1"));
|
||||||
connect(faceRadio1, &QRadioButton::clicked, this, [=] {
|
connect(faceRadio1, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setFace(1);
|
gearView->setFace(1);
|
||||||
});
|
});
|
||||||
faceGroupLayout->addWidget(faceRadio1);
|
faceGroupLayout->addWidget(faceRadio1);
|
||||||
|
|
||||||
auto faceRadio2 = new QRadioButton("Face 2");
|
auto faceRadio2 = new QRadioButton(QStringLiteral("Face 2"));
|
||||||
connect(faceRadio2, &QRadioButton::clicked, this, [=] {
|
connect(faceRadio2, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setFace(2);
|
gearView->setFace(2);
|
||||||
});
|
});
|
||||||
faceGroupLayout->addWidget(faceRadio2);
|
faceGroupLayout->addWidget(faceRadio2);
|
||||||
|
|
||||||
auto faceRadio3 = new QRadioButton("Face 3");
|
auto faceRadio3 = new QRadioButton(QStringLiteral("Face 3"));
|
||||||
connect(faceRadio3, &QRadioButton::clicked, this, [=] {
|
connect(faceRadio3, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setFace(3);
|
gearView->setFace(3);
|
||||||
});
|
});
|
||||||
|
@ -292,23 +290,23 @@ QGroupBox* FullModelViewer::addFaceGroup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QGroupBox* FullModelViewer::addHairGroup() {
|
QGroupBox* FullModelViewer::addHairGroup() {
|
||||||
auto hairGroup = new QGroupBox("Hair");
|
auto hairGroup = new QGroupBox(QStringLiteral("Hair"));
|
||||||
auto hairGroupLayout = new QVBoxLayout();
|
auto hairGroupLayout = new QVBoxLayout();
|
||||||
hairGroup->setLayout(hairGroupLayout);
|
hairGroup->setLayout(hairGroupLayout);
|
||||||
|
|
||||||
auto hairRadio1 = new QRadioButton("Hair 1");
|
auto hairRadio1 = new QRadioButton(QStringLiteral("Hair 1"));
|
||||||
connect(hairRadio1, &QRadioButton::clicked, this, [=] {
|
connect(hairRadio1, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setHair(1);
|
gearView->setHair(1);
|
||||||
});
|
});
|
||||||
hairGroupLayout->addWidget(hairRadio1);
|
hairGroupLayout->addWidget(hairRadio1);
|
||||||
|
|
||||||
auto hairRadio2 = new QRadioButton("Hair 2");
|
auto hairRadio2 = new QRadioButton(QStringLiteral("Hair 2"));
|
||||||
connect(hairRadio2, &QRadioButton::clicked, this, [=] {
|
connect(hairRadio2, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setHair(2);
|
gearView->setHair(2);
|
||||||
});
|
});
|
||||||
hairGroupLayout->addWidget(hairRadio2);
|
hairGroupLayout->addWidget(hairRadio2);
|
||||||
|
|
||||||
auto hairRadio3 = new QRadioButton("Hair 3");
|
auto hairRadio3 = new QRadioButton(QStringLiteral("Hair 3"));
|
||||||
connect(hairRadio3, &QRadioButton::clicked, this, [=] {
|
connect(hairRadio3, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setHair(3);
|
gearView->setHair(3);
|
||||||
});
|
});
|
||||||
|
@ -318,23 +316,23 @@ QGroupBox* FullModelViewer::addHairGroup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QGroupBox* FullModelViewer::addEarGroup() {
|
QGroupBox* FullModelViewer::addEarGroup() {
|
||||||
auto earGroup = new QGroupBox("Ears");
|
auto earGroup = new QGroupBox(QStringLiteral("Ears"));
|
||||||
auto earGroupLayout = new QVBoxLayout();
|
auto earGroupLayout = new QVBoxLayout();
|
||||||
earGroup->setLayout(earGroupLayout);
|
earGroup->setLayout(earGroupLayout);
|
||||||
|
|
||||||
auto earRadio1 = new QRadioButton("Ears 1");
|
auto earRadio1 = new QRadioButton(QStringLiteral("Ears 1"));
|
||||||
connect(earRadio1, &QRadioButton::clicked, this, [=] {
|
connect(earRadio1, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setEar(1);
|
gearView->setEar(1);
|
||||||
});
|
});
|
||||||
earGroupLayout->addWidget(earRadio1);
|
earGroupLayout->addWidget(earRadio1);
|
||||||
|
|
||||||
auto earRadio2 = new QRadioButton("Ears 2");
|
auto earRadio2 = new QRadioButton(QStringLiteral("Ears 2"));
|
||||||
connect(earRadio2, &QRadioButton::clicked, this, [=] {
|
connect(earRadio2, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setEar(2);
|
gearView->setEar(2);
|
||||||
});
|
});
|
||||||
earGroupLayout->addWidget(earRadio2);
|
earGroupLayout->addWidget(earRadio2);
|
||||||
|
|
||||||
auto earRadio3 = new QRadioButton("Ears 3");
|
auto earRadio3 = new QRadioButton(QStringLiteral("Ears 3"));
|
||||||
connect(earRadio3, &QRadioButton::clicked, this, [=] {
|
connect(earRadio3, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setEar(3);
|
gearView->setEar(3);
|
||||||
});
|
});
|
||||||
|
@ -344,23 +342,23 @@ QGroupBox* FullModelViewer::addEarGroup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QGroupBox* FullModelViewer::addTailGroup() {
|
QGroupBox* FullModelViewer::addTailGroup() {
|
||||||
auto tailGroup = new QGroupBox("Tail");
|
auto tailGroup = new QGroupBox(QStringLiteral("Tail"));
|
||||||
auto tailGroupLayout = new QVBoxLayout();
|
auto tailGroupLayout = new QVBoxLayout();
|
||||||
tailGroup->setLayout(tailGroupLayout);
|
tailGroup->setLayout(tailGroupLayout);
|
||||||
|
|
||||||
auto tailRadio1 = new QRadioButton("Tail 1");
|
auto tailRadio1 = new QRadioButton(QStringLiteral("Tail 1"));
|
||||||
connect(tailRadio1, &QRadioButton::clicked, this, [=] {
|
connect(tailRadio1, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setTail(1);
|
gearView->setTail(1);
|
||||||
});
|
});
|
||||||
tailGroupLayout->addWidget(tailRadio1);
|
tailGroupLayout->addWidget(tailRadio1);
|
||||||
|
|
||||||
auto tailRadio2 = new QRadioButton("Tail 2");
|
auto tailRadio2 = new QRadioButton(QStringLiteral("Tail 2"));
|
||||||
connect(tailRadio2, &QRadioButton::clicked, this, [=] {
|
connect(tailRadio2, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setTail(2);
|
gearView->setTail(2);
|
||||||
});
|
});
|
||||||
tailGroupLayout->addWidget(tailRadio2);
|
tailGroupLayout->addWidget(tailRadio2);
|
||||||
|
|
||||||
auto tailRadio3 = new QRadioButton("Tail 3");
|
auto tailRadio3 = new QRadioButton(QStringLiteral("Tail 3"));
|
||||||
connect(tailRadio3, &QRadioButton::clicked, this, [=] {
|
connect(tailRadio3, &QRadioButton::clicked, this, [=] {
|
||||||
gearView->setTail(3);
|
gearView->setTail(3);
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,7 +44,7 @@ GearListModel::GearListModel(GameData* data) : gameData(data), QAbstractItemMode
|
||||||
exdFuture->setFuture(QtConcurrent::mapped(pages, loadEXD));
|
exdFuture->setFuture(QtConcurrent::mapped(pages, loadEXD));
|
||||||
|
|
||||||
for (auto slotName : magic_enum::enum_names<Slot>()) {
|
for (auto slotName : magic_enum::enum_names<Slot>()) {
|
||||||
slotNames.push_back(slotName.data());
|
slotNames.push_back(QLatin1String(slotName.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
rootItem = new TreeInformation();
|
rootItem = new TreeInformation();
|
||||||
|
@ -110,9 +110,9 @@ QVariant GearListModel::data(const QModelIndex& index, int role) const {
|
||||||
TreeInformation* item = static_cast<TreeInformation*>(index.internalPointer());
|
TreeInformation* item = static_cast<TreeInformation*>(index.internalPointer());
|
||||||
|
|
||||||
if (item->type == TreeType::Category) {
|
if (item->type == TreeType::Category) {
|
||||||
return magic_enum::enum_name(*item->slotType).data();
|
return QLatin1String(magic_enum::enum_name(*item->slotType).data());
|
||||||
} else if (item->type == TreeType::Item) {
|
} else if (item->type == TreeType::Item) {
|
||||||
return item->gear->name.data();
|
return QLatin1String(item->gear->name.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -121,7 +121,7 @@ QVariant GearListModel::data(const QModelIndex& index, int role) const {
|
||||||
QVariant GearListModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
QVariant GearListModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||||
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||||
if (section == 0) {
|
if (section == 0) {
|
||||||
return "Name";
|
return QStringLiteral("Name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ GearListWidget::GearListWidget(GameData* data, QWidget* parent) : data(data) {
|
||||||
searchModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
searchModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
||||||
|
|
||||||
auto searchEdit = new QLineEdit();
|
auto searchEdit = new QLineEdit();
|
||||||
searchEdit->setPlaceholderText("Search...");
|
searchEdit->setPlaceholderText(QStringLiteral("Search..."));
|
||||||
searchEdit->setClearButtonEnabled(true);
|
searchEdit->setClearButtonEnabled(true);
|
||||||
connect(searchEdit, &QLineEdit::textChanged, this, [=](const QString& text) {
|
connect(searchEdit, &QLineEdit::textChanged, this, [=](const QString& text) {
|
||||||
searchModel->setFilterRegularExpression(text);
|
searchModel->setFilterRegularExpression(text);
|
||||||
|
|
|
@ -227,12 +227,12 @@ void GearView::reloadRaceDeforms()
|
||||||
const int raceCode = physis_get_race_code(currentRace, currentSubrace, currentGender);
|
const int raceCode = physis_get_race_code(currentRace, currentSubrace, currentGender);
|
||||||
qDebug() << "Race code: " << raceCode;
|
qDebug() << "Race code: " << raceCode;
|
||||||
|
|
||||||
QString skelName = QString{"c%1b0001.skel"}.arg(raceCode, 4, 10, QLatin1Char{'0'});
|
QString skelName = QStringLiteral("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 Midlander, not needed? TODO not sure
|
// racial deforms don't work on Hyur Midlander, not needed? TODO not sure
|
||||||
if (currentSubrace != Subrace::Midlander) {
|
if (currentSubrace != Subrace::Midlander) {
|
||||||
QString deformName = QString{"c%1_deform.json"}.arg(raceCode, 4, 10, QLatin1Char{'0'});
|
QString deformName = QStringLiteral("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) {
|
||||||
|
@ -262,16 +262,16 @@ void GearView::updatePart()
|
||||||
|
|
||||||
if (gearDirty) {
|
if (gearDirty) {
|
||||||
for (auto &gearAddition : queuedGearAdditions) {
|
for (auto &gearAddition : queuedGearAdditions) {
|
||||||
auto mdl_data = cache.lookupFile(
|
auto mdl_data = cache.lookupFile(QLatin1String(
|
||||||
physis_build_equipment_path(gearAddition.info.modelInfo.primaryID, currentRace, currentSubrace, currentGender, gearAddition.info.slot));
|
physis_build_equipment_path(gearAddition.info.modelInfo.primaryID, currentRace, currentSubrace, currentGender, gearAddition.info.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
|
||||||
Race fallbackRace = currentRace;
|
Race fallbackRace = currentRace;
|
||||||
Subrace fallbackSubrace = currentSubrace;
|
Subrace fallbackSubrace = currentSubrace;
|
||||||
if (mdl_data.size == 0) {
|
if (mdl_data.size == 0) {
|
||||||
mdl_data = cache.lookupFile(
|
mdl_data = cache.lookupFile(QLatin1String(
|
||||||
physis_build_equipment_path(gearAddition.info.modelInfo.primaryID, Race::Hyur, Subrace::Midlander, currentGender, gearAddition.info.slot));
|
physis_build_equipment_path(gearAddition.info.modelInfo.primaryID, Race::Hyur, Subrace::Midlander, currentGender, gearAddition.info.slot)));
|
||||||
fallbackRace = Race::Hyur;
|
fallbackRace = Race::Hyur;
|
||||||
fallbackSubrace = Subrace::Midlander;
|
fallbackSubrace = Subrace::Midlander;
|
||||||
}
|
}
|
||||||
|
@ -288,12 +288,12 @@ void GearView::updatePart()
|
||||||
physis_build_skin_material_path(physis_get_race_code(fallbackRace, fallbackSubrace, currentGender), 1, material_name);
|
physis_build_skin_material_path(physis_get_race_code(fallbackRace, fallbackSubrace, currentGender), 1, material_name);
|
||||||
|
|
||||||
if (cache.fileExists(QLatin1String(mtrl_path.c_str()))) {
|
if (cache.fileExists(QLatin1String(mtrl_path.c_str()))) {
|
||||||
auto mat = physis_material_parse(cache.lookupFile(mtrl_path.c_str()));
|
auto mat = physis_material_parse(cache.lookupFile(QLatin1String(mtrl_path.c_str())));
|
||||||
materials.push_back(mat);
|
materials.push_back(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
||||||
auto mat = physis_material_parse(cache.lookupFile(skinmtrl_path.c_str()));
|
auto mat = physis_material_parse(cache.lookupFile(QLatin1String(skinmtrl_path.c_str())));
|
||||||
materials.push_back(mat);
|
materials.push_back(mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,8 @@ void GearView::updatePart()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (face) {
|
if (face) {
|
||||||
auto mdl_data = cache.lookupFile(physis_build_character_path(CharacterCategory::Face, *face, currentRace, currentSubrace, currentGender));
|
auto mdl_data =
|
||||||
|
cache.lookupFile(QLatin1String(physis_build_character_path(CharacterCategory::Face, *face, currentRace, currentSubrace, currentGender)));
|
||||||
|
|
||||||
if (mdl_data.size > 0) {
|
if (mdl_data.size > 0) {
|
||||||
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
||||||
|
@ -329,7 +330,7 @@ void GearView::updatePart()
|
||||||
const std::string skinmtrl_path = physis_build_face_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *face, material_name);
|
const std::string skinmtrl_path = physis_build_face_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *face, material_name);
|
||||||
|
|
||||||
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
||||||
auto mat = physis_material_parse(cache.lookupFile(skinmtrl_path.c_str()));
|
auto mat = physis_material_parse(cache.lookupFile(QLatin1String(skinmtrl_path.c_str())));
|
||||||
materials.push_back(mat);
|
materials.push_back(mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,7 +340,8 @@ void GearView::updatePart()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hair) {
|
if (hair) {
|
||||||
auto mdl_data = cache.lookupFile(physis_build_character_path(CharacterCategory::Hair, *hair, currentRace, currentSubrace, currentGender));
|
auto mdl_data =
|
||||||
|
cache.lookupFile(QLatin1String(physis_build_character_path(CharacterCategory::Hair, *hair, currentRace, currentSubrace, currentGender)));
|
||||||
|
|
||||||
if (mdl_data.size > 0) {
|
if (mdl_data.size > 0) {
|
||||||
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
||||||
|
@ -350,7 +352,7 @@ void GearView::updatePart()
|
||||||
const std::string skinmtrl_path = physis_build_hair_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *hair, material_name);
|
const std::string skinmtrl_path = physis_build_hair_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *hair, material_name);
|
||||||
|
|
||||||
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
||||||
auto mat = physis_material_parse(cache.lookupFile(skinmtrl_path.c_str()));
|
auto mat = physis_material_parse(cache.lookupFile(QLatin1String(skinmtrl_path.c_str())));
|
||||||
materials.push_back(mat);
|
materials.push_back(mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +362,7 @@ void GearView::updatePart()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ear) {
|
if (ear) {
|
||||||
auto mdl_data = cache.lookupFile(physis_build_character_path(CharacterCategory::Hair, *ear, currentRace, currentSubrace, currentGender));
|
auto mdl_data = cache.lookupFile(QLatin1String(physis_build_character_path(CharacterCategory::Hair, *ear, currentRace, currentSubrace, currentGender)));
|
||||||
|
|
||||||
if (mdl_data.size > 0) {
|
if (mdl_data.size > 0) {
|
||||||
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
||||||
|
@ -371,7 +373,7 @@ void GearView::updatePart()
|
||||||
const std::string skinmtrl_path = physis_build_ear_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *ear, material_name);
|
const std::string skinmtrl_path = physis_build_ear_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *ear, material_name);
|
||||||
|
|
||||||
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
||||||
auto mat = physis_material_parse(cache.lookupFile(skinmtrl_path.c_str()));
|
auto mat = physis_material_parse(cache.lookupFile(QLatin1String(skinmtrl_path.c_str())));
|
||||||
materials.push_back(mat);
|
materials.push_back(mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +383,8 @@ void GearView::updatePart()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tail) {
|
if (tail) {
|
||||||
auto mdl_data = cache.lookupFile(physis_build_character_path(CharacterCategory::Tail, *tail, currentRace, currentSubrace, currentGender));
|
auto mdl_data =
|
||||||
|
cache.lookupFile(QLatin1String(physis_build_character_path(CharacterCategory::Tail, *tail, currentRace, currentSubrace, currentGender)));
|
||||||
|
|
||||||
if (mdl_data.size > 0) {
|
if (mdl_data.size > 0) {
|
||||||
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
auto mdl = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
||||||
|
@ -390,7 +393,7 @@ void GearView::updatePart()
|
||||||
const std::string skinmtrl_path = physis_build_tail_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *tail, material_name);
|
const std::string skinmtrl_path = physis_build_tail_material_path(physis_get_race_code(currentRace, currentSubrace, currentGender), *tail, material_name);
|
||||||
|
|
||||||
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
if (cache.fileExists(QLatin1String(skinmtrl_path.c_str()))) {
|
||||||
auto mat = physis_material_parse(cache.lookupFile(skinmtrl_path.c_str()));
|
auto mat = physis_material_parse(cache.lookupFile(QLatin1String(skinmtrl_path.c_str())));
|
||||||
mdlPart->addModel(mdl, {mat}, currentLod);
|
mdlPart->addModel(mdl, {mat}, currentLod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,43 +27,43 @@
|
||||||
#include "gearlistwidget.h"
|
#include "gearlistwidget.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(GameData* in_data) : data(*in_data), cache(FileCache{*in_data}) {
|
MainWindow::MainWindow(GameData* in_data) : data(*in_data), cache(FileCache{*in_data}) {
|
||||||
setWindowTitle("Armoury Editor");
|
setWindowTitle(QStringLiteral("Armoury Editor"));
|
||||||
setMinimumSize(QSize(800, 600));
|
setMinimumSize(QSize(800, 600));
|
||||||
|
|
||||||
auto fileMenu = menuBar()->addMenu("File");
|
auto fileMenu = menuBar()->addMenu(QStringLiteral("File"));
|
||||||
|
|
||||||
auto quitAction = fileMenu->addAction("Quit");
|
auto quitAction = fileMenu->addAction(QStringLiteral("Quit"));
|
||||||
quitAction->setIcon(QIcon::fromTheme("gtk-quit"));
|
quitAction->setIcon(QIcon::fromTheme(QStringLiteral("gtk-quit")));
|
||||||
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||||
|
|
||||||
auto toolsMenu = menuBar()->addMenu("Tools");
|
auto toolsMenu = menuBar()->addMenu(QStringLiteral("Tools"));
|
||||||
|
|
||||||
auto cmpEditorMenu = toolsMenu->addAction("CMP Editor");
|
auto cmpEditorMenu = toolsMenu->addAction(QStringLiteral("CMP Editor"));
|
||||||
cmpEditorMenu->setIcon(QIcon::fromTheme("document-edit"));
|
cmpEditorMenu->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
|
||||||
connect(cmpEditorMenu, &QAction::triggered, [=] {
|
connect(cmpEditorMenu, &QAction::triggered, [=] {
|
||||||
auto cmpEditor = new CmpEditor(in_data);
|
auto cmpEditor = new CmpEditor(in_data);
|
||||||
cmpEditor->show();
|
cmpEditor->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto helpMenu = menuBar()->addMenu("Help");
|
auto helpMenu = menuBar()->addMenu(QStringLiteral("Help"));
|
||||||
|
|
||||||
auto donateAction = helpMenu->addAction("Donate");
|
auto donateAction = helpMenu->addAction(QStringLiteral("Donate"));
|
||||||
connect(donateAction, &QAction::triggered, this, [] {
|
connect(donateAction, &QAction::triggered, this, [] {
|
||||||
QDesktopServices::openUrl(QUrl("https://redstrate.com/fund"));
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://redstrate.com/fund")));
|
||||||
});
|
});
|
||||||
donateAction->setIcon(QIcon::fromTheme("help-donate"));
|
donateAction->setIcon(QIcon::fromTheme(QStringLiteral("help-donate")));
|
||||||
|
|
||||||
helpMenu->addSeparator();
|
helpMenu->addSeparator();
|
||||||
|
|
||||||
auto aboutNovusAction = helpMenu->addAction("About Armoury Editor");
|
auto aboutNovusAction = helpMenu->addAction(QStringLiteral("About Armoury Editor"));
|
||||||
aboutNovusAction->setIcon(QIcon::fromTheme("help-about"));
|
aboutNovusAction->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
|
||||||
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
||||||
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
||||||
window->show();
|
window->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto aboutQtAction = helpMenu->addAction("About Qt");
|
auto aboutQtAction = helpMenu->addAction(QStringLiteral("About Qt"));
|
||||||
aboutQtAction->setIcon(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"));
|
aboutQtAction->setIcon(QIcon(QStringLiteral(":/qt-project.org/qmessagebox/images/qtlogo-64.png")));
|
||||||
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
||||||
|
|
||||||
auto dummyWidget = new QWidget();
|
auto dummyWidget = new QWidget();
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
QuaternionEdit::QuaternionEdit(glm::quat& quat, QWidget* parent) : QWidget(parent), quat(quat) {
|
QuaternionEdit::QuaternionEdit(glm::quat& quat, QWidget* parent) : QWidget(parent), quat(quat) {
|
||||||
auto itemsLayout = new QHBoxLayout(this);
|
auto itemsLayout = new QHBoxLayout(this);
|
||||||
itemsLayout->setMargin(0);
|
|
||||||
|
|
||||||
spinBoxes.x = new QDoubleSpinBox();
|
spinBoxes.x = new QDoubleSpinBox();
|
||||||
spinBoxes.y = new QDoubleSpinBox();
|
spinBoxes.y = new QDoubleSpinBox();
|
||||||
|
|
|
@ -63,7 +63,7 @@ SingleGearView::SingleGearView(GameData* data, FileCache& cache) : data(data) {
|
||||||
});
|
});
|
||||||
controlLayout->addWidget(lodCombo);
|
controlLayout->addWidget(lodCombo);
|
||||||
|
|
||||||
addToFMVButton = new QPushButton("Add to FMV");
|
addToFMVButton = new QPushButton(QStringLiteral("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);
|
||||||
|
@ -71,11 +71,10 @@ SingleGearView::SingleGearView(GameData* data, FileCache& cache) : data(data) {
|
||||||
});
|
});
|
||||||
controlLayout->addWidget(addToFMVButton);
|
controlLayout->addWidget(addToFMVButton);
|
||||||
|
|
||||||
exportButton = new QPushButton("Export...");
|
exportButton = new QPushButton(QStringLiteral("Export..."));
|
||||||
connect(exportButton, &QPushButton::clicked, this, [this](bool) {
|
connect(exportButton, &QPushButton::clicked, this, [this](bool) {
|
||||||
if (currentGear.has_value()) {
|
if (currentGear.has_value()) {
|
||||||
QString fileName =
|
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Model"), QStringLiteral("model.glb"), tr("glTF Binary File (*.glb)"));
|
||||||
QFileDialog::getSaveFileName(this, tr("Save Model"), "model.glb", tr("glTF Binary File (*.glb)"));
|
|
||||||
|
|
||||||
gearView->exportModel(fileName);
|
gearView->exportModel(fileName);
|
||||||
}
|
}
|
||||||
|
@ -184,10 +183,10 @@ void SingleGearView::reloadGear()
|
||||||
for (auto [race, subrace] : supportedRaces) {
|
for (auto [race, subrace] : supportedRaces) {
|
||||||
// TODO: supportedRaces should be designed better
|
// TODO: supportedRaces should be designed better
|
||||||
if (!addedRaces.contains(race)) {
|
if (!addedRaces.contains(race)) {
|
||||||
raceCombo->addItem(magic_enum::enum_name(race).data(), static_cast<int>(race));
|
raceCombo->addItem(QLatin1String(magic_enum::enum_name(race).data(), static_cast<int>(race)));
|
||||||
addedRaces.push_back(race);
|
addedRaces.push_back(race);
|
||||||
}
|
}
|
||||||
subraceCombo->addItem(magic_enum::enum_name(subrace).data(), static_cast<int>(subrace));
|
subraceCombo->addItem(QLatin1String(magic_enum::enum_name(subrace).data(), static_cast<int>(subrace)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto it = std::find_if(supportedRaces.begin(), supportedRaces.end(), [oldRace](auto p) { return std::get<0>(p) == oldRace; }); it != supportedRaces.end()) {
|
if (auto it = std::find_if(supportedRaces.begin(), supportedRaces.end(), [oldRace](auto p) { return std::get<0>(p) == oldRace; }); it != supportedRaces.end()) {
|
||||||
|
@ -203,7 +202,7 @@ void SingleGearView::reloadGear()
|
||||||
|
|
||||||
const auto supportedGenders = gearView->supportedGenders();
|
const auto supportedGenders = gearView->supportedGenders();
|
||||||
for (auto gender : supportedGenders) {
|
for (auto gender : supportedGenders) {
|
||||||
genderCombo->addItem(magic_enum::enum_name(gender).data(), static_cast<int>(gender));
|
genderCombo->addItem(QLatin1String(magic_enum::enum_name(gender).data(), static_cast<int>(gender)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto it = std::find_if(supportedGenders.begin(), supportedGenders.end(), [oldGender](auto p) { return p == oldGender; }); it != supportedGenders.end()) {
|
if (auto it = std::find_if(supportedGenders.begin(), supportedGenders.end(), [oldGender](auto p) { return p == oldGender; }); it != supportedGenders.end()) {
|
||||||
|
|
|
@ -35,21 +35,21 @@ Vector3Edit::Vector3Edit(glm::vec3& vec, QWidget* parent) : QWidget(parent), vec
|
||||||
static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
||||||
[this, &vec](double d) {
|
[this, &vec](double d) {
|
||||||
vec.x = d;
|
vec.x = d;
|
||||||
emit onValueChanged();
|
Q_EMIT onValueChanged();
|
||||||
});
|
});
|
||||||
connect(
|
connect(
|
||||||
spinBoxes.y,
|
spinBoxes.y,
|
||||||
static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
||||||
[this, &vec](double d) {
|
[this, &vec](double d) {
|
||||||
vec.y = d;
|
vec.y = d;
|
||||||
emit onValueChanged();
|
Q_EMIT onValueChanged();
|
||||||
});
|
});
|
||||||
connect(
|
connect(
|
||||||
spinBoxes.z,
|
spinBoxes.z,
|
||||||
static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
|
||||||
[this, &vec](double d) {
|
[this, &vec](double d) {
|
||||||
vec.z = d;
|
vec.z = d;
|
||||||
emit onValueChanged();
|
Q_EMIT onValueChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
add_executable(bonedecomp
|
add_executable(bonedecomp
|
||||||
src/main.cpp)
|
src/main.cpp)
|
||||||
target_link_libraries(bonedecomp PUBLIC libxiv ${LIBRARIES} Qt5::Core Qt5::Widgets magic_enum)
|
target_link_libraries(bonedecomp PUBLIC libxiv ${LIBRARIES} Qt6::Core Qt6::Widgets magic_enum)
|
||||||
|
|
||||||
install(TARGETS bonedecomp
|
install(TARGETS bonedecomp
|
||||||
DESTINATION "${INSTALL_BIN_PATH}")
|
DESTINATION "${INSTALL_BIN_PATH}")
|
||||||
|
|
|
@ -13,4 +13,4 @@ target_include_directories(NovusCommon PUBLIC
|
||||||
include
|
include
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_BINARY_DIR})
|
${CMAKE_BINARY_DIR})
|
||||||
target_link_libraries(NovusCommon PUBLIC Qt5::Core Qt5::Widgets KF5::ConfigCore KF5::XmlGui physis)
|
target_link_libraries(NovusCommon PUBLIC Qt6::Core Qt6::Widgets KF6::CoreAddons KF6::ConfigCore KF6::XmlGui physis)
|
||||||
|
|
|
@ -15,10 +15,10 @@ public:
|
||||||
explicit FileCache(GameData& data);
|
explicit FileCache(GameData& data);
|
||||||
|
|
||||||
bool fileExists(const QLatin1String &path);
|
bool fileExists(const QLatin1String &path);
|
||||||
physis_Buffer& lookupFile(const QString& path);
|
physis_Buffer &lookupFile(const QLatin1String &path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString, physis_Buffer> cachedBuffers;
|
QMap<QLatin1String, physis_Buffer> cachedBuffers;
|
||||||
QHash<QLatin1String, bool> cachedExist;
|
QHash<QLatin1String, bool> cachedExist;
|
||||||
GameData& data;
|
GameData& data;
|
||||||
};
|
};
|
|
@ -21,18 +21,16 @@ void customizeAboutData(
|
||||||
QStringLiteral("josh@redstrate.com"),
|
QStringLiteral("josh@redstrate.com"),
|
||||||
QStringLiteral("https://redstrate.com/"));
|
QStringLiteral("https://redstrate.com/"));
|
||||||
about.setHomepage(QStringLiteral("https://xiv.zone/astra"));
|
about.setHomepage(QStringLiteral("https://xiv.zone/astra"));
|
||||||
about.addComponent(
|
about.addComponent(QStringLiteral("physis"),
|
||||||
QStringLiteral("physis"),
|
QStringLiteral("Library to access FFXIV data"),
|
||||||
QStringLiteral("Library to access FFXIV data"),
|
QLatin1String(physis_get_physis_version()),
|
||||||
physis_get_physis_version(),
|
QStringLiteral("https://xiv.zone/physis"),
|
||||||
QStringLiteral("https://xiv.zone/physis"),
|
KAboutLicense::GPL_V3);
|
||||||
KAboutLicense::GPL_V3);
|
about.addComponent(QStringLiteral("libphysis"),
|
||||||
about.addComponent(
|
QStringLiteral("C bindings for physis"),
|
||||||
QStringLiteral("libphysis"),
|
QLatin1String(physis_get_libphysis_version()),
|
||||||
QStringLiteral("C bindings for physis"),
|
{},
|
||||||
physis_get_libphysis_version(),
|
KAboutLicense::GPL_V3);
|
||||||
{},
|
|
||||||
KAboutLicense::GPL_V3);
|
|
||||||
about.setBugAddress(QByteArrayLiteral("https://lists.sr.ht/~redstrate/public-inbox"));
|
about.setBugAddress(QByteArrayLiteral("https://lists.sr.ht/~redstrate/public-inbox"));
|
||||||
about.setComponentName(componentName);
|
about.setComponentName(componentName);
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
|
|
||||||
FileCache::FileCache(GameData& data) : data(data) {}
|
FileCache::FileCache(GameData& data) : data(data) {}
|
||||||
|
|
||||||
physis_Buffer& FileCache::lookupFile(const QString& path) {
|
physis_Buffer &FileCache::lookupFile(const QLatin1String &path)
|
||||||
|
{
|
||||||
if (!cachedBuffers.contains(path)) {
|
if (!cachedBuffers.contains(path)) {
|
||||||
cachedBuffers[path] = physis_gamedata_extract_file(&data, path.toStdString().c_str());
|
cachedBuffers[path] = physis_gamedata_extract_file(&data, path.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
return cachedBuffers[path];
|
return cachedBuffers[path];
|
||||||
|
|
|
@ -9,14 +9,14 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
QString getGameDirectory() {
|
QString getGameDirectory() {
|
||||||
KConfig config("novusrc");
|
KConfig config(QStringLiteral("novusrc"));
|
||||||
KConfigGroup game = config.group("Game");
|
KConfigGroup game = config.group(QStringLiteral("Game"));
|
||||||
|
|
||||||
if (game.hasKey("GameDir")) {
|
if (game.hasKey(QStringLiteral("GameDir"))) {
|
||||||
return game.readEntry("GameDir");
|
return game.readEntry(QStringLiteral("GameDir"));
|
||||||
} else {
|
} else {
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setText("The game directory has not been set. Please open the Novus SDK launcher and set it.");
|
msgBox.setText(QStringLiteral("The game directory has not been set. Please open the Novus SDK launcher and set it."));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -7,7 +7,7 @@ add_executable(exdviewer
|
||||||
target_include_directories(exdviewer
|
target_include_directories(exdviewer
|
||||||
PUBLIC
|
PUBLIC
|
||||||
include)
|
include)
|
||||||
target_link_libraries(exdviewer PUBLIC physis z ${LIBRARIES} Qt5::Core Qt5::Widgets exdpart NovusCommon)
|
target_link_libraries(exdviewer PUBLIC physis z ${LIBRARIES} Qt6::Core Qt6::Widgets exdpart NovusCommon)
|
||||||
|
|
||||||
install(TARGETS exdviewer
|
install(TARGETS exdviewer
|
||||||
DESTINATION "${INSTALL_BIN_PATH}")
|
DESTINATION "${INSTALL_BIN_PATH}")
|
||||||
|
|
|
@ -18,34 +18,34 @@
|
||||||
#include "exdpart.h"
|
#include "exdpart.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(GameData* data) : data(data) {
|
MainWindow::MainWindow(GameData* data) : data(data) {
|
||||||
setWindowTitle("exdviewer");
|
setWindowTitle(QStringLiteral("exdviewer"));
|
||||||
setMinimumSize(1280, 720);
|
setMinimumSize(1280, 720);
|
||||||
|
|
||||||
auto fileMenu = menuBar()->addMenu("File");
|
auto fileMenu = menuBar()->addMenu(QStringLiteral("File"));
|
||||||
|
|
||||||
auto quitAction = fileMenu->addAction("Quit");
|
auto quitAction = fileMenu->addAction(QStringLiteral("Quit"));
|
||||||
quitAction->setIcon(QIcon::fromTheme("gtk-quit"));
|
quitAction->setIcon(QIcon::fromTheme(QStringLiteral("gtk-quit")));
|
||||||
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||||
|
|
||||||
auto helpMenu = menuBar()->addMenu("Help");
|
auto helpMenu = menuBar()->addMenu(QStringLiteral("Help"));
|
||||||
|
|
||||||
auto donateAction = helpMenu->addAction("Donate");
|
auto donateAction = helpMenu->addAction(QStringLiteral("Donate"));
|
||||||
connect(donateAction, &QAction::triggered, this, [] {
|
connect(donateAction, &QAction::triggered, this, [] {
|
||||||
QDesktopServices::openUrl(QUrl("https://redstrate.com/fund"));
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://redstrate.com/fund")));
|
||||||
});
|
});
|
||||||
donateAction->setIcon(QIcon::fromTheme("help-donate"));
|
donateAction->setIcon(QIcon::fromTheme(QStringLiteral("help-donate")));
|
||||||
|
|
||||||
helpMenu->addSeparator();
|
helpMenu->addSeparator();
|
||||||
|
|
||||||
auto aboutNovusAction = helpMenu->addAction("About exdviewer");
|
auto aboutNovusAction = helpMenu->addAction(QStringLiteral("About exdviewer"));
|
||||||
aboutNovusAction->setIcon(QIcon::fromTheme("help-about"));
|
aboutNovusAction->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
|
||||||
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
||||||
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
||||||
window->show();
|
window->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto aboutQtAction = helpMenu->addAction("About Qt");
|
auto aboutQtAction = helpMenu->addAction(QStringLiteral("About Qt"));
|
||||||
aboutQtAction->setIcon(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"));
|
aboutQtAction->setIcon(QIcon(QStringLiteral(":/qt-project.org/qmessagebox/images/qtlogo-64.png")));
|
||||||
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
||||||
|
|
||||||
auto dummyWidget = new QWidget();
|
auto dummyWidget = new QWidget();
|
||||||
|
@ -58,7 +58,7 @@ MainWindow::MainWindow(GameData* data) : data(data) {
|
||||||
|
|
||||||
auto names = physis_gamedata_get_all_sheet_names(data);
|
auto names = physis_gamedata_get_all_sheet_names(data);
|
||||||
for (int i = 0; i < names.name_count; i++) {
|
for (int i = 0; i < names.name_count; i++) {
|
||||||
listWidget->addItem(names.names[i]);
|
listWidget->addItem(QString::fromStdString(names.names[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
listWidget->setMaximumWidth(200);
|
listWidget->setMaximumWidth(200);
|
||||||
|
@ -72,6 +72,6 @@ MainWindow::MainWindow(GameData* data) : data(data) {
|
||||||
auto name = item->text().toStdString();
|
auto name = item->text().toStdString();
|
||||||
auto nameLowercase = item->text().toLower().toStdString();
|
auto nameLowercase = item->text().toLower().toStdString();
|
||||||
|
|
||||||
exdPart->loadSheet(name.c_str());
|
exdPart->loadSheet(QString::fromStdString(name.c_str()));
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ add_executable(explorer
|
||||||
target_include_directories(explorer
|
target_include_directories(explorer
|
||||||
PUBLIC
|
PUBLIC
|
||||||
include)
|
include)
|
||||||
target_link_libraries(explorer PUBLIC physis z ${LIBRARIES} Qt5::Core Qt5::Widgets NovusCommon)
|
target_link_libraries(explorer PUBLIC physis z ${LIBRARIES} Qt6::Core Qt6::Widgets NovusCommon)
|
||||||
|
|
||||||
install(TARGETS explorer
|
install(TARGETS explorer
|
||||||
DESTINATION "${INSTALL_BIN_PATH}")
|
DESTINATION "${INSTALL_BIN_PATH}")
|
||||||
|
|
|
@ -30,6 +30,6 @@ private:
|
||||||
|
|
||||||
QTreeWidgetItem* addPartAndChildren(const QString& qString, const PathPart& part, const QString& pathSoFar);
|
QTreeWidgetItem* addPartAndChildren(const QString& qString, const PathPart& part, const QString& pathSoFar);
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void openFileProperties(QString path);
|
void openFileProperties(QString path);
|
||||||
};
|
};
|
|
@ -11,21 +11,21 @@
|
||||||
|
|
||||||
FilePropertiesWindow::FilePropertiesWindow(GameData* data, QString path, QWidget* parent)
|
FilePropertiesWindow::FilePropertiesWindow(GameData* data, QString path, QWidget* parent)
|
||||||
: QWidget(parent), data(data) {
|
: QWidget(parent), data(data) {
|
||||||
setWindowTitle("Properties for " + path);
|
setWindowTitle(QStringLiteral("Properties for ") + path);
|
||||||
|
|
||||||
auto layout = new QFormLayout();
|
auto layout = new QFormLayout();
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
auto pathLabel = new QLabel(path);
|
auto pathLabel = new QLabel(path);
|
||||||
layout->addRow("Path", pathLabel);
|
layout->addRow(QStringLiteral("Path"), pathLabel);
|
||||||
|
|
||||||
auto typeLabel = new QLabel("Unknown type");
|
auto typeLabel = new QLabel(QStringLiteral("Unknown type"));
|
||||||
layout->addRow("Type", typeLabel);
|
layout->addRow(QStringLiteral("Type"), typeLabel);
|
||||||
|
|
||||||
auto file = physis_gamedata_extract_file(data, path.toStdString().c_str());
|
auto file = physis_gamedata_extract_file(data, path.toStdString().c_str());
|
||||||
|
|
||||||
auto sizeLabel = new QLabel(QString::number(file.size));
|
auto sizeLabel = new QLabel(QString::number(file.size));
|
||||||
layout->addRow("Size (in bytes)", sizeLabel);
|
layout->addRow(QStringLiteral("Size (in bytes)"), sizeLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_filepropertieswindow.cpp"
|
#include "moc_filepropertieswindow.cpp"
|
|
@ -9,33 +9,33 @@
|
||||||
#include "filetreewindow.h"
|
#include "filetreewindow.h"
|
||||||
|
|
||||||
FileTreeWindow::FileTreeWindow(GameData* data, QWidget* parent) : QWidget(parent), data(data) {
|
FileTreeWindow::FileTreeWindow(GameData* data, QWidget* parent) : QWidget(parent), data(data) {
|
||||||
setWindowTitle("File Tree");
|
setWindowTitle(QStringLiteral("File Tree"));
|
||||||
|
|
||||||
auto layout = new QHBoxLayout();
|
auto layout = new QHBoxLayout();
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
auto treeWidget = new QTreeWidget();
|
auto treeWidget = new QTreeWidget();
|
||||||
treeWidget->setHeaderLabel("Name");
|
treeWidget->setHeaderLabel(QStringLiteral("Name"));
|
||||||
layout->addWidget(treeWidget);
|
layout->addWidget(treeWidget);
|
||||||
|
|
||||||
addPath("common/font/AXIS_12.fdt");
|
addPath(QStringLiteral("common/font/AXIS_12.fdt"));
|
||||||
|
|
||||||
addPath("exd/root.exl");
|
addPath(QStringLiteral("exd/root.exl"));
|
||||||
|
|
||||||
auto sheetNames = physis_gamedata_get_all_sheet_names(data);
|
auto sheetNames = physis_gamedata_get_all_sheet_names(data);
|
||||||
|
|
||||||
for(int i = 0; i < sheetNames.name_count; i++) {
|
for(int i = 0; i < sheetNames.name_count; i++) {
|
||||||
auto sheetName = sheetNames.names[i];
|
auto sheetName = sheetNames.names[i];
|
||||||
auto nameLowercase = QString(sheetName).toLower().toStdString();
|
auto nameLowercase = QString::fromStdString(sheetName).toLower().toStdString();
|
||||||
|
|
||||||
addPath("exd/" + QString(nameLowercase.c_str()) + ".exh");
|
addPath(QStringLiteral("exd/") + QLatin1String(nameLowercase.c_str()) + QStringLiteral(".exh"));
|
||||||
|
|
||||||
auto exh = physis_gamedata_read_excel_sheet_header(data, sheetName);
|
auto exh = physis_gamedata_read_excel_sheet_header(data, sheetName);
|
||||||
for (int j = 0; j < exh->page_count; j++) {
|
for (int j = 0; j < exh->page_count; j++) {
|
||||||
for (int z = 0; z < exh->language_count; z++) {
|
for (int z = 0; z < exh->language_count; z++) {
|
||||||
std::string path = physis_gamedata_get_exd_filename(nameLowercase.c_str(), exh, exh->languages[z], j);
|
std::string path = physis_gamedata_get_exd_filename(nameLowercase.c_str(), exh, exh->languages[z], j);
|
||||||
|
|
||||||
addPath(("exd/" + path).c_str());
|
addPath(QStringLiteral("exd/") + QString::fromStdString(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,9 @@ FileTreeWindow::FileTreeWindow(GameData* data, QWidget* parent) : QWidget(parent
|
||||||
|
|
||||||
auto menu = new QMenu();
|
auto menu = new QMenu();
|
||||||
|
|
||||||
QAction *propertiesAction = menu->addAction("Properties");
|
QAction *propertiesAction = menu->addAction(QStringLiteral("Properties"));
|
||||||
connect(propertiesAction, &QAction::triggered, this, [=] {
|
connect(propertiesAction, &QAction::triggered, this, [=] {
|
||||||
emit openFileProperties(path);
|
Q_EMIT openFileProperties(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
QPoint pt(pos);
|
QPoint pt(pos);
|
||||||
|
@ -64,7 +64,7 @@ FileTreeWindow::FileTreeWindow(GameData* data, QWidget* parent) : QWidget(parent
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileTreeWindow::addPath(QString path) {
|
void FileTreeWindow::addPath(QString path) {
|
||||||
auto tokens = path.split('/');
|
auto tokens = path.split(QStringLiteral("/"));
|
||||||
auto nextToken = tokens[0];
|
auto nextToken = tokens[0];
|
||||||
tokens.pop_front();
|
tokens.pop_front();
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ void FileTreeWindow::traversePart(QList<QString> tokens, PathPart& part, QString
|
||||||
auto nextToken = tokens[0];
|
auto nextToken = tokens[0];
|
||||||
tokens.pop_front();
|
tokens.pop_front();
|
||||||
|
|
||||||
pathSoFar = pathSoFar + "/" + nextToken;
|
pathSoFar = pathSoFar + QStringLiteral("/") + nextToken;
|
||||||
part.children[nextToken].crcHash = physis_calculate_hash(pathSoFar.toStdString().c_str());
|
part.children[nextToken].crcHash = physis_calculate_hash(pathSoFar.toStdString().c_str());
|
||||||
|
|
||||||
traversePart(tokens, part.children[nextToken], pathSoFar);
|
traversePart(tokens, part.children[nextToken], pathSoFar);
|
||||||
|
@ -86,13 +86,13 @@ void FileTreeWindow::traversePart(QList<QString> tokens, PathPart& part, QString
|
||||||
|
|
||||||
void FileTreeWindow::addPaths(QTreeWidget *pWidget) {
|
void FileTreeWindow::addPaths(QTreeWidget *pWidget) {
|
||||||
for(const auto& name : rootParts.keys()) {
|
for(const auto& name : rootParts.keys()) {
|
||||||
auto item = addPartAndChildren(name, rootParts.value(name), "");
|
auto item = addPartAndChildren(name, rootParts.value(name), QStringLiteral(""));
|
||||||
pWidget->addTopLevelItem(item);
|
pWidget->addTopLevelItem(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QTreeWidgetItem* FileTreeWindow::addPartAndChildren(const QString& qString, const PathPart& part, const QString& pathSoFar) {
|
QTreeWidgetItem* FileTreeWindow::addPartAndChildren(const QString& qString, const PathPart& part, const QString& pathSoFar) {
|
||||||
QString newPath = pathSoFar.isEmpty() ? qString : pathSoFar + "/" + qString;
|
QString newPath = pathSoFar.isEmpty() ? qString : pathSoFar + QStringLiteral("/") + qString;
|
||||||
|
|
||||||
auto item = new QTreeWidgetItem();
|
auto item = new QTreeWidgetItem();
|
||||||
item->setData(0, Qt::UserRole, newPath);
|
item->setData(0, Qt::UserRole, newPath);
|
||||||
|
@ -111,7 +111,7 @@ void FileTreeWindow::addUnknownPath(QString knownDirectory, uint32_t crcHash) {
|
||||||
if(found)
|
if(found)
|
||||||
addPath(path);
|
addPath(path);
|
||||||
else
|
else
|
||||||
addPath(knownDirectory + "/Unknown File Hash " + QString::number(crcHash));
|
addPath(knownDirectory + QStringLiteral("/Unknown File Hash ") + QString::number(crcHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<bool, QString> FileTreeWindow::traverseUnknownPath(uint32_t crcHash, PathPart &part, QString pathSoFar) {
|
std::tuple<bool, QString> FileTreeWindow::traverseUnknownPath(uint32_t crcHash, PathPart &part, QString pathSoFar) {
|
||||||
|
@ -121,10 +121,10 @@ std::tuple<bool, QString> FileTreeWindow::traverseUnknownPath(uint32_t crcHash,
|
||||||
bool found = false;
|
bool found = false;
|
||||||
QString childPath = pathSoFar;
|
QString childPath = pathSoFar;
|
||||||
for(auto path : part.children.keys()) {
|
for(auto path : part.children.keys()) {
|
||||||
if(path.contains("Unknown"))
|
if (path.contains(QStringLiteral("Unknown")))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto [childFound, newPath] = traverseUnknownPath(crcHash, part.children[path], pathSoFar + "/" + path);
|
auto [childFound, newPath] = traverseUnknownPath(crcHash, part.children[path], pathSoFar + QStringLiteral("/") + path);
|
||||||
found |= childFound;
|
found |= childFound;
|
||||||
if(childFound)
|
if(childFound)
|
||||||
childPath = newPath;
|
childPath = newPath;
|
||||||
|
|
|
@ -18,7 +18,7 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
physis_initialize_logging();
|
physis_initialize_logging();
|
||||||
|
|
||||||
app.setStyle("Windows");
|
app.setStyle(QStringLiteral("Windows"));
|
||||||
|
|
||||||
const QString gameDir{getGameDirectory()};
|
const QString gameDir{getGameDirectory()};
|
||||||
const std::string gameDirStd{gameDir.toStdString()};
|
const std::string gameDirStd{gameDir.toStdString()};
|
||||||
|
|
|
@ -19,33 +19,33 @@
|
||||||
#include "filetreewindow.h"
|
#include "filetreewindow.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(GameData* data) : data(data) {
|
MainWindow::MainWindow(GameData* data) : data(data) {
|
||||||
setWindowTitle("explorer");
|
setWindowTitle(QStringLiteral("explorer"));
|
||||||
|
|
||||||
auto fileMenu = menuBar()->addMenu("File");
|
auto fileMenu = menuBar()->addMenu(QStringLiteral("File"));
|
||||||
|
|
||||||
auto quitAction = fileMenu->addAction("Quit");
|
auto quitAction = fileMenu->addAction(QStringLiteral("Quit"));
|
||||||
quitAction->setIcon(QIcon::fromTheme("gtk-quit"));
|
quitAction->setIcon(QIcon::fromTheme(QStringLiteral("gtk-quit")));
|
||||||
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||||
|
|
||||||
auto helpMenu = menuBar()->addMenu("Help");
|
auto helpMenu = menuBar()->addMenu(QStringLiteral("Help"));
|
||||||
|
|
||||||
auto donateAction = helpMenu->addAction("Donate");
|
auto donateAction = helpMenu->addAction(QStringLiteral("Donate"));
|
||||||
connect(donateAction, &QAction::triggered, this, [] {
|
connect(donateAction, &QAction::triggered, this, [] {
|
||||||
QDesktopServices::openUrl(QUrl("https://redstrate.com/fund"));
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://redstrate.com/fund")));
|
||||||
});
|
});
|
||||||
donateAction->setIcon(QIcon::fromTheme("help-donate"));
|
donateAction->setIcon(QIcon::fromTheme(QStringLiteral("help-donate")));
|
||||||
|
|
||||||
helpMenu->addSeparator();
|
helpMenu->addSeparator();
|
||||||
|
|
||||||
auto aboutNovusAction = helpMenu->addAction("About explorer");
|
auto aboutNovusAction = helpMenu->addAction(QStringLiteral("About explorer"));
|
||||||
aboutNovusAction->setIcon(QIcon::fromTheme("help-about"));
|
aboutNovusAction->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
|
||||||
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
||||||
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
||||||
window->show();
|
window->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto aboutQtAction = helpMenu->addAction("About Qt");
|
auto aboutQtAction = helpMenu->addAction(QStringLiteral("About Qt"));
|
||||||
aboutQtAction->setIcon(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"));
|
aboutQtAction->setIcon(QIcon(QStringLiteral(":/qt-project.org/qmessagebox/images/qtlogo-64.png")));
|
||||||
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
||||||
|
|
||||||
mdiArea = new QMdiArea();
|
mdiArea = new QMdiArea();
|
||||||
|
|
|
@ -7,7 +7,7 @@ add_executable(mdlviewer
|
||||||
target_include_directories(mdlviewer
|
target_include_directories(mdlviewer
|
||||||
PUBLIC
|
PUBLIC
|
||||||
include)
|
include)
|
||||||
target_link_libraries(mdlviewer PUBLIC physis z ${LIBRARIES} Qt5::Core Qt5::Widgets KF5::XmlGui mdlpart NovusCommon)
|
target_link_libraries(mdlviewer PUBLIC physis z ${LIBRARIES} Qt6::Core Qt6::Widgets KF6::XmlGui mdlpart NovusCommon)
|
||||||
|
|
||||||
install(TARGETS mdlviewer
|
install(TARGETS mdlviewer
|
||||||
DESTINATION "${INSTALL_BIN_PATH}")
|
DESTINATION "${INSTALL_BIN_PATH}")
|
||||||
|
|
|
@ -19,18 +19,15 @@
|
||||||
#include "mdlpart.h"
|
#include "mdlpart.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(GameData* data) : data(data), cache(FileCache{*data}) {
|
MainWindow::MainWindow(GameData* data) : data(data), cache(FileCache{*data}) {
|
||||||
setWindowTitle("Model Viewer");
|
setWindowTitle(QStringLiteral("Model Viewer"));
|
||||||
setMinimumSize(640, 480);
|
setMinimumSize(640, 480);
|
||||||
|
|
||||||
auto fileMenu = menuBar()->addMenu("File");
|
auto fileMenu = menuBar()->addMenu(QStringLiteral("File"));
|
||||||
|
|
||||||
auto openMDLFile = fileMenu->addAction("Open MDL...");
|
auto openMDLFile = fileMenu->addAction(QStringLiteral("Open MDL..."));
|
||||||
openMDLFile->setIcon(QIcon::fromTheme("document-open"));
|
openMDLFile->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
|
||||||
connect(openMDLFile, &QAction::triggered, [=] {
|
connect(openMDLFile, &QAction::triggered, [=] {
|
||||||
auto fileName = QFileDialog::getOpenFileName(nullptr,
|
auto fileName = QFileDialog::getOpenFileName(nullptr, QStringLiteral("Open MDL File"), QStringLiteral("~"), QStringLiteral("FFXIV Model File (*.mdl)"));
|
||||||
"Open MDL File",
|
|
||||||
"~",
|
|
||||||
"FFXIV Model File (*.mdl)");
|
|
||||||
|
|
||||||
auto buffer = physis_read_file(fileName.toStdString().c_str());
|
auto buffer = physis_read_file(fileName.toStdString().c_str());
|
||||||
|
|
||||||
|
@ -39,42 +36,42 @@ MainWindow::MainWindow(GameData* data) : data(data), cache(FileCache{*data}) {
|
||||||
|
|
||||||
fileMenu->addSeparator();
|
fileMenu->addSeparator();
|
||||||
|
|
||||||
auto quitAction = fileMenu->addAction("Quit");
|
auto quitAction = fileMenu->addAction(QStringLiteral("Quit"));
|
||||||
quitAction->setIcon(QIcon::fromTheme("gtk-quit"));
|
quitAction->setIcon(QIcon::fromTheme(QStringLiteral("gtk-quit")));
|
||||||
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
connect(quitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
|
||||||
|
|
||||||
auto helpMenu = menuBar()->addMenu("Help");
|
auto helpMenu = menuBar()->addMenu(QStringLiteral("Help"));
|
||||||
|
|
||||||
auto donateAction = helpMenu->addAction("Donate");
|
auto donateAction = helpMenu->addAction(QStringLiteral("Donate"));
|
||||||
connect(donateAction, &QAction::triggered, this, [] {
|
connect(donateAction, &QAction::triggered, this, [] {
|
||||||
QDesktopServices::openUrl(QUrl("https://redstrate.com/fund"));
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://redstrate.com/fund")));
|
||||||
});
|
});
|
||||||
donateAction->setIcon(QIcon::fromTheme("help-donate"));
|
donateAction->setIcon(QIcon::fromTheme(QStringLiteral("help-donate")));
|
||||||
|
|
||||||
helpMenu->addSeparator();
|
helpMenu->addSeparator();
|
||||||
|
|
||||||
auto aboutNovusAction = helpMenu->addAction("About Model Viewer");
|
auto aboutNovusAction = helpMenu->addAction(QStringLiteral("About Model Viewer"));
|
||||||
aboutNovusAction->setIcon(QIcon::fromTheme("help-about"));
|
aboutNovusAction->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
|
||||||
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
connect(aboutNovusAction, &QAction::triggered, this, [this] {
|
||||||
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
auto window = new KAboutApplicationDialog(KAboutData::applicationData(), this);
|
||||||
window->show();
|
window->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto aboutQtAction = helpMenu->addAction("About Qt");
|
auto aboutQtAction = helpMenu->addAction(QStringLiteral("About Qt"));
|
||||||
aboutQtAction->setIcon(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"));
|
aboutQtAction->setIcon(QIcon(QStringLiteral(":/qt-project.org/qmessagebox/images/qtlogo-64.png")));
|
||||||
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
connect(aboutQtAction, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
|
||||||
|
|
||||||
auto dummyWidget = new QWidget();
|
auto dummyWidget = new QWidget();
|
||||||
setCentralWidget(dummyWidget);
|
setCentralWidget(dummyWidget);
|
||||||
|
|
||||||
auto layout = new QHBoxLayout();
|
auto layout = new QHBoxLayout();
|
||||||
layout->setMargin(0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
dummyWidget->setLayout(layout);
|
dummyWidget->setLayout(layout);
|
||||||
|
|
||||||
part = new MDLPart(data, cache);
|
part = new MDLPart(data, cache);
|
||||||
|
|
||||||
const int raceCode = physis_get_race_code(Race::Hyur, Subrace::Midlander, Gender::Male);
|
const int raceCode = physis_get_race_code(Race::Hyur, Subrace::Midlander, Gender::Male);
|
||||||
QString skelName = QString{"c%1b0001.skel"}.arg(raceCode, 4, 10, QLatin1Char{'0'});
|
QString skelName = QStringLiteral("c%1b0001.skel").arg(raceCode, 4, 10, QLatin1Char{'0'});
|
||||||
part->setSkeleton(physis_skeleton_from_skel(physis_read_file(skelName.toStdString().c_str())));
|
part->setSkeleton(physis_skeleton_from_skel(physis_read_file(skelName.toStdString().c_str())));
|
||||||
|
|
||||||
layout->addWidget(part);
|
layout->addWidget(part);
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
add_library(exdpart STATIC exdpart.cpp)
|
add_library(exdpart STATIC exdpart.cpp)
|
||||||
target_link_libraries(exdpart PUBLIC physis z ${LIBRARIES} Qt5::Core Qt5::Widgets)
|
target_link_libraries(exdpart PUBLIC physis z ${LIBRARIES} Qt6::Core Qt6::Widgets)
|
||||||
target_include_directories(exdpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(exdpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
|
@ -25,15 +25,16 @@ void EXDPart::loadSheet(const QString& name) {
|
||||||
|
|
||||||
pageTabWidget->clear();
|
pageTabWidget->clear();
|
||||||
|
|
||||||
QFile definitionFile("Achievement.json");
|
QFile definitionFile(QStringLiteral("Achievement.json"));
|
||||||
definitionFile.open(QIODevice::ReadOnly);
|
definitionFile.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
auto document = QJsonDocument::fromJson(definitionFile.readAll());
|
auto document = QJsonDocument::fromJson(definitionFile.readAll());
|
||||||
auto definitionList = document.object()["definitions"].toArray();
|
auto definitionList = document.object()[QLatin1String("definitions")].toArray();
|
||||||
|
|
||||||
for (auto definition : definitionList) {
|
for (auto definition : definitionList) {
|
||||||
if (definition.toObject().contains("converter") && definition.toObject()["converter"].toObject()["type"].toString() == "link") {
|
if (definition.toObject().contains(QLatin1String("converter"))
|
||||||
auto linkName = definition.toObject()["converter"].toObject()["target"].toString();
|
&& definition.toObject()[QLatin1String("converter")].toObject()[QLatin1String("type")].toString() == QStringLiteral("link")) {
|
||||||
|
auto linkName = definition.toObject()[QLatin1String("converter")].toObject()[QLatin1String("target")].toString();
|
||||||
|
|
||||||
auto linkExh = physis_gamedata_read_excel_sheet_header(data, linkName.toStdString().c_str());
|
auto linkExh = physis_gamedata_read_excel_sheet_header(data, linkName.toStdString().c_str());
|
||||||
auto linkExd = physis_gamedata_read_excel_sheet(data, linkName.toStdString().c_str(), linkExh, getSuitableLanguage(linkExh), 0);
|
auto linkExd = physis_gamedata_read_excel_sheet(data, linkName.toStdString().c_str(), linkExh, getSuitableLanguage(linkExh), 0);
|
||||||
|
@ -61,41 +62,41 @@ void EXDPart::loadSheet(const QString& name) {
|
||||||
QString columnType;
|
QString columnType;
|
||||||
switch (columnData.tag) {
|
switch (columnData.tag) {
|
||||||
case physis_ColumnData::Tag::String:
|
case physis_ColumnData::Tag::String:
|
||||||
columnType = "String";
|
columnType = QStringLiteral("String");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Bool:
|
case physis_ColumnData::Tag::Bool:
|
||||||
columnType = "Bool";
|
columnType = QStringLiteral("Bool");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Int8:
|
case physis_ColumnData::Tag::Int8:
|
||||||
columnType = "Int8";
|
columnType = QStringLiteral("Int8");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::UInt8:
|
case physis_ColumnData::Tag::UInt8:
|
||||||
columnType = "UInt8";
|
columnType = QStringLiteral("UInt8");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Int16:
|
case physis_ColumnData::Tag::Int16:
|
||||||
columnType = "Int16";
|
columnType = QStringLiteral("Int16");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::UInt16:
|
case physis_ColumnData::Tag::UInt16:
|
||||||
columnType = "UInt16";
|
columnType = QStringLiteral("UInt16");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Int32:
|
case physis_ColumnData::Tag::Int32:
|
||||||
columnType = "Int32";
|
columnType = QStringLiteral("Int32");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::UInt32:
|
case physis_ColumnData::Tag::UInt32:
|
||||||
columnType = "UInt32";
|
columnType = QStringLiteral("UInt32");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Float32:
|
case physis_ColumnData::Tag::Float32:
|
||||||
columnType = "Float32";
|
columnType = QStringLiteral("Float32");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Int64:
|
case physis_ColumnData::Tag::Int64:
|
||||||
columnType = "Int64";
|
columnType = QStringLiteral("Int64");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::UInt64:
|
case physis_ColumnData::Tag::UInt64:
|
||||||
columnType = "UInt64";
|
columnType = QStringLiteral("UInt64");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
columnType = definitionList[z].toObject()["name"].toString();
|
columnType = definitionList[z].toObject()[QLatin1String("name")].toString();
|
||||||
|
|
||||||
auto headerItem = new QTableWidgetItem();
|
auto headerItem = new QTableWidgetItem();
|
||||||
headerItem->setText(columnType);
|
headerItem->setText(columnType);
|
||||||
|
@ -111,10 +112,10 @@ void EXDPart::loadSheet(const QString& name) {
|
||||||
int columnRow;
|
int columnRow;
|
||||||
switch (columnData.tag) {
|
switch (columnData.tag) {
|
||||||
case physis_ColumnData::Tag::String:
|
case physis_ColumnData::Tag::String:
|
||||||
columnString = QString(columnData.string._0);
|
columnString = QString::fromStdString(columnData.string._0);
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Bool:
|
case physis_ColumnData::Tag::Bool:
|
||||||
columnString = columnData.bool_._0 ? "True" : "False";
|
columnString = columnData.bool_._0 ? QStringLiteral("True") : QStringLiteral("False");
|
||||||
break;
|
break;
|
||||||
case physis_ColumnData::Tag::Int8:
|
case physis_ColumnData::Tag::Int8:
|
||||||
columnString = QString::number(columnData.int8._0);
|
columnString = QString::number(columnData.int8._0);
|
||||||
|
@ -154,15 +155,16 @@ void EXDPart::loadSheet(const QString& name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto definition = definitionList[z].toObject();
|
auto definition = definitionList[z].toObject();
|
||||||
if (definition.contains("converter") && definition["converter"].toObject()["type"].toString() == "link") {
|
if (definition.contains(QLatin1String("converter"))
|
||||||
auto linkName = definition["converter"].toObject()["target"].toString();
|
&& definition[QLatin1String("converter")].toObject()[QLatin1String("type")].toString() == QLatin1String("link")) {
|
||||||
|
auto linkName = definition[QLatin1String("converter")].toObject()[QLatin1String("target")].toString();
|
||||||
|
|
||||||
if (cachedExcelSheets.contains(linkName)) {
|
if (cachedExcelSheets.contains(linkName)) {
|
||||||
auto cachedExcel = cachedExcelSheets[linkName];
|
auto cachedExcel = cachedExcelSheets[linkName];
|
||||||
if (columnRow < cachedExcel.exd.row_count) {
|
if (columnRow < cachedExcel.exd.row_count) {
|
||||||
columnString = cachedExcel.exd.row_data[columnRow].column_data->string._0;
|
columnString = QString::fromStdString(cachedExcel.exd.row_data[columnRow].column_data->string._0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newItem = new QTableWidgetItem(columnString);
|
auto newItem = new QTableWidgetItem(columnString);
|
||||||
|
@ -173,7 +175,7 @@ void EXDPart::loadSheet(const QString& name) {
|
||||||
|
|
||||||
tableWidget->resizeColumnsToContents();
|
tableWidget->resizeColumnsToContents();
|
||||||
|
|
||||||
pageTabWidget->addTab(tableWidget, QString("Page %1").arg(i));
|
pageTabWidget->addTab(tableWidget, QStringLiteral("Page %1").arg(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
add_library(mdlpart STATIC mdlpart.cpp)
|
add_library(mdlpart STATIC mdlpart.cpp)
|
||||||
target_link_libraries(mdlpart PUBLIC physis z Qt5::Core Qt5::Widgets renderer NovusCommon tinygltf)
|
target_link_libraries(mdlpart PUBLIC physis z Qt6::Core Qt6::Widgets renderer NovusCommon tinygltf)
|
||||||
target_include_directories(mdlpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(mdlpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
|
@ -395,9 +395,9 @@ void MDLPart::setSkeleton(physis_Skeleton newSkeleton) {
|
||||||
|
|
||||||
void MDLPart::loadRaceDeformMatrices(physis_Buffer buffer) {
|
void MDLPart::loadRaceDeformMatrices(physis_Buffer buffer) {
|
||||||
QJsonDocument document = QJsonDocument::fromJson(QByteArray((const char*)buffer.data, buffer.size));
|
QJsonDocument document = QJsonDocument::fromJson(QByteArray((const char*)buffer.data, buffer.size));
|
||||||
for (auto boneObj : document.object()["Data"].toArray()) {
|
for (auto boneObj : document.object()[QLatin1String("Data")].toArray()) {
|
||||||
QJsonArray matrix = boneObj.toObject()["Matrix"].toArray();
|
QJsonArray matrix = boneObj.toObject()[QLatin1String("Matrix")].toArray();
|
||||||
QString boneName = boneObj.toObject()["Name"].toString();
|
QString boneName = boneObj.toObject()[QLatin1String("Name")].toString();
|
||||||
|
|
||||||
glm::mat4 actualMatrix;
|
glm::mat4 actualMatrix;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -486,28 +486,28 @@ RenderMaterial MDLPart::createMaterial(const physis_Material& material) {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'm': {
|
case 'm': {
|
||||||
auto texture = physis_texture_parse(cache.lookupFile(material.textures[i]));
|
auto texture = physis_texture_parse(cache.lookupFile(QLatin1String(material.textures[i])));
|
||||||
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
||||||
|
|
||||||
newMaterial.multiTexture = new RenderTexture(tex);
|
newMaterial.multiTexture = new RenderTexture(tex);
|
||||||
}
|
}
|
||||||
case 'd': {
|
case 'd': {
|
||||||
auto texture = physis_texture_parse(cache.lookupFile(material.textures[i]));
|
auto texture = physis_texture_parse(cache.lookupFile(QLatin1String(material.textures[i])));
|
||||||
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
||||||
|
|
||||||
newMaterial.diffuseTexture = new RenderTexture(tex);
|
newMaterial.diffuseTexture = new RenderTexture(tex);
|
||||||
} break;
|
} break;
|
||||||
case 'n': {
|
case 'n': {
|
||||||
auto texture = physis_texture_parse(cache.lookupFile(material.textures[i]));
|
auto texture = physis_texture_parse(cache.lookupFile(QLatin1String(material.textures[i])));
|
||||||
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
||||||
|
|
||||||
newMaterial.normalTexture = new RenderTexture(tex);
|
newMaterial.normalTexture = new RenderTexture(tex);
|
||||||
} break;
|
} break;
|
||||||
case 's': {
|
case 's': {
|
||||||
auto texture = physis_texture_parse(cache.lookupFile(material.textures[i]));
|
auto texture = physis_texture_parse(cache.lookupFile(QLatin1String(material.textures[i])));
|
||||||
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
auto tex = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size);
|
||||||
|
|
||||||
newMaterial.specularTexture = new RenderTexture(tex);
|
newMaterial.specularTexture = new RenderTexture(tex);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
qDebug() << "unhandled type" << type;
|
qDebug() << "unhandled type" << type;
|
||||||
|
|
|
@ -9,7 +9,7 @@ endif()
|
||||||
|
|
||||||
add_library(renderer STATIC src/renderer.cpp ${EXTRA_SRC})
|
add_library(renderer STATIC src/renderer.cpp ${EXTRA_SRC})
|
||||||
target_include_directories(renderer PUBLIC include)
|
target_include_directories(renderer PUBLIC include)
|
||||||
target_link_libraries(renderer PUBLIC Qt5::Core Vulkan::Vulkan physis z glm::glm ${EXTRA_LIBRARIES})
|
target_link_libraries(renderer PUBLIC Qt6::Core Vulkan::Vulkan physis z glm::glm ${EXTRA_LIBRARIES})
|
||||||
target_compile_definitions(renderer PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE)
|
target_compile_definitions(renderer PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE)
|
||||||
|
|
||||||
if(USE_STANDALONE_WINDOW)
|
if(USE_STANDALONE_WINDOW)
|
||||||
|
|
|
@ -88,12 +88,19 @@ Renderer::Renderer() {
|
||||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||||
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||||
|
|
||||||
|
int preferredDevice = 0;
|
||||||
|
int deviceIndex = 0;
|
||||||
for (auto device : devices) {
|
for (auto device : devices) {
|
||||||
VkPhysicalDeviceProperties deviceProperties;
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||||
|
|
||||||
|
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
||||||
|
preferredDevice = deviceIndex;
|
||||||
|
}
|
||||||
|
deviceIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
physicalDevice = devices[0];
|
physicalDevice = devices[preferredDevice];
|
||||||
|
|
||||||
extensionCount = 0;
|
extensionCount = 0;
|
||||||
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr,
|
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr,
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
add_executable(sdklauncher
|
add_executable(sdklauncher
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/mainwindow.cpp)
|
src/mainwindow.cpp)
|
||||||
target_link_libraries(sdklauncher PUBLIC Qt5::Widgets KF5::ConfigCore physis z)
|
target_link_libraries(sdklauncher PUBLIC Qt6::Widgets KF6::ConfigCore physis z)
|
||||||
target_include_directories(sdklauncher PUBLIC include)
|
target_include_directories(sdklauncher PUBLIC include)
|
||||||
|
|
|
@ -13,20 +13,19 @@
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
KConfig config("novusrc");
|
KConfig config(QStringLiteral("novusrc"));
|
||||||
KConfigGroup game = config.group("Game");
|
KConfigGroup game = config.group(QStringLiteral("Game"));
|
||||||
|
|
||||||
if (!game.hasKey("GameDir")) {
|
if (!game.hasKey("GameDir")) {
|
||||||
while (true) {
|
while (true) {
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setText("The game directory has not been set, please select it now. Select the 'game' folder.");
|
msgBox.setText(QStringLiteral("The game directory has not been set, please select it now. Select the 'game' folder."));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
|
||||||
const QString dir = QFileDialog::getExistingDirectory(
|
const QString dir = QFileDialog::getExistingDirectory(nullptr,
|
||||||
nullptr,
|
QStringLiteral("Open Game Directory"),
|
||||||
"Open Game Directory",
|
QStandardPaths::standardLocations(QStandardPaths::StandardLocation::HomeLocation).last(),
|
||||||
QStandardPaths::standardLocations(QStandardPaths::StandardLocation::HomeLocation).last(),
|
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
||||||
|
|
||||||
const std::string dirStd = dir.toStdString();
|
const std::string dirStd = dir.toStdString();
|
||||||
|
|
||||||
|
|
|
@ -12,20 +12,18 @@
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
static QMap<QString, QString> applications = {
|
static QMap<QString, QString> applications = {{QStringLiteral("Armoury"), QStringLiteral("armoury")},
|
||||||
{"Armoury", "armoury"},
|
{QStringLiteral("EXD Viewer"), QStringLiteral("exdviewer")},
|
||||||
{"EXD Viewer", "exdviewer"},
|
{QStringLiteral("Explorer"), QStringLiteral("explorer")},
|
||||||
{"Explorer", "explorer"},
|
{QStringLiteral("Model Viewer"), QStringLiteral("mdlviewer")}};
|
||||||
{"Model Viewer", "mdlviewer"}
|
|
||||||
};
|
|
||||||
|
|
||||||
MainWindow::MainWindow() {
|
MainWindow::MainWindow() {
|
||||||
setWindowTitle("Novus SDK");
|
setWindowTitle(QStringLiteral("Novus SDK"));
|
||||||
|
|
||||||
auto appList = new QListWidget();
|
auto appList = new QListWidget();
|
||||||
|
|
||||||
auto applicationHeader = new QListWidgetItem();
|
auto applicationHeader = new QListWidgetItem();
|
||||||
applicationHeader->setText("Applications");
|
applicationHeader->setText(QStringLiteral("Applications"));
|
||||||
applicationHeader->setFlags(Qt::NoItemFlags);
|
applicationHeader->setFlags(Qt::NoItemFlags);
|
||||||
|
|
||||||
appList->addItem(applicationHeader);
|
appList->addItem(applicationHeader);
|
||||||
|
@ -34,8 +32,8 @@ MainWindow::MainWindow() {
|
||||||
appList->addItem(name);
|
appList->addItem(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(appList, &QListWidget::itemClicked, [this](QListWidgetItem* item) {
|
connect(appList, &QListWidget::itemClicked, [this](QListWidgetItem *item) {
|
||||||
QString exec = "./" + applications[item->text()];
|
const QString exec = QStringLiteral("./") + applications[item->text()];
|
||||||
|
|
||||||
qDebug() << "Launching" << exec;
|
qDebug() << "Launching" << exec;
|
||||||
|
|
||||||
|
@ -50,11 +48,11 @@ MainWindow::MainWindow() {
|
||||||
|
|
||||||
auto formLayout = new QFormLayout();
|
auto formLayout = new QFormLayout();
|
||||||
|
|
||||||
KConfig config("novusrc");
|
KConfig config(QStringLiteral("novusrc"));
|
||||||
KConfigGroup game = config.group("Game");
|
KConfigGroup game = config.group("Game");
|
||||||
|
|
||||||
auto gameCombo = new QComboBox();
|
auto gameCombo = new QComboBox();
|
||||||
formLayout->addRow("Current Game", gameCombo);
|
formLayout->addRow(QStringLiteral("Current Game"), gameCombo);
|
||||||
formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||||
gameCombo->addItem(game.readEntry("GameDir"));
|
gameCombo->addItem(game.readEntry("GameDir"));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue