Merge pull request #4 from NickJohn547745/feature/new_shit

Add a tonnn of stuff
This commit is contained in:
Nicholas Johnson 2025-04-04 20:48:02 -04:00 committed by GitHub
commit 0df96fe804
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
235 changed files with 21419 additions and 2383 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,72 +1,12 @@
QT += core gui 3dcore 3drender 3dinput 3dextras
TEMPLATE = subdirs
RC_ICONS = XPlor.ico
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
SOURCES += \
aboutdialog.cpp \
ddsfile.cpp \
ddsviewer.cpp \
fastfile.cpp \
fastfileviewer.cpp \
imagewidget.cpp \
iwifile.cpp \
iwiviewer.cpp \
localstringviewer.cpp \
lzokay.cpp \
main.cpp \
mainwindow.cpp \
modelviewer.cpp \
iwifile.cpp \
techsetviewer.cpp \
xtreewidget.cpp \
zonefile.cpp \
zonefileviewer.cpp
HEADERS += \
aboutdialog.h \
asset_structs.h \
compressor.h \
d3dbsp_structs.h \
dds_structs.h \
ddsfile.h \
ddsviewer.h \
enums.h \
fastfile.h \
fastfileviewer.h \
imagewidget.h \
ipak_structs.h \
iwifile.h \
iwiviewer.h \
localstringviewer.h \
lzokay.hpp \
lzx.h \
mainwindow.h \
modelviewer.h \
techsetviewer.h \
utils.h \
xtreewidget.h \
iwifile.h \
zonefile.h \
zonefileviewer.h
FORMS += \
aboutdialog.ui \
ddsviewer.ui \
fastfileviewer.ui \
imagewidget.ui \
iwiviewer.ui \
localstringviewer.ui \
mainwindow.ui \
techsetviewer.ui \
zonefileviewer.ui
RESOURCES += \
data/Data.qrc
LIBS += -L$$PWD/DevILSDK/lib/x64/Unicode/Release -lDevIL
LIBS += -L$$PWD/DevILSDK/lib/x64/Unicode/Release -lILU
LIBS += -L$$PWD/DevILSDK/lib/x64/Unicode/Release -lILUT
SUBDIRS += libs/core \
libs/compression \
libs/encryption \
libs/fastfile \
libs/zonefile \
libs/ddsfile \
libs/iwifile \
libs/ipakfile \
app \
tests

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

113
app/app.pro Normal file
View File

@ -0,0 +1,113 @@
QT += core widgets gui multimedia
RC_ICONS = app.ico
SUBDIRS += app
CONFIG += c++17
SOURCES += \
aboutdialog.cpp \
ddsviewer.cpp \
fastfileviewer.cpp \
imagewidget.cpp \
iwiviewer.cpp \
localstringviewer.cpp \
main.cpp \
mainwindow.cpp \
materialviewer.cpp \
preferenceeditor.cpp \
soundviewer.cpp \
stringtableviewer.cpp \
techsetviewer.cpp \
xtreewidget.cpp \
xtreewidgetitem.cpp \
zonefileviewer.cpp
HEADERS += \
aboutdialog.h \
d3dbsp_structs.h \
ddsviewer.h \
fastfileviewer.h \
imagewidget.h \
iwiviewer.h \
localstringviewer.h \
mainwindow.h \
materialviewer.h \
preferenceeditor.h \
soundviewer.h \
stringtableviewer.h \
techsetviewer.h \
xtreewidget.h \
xtreewidgetitem.h \
zonefileviewer.h
FORMS += \
aboutdialog.ui \
ddsviewer.ui \
fastfileviewer.ui \
imagewidget.ui \
iwiviewer.ui \
localstringviewer.ui \
mainwindow.ui \
materialviewer.ui \
modelviewer.ui \
preferenceeditor.ui \
soundviewer.ui \
stringtableviewer.ui \
techsetviewer.ui \
zonefileviewer.ui
RESOURCES += ../data/data.qrc
app.depends += \
libs/core \
libs/compression \
libs/encryption \
libs/fastfile \
libs/ddsfile \
libs/ipakfile \
libs/iwifile \
libs/zonefile
LIBS += \
-L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
-L$$PWD/../third_party/zlib/lib/ -lzlib \
-L$$OUT_PWD/../libs/ -lcore \
-L$$OUT_PWD/../libs/ -lcompression \
-L$$OUT_PWD/../libs/ -lencryption \
-L$$OUT_PWD/../libs/ -lfastfile \
-L$$OUT_PWD/../libs/ -lddsfile \
-L$$OUT_PWD/../libs/ -lipakfile \
-L$$OUT_PWD/../libs/ -liwifile \
-L$$OUT_PWD/../libs/ -lzonefile
INCLUDEPATH += \
$$PWD/../third_party/devil_sdk/include/ \
$$PWD/../third_party/zlib/include \
$$PWD/../libs/core \
$$PWD/../libs/compression \
$$PWD/../libs/encryption \
$$PWD/../libs/fastfile \
$$PWD/../libs/ddsfile \
$$PWD/../libs/ipakfile \
$$PWD/../libs/iwifile \
$$PWD/../libs/zonefile
DEPENDPATH += \
$$PWD/../third_party/devil_sdk/include/ \
$$PWD/../third_party/zlib/include \
$$PWD/../libs/core \
$$PWD/../libs/compression \
$$PWD/../libs/encryption \
$$PWD/../libs/fastfile \
$$PWD/../libs/ddsfile \
$$PWD/../libs/ipakfile \
$$PWD/../libs/iwifile \
$$PWD/../libs/zonefile
# Copy DLLs to Debug folder
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
# Copy DLLs to Release folder
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)

View File

@ -18,9 +18,9 @@ FastFileViewer::~FastFileViewer()
void FastFileViewer::SetFastFile(std::shared_ptr<FastFile> aFastFile) {
mFastFile.swap(aFastFile);
ui->label_Title->setText(mFastFile->GetFileStem());
ui->label_Title->setText(mFastFile->GetStem() + ".ff");
ui->comboBox_Company->setCurrentIndex(mFastFile->GetCompany());
ui->comboBox_FileType->setCurrentIndex(mFastFile->GetFileType());
ui->comboBox_FileType->setCurrentIndex(mFastFile->GetType());
ui->checkBox_Signed->setChecked(mFastFile->GetSignage() == SIGNAGE_SIGNED);
ui->lineEdit_Magic->setText(mFastFile->GetMagic());
ui->spinBox_Version->setValue(mFastFile->GetVersion());

View File

@ -52,7 +52,7 @@ void LocalStringViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
mLocalStrings.clear();
ui->tableWidget_Strings->clear();
ui->label_Title->setText(aZoneFile->GetFileStem().section('.', 0, 0) + ".str");
ui->label_Title->setText(aZoneFile->GetStem().section('.', 0, 0) + ".str");
for (LocalString localStr : aZoneFile->GetAssetMap().localStrings) {
AddLocalString(localStr);
}

View File

@ -1,18 +1,29 @@
#include "mainwindow.h"
#include "aboutdialog.h"
#include "fastfile.h"
#include "qheaderview.h"
#include "materialviewer.h"
#include "preferenceeditor.h"
#include "soundviewer.h"
#include "stringtableviewer.h"
#include "techsetviewer.h"
#include "ui_mainwindow.h"
#include "compressor.h"
#include "dds_structs.h"
#include "compression.h"
#include "iwifile.h"
#include "ddsfile.h"
#include "statusbarmanager.h"
#include "ddsviewer.h"
#include "fastfileviewer.h"
#include "ipak_structs.h"
#include "iwiviewer.h"
#include "localstringviewer.h"
#include "imagewidget.h"
#include "xtreewidget.h"
#include "zonefileviewer.h"
#include "techsetviewer.h"
#include "logmanager.h"
#include <qmath.h>
#include "DevILSDK/include/IL/il.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
@ -30,10 +41,33 @@ MainWindow::MainWindow(QWidget *parent)
mDiskLumpOrder = QVector<quint32>();
mLumps = QMap<quint32, Lump>();
mTreeWidget = new XTreeWidget(this);
mLogWidget = new QPlainTextEdit(this);
//ModelViewer *mModelViewer = new ModelViewer(container);
//mModelViewer->setAcceptDrops(false);
mProgressBar = new QProgressBar(this);
mProgressBar->setMaximum(100); // Default max value
mProgressBar->setVisible(false); // Initially hidden
connect(&StatusBarManager::instance(), &StatusBarManager::statusUpdated,
this, &MainWindow::HandleStatusUpdate);
connect(&StatusBarManager::instance(), &StatusBarManager::progressUpdated,
this, &MainWindow::HandleProgressUpdate);
connect(&LogManager::instance(), &LogManager::entryAdded,
this, &MainWindow::HandleLogEntry);
statusBar()->addPermanentWidget(mProgressBar);
connect(ui->actionPreferences, &QAction::triggered, this, [this](bool checked) {
Q_UNUSED(checked);
PreferenceEditor *prefEditor = new PreferenceEditor(this);
prefEditor->exec();
});
ui->tabWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tabWidget, &QTabWidget::customContextMenuRequested, this, [this](const QPoint &pos) {
if (pos.isNull())
@ -104,9 +138,14 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->removeTab(index);
});
connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr<RawFile> rawFile) {
connect(mTreeWidget, &XTreeWidget::Cleared, this, [this]() {
ui->tabWidget->clear();
});
connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr<RawFile> rawFile, const QString aParentName) {
QPlainTextEdit *scriptEditor = new QPlainTextEdit(this);
scriptEditor->setAcceptDrops(false);
scriptEditor->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
if (rawFile->contents.isEmpty()) {
scriptEditor->setPlainText("EMPTY");
@ -121,15 +160,19 @@ MainWindow::MainWindow(QWidget *parent)
}
}
ui->tabWidget->addTab(scriptEditor, fileStem);
QScrollArea *scrollArea = new QScrollArea(ui->tabWidget);
scrollArea->layout()->addWidget(scriptEditor);
ui->tabWidget->addTab(scrollArea, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_GSCFile.png"));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::ImageSelected, this, [this](std::shared_ptr<Image> image) {
connect(mTreeWidget, &XTreeWidget::ImageSelected, this, [this](std::shared_ptr<Image> image, const QString aParentName) {
ImageWidget *mImageWidget = new ImageWidget(this);
mImageWidget->setAcceptDrops(false);
mImageWidget->SetImage(image);
mImageWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = image->materialName;
for (int i = 0; i < ui->tabWidget->count(); i++) {
@ -143,14 +186,15 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::MenuSelected, this, [this](std::shared_ptr<Menu> menu) {
connect(mTreeWidget, &XTreeWidget::MenuSelected, this, [](std::shared_ptr<Menu> menu, const QString aParentName) {
Q_UNUSED(menu);
});
connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](std::shared_ptr<DDSFile> ddsFile) {
connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](std::shared_ptr<DDSFile> ddsFile, const QString aParentName) {
DDSViewer *ddsViewer = new DDSViewer(this);
ddsViewer->setAcceptDrops(false);
ddsViewer->SetDDSFile(ddsFile);
ddsViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = ddsFile->fileStem + ".dds";
for (int i = 0; i < ui->tabWidget->count(); i++) {
@ -164,10 +208,47 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::IWIFileSelected, this, [this](std::shared_ptr<IWIFile> iwiFile) {
connect(mTreeWidget, &XTreeWidget::MaterialSelected, this, [this](std::shared_ptr<Material> material, const QString aParentName) {
MaterialViewer *matViewer = new MaterialViewer(this);
matViewer->setAcceptDrops(false);
matViewer->SetMaterial(material);
matViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = material->name;
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) {
return;
}
}
ui->tabWidget->addTab(matViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_Material.png"));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](std::shared_ptr<DDSFile> ddsFile, const QString aParentName) {
DDSViewer *ddsViewer = new DDSViewer(this);
ddsViewer->setAcceptDrops(false);
ddsViewer->SetDDSFile(ddsFile);
ddsViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = ddsFile->fileStem + ".dds";
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) {
return;
}
}
ui->tabWidget->addTab(ddsViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_DDSFile.png"));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::IWIFileSelected, this, [this](std::shared_ptr<IWIFile> iwiFile, const QString aParentName) {
IWIViewer *iwiViewer = new IWIViewer(this);
iwiViewer->setAcceptDrops(false);
iwiViewer->SetIWIFile(iwiFile);
iwiViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = iwiFile->fileStem + ".iwi";
for (int i = 0; i < ui->tabWidget->count(); i++) {
@ -181,12 +262,13 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::FastFileSelected, this, [this](std::shared_ptr<FastFile> aFastFile) {
connect(mTreeWidget, &XTreeWidget::FastFileSelected, this, [this](std::shared_ptr<FastFile> aFastFile, const QString aParentName) {
FastFileViewer *fastFileViewer = new FastFileViewer(this);
fastFileViewer->setAcceptDrops(false);
fastFileViewer->SetFastFile(aFastFile);
fastFileViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aFastFile->GetFileStem();
QString fileStem = aFastFile->GetStem() + ".ff";
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) {
return;
@ -198,29 +280,43 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::ZoneFileSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile) {
connect(mTreeWidget, &XTreeWidget::ZoneFileSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName) {
ZoneFileViewer *zoneFileViewer = new ZoneFileViewer(this);
zoneFileViewer->setAcceptDrops(false);
zoneFileViewer->SetZoneFile(aZoneFile);
zoneFileViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aZoneFile->GetFileStem();
QString fileStem = aZoneFile->GetStem() + ".zone";
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) {
return;
}
}
ui->tabWidget->addTab(zoneFileViewer, fileStem);
QWidget *containerWidget = new QWidget();
QVBoxLayout *layout = new QVBoxLayout(containerWidget);
layout->addWidget(zoneFileViewer);
containerWidget->setLayout(layout);
// Create a scroll area and set its properties
QScrollArea *scrollArea = new QScrollArea(ui->tabWidget);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scrollArea->setWidgetResizable(true); // Important to allow resizing
scrollArea->setWidget(containerWidget);
ui->tabWidget->addTab(scrollArea, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_ZoneFile.png"));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::LocalStringSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile) {
connect(mTreeWidget, &XTreeWidget::LocalStringSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName) {
LocalStringViewer *localStrViewer = new LocalStringViewer(this);
localStrViewer->setAcceptDrops(false);
localStrViewer->SetZoneFile(aZoneFile);
localStrViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aZoneFile->GetFileStem() + ".str";
QString fileStem = aZoneFile->GetStem() + ".str";
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) {
return;
@ -232,11 +328,11 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::TechSetSelected, this, [this](std::shared_ptr<TechSet> aTechSet) {
connect(mTreeWidget, &XTreeWidget::TechSetSelected, this, [this](std::shared_ptr<TechSet> aTechSet, const QString aParentName) {
TechSetViewer *techSetViewer = new TechSetViewer(this);
techSetViewer->setAcceptDrops(false);
techSetViewer->SetTechSet(aTechSet);
techSetViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aTechSet->name;
for (int i = 0; i < ui->tabWidget->count(); i++) {
@ -250,6 +346,61 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::StrTableSelected, this, [this](std::shared_ptr<StringTable> aStrTable, const QString aParentName) {
StringTableViewer *strTableViewer = new StringTableViewer(this);
strTableViewer->setAcceptDrops(false);
strTableViewer->SetStringTable(aStrTable);
strTableViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aStrTable->name;
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) {
return;
}
}
ui->tabWidget->addTab(strTableViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_StringTable.png"));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::SoundSelected, this, [this](std::shared_ptr<Sound> aSound, const QString aParentName) {
SoundViewer *soundViewer = new SoundViewer(this);
soundViewer->setAcceptDrops(false);
soundViewer->SetSound(aSound);
soundViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
QString fileStem = aSound->path.split('/').last();
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == fileStem) {
return;
}
}
ui->tabWidget->addTab(soundViewer, fileStem);
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_Sound.png"));
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
});
connect(mTreeWidget, &XTreeWidget::ItemSelected, this, [this](const QString itemText) {
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == itemText) {
ui->tabWidget->setCurrentIndex(i);
break;
}
}
});
connect(mTreeWidget, &XTreeWidget::ItemClosed, this, [this](const QString itemText) {
for (int i = 0; i < ui->tabWidget->count(); i++) {
const QString parentName = ui->tabWidget->widget(i)->property("PARENT_NAME").toString();
if (parentName == itemText) {
ui->tabWidget->removeTab(i);
break;
}
}
});
// Connect Help > About dialog
connect(ui->actionAbout, &QAction::triggered, this, [this](bool checked) {
Q_UNUSED(checked);
@ -273,8 +424,14 @@ MainWindow::MainWindow(QWidget *parent)
QDockWidget *treeDockWidget = new QDockWidget(this);
treeDockWidget->setWidget(mTreeWidget);
treeDockWidget->setWindowTitle("Tree Browser");
addDockWidget(Qt::LeftDockWidgetArea, treeDockWidget);
QDockWidget *logDockWidget = new QDockWidget(this);
logDockWidget->setWidget(mLogWidget);
logDockWidget->setWindowTitle("Logs");
addDockWidget(Qt::RightDockWidgetArea, logDockWidget);
ui->toolBar->addAction(ui->actionNew_Fast_File);
ui->toolBar->addAction(ui->actionNew_Zone_File);
ui->toolBar->addAction(ui->actionOpen_Fast_File);
@ -318,15 +475,18 @@ void MainWindow::Reset() {
and opens the selected file.
*/
bool MainWindow::OpenFastFile(const QString aFastFilePath) {
FastFile fastFile;
if (!fastFile.Load(aFastFilePath)) {
qDebug() << "Error: Failed to load fast file!";
const QString fastFileStem = aFastFilePath.section("/", -1, -1).section('.', 0, 0);
if (mTreeWidget->HasFastFile(fastFileStem)) {
LogManager::instance().addError("Can't add duplicate file!");
return false;
}
mTreeWidget->AddFastFile(std::make_shared<FastFile>(fastFile));
std::shared_ptr<FastFile> fastFile = FastFile::Open(aFastFilePath);
fastFile->SetStem(fastFileStem);
mTreeWidget->AddFastFile(fastFile);
// Open zone file after decompressing ff and writing
return false;
return true;
}
/*
@ -351,14 +511,15 @@ bool MainWindow::OpenFastFile() {
and opens the selected file.
*/
bool MainWindow::OpenZoneFile(const QString aZoneFilePath, bool fromFF) {
Q_UNUSED(aZoneFilePath);
Q_UNUSED(fromFF);
ZoneFile zoneFile;
if (!zoneFile.Load(aZoneFilePath)) {
qDebug() << "Error: Failed to load zone file!";
return false;
}
mTreeWidget->AddZoneFile(std::make_shared<ZoneFile>(zoneFile));
//ZoneFile zoneFile;
//if (!zoneFile.Load(aZoneFilePath)) {
// qDebug() << "Error: Failed to load zone file!";
// return false;
//}
//mTreeWidget->AddZoneFile(std::make_shared<ZoneFile>(zoneFile));
return true;
}
@ -453,6 +614,28 @@ int MainWindow::LoadFile_DDSFiles(const QStringList aFilePaths) {
return 0;
}
void MainWindow::HandleLogEntry(const QString &entry) {
QString logContents = mLogWidget->toPlainText() + "\n" + entry;
if (mLogWidget->toPlainText().isEmpty()) {
logContents = entry;
}
mLogWidget->setPlainText(logContents);
}
void MainWindow::HandleStatusUpdate(const QString &message, int timeout) {
statusBar()->showMessage(message, timeout);
mProgressBar->setVisible(false); // Hide progress bar if just a message
}
void MainWindow::HandleProgressUpdate(const QString &message, int progress, int max) {
mProgressBar->setMaximum(max);
mProgressBar->setValue(progress);
mProgressBar->setVisible(true);
QString progressText = QString("%1 (%2/%3)").arg(message).arg(progress).arg(max);
statusBar()->showMessage(progressText);
}
int MainWindow::LoadFile_DDS(const QString aFilePath) {
if (!aFilePath.endsWith(".dds", Qt::CaseInsensitive)) {
qDebug() << "Error: Invalid filename " << aFilePath;
@ -572,7 +755,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
QString outputFilePath = outputFolder.filePath(QString("%1.iwi").arg(j));
if (command.compressed) {
data = Compressor::DecompressLZO(data);
data = Compression::DecompressLZO(data);
}
QFile outputFile(outputFilePath);
if (!outputFile.open(QIODevice::WriteOnly)) {
@ -666,9 +849,9 @@ void MainWindow::dropEvent(QDropEvent *event) {
foreach (const QUrl url, mimeData->urls()) {
const QString urlStr = url.toLocalFile();
if (urlStr.contains(".zone")) {
OpenZoneFile(urlStr);
qDebug() << "OpenZoneFile Returned: " << OpenZoneFile(urlStr);
} else if (urlStr.contains(".ff")) {
OpenFastFile(urlStr);
qDebug() << "OpenFastFile Returned: " << OpenFastFile(urlStr);
} else if (urlStr.contains(".ipak")) {
qDebug() << "LoadFile_IPAK Returned: " << LoadFile_IPAK(urlStr);
} else if (urlStr.contains(".xsub")) {
@ -689,11 +872,11 @@ void MainWindow::dropEvent(QDropEvent *event) {
qDebug() << "LZO: Failed to read file!";
continue;
}
QByteArray data = Compressor::DecompressLZO(lzoFile.readAll());
QByteArray data = Compression::DecompressLZO(lzoFile.readAll());
lzoFile.close();
if (data.isEmpty()) {
qDebug() << "LZO: Decompressor gave empty result!";
qDebug() << "LZO: Decompression gave empty result!";
continue;
}

View File

@ -3,16 +3,7 @@
#include "d3dbsp_structs.h"
#include "asset_structs.h"
#include "ddsviewer.h"
#include "fastfileviewer.h"
#include "ipak_structs.h"
#include "iwiviewer.h"
#include "localstringviewer.h"
#include "modelviewer.h"
#include "imagewidget.h"
#include "xtreewidget.h"
#include "zonefileviewer.h"
#include "techsetviewer.h"
#include <QMainWindow>
#include <QFileDialog>
@ -24,6 +15,7 @@
#include <QDockWidget>
#include <QPlainTextEdit>
#include <QMimeData>
#include <QProgressBar>
#include <windows.h>
QT_BEGIN_NAMESPACE
@ -55,6 +47,10 @@ private slots:
int LoadFile_DDS(const QString aFilePath);
int LoadFile_DDSFiles(const QStringList aFilePaths);
void HandleLogEntry(const QString &entry);
void HandleStatusUpdate(const QString &message, int timeout);
void HandleProgressUpdate(const QString &message, int progress, int max);
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
@ -72,6 +68,8 @@ private:
QMap<QString, QTreeWidgetItem*> mTreeMap;
QMap<QString, QVector<QPair<QString, QString>>> mStrTableMap;
XTreeWidget *mTreeWidget;
QPlainTextEdit *mLogWidget;
QProgressBar *mProgressBar;
quint32 mBSPVersion;
quint32 mDiskLumpCount;

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>986</width>
<height>692</height>
<width>1579</width>
<height>857</height>
</rect>
</property>
<property name="minimumSize">
@ -46,7 +46,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>986</width>
<width>1579</width>
<height>21</height>
</rect>
</property>
@ -58,17 +58,11 @@
<property name="title">
<string>Recent...</string>
</property>
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentOpenRecent"/>
</property>
</widget>
<widget class="QMenu" name="menuImport">
<property name="title">
<string>Import...</string>
</property>
<property name="icon">
<iconset theme="QIcon::ThemeIcon::FolderNew"/>
</property>
</widget>
<addaction name="actionNew_File_2"/>
<addaction name="actionNew_Fast_File"/>
@ -114,6 +108,8 @@
<addaction name="menuUndo_History"/>
<addaction name="menuRedo_History"/>
<addaction name="actionClear_Undo_History"/>
<addaction name="separator"/>
<addaction name="actionPreferences"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
@ -140,7 +136,8 @@
<widget class="QStatusBar" name="statusBar"/>
<action name="actionNew_File_2">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentNew"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_NewFile.png</normaloff>:/icons/icons/Icon_NewFile.png</iconset>
</property>
<property name="text">
<string>New</string>
@ -148,7 +145,8 @@
</action>
<action name="actionNew_Fast_File">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentNew"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_NewFile.png</normaloff>:/icons/icons/Icon_NewFile.png</iconset>
</property>
<property name="text">
<string>New Fast File</string>
@ -156,7 +154,8 @@
</action>
<action name="actionNew_Zone_File">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentNew"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_NewFile.png</normaloff>:/icons/icons/Icon_NewFile.png</iconset>
</property>
<property name="text">
<string>New Zone File</string>
@ -164,7 +163,8 @@
</action>
<action name="actionOpen_Fast_File">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_OpenFile.png</normaloff>:/icons/icons/Icon_OpenFile.png</iconset>
</property>
<property name="text">
<string>Open Fast File</string>
@ -172,7 +172,8 @@
</action>
<action name="actionOpen_Zone_File">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_OpenFile.png</normaloff>:/icons/icons/Icon_OpenFile.png</iconset>
</property>
<property name="text">
<string>Open Zone File</string>
@ -180,7 +181,8 @@
</action>
<action name="actionOpen_Folder">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentOpen"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_OpenFile.png</normaloff>:/icons/icons/Icon_OpenFile.png</iconset>
</property>
<property name="text">
<string>Open Folder</string>
@ -188,16 +190,14 @@
</action>
<action name="actionSave">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentSave"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_Save.png</normaloff>:/icons/icons/Icon_Save.png</iconset>
</property>
<property name="text">
<string>Save</string>
</property>
</action>
<action name="actionSave_As">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentSaveAs"/>
</property>
<property name="text">
<string>Save As</string>
</property>
@ -248,24 +248,19 @@
</property>
</action>
<action name="actionUndo">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditUndo"/>
</property>
<property name="text">
<string>Undo</string>
</property>
</action>
<action name="actionRedo">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditRedo"/>
</property>
<property name="text">
<string>Redo</string>
</property>
</action>
<action name="actionCut">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditCut"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_Cut.png</normaloff>:/icons/icons/Icon_Cut.png</iconset>
</property>
<property name="text">
<string>Cut</string>
@ -273,7 +268,8 @@
</action>
<action name="actionCopy">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditCopy"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_Copy.png</normaloff>:/icons/icons/Icon_Copy.png</iconset>
</property>
<property name="text">
<string>Copy</string>
@ -281,16 +277,14 @@
</action>
<action name="actionPaste">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditPaste"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_Paste.png</normaloff>:/icons/icons/Icon_Paste.png</iconset>
</property>
<property name="text">
<string>Paste</string>
</property>
</action>
<action name="actionRename">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::MailMessageNew"/>
</property>
<property name="text">
<string>Rename</string>
</property>
@ -306,9 +300,6 @@
</property>
</action>
<action name="actionDelete">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditDelete"/>
</property>
<property name="text">
<string>Delete</string>
</property>
@ -334,9 +325,6 @@
</property>
</action>
<action name="actionAbout">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::HelpAbout"/>
</property>
<property name="text">
<string>About</string>
</property>
@ -347,22 +335,27 @@
</property>
</action>
<action name="actionCheck_for_Updates">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::SyncSynchronizing"/>
</property>
<property name="text">
<string>Check for Updates</string>
</property>
</action>
<action name="actionFind_2">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditFind"/>
<iconset resource="../data/data.qrc">
<normaloff>:/icons/icons/Icon_Find.png</normaloff>:/icons/icons/Icon_Find.png</iconset>
</property>
<property name="text">
<string>Find</string>
</property>
</action>
<action name="actionPreferences">
<property name="text">
<string>Preferences...</string>
</property>
</action>
</widget>
<resources/>
<resources>
<include location="../data/data.qrc"/>
</resources>
<connections/>
</ui>

42
app/materialviewer.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "materialviewer.h"
#include "ui_materialviewer.h"
MaterialViewer::MaterialViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MaterialViewer) {
ui->setupUi(this);
}
MaterialViewer::~MaterialViewer() {
delete ui;
}
QString ToHexStr(quint32 in) {
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
}
void MaterialViewer::SetMaterial(std::shared_ptr<Material> aMaterial) {
ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
ui->lineEdit_Name->setText(aMaterial->name);
ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));
ui->lineEdit_RefName->setText(aMaterial->refName);
ui->lineEdit_Unknowns->setText(ToHexStr(aMaterial->unknownA[0])
+ ToHexStr(aMaterial->unknownA[1])
+ ToHexStr(aMaterial->unknownA[2])
+ ToHexStr(aMaterial->unknownA[3])
+ ToHexStr(aMaterial->unknownA[4])
+ ToHexStr(aMaterial->unknownA[5])
+ ToHexStr(aMaterial->unknownA[6])
+ ToHexStr(aMaterial->unknownA[7])
+ ToHexStr(aMaterial->unknownA[8])
+ ToHexStr(aMaterial->unknownA[9])
+ ToHexStr(aMaterial->unknownA[10])
+ ToHexStr(aMaterial->unknownA[11]));
ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[0]));
ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[1]));
ui->spinBox_TextureCount->setValue(aMaterial->textureCount);
ui->spinBox_ConstCount->setValue(aMaterial->constCount);
ui->lineEdit_TechSetPtr->setText(ToHexStr(aMaterial->techSetPtr));
ui->lineEdit_TexturePtr->setText(ToHexStr(aMaterial->texturePtr));
ui->lineEdit_ConstantPtr->setText(ToHexStr(aMaterial->constPtr));
}

27
app/materialviewer.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef MATERIALVIEWER_H
#define MATERIALVIEWER_H
#include "asset_structs.h"
#include <QWidget>
#include <QScrollArea>
namespace Ui {
class MaterialViewer;
}
class MaterialViewer : public QWidget
{
Q_OBJECT
public:
explicit MaterialViewer(QWidget *parent = nullptr);
~MaterialViewer();
void SetMaterial(std::shared_ptr<Material> aMaterial);
private:
Ui::MaterialViewer *ui;
};
#endif // MATERIALVIEWER_H

236
app/materialviewer.ui Normal file
View File

@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MaterialViewer</class>
<widget class="QWidget" name="MaterialViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1001</width>
<height>650</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_Title">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Material 0</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_3">
<property name="minimumSize">
<size>
<width>325</width>
<height>398</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>325</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="title">
<string>Header</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name Ptr:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_NamePtr"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Ref Ptr:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Ref Name:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Unknowns:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>State A:</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>State B:</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Texture Count:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_Name"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_RefPtr"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_RefName"/>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEdit_Unknowns"/>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineEdit_StateA"/>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="lineEdit_StateB"/>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="spinBox_TextureCount"/>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="spinBox_ConstCount"/>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="lineEdit_TechSetPtr"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Constant Count:</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Tech Set Ptr:</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Texture Ptr:</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Constant Ptr:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLineEdit" name="lineEdit_TexturePtr"/>
</item>
<item row="11" column="1">
<widget class="QLineEdit" name="lineEdit_ConstantPtr"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="minimumSize">
<size>
<width>400</width>
<height>400</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="title">
<string>Data</string>
</property>
<layout class="QGridLayout" name="gridLayout_6"/>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>143</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

14
app/modelviewer.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "modelviewer.h"
#include "ui_modelviewer.h"
ModelViewer::ModelViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::ModelViewer)
{
ui->setupUi(this);
}
ModelViewer::~ModelViewer()
{
delete ui;
}

22
app/modelviewer.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef MODELVIEWER_H
#define MODELVIEWER_H
#include <QWidget>
namespace Ui {
class ModelViewer;
}
class ModelViewer : public QWidget
{
Q_OBJECT
public:
explicit ModelViewer(QWidget *parent = nullptr);
~ModelViewer();
private:
Ui::ModelViewer *ui;
};
#endif // MODELVIEWER_H

624
app/modelviewer.ui Normal file
View File

@ -0,0 +1,624 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ModelViewer</class>
<widget class="QWidget" name="ModelViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1001</width>
<height>897</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Properties</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name Pointer:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox_NamePtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_42">
<property name="text">
<string>Model Name:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Tag Count:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_TagCount">
<property name="suffix">
<string> tags</string>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Root Tag Count: </string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBox_RootTagCount">
<property name="suffix">
<string> root tags</string>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Surface Count: </string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBox_SurfaceCount">
<property name="suffix">
<string> surfaces</string>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Unknown A:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="spinBox_UnknownA">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Bone Name Pointer:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Parent List Pointer:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="spinBox_ParentListPtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Quats Pointer:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="spinBox_QuatsPtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Transformation Pointer:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QSpinBox" name="spinBox_TransPtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Classification Pointer:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Base Material Pointer:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QSpinBox" name="spinBox_BaseMatPtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Surfaces Pointer;</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QSpinBox" name="spinBox_SurfacesPtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Material Handlers Pointer:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QSpinBox" name="spinBox_MatHandlesPtr">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Coll Surf Pointer:</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_2">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Coll Surface Count:</string>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_3">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="label_25">
<property name="text">
<string>Contents:</string>
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_4">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Bone Info Pointer:</string>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_5">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>Radius:</string>
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_2"/>
</item>
<item row="19" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Min X: </string>
</property>
</widget>
</item>
<item row="19" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_3"/>
</item>
<item row="20" column="0">
<widget class="QLabel" name="label_30">
<property name="text">
<string>Min Y: </string>
</property>
</widget>
</item>
<item row="20" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_4"/>
</item>
<item row="21" column="0">
<widget class="QLabel" name="label_31">
<property name="text">
<string>Min Z: </string>
</property>
</widget>
</item>
<item row="21" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_5"/>
</item>
<item row="22" column="0">
<widget class="QLabel" name="label_32">
<property name="text">
<string>Max X: </string>
</property>
</widget>
</item>
<item row="22" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_6"/>
</item>
<item row="23" column="0">
<widget class="QLabel" name="label_33">
<property name="text">
<string>Max Y: </string>
</property>
</widget>
</item>
<item row="23" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_7"/>
</item>
<item row="24" column="0">
<widget class="QLabel" name="label_34">
<property name="text">
<string>Max Z: </string>
</property>
</widget>
</item>
<item row="24" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_8"/>
</item>
<item row="25" column="0">
<widget class="QLabel" name="label_35">
<property name="text">
<string>Lod Count:</string>
</property>
</widget>
</item>
<item row="25" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_7">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="26" column="0">
<widget class="QLabel" name="label_36">
<property name="text">
<string>Coll Lod:</string>
</property>
</widget>
</item>
<item row="26" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_8">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="27" column="0">
<widget class="QLabel" name="label_37">
<property name="text">
<string>Stream Info Pointer:</string>
</property>
</widget>
</item>
<item row="27" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_9">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="28" column="0">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Memory Usage:</string>
</property>
</widget>
</item>
<item row="28" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_10">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="29" column="0">
<widget class="QLabel" name="label_39">
<property name="text">
<string>Flags:</string>
</property>
</widget>
</item>
<item row="29" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_11">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="30" column="0">
<widget class="QLabel" name="label_40">
<property name="text">
<string>Phys Preset Pointer:</string>
</property>
</widget>
</item>
<item row="30" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_12">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="31" column="0">
<widget class="QLabel" name="label_41">
<property name="text">
<string>Phys Geometry Pointer:</string>
</property>
</widget>
</item>
<item row="31" column="1">
<widget class="QSpinBox" name="spinBox_ClassPtr_13">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Lod Info</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Lod Info Index:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBox_LodIndex"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Distance:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Surface Count:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr_2">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Surface Index:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr_3">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Part Bit 1: </string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr_4">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Part Bit 2: </string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr_5">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Part Bit 3: </string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr_6">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Part Bit 4: </string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr_7">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Part Bit 5: </string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QSpinBox" name="spinBox_BoneNamePtr_8">
<property name="maximum">
<number>1000000000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3DWindow">
<property name="title">
<string>3D Window</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

35
app/preferenceeditor.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "preferenceeditor.h"
#include "ui_preferenceeditor.h"
PreferenceEditor::PreferenceEditor(QWidget *parent)
: QDialog(parent)
, ui(new Ui::PreferenceEditor)
{
ui->setupUi(this);
ui->frame_View->show();
ui->frame_TreeWidget->hide();
ui->frame_FileEditors->hide();
connect(ui->listWidget_Categories, &QListWidget::itemSelectionChanged, this, [this]() {
const QString itemText = ui->listWidget_Categories->selectedItems().first()->text();
if (itemText == "View") {
ui->frame_View->show();
ui->frame_TreeWidget->hide();
ui->frame_FileEditors->hide();
} else if (itemText == "Tree Widget") {
ui->frame_View->hide();
ui->frame_TreeWidget->show();
ui->frame_FileEditors->hide();
} else if (itemText == "File Editors") {
ui->frame_View->hide();
ui->frame_TreeWidget->hide();
ui->frame_FileEditors->show();
}
});
}
PreferenceEditor::~PreferenceEditor()
{
delete ui;
}

22
app/preferenceeditor.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef PREFERENCEEDITOR_H
#define PREFERENCEEDITOR_H
#include <QDialog>
namespace Ui {
class PreferenceEditor;
}
class PreferenceEditor : public QDialog
{
Q_OBJECT
public:
explicit PreferenceEditor(QWidget *parent = nullptr);
~PreferenceEditor();
private:
Ui::PreferenceEditor *ui;
};
#endif // PREFERENCEEDITOR_H

528
app/preferenceeditor.ui Normal file
View File

@ -0,0 +1,528 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PreferenceEditor</class>
<widget class="QDialog" name="PreferenceEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1118</width>
<height>861</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>703</width>
<height>512</height>
</size>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="placeholderText">
<string>Filter</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidget_Categories">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="currentRow">
<number>0</number>
</property>
<item>
<property name="text">
<string>View</string>
</property>
<property name="icon">
<iconset resource="data/Data.qrc">
<normaloff>:/icons/icons/Icon_Views.png</normaloff>:/icons/icons/Icon_Views.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>Tree Widget</string>
</property>
<property name="icon">
<iconset resource="data/Data.qrc">
<normaloff>:/icons/icons/Icon_Tree.png</normaloff>:/icons/icons/Icon_Tree.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>File Editors</string>
</property>
<property name="icon">
<iconset resource="data/Data.qrc">
<normaloff>:/icons/icons/Icon_Editor.png</normaloff>:/icons/icons/Icon_Editor.png</iconset>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="frame_View">
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="data/Data.qrc">:/icons/icons/Icon_Views.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>12</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>View</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget_Editors_3">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Font &amp;&amp; Colors</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Font</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Family:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_FontFamily"/>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Size:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_FontSize"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Zoom:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_ViewZoom">
<property name="suffix">
<string>%</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>588</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_TreeWidget">
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_9">
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="data/Data.qrc">:/icons/icons/Icon_Tree.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>12</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Tree Widget</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget_Editors">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 2</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_FileEditors">
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_7">
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="data/Data.qrc">:/icons/icons/Icon_Editor.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>12</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>File Editors</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget_Editors_2">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="currentIndex">
<number>7</number>
</property>
<widget class="QWidget" name="tab_FastFile">
<attribute name="title">
<string>Fast File</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_Zone">
<attribute name="title">
<string>Zone File</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_IWIFile">
<attribute name="title">
<string>Images</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_LocalString">
<attribute name="title">
<string>Local Strings</string>
</attribute>
</widget>
<widget class="QWidget" name="tab__StringTable">
<attribute name="title">
<string>String Table</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_Sounds">
<attribute name="title">
<string>Sounds</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_TechSet">
<attribute name="title">
<string>Tech Set</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_Model">
<attribute name="title">
<string>Model</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>Page</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="data/Data.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PreferenceEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PreferenceEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

80
app/soundviewer.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "soundviewer.h"
#include "ui_soundviewer.h"
SoundViewer::SoundViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::SoundViewer)
, player(new QMediaPlayer())
, buffer(new QBuffer())
{
ui->setupUi(this);
connect(ui->pushButton_Play, &QPushButton::clicked, player, &QMediaPlayer::play);
connect(ui->pushButton_Pause, &QPushButton::clicked, player, &QMediaPlayer::pause);
connect(ui->pushButton_Stop, &QPushButton::clicked, this, [this]() {
if (player->isPlaying()) {
player->stop();
}
});
connect(ui->pushButton_SkipForward, &QPushButton::clicked, this, [this]() {
player->setPosition(player->position() + 30);
});
connect(ui->pushButton_SkipBack, &QPushButton::clicked, this, [this]() {
player->setPosition(player->position() - 30);
});
connect(player, &QMediaPlayer::positionChanged, player, [this](qint64 position) {
ui->horizontalSlider->setSliderPosition(position);
ui->label_Time->setText(QString("%1:%2:%3")
.arg(position / 60000)
.arg((position % 60000) / 1000)
.arg(position % 1000));
});
connect(player, &QMediaPlayer::durationChanged, player, [this](qint64 duration) {
ui->horizontalSlider->setMaximum(duration);
ui->label_TimeMax->setText(QString("%1:%2:%3")
.arg(duration / 60000)
.arg((duration % 60000) / 1000)
.arg(duration % 1000));
});
connect(ui->horizontalSlider, &QSlider::sliderMoved, this, [this](int position) {
player->setPosition(position);
});
for (auto outputDevice : QMediaDevices::audioOutputs()) {
ui->comboBox_Output->addItem(outputDevice.description());
}
connect(ui->comboBox_Output, &QComboBox::currentIndexChanged, this, [this](int index) {
auto outputDevice = QMediaDevices::audioOutputs()[index];
QAudioOutput *audioOutput = new QAudioOutput(outputDevice);
player->setAudioOutput(audioOutput);
});
auto outputDevice = QMediaDevices::defaultAudioOutput();
QAudioOutput *audioOutput = new QAudioOutput(outputDevice);
player->setAudioOutput(audioOutput);
}
SoundViewer::~SoundViewer()
{
delete buffer;
delete player;
delete ui;
}
void SoundViewer::SetSound(std::shared_ptr<Sound> aSound)
{
buffer->setData(aSound->data);
if (!buffer->open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open QBuffer.";
return;
}
ui->groupBox->setTitle(aSound->path);
player->setSourceDevice(buffer);
}
void SoundViewer::SetOutput(QAudioOutput *aOutput) {
if (!aOutput) { return; }
player->setAudioOutput(aOutput);
}

34
app/soundviewer.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef SOUNDVIEWER_H
#define SOUNDVIEWER_H
#include "asset_structs.h"
#include <QWidget>
#include <QMediaPlayer>
#include <QBuffer>
#include <QAudioDevice>
#include <QMediaDevices>
#include <QAudioOutput>
namespace Ui {
class SoundViewer;
}
class SoundViewer : public QWidget
{
Q_OBJECT
public:
explicit SoundViewer(QWidget *parent = nullptr);
~SoundViewer();
void SetSound(std::shared_ptr<Sound> aSound);
void SetOutput(QAudioOutput *aOutput);
private:
Ui::SoundViewer *ui;
QMediaPlayer *player;
QBuffer *buffer;
};
#endif // SOUNDVIEWER_H

2573
app/soundviewer.ui Normal file

File diff suppressed because it is too large Load Diff

36
app/stringtableviewer.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "stringtableviewer.h"
#include "ui_stringtableviewer.h"
StringTableViewer::StringTableViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::StringTableViewer)
{
ui->setupUi(this);
}
StringTableViewer::~StringTableViewer()
{
delete ui;
}
void StringTableViewer::SetStringTable(std::shared_ptr<StringTable> aStringTable) {
ui->tableWidget_Strings->clear();
ui->tableWidget_Strings->setRowCount(aStringTable->rowCount);
ui->tableWidget_Strings->setColumnCount(aStringTable->columnCount);
int currentIndex = 0;
for (const QString &key : aStringTable->content.keys()) {
const QString value = aStringTable->content[key];
QTableWidgetItem *tableKeyItem = new QTableWidgetItem();
tableKeyItem->setText(key);
ui->tableWidget_Strings->setItem(currentIndex, 0, tableKeyItem);
QTableWidgetItem *tableValItem = new QTableWidgetItem();
tableValItem->setText(value);
ui->tableWidget_Strings->setItem(currentIndex, 1, tableValItem);
currentIndex++;
}
}

25
app/stringtableviewer.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef STRINGTABLEVIEWER_H
#define STRINGTABLEVIEWER_H
#include "asset_structs.h"
#include <QWidget>
namespace Ui {
class StringTableViewer;
}
class StringTableViewer : public QWidget
{
Q_OBJECT
public:
explicit StringTableViewer(QWidget *parent = nullptr);
~StringTableViewer();
void SetStringTable(std::shared_ptr<StringTable> aStringTable);
private:
Ui::StringTableViewer *ui;
};
#endif // STRINGTABLEVIEWER_H

24
app/stringtableviewer.ui Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StringTableViewer</class>
<widget class="QWidget" name="StringTableViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>525</width>
<height>752</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTableWidget" name="tableWidget_Strings"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

800
app/xtreewidget.cpp Normal file
View File

@ -0,0 +1,800 @@
#include "xtreewidget.h"
#include "qheaderview.h"
#include "qmenu.h"
#include "logmanager.h"
XTreeWidget::XTreeWidget(QWidget *parent)
: QTreeWidget(parent) {
mFastFiles = QMap<QString, std::shared_ptr<FastFile>>();
mZoneFiles = QMap<QString, std::shared_ptr<ZoneFile>>();
mDDSFiles = QMap<QString, std::shared_ptr<DDSFile>>();
mIWIFiles = QMap<QString, std::shared_ptr<IWIFile>>();
setContextMenuPolicy(Qt::CustomContextMenu);
setSelectionMode(QTreeWidget::SingleSelection);
setColumnCount(3);
header()->hide();
setMinimumWidth(350);
setSortingEnabled(true);
header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
// Set the last two columns to a fixed width
//header()->setSectionResizeMode(1, QHeaderView::Fixed);
//header()->setSectionResizeMode(2, QHeaderView::Fixed);
// Adjust the fixed widths to suit your icon size (e.g., 32 pixels)
//header()->resizeSection(0, 275);
//header()->resizeSection(1, 32);
//header()->resizeSection(2, 32);
connect(this, &XTreeWidget::itemSelectionChanged, this, &XTreeWidget::ItemSelectionChanged);
connect(this, &XTreeWidget::customContextMenuRequested, this, &XTreeWidget::PrepareContextMenu);
}
XTreeWidget::~XTreeWidget() {
}
void XTreeWidget::AddFastFile(std::shared_ptr<FastFile> aFastFile) {
XTreeWidgetItem *fastFileItem = new XTreeWidgetItem(this);
fastFileItem->setText(0, aFastFile->GetStem() + ".ff");
fastFileItem->setIcon(0, QIcon(":/icons/icons/Icon_FastFile.png"));
if (aFastFile->GetPlatform() == "PC") {
fastFileItem->setIcon(1, QIcon(":/icons/icons/Icon_PC.png"));
} else if (aFastFile->GetPlatform() == "360") {
fastFileItem->setIcon(1, QIcon(":/icons/icons/Icon_Xbox.png"));
} else if (aFastFile->GetPlatform() == "Wii") {
fastFileItem->setIcon(1, QIcon(":/icons/icons/Icon_Wii.png"));
} else if (aFastFile->GetPlatform() == "WiiU") {
fastFileItem->setIcon(1, QIcon(":/icons/icons/Icon_WiiU.png"));
}
if (aFastFile->GetGame() == "COD2") {
fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD2.png"));
} if (aFastFile->GetGame() == "COD4") {
fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD4.png"));
} else if (aFastFile->GetGame() == "COD5") {
fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD5.png"));
} else if (aFastFile->GetGame() == "COD6") {
fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD6.png"));
} else if (aFastFile->GetGame() == "COD7") {
fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD7.png"));
} else if (aFastFile->GetGame() == "COD8") {
fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD8.png"));
} else if (aFastFile->GetGame() == "COD9") {
fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD9.png"));
}
AddZoneFile(aFastFile->GetZoneFile(), fastFileItem);
mFastFiles[aFastFile->GetStem().section(".", 0, 0)] = aFastFile;
resizeColumnToContents(1);
setSortingEnabled(true);
sortByColumn(0, Qt::AscendingOrder);
}
void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem) {
XTreeWidgetItem *zoneItem;
if (aParentItem != nullptr) {
zoneItem = new XTreeWidgetItem(aParentItem);
} else {
zoneItem = new XTreeWidgetItem(this);
}
zoneItem->setIcon(0, QIcon(":/icons/icons/Icon_ZoneFile.png"));
zoneItem->setText(0, aZoneFile->GetStem() + ".zone");
auto assetMap = aZoneFile->GetAssetMap();
if (!assetMap.localStrings.isEmpty()) {
XTreeWidgetItem *localStrRoot = new XTreeWidgetItem(zoneItem);
localStrRoot->setText(0, "String Files");
localStrRoot->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png"));
XTreeWidgetItem *localStrItem = new XTreeWidgetItem(localStrRoot);
localStrItem->setText(0, aZoneFile->GetStem().section('.', 0, 0) + ".str");
localStrItem->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png"));
}
if (!assetMap.techSets.isEmpty()) {
XTreeWidgetItem *techSetRoot = new XTreeWidgetItem(zoneItem);
techSetRoot->setText(0, "Tech Sets");
techSetRoot->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png"));
for (TechSet techSet : assetMap.techSets) {
XTreeWidgetItem *techSetItem = new XTreeWidgetItem(techSetRoot);
techSetItem->setText(0, techSet.name);
techSetItem->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png"));
}
}
if (!assetMap.rawFiles.isEmpty()) {
XTreeWidgetItem *rawFileRoot = new XTreeWidgetItem(zoneItem);
rawFileRoot->setText(0, "Raw Files");
rawFileRoot->setIcon(0, QIcon(":/icons/icons/Icon_GSCFile.png"));
for (RawFile rawFile : assetMap.rawFiles) {
if (!rawFile.length) { continue; }
XTreeWidgetItem *tempItem = rawFileRoot;
for (const QString &pathPart : rawFile.path.split('/')) {
bool childFound = false;
for (int i = 0; i < tempItem->childCount(); i++) {
QTreeWidgetItem *rawChildItem = tempItem->child(i);
XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(rawChildItem);
if (childItem->text(0) == pathPart) {
tempItem = childItem;
childFound = true;
break;
}
}
if (pathPart.contains(".gsc")) {
XTreeWidgetItem *rawFileItem = new XTreeWidgetItem(tempItem);
rawFileItem->setText(0, pathPart);
tempItem = rawFileItem;
} else if (!childFound) {
tempItem = new XTreeWidgetItem(tempItem);
tempItem->setText(0, pathPart);
}
}
tempItem->setIcon(0, QIcon(":/icons/icons/Icon_GSCFile.png"));
}
}
if (!assetMap.menuFiles.isEmpty()) {
XTreeWidgetItem *menuRoot = new XTreeWidgetItem(zoneItem);
menuRoot->setText(0, "Menu Files");
menuRoot->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png"));
int menuIndex = 1;
for (MenuFile menuFile : assetMap.menuFiles) {
XTreeWidgetItem *menuFileRoot = new XTreeWidgetItem(menuRoot);
menuFileRoot->setText(0, QString("Menu %1").arg(menuIndex));
for (Menu menu : menuFile.menuDefs) {
XTreeWidgetItem *menuItem = new XTreeWidgetItem(menuFileRoot);
menuItem->setText(0, menu.name);
menuItem->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png"));
}
menuIndex++;
}
}
if (!assetMap.images.isEmpty()) {
XTreeWidgetItem *imageRoot = new XTreeWidgetItem(zoneItem);
imageRoot->setText(0, "Images");
imageRoot->setIcon(0, QIcon(":/icons/icons/Icon_Image.png"));
for (Image image : assetMap.images) {
XTreeWidgetItem *imageItem = new XTreeWidgetItem(imageRoot);
imageItem->setText(0, image.materialName);
imageItem->setIcon(0, QIcon(":/icons/icons/Icon_Image.png"));
}
}
if (!assetMap.models.isEmpty()) {
XTreeWidgetItem *modelsRoot = new XTreeWidgetItem(zoneItem);
modelsRoot->setText(0, "Models");
modelsRoot->setIcon(0, QIcon(":/icons/icons/Icon_Model.png"));
for (Model model: assetMap.models) {
XTreeWidgetItem *modelItem = new XTreeWidgetItem(modelsRoot);
modelItem->setText(0, model.modelName);
modelItem->setIcon(0, QIcon(":/icons/icons/Icon_Model.png"));
}
}
if (!assetMap.materials.isEmpty()) {
XTreeWidgetItem *materialsRoot = new XTreeWidgetItem(zoneItem);
materialsRoot->setText(0, "Materials");
materialsRoot->setIcon(0, QIcon(":/icons/icons/Icon_Material.png"));
for (Material material: assetMap.materials) {
XTreeWidgetItem *materialItem = new XTreeWidgetItem(materialsRoot);
materialItem->setText(0, material.name);
materialItem->setIcon(0, QIcon(":/icons/icons/Icon_Material.png"));
}
}
if (!assetMap.stringTables.isEmpty()) {
XTreeWidgetItem *strTableRoot = new XTreeWidgetItem(zoneItem);
strTableRoot->setText(0, "String Tables");
strTableRoot->setIcon(0, QIcon(":/icons/icons/Icon_StringTable.png"));
for (StringTable strTable: assetMap.stringTables) {
XTreeWidgetItem *modelItem = new XTreeWidgetItem(strTableRoot);
modelItem->setText(0, strTable.name);
modelItem->setIcon(0, QIcon(":/icons/icons/Icon_StringTable.png"));
}
}
if (!assetMap.sounds.isEmpty()) {
XTreeWidgetItem *soundsRoot = new XTreeWidgetItem(zoneItem);
soundsRoot->setText(0, "Sounds");
soundsRoot->setIcon(0, QIcon(":/icons/icons/Icon_Sound.png"));
for (SoundAsset soundAsset : assetMap.sounds) {
for (Sound sound : soundAsset.sounds) {
XTreeWidgetItem *tempItem = soundsRoot;
if (!sound.dataLength) { continue; }
for (const QString &pathPart : sound.path.split('/')) {
if (pathPart.isEmpty()) { continue; }
bool childFound = false;
for (int i = 0; i < tempItem->childCount(); i++) {
XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(tempItem->child(i));
if (childItem->text(0) == pathPart) {
tempItem = childItem;
childFound = true;
break;
}
}
if (pathPart.contains(".wav")) {
XTreeWidgetItem *soundItem = new XTreeWidgetItem(tempItem);
soundItem->setText(0, pathPart);
tempItem = soundItem;
} else if (!childFound) {
tempItem = new XTreeWidgetItem(tempItem);
tempItem->setText(0, pathPart);
}
}
tempItem->setIcon(0, QIcon(":/icons/icons/Icon_Sound.png"));
}
}
}
mZoneFiles[aZoneFile->GetStem().section(".", 0, 0)] = aZoneFile;
}
void XTreeWidget::CloseFastFile(const QString aFFName) {
const QString fileStem = aFFName.section(".", 0, 0);
emit ItemClosed(fileStem);
}
void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
auto activeItem = itemAt(pos);
if (!activeItem) { return; }
if (activeItem->text(0).isEmpty()) { return; }
QString activeText = activeItem->text(0);
QMenu *contextMenu = new QMenu(this);
if (activeText.contains(".dds")) {
const QString fileStem = activeText.replace(".dds", "");
if (!mDDSFiles.contains(fileStem)) {
qDebug() << "Error: Could not find " << fileStem << " in DDS map!";
return;
}
QAction *closeAction = new QAction("Close File");
contextMenu->addAction(closeAction);
connect(closeAction, &QAction::triggered, this, [this, &fileStem, &activeItem](bool checked) {
Q_UNUSED(checked);
mDDSFiles.remove(fileStem);
invisibleRootItem()->removeChild(activeItem);
});
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
std::shared_ptr<DDSFile> ddsFile = mDDSFiles[fileStem];
QAction *exportIWIAction = new QAction("Export as IWI");
exportSubmenu->addAction(exportIWIAction);
connect(exportIWIAction, &QAction::triggered, this, [ddsFile](bool checked) {
Q_UNUSED(checked);
ddsFile->SaveIWI();
});
QAction *exportPNGAction = new QAction("Export as PNG");
exportSubmenu->addAction(exportPNGAction);
connect(exportPNGAction, &QAction::triggered, this, [ddsFile](bool checked) {
Q_UNUSED(checked);
ddsFile->SavePNG();
});
QAction *exportJPGAction = new QAction("Export as JPG");
exportSubmenu->addAction(exportJPGAction);
connect(exportJPGAction, &QAction::triggered, this, [ddsFile](bool checked) {
Q_UNUSED(checked);
ddsFile->SaveJPG();
});
} else if (activeText.contains(".iwi")) {
const QString fileStem = activeText.replace(".iwi", "");
if (!mIWIFiles.contains(fileStem)) {
qDebug() << "Error: Could not find " << fileStem << " in IWI map!";
return;
}
QAction *closeAction = new QAction("Close File");
contextMenu->addAction(closeAction);
connect(closeAction, &QAction::triggered, this, [this, &fileStem, &activeItem](bool checked) {
Q_UNUSED(checked);
mIWIFiles.remove(fileStem);
invisibleRootItem()->removeChild(activeItem);
});
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
std::shared_ptr<IWIFile> iwiFile = mIWIFiles[fileStem];
QAction *exportDDSAction = new QAction("Export as DDS");
exportSubmenu->addAction(exportDDSAction);
connect(exportDDSAction, &QAction::triggered, this, [iwiFile](bool checked) {
Q_UNUSED(checked);
iwiFile->SaveDDS();
});
QAction *exportPNGAction = new QAction("Export as PNG");
exportSubmenu->addAction(exportPNGAction);
connect(exportPNGAction, &QAction::triggered, this, [iwiFile](bool checked) {
Q_UNUSED(checked);
iwiFile->SavePNG();
});
QAction *exportJPGAction = new QAction("Export as JPG");
exportSubmenu->addAction(exportJPGAction);
connect(exportJPGAction, &QAction::triggered, this, [iwiFile](bool checked) {
Q_UNUSED(checked);
iwiFile->SaveJPG();
});
} else if (activeText.contains(".ff")) {
const QString fileStem = activeText.replace(".zone", "");
QMenu *closeMultipleAction = new QMenu("Close Multiple Tabs");
QAction *closeAllAction = new QAction("Close All");
closeMultipleAction->addAction(closeAllAction);
connect(closeAllAction, &QAction::triggered, this, [this](bool checked) {
Q_UNUSED(checked);
mFastFiles.clear();
clear();
emit Cleared();
});
QAction *closeAllButAction = new QAction("Close All BUT This");
closeMultipleAction->addAction(closeAllButAction);
connect(closeAllButAction, &QAction::triggered, this, [this, &activeItem](bool checked) {
Q_UNUSED(checked);
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
auto childItem = invisibleRootItem()->child(i);
if (childItem == activeItem) { continue; }
const QString fileStem = childItem->text(0).replace(".ff", "");
if (!mFastFiles.contains(fileStem)) {
qDebug() << "Error: Could not find " << fileStem << " in Fast File map!";
return;
}
mFastFiles.remove(fileStem);
CloseFastFile(fileStem);
invisibleRootItem()->removeChild(childItem);
i--;
}
});
QAction *closeAboveAction = new QAction("Close All Above");
closeMultipleAction->addAction(closeAboveAction);
connect(closeAboveAction, &QAction::triggered, this, [this, &activeItem](bool checked) {
Q_UNUSED(checked);
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
auto childItem = invisibleRootItem()->child(i);
if (childItem == activeItem) { return; }
const QString fileStem = childItem->text(0).replace(".ff", "");
if (!mFastFiles.contains(fileStem)) {
qDebug() << "Error: Could not find " << fileStem << " in Fast File map!";
return;
}
mFastFiles.remove(fileStem);
CloseFastFile(fileStem);
invisibleRootItem()->removeChild(childItem);
i--;
}
});
QAction *closeBelowAction = new QAction("Close All Below");
closeMultipleAction->addAction(closeBelowAction);
connect(closeBelowAction, &QAction::triggered, this, [this, &activeItem](bool checked) {
Q_UNUSED(checked);
bool ready = false;
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
auto childItem = invisibleRootItem()->child(i);
if (!ready && (childItem != activeItem)) { continue; }
if (childItem == activeItem) {
ready = true;
continue;
}
const QString fileStem = childItem->text(0).replace(".ff", "");
if (!mFastFiles.contains(fileStem)) {
qDebug() << "Error: Could not find " << fileStem << " in Fast File map!";
return;
}
mFastFiles.remove(fileStem);
CloseFastFile(fileStem);
invisibleRootItem()->removeChild(childItem);
i--;
}
});
contextMenu->addMenu(closeMultipleAction);
QAction *closeAction = new QAction("Close File");
contextMenu->addAction(closeAction);
connect(closeAction, &QAction::triggered, this, [this, &activeItem, &activeText](bool checked) {
Q_UNUSED(checked);
const QString fileStem = activeItem->text(0).replace(".ff", "");
mFastFiles.remove(fileStem);
CloseFastFile(activeText);
invisibleRootItem()->removeChild(activeItem);
});
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
std::shared_ptr<FastFile> fastFile = mFastFiles[fileStem];
QAction *exportFastFileAction = new QAction("Export Fast File");
exportSubmenu->addAction(exportFastFileAction);
connect(exportFastFileAction, &QAction::triggered, this, [fastFile](bool checked) {
Q_UNUSED(checked);
const QString fastFilePath = QFileDialog::getSaveFileName(
nullptr, "Export Fast File...", QDir::currentPath(),
"Fast File (*.ff);;All Files(*.*)");
fastFile->ExportFastFile(fastFilePath);
});
QAction *exportZoneFileAction = new QAction("Export Zone File");
exportSubmenu->addAction(exportZoneFileAction);
connect(exportZoneFileAction, &QAction::triggered, this, [fastFile](bool checked) {
Q_UNUSED(checked);
const QString zoneFilePath = QFileDialog::getSaveFileName(
nullptr, "Export Zone File...", QDir::currentPath(),
"Zone File (*.zone);;All Files(*.*)");
fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
});
} else if (activeText.contains(".zone")) {
const QString fileStem = activeText.replace(".zone", "");
if (!mZoneFiles.contains(fileStem)) {
qDebug() << "Error: Could not find " << fileStem << " in Zone File map!";
return;
}
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
std::shared_ptr<ZoneFile> zoneFile = mZoneFiles[fileStem];
QAction *exportZoneFileAction = new QAction("Export Zone File");
exportSubmenu->addAction(exportZoneFileAction);
connect(exportZoneFileAction, &QAction::triggered, this, [](bool checked) {
Q_UNUSED(checked);
});
QAction *exportFastFileAction = new QAction("Export Fast File");
exportSubmenu->addAction(exportFastFileAction);
connect(exportFastFileAction, &QAction::triggered, this, [](bool checked) {
Q_UNUSED(checked);
});
} else if (activeItem && activeText.contains(".wav")) {
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(activeItem->parent());
while (parentItem && !parentItem->text(0).contains(".zone")) {
parentItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (parentItem == invisibleRootItem()) {
break;
}
}
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
const QString fileStem = parentItem->text(0).section('.', 0, 0);
QVector<SoundAsset> soundAssets = mZoneFiles[fileStem]->GetAssetMap().sounds;
for (SoundAsset soundAsset : soundAssets) {
for (Sound sound : soundAsset.sounds) {
if (sound.path.contains(activeText)) {
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
QAction *exportWAVAction = new QAction("Export as WAV File");
exportSubmenu->addAction(exportWAVAction);
connect(exportWAVAction, &QAction::triggered, this, [sound](bool checked) {
Q_UNUSED(checked);
QDir dir = QDir::currentPath();
if (!dir.exists("exports/")) {
dir.mkdir("exports/");
}
if (!dir.exists("exports/sounds/")) {
dir.mkdir("exports/sounds/");
}
const QString fileName = "exports/sounds/" + sound.path.split('/').last();
QFile wavFile(fileName);
if (!wavFile.open(QIODevice::WriteOnly)) {
qDebug() << "Failed to write wav file!";
return;
}
wavFile.write(sound.data);
wavFile.close();
});
break;
}
}
}
}
} else if (activeItem && activeText == "Sounds") {
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(activeItem->parent());
while (parentItem && !parentItem->text(0).contains(".zone")) {
parentItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (parentItem == invisibleRootItem()) {
break;
}
}
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
const QString fileStem = parentItem->text(0).section('.', 0, 0);
auto zoneFile = mZoneFiles[fileStem];
QMenu *exportSubmenu = new QMenu("Export...", this);
contextMenu->addMenu(exportSubmenu);
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
exportSubmenu->addAction(exportAllWAVAction);
connect(exportAllWAVAction, &QAction::triggered, this, [zoneFile](bool checked) {
Q_UNUSED(checked);
for (SoundAsset soundAsset : zoneFile->GetAssetMap().sounds) {
for (Sound sound : soundAsset.sounds) {
if (!sound.dataLength) { continue; }
QDir dir = QDir::currentPath();
if (!dir.exists("exports/")) {
dir.mkdir("exports/");
}
if (!dir.exists("exports/sounds/")) {
dir.mkdir("exports/sounds/");
}
const QString fileName = "exports/sounds/" + sound.path.split('/').last();
QFile wavFile(fileName);
if (!wavFile.open(QIODevice::WriteOnly)) {
qDebug() << "Failed to write wav file!";
return;
}
wavFile.write(sound.data);
wavFile.close();
}
}
});
}
}
QPoint pt(pos);
contextMenu->exec(mapToGlobal(pt));
delete contextMenu;
}
void XTreeWidget::ItemSelectionChanged() {
if (selectedItems().isEmpty()) { return; }
XTreeWidgetItem *selectedItem = dynamic_cast<XTreeWidgetItem*>(selectedItems().first());
if (!selectedItem) { return; }
if (selectedItem->text(0).isEmpty()) { return; }
QString selectedText = selectedItem->text(0);
emit ItemSelected(selectedText);
const QString fileStem = selectedText.section(".", 0, 0);
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(selectedItem->parent());
if (selectedText.contains(".dds")) {
if (!mDDSFiles.contains(fileStem)) {
LogManager::instance().addError("Could not find " + fileStem + " in DDS map!");
return;
}
std::shared_ptr<DDSFile> ddsFile = mDDSFiles[fileStem];
emit DDSFileSelected(ddsFile, fileStem);
} else if (selectedText.contains(".iwi")) {
if (!mIWIFiles.contains(fileStem)) {
LogManager::instance().addError("Could not find " + fileStem + " in IWI map!");
return;
}
emit IWIFileSelected(mIWIFiles[fileStem], fileStem);
} else if (selectedText.contains(".ff")) {
if (!mFastFiles.contains(fileStem)) {
LogManager::instance().addError("Could not find " + fileStem + " in Fast File map!");
return;
}
emit FastFileSelected(mFastFiles[fileStem], fileStem);
} else if (selectedText.contains(".zone")) {
if (!mZoneFiles.contains(fileStem)) {
LogManager::instance().addError("Could not find " + fileStem + " in Zone File map!");
return;
}
emit ZoneFileSelected(mZoneFiles[fileStem], fileStem);
} else if (selectedText.contains(".str")) {
if (!mZoneFiles.contains(fileStem)) {
LogManager::instance().addError("Could not find " + fileStem + " in Zone File map!");
return;
}
emit LocalStringSelected(mZoneFiles[fileStem], fileStem);
} else if (selectedText.contains(".gsc")) {
XTreeWidgetItem *zoneRoot = selectedItem;
if (!zoneRoot) { return; }
while (!zoneRoot->text(0).contains(".zone")) {
zoneRoot = dynamic_cast<XTreeWidgetItem*>(zoneRoot->parent());
if (!zoneRoot) { return; }
}
const QString fileStem = zoneRoot->text(0).section('.', 0, 0);
if (!mZoneFiles.contains(fileStem)) {
LogManager::instance().addError("Could not find " + fileStem + " in Zone File map!");
return;
}
QVector<RawFile> rawFiles = mZoneFiles[fileStem]->GetAssetMap().rawFiles;
for (RawFile rawFile : rawFiles) {
if (rawFile.path.contains(selectedText)) {
emit RawFileSelected(std::make_shared<RawFile>(rawFile), fileStem);
return;
}
}
} else if (parentItem && (parentItem->text(0) == "Images")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
QVector<Image> images = mZoneFiles[fileStem]->GetAssetMap().images;
for (Image image : images) {
if (image.materialName == selectedText) {
emit ImageSelected(std::make_shared<Image>(image), fileStem);
break;
}
}
}
} else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets;
for (auto techset : techsets) {
if (techset.name == selectedText) {
emit TechSetSelected(std::make_shared<TechSet>(techset), fileStem);
break;
}
}
}
} else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets;
for (auto techset : techsets) {
if (techset.name == selectedText) {
emit TechSetSelected(std::make_shared<TechSet>(techset), fileStem);
break;
}
}
}
} else if (parentItem && (parentItem->text(0) == "Materials")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
QVector<Material> materials = mZoneFiles[fileStem]->GetAssetMap().materials;
for (Material material : materials) {
if (material.name == selectedText) {
emit MaterialSelected(std::make_shared<Material>(material), fileStem);
break;
}
}
}
} else if (parentItem && selectedText.contains(".wav")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
while (grandpaItem && !grandpaItem->text(0).contains(".zone")) {
grandpaItem = dynamic_cast<XTreeWidgetItem*>(grandpaItem->parent());
if (grandpaItem == invisibleRootItem()) {
break;
}
}
if (grandpaItem && grandpaItem != invisibleRootItem() && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
QVector<SoundAsset> soundAssets = mZoneFiles[fileStem]->GetAssetMap().sounds;
for (SoundAsset soundAsset : soundAssets) {
for (Sound sound : soundAsset.sounds) {
if (sound.path.contains(selectedText)) {
emit SoundSelected(std::make_shared<Sound>(sound), fileStem);
break;
}
}
}
}
}
}
std::shared_ptr<ZoneFile> XTreeWidget::FindZoneFile(const QString aStem) {
foreach (auto zoneFile, mZoneFiles) {
if (zoneFile->GetStem() == aStem) {
return zoneFile;
}
}
return nullptr;
}
std::shared_ptr<FastFile> XTreeWidget::FindFastFile(const QString aStem) {
foreach (auto fastFile, mFastFiles) {
if (fastFile->GetStem() == aStem) {
return fastFile;
}
}
return nullptr;
}
bool XTreeWidget::HasZoneFile(const QString aStem) {
return FindZoneFile(aStem) != nullptr;
}
bool XTreeWidget::HasFastFile(const QString aStem) {
return FindFastFile(aStem) != nullptr;
}
void XTreeWidget::AddIWIFile(std::shared_ptr<IWIFile> aIWIFile) {
const QString iwiFileName = QString(aIWIFile->fileStem + ".iwi");
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
auto iwiFileItem = invisibleRootItem()->child(i);
if (iwiFileItem->text(0) == iwiFileName) {
delete iwiFileItem;
}
}
XTreeWidgetItem *iwiItem = new XTreeWidgetItem(this);
iwiItem->setIcon(0, QIcon(":/icons/icons/Icon_IWIFile.png"));
iwiItem->setText(0, iwiFileName);
mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile;
}
void XTreeWidget::AddDDSFile(std::shared_ptr<DDSFile> aDDSFile) {
const QString ddsFileName = QString(aDDSFile->fileStem + ".dds");
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
auto ddsFileItem = invisibleRootItem()->child(i);
if (ddsFileItem->text(0) == ddsFileName) {
delete ddsFileItem;
}
}
XTreeWidgetItem *ddsItem = new XTreeWidgetItem(this);
ddsItem->setIcon(0, QIcon(":/icons/icons/Icon_DDSFile.png"));
ddsItem->setText(0, ddsFileName);
mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile;
}

62
app/xtreewidget.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef XTREEWIDGET_H
#define XTREEWIDGET_H
#include "d3dbsp_structs.h"
#include "asset_structs.h"
#include "ddsfile.h"
#include "iwifile.h"
#include "fastfile.h"
#include "xtreewidgetitem.h"
#include "zonefile.h"
#include <QTreeWidget>
class XTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
explicit XTreeWidget(QWidget *parent = nullptr);
~XTreeWidget();
void AddFastFile(std::shared_ptr<FastFile> aFastFile);
void AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem = nullptr);
void AddIWIFile(std::shared_ptr<IWIFile> aIWIFile);
void AddDDSFile(std::shared_ptr<DDSFile> aDDSFile);
std::shared_ptr<ZoneFile> FindZoneFile(const QString aStem);
std::shared_ptr<FastFile> FindFastFile(const QString aStem);
bool HasZoneFile(const QString aStem);
bool HasFastFile(const QString aStem);
void CloseFastFile(const QString aFFName);
signals:
void DDSFileSelected(std::shared_ptr<DDSFile> aDDSFile, const QString aParentName);
void IWIFileSelected(std::shared_ptr<IWIFile> aIWIFile, const QString aParentName);
void FastFileSelected(std::shared_ptr<FastFile> aFastFile, const QString aParentName);
void ZoneFileSelected(std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName);
void LocalStringSelected(std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName);
void RawFileSelected(std::shared_ptr<RawFile> aRawFile, const QString aParentName);
void ImageSelected(std::shared_ptr<Image> aImage, const QString aParentName);
void TechSetSelected(std::shared_ptr<TechSet> aZoneFile, const QString aParentName);
void StrTableSelected(std::shared_ptr<StringTable> aStrTable, const QString aParentName);
void MenuSelected(std::shared_ptr<Menu> aMenu, const QString aParentName);
void SoundSelected(std::shared_ptr<Sound> aSound, const QString aParentName);
void MaterialSelected(std::shared_ptr<Material> aMaterial, const QString aParentName);
void ItemSelected(const QString itemText);
void ItemClosed(const QString itemText);
void Cleared();
protected:
void ItemSelectionChanged();
void PrepareContextMenu(const QPoint &pos);
private:
QMap<QString, std::shared_ptr<FastFile>> mFastFiles;
QMap<QString, std::shared_ptr<ZoneFile>> mZoneFiles;
QMap<QString, std::shared_ptr<DDSFile>> mDDSFiles;
QMap<QString, std::shared_ptr<IWIFile>> mIWIFiles;
};
#endif // XTREEWIDGET_H

42
app/xtreewidgetitem.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "xtreewidgetitem.h"
XTreeWidgetItem::XTreeWidgetItem(QTreeWidget *parent, bool group)
: QTreeWidgetItem(parent), isGroup(group) {
}
XTreeWidgetItem::XTreeWidgetItem(QTreeWidgetItem *parent, bool group)
: QTreeWidgetItem(parent), isGroup(group) {
}
bool XTreeWidgetItem::operator<(const QTreeWidgetItem &other) const {
// Attempt to cast the other item to our custom type.
const XTreeWidgetItem* otherItem = dynamic_cast<const XTreeWidgetItem*>(&other);
if (otherItem) {
bool thisIsGroup = this->childCount() > 0;
bool otherIsGroup = otherItem->childCount() > 0;
if (thisIsGroup != otherIsGroup) {
return otherIsGroup; // Groups should come before non-groups
}
}
// Fallback to the default string comparison on the current sort column.
return QTreeWidgetItem::operator<(other);
}
XTreeWidgetItem& XTreeWidgetItem::operator=(const XTreeWidgetItem &other)
{
if (this != &other) {
// Copy text and icon for each column.
const int colCount = other.columnCount();
for (int i = 0; i < colCount; ++i) {
setText(i, other.text(i));
setIcon(i, other.icon(i));
}
// Copy custom members.
this->isGroup = other.isGroup;
}
return *this;
}

24
app/xtreewidgetitem.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef XTREEWIDGETITEM_H
#define XTREEWIDGETITEM_H
#include <QTreeWidget>
#include <QTreeWidgetItem>
// Custom item class
class XTreeWidgetItem : public QTreeWidgetItem
{
public:
// Flag to indicate if the item is a collapsible group/header.
bool isGroup;
// Constructors: default to non-group unless specified.
XTreeWidgetItem(QTreeWidget *parent, bool group = false);
XTreeWidgetItem(QTreeWidgetItem *parent, bool group = false);
// Override the less-than operator to customize sorting.
bool operator<(const QTreeWidgetItem &other) const override;
XTreeWidgetItem &operator =(const XTreeWidgetItem &other);
};
#endif // XTREEWIDGETITEM_H

View File

@ -3,33 +3,32 @@
ZoneFileViewer::ZoneFileViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::ZoneFileViewer)
{
, ui(new Ui::ZoneFileViewer) {
ui->setupUi(this);
aZoneFile = nullptr;
ui->tableWidget_RecordCounts->setColumnCount(2);
ui->tableWidget_RecordCounts->setHorizontalHeaderLabels({ "Asset", "Count" });
ui->tableWidget_RecordCounts->setColumnCount(4);
ui->tableWidget_RecordCounts->setHorizontalHeaderLabels({ "Identifier", "Asset", "Count", "Icon" });
ui->tableWidget_RecordCounts->horizontalHeader()->setStretchLastSection(true);
ui->tableWidget_RecordOrder->setColumnCount(2);
ui->tableWidget_RecordOrder->setHorizontalHeaderLabels({ "Asset", "Count" });
ui->tableWidget_RecordOrder->setColumnCount(4);
ui->tableWidget_RecordOrder->setHorizontalHeaderLabels({ "Identifier", "Asset", "Count", "Icon" });
ui->tableWidget_RecordOrder->horizontalHeader()->setStretchLastSection(true);
}
ZoneFileViewer::~ZoneFileViewer()
{
ZoneFileViewer::~ZoneFileViewer() {
delete ui;
}
void ZoneFileViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
ui->tableWidget_RecordCounts->clear();
ui->tableWidget_RecordCounts->clearContents();
ui->tableWidget_RecordOrder->clearContents();
ui->listWidget_Tags->clear();
const QStringList tags = aZoneFile->GetTags();
ui->listWidget_Tags->addItems(tags);
ui->label_Title->setText(aZoneFile->GetFileStem());
ui->label_Title->setText(aZoneFile->GetStem() + ".zone");
if (tags.isEmpty()) {
ui->groupBox_Tags->hide();
@ -38,74 +37,91 @@ void ZoneFileViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
}
QString lastAsset = "";
QString lastRecord = "";
QIcon assetIcon;
int consecutiveCount = 1;
int consecutiveIndex = 0;
const QStringList records = aZoneFile->GetRecords();
QMap<QString, int> recordCounts = QMap<QString, int>();
for (const QString &record : records) {
lastRecord = record;
if (record == "ffffffff") { break; }
if (!recordCounts.contains(record)) {
recordCounts[record] = 0;
}
recordCounts[record]++;
QString assetType = Utils::AssetTypeToString(record);
QString assetType = aZoneFile->AssetTypeToString(record);
if (assetIcon.isNull()) {
qDebug() << "Icon is null for record: " << record;
}
if (lastAsset.isEmpty()) {
lastAsset = assetType;
lastRecord = record;
} else if (lastAsset == assetType) {
consecutiveCount++;
} else {
ui->tableWidget_RecordOrder->setRowCount(consecutiveIndex + 1);
QTableWidgetItem *recordItem = new QTableWidgetItem(lastRecord.toUpper());
QTableWidgetItem *recordStrItem = new QTableWidgetItem(lastAsset);
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(consecutiveCount));
QTableWidgetItem *recordIconItem = new QTableWidgetItem();
assetIcon = aZoneFile->AssetStrToIcon(lastAsset);
recordIconItem->setIcon(assetIcon);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 0, recordStrItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 1, recordCountItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 0, recordItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 1, recordStrItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 2, recordCountItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 3, recordIconItem);
consecutiveCount = 1;
consecutiveIndex++;
lastAsset = assetType;
lastRecord = record;
}
}
ui->tableWidget_RecordOrder->setRowCount(consecutiveIndex + 1);
QTableWidgetItem *recordItem = new QTableWidgetItem(lastRecord.toUpper());
QTableWidgetItem *recordStrItem = new QTableWidgetItem(lastAsset);
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(consecutiveCount));
QTableWidgetItem *recordIconItem = new QTableWidgetItem();
assetIcon = aZoneFile->AssetStrToIcon(lastAsset);
recordIconItem->setIcon(assetIcon);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 0, recordStrItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 1, recordCountItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 0, recordItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 1, recordStrItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 2, recordCountItem);
ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 3, recordIconItem);
int recordIndex = 0;
for (const QString &record : recordCounts.keys()) {
int recordCount = recordCounts[record];
QString assetType = Utils::AssetTypeToString(record);
QString assetType = aZoneFile->AssetTypeToString(record);
assetIcon = aZoneFile->AssetStrToIcon(assetType);
if (assetIcon.isNull()) {
qDebug() << "Icon is null for record: " << record;
}
ui->tableWidget_RecordCounts->setRowCount(recordIndex + 1);
QTableWidgetItem *recordCountStrItem = new QTableWidgetItem(assetType);
QTableWidgetItem *recordItem = new QTableWidgetItem(record.toUpper());
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(recordCount));
QTableWidgetItem *recordIconItem = new QTableWidgetItem();
recordIconItem->setIcon(assetIcon);
ui->tableWidget_RecordCounts->setItem(recordIndex, 0, recordCountStrItem);
ui->tableWidget_RecordCounts->setItem(recordIndex, 1, recordCountItem);
ui->tableWidget_RecordCounts->setItem(recordIndex, 0, recordItem);
ui->tableWidget_RecordCounts->setItem(recordIndex, 1, recordCountStrItem);
ui->tableWidget_RecordCounts->setItem(recordIndex, 2, recordCountItem);
ui->tableWidget_RecordCounts->setItem(recordIndex, 3, recordIconItem);
recordIndex++;
}
auto assetMap = aZoneFile->GetAssetMap();
for (LocalString localString : assetMap.localStrings) {
}
for (RawFile rawFile : assetMap.rawFiles) {
}
for (TechSet techSet : assetMap.techSets) {
}
for (Image image : assetMap.images) {
}
for (Animation animation : assetMap.animations) {
}
for (StringTable stringTable : assetMap.stringTables) {
}
for (MenuFile menuFile : assetMap.menuFiles) {
}
ui->tableWidget_RecordOrder->resizeColumnsToContents();
ui->tableWidget_RecordCounts->resizeColumnsToContents();
}

99
app/zonefileviewer.ui Normal file
View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ZoneFileViewer</class>
<widget class="QWidget" name="ZoneFileViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>556</width>
<height>428</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_Title">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>ZoneFile 0</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_Tags">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="title">
<string>Tags</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Search:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_TagSearch">
<property name="placeholderText">
<string>Search tags...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="listWidget_Tags"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_RecordCounts">
<property name="title">
<string>Record Counts</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QTableWidget" name="tableWidget_RecordCounts"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_RecordOrder">
<property name="title">
<string>Record Order</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTableWidget" name="tableWidget_RecordOrder"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,410 +0,0 @@
#ifndef COMPRESSOR_H
#define COMPRESSOR_H
#include "utils.h"
#include "QtZlib/zlib.h"
#include "lzokay.hpp"
#include "lzx.h"
#include <stdint.h>
#include <stddef.h>
#include <QByteArray>
#include <QDebug>
#include <QDataStream>
#include <QVector>
#include <algorithm>
typedef enum {
EResult_LookbehindOverrun = -4,
EResult_OutputOverrun = -3,
EResult_InputOverrun = -2,
EResult_Error = -1,
EResult_Success = 0,
EResult_InputNotConsumed = 1,
} lzokay_EResult;
static_assert(EResult_LookbehindOverrun == lzokay_EResult(lzokay::EResult::LookbehindOverrun), "LookbehindOverrun mismatch");
static_assert(EResult_OutputOverrun == lzokay_EResult(lzokay::EResult::OutputOverrun), "OutputOverrun mismatch");
static_assert(EResult_InputOverrun == lzokay_EResult(lzokay::EResult::InputOverrun), "InputOverrun mismatch");
static_assert(EResult_Error == lzokay_EResult(lzokay::EResult::Error), "Error mismatch");
static_assert(EResult_Success == lzokay_EResult(lzokay::EResult::Success), "Success mismatch");
static_assert(EResult_InputNotConsumed == lzokay_EResult(lzokay::EResult::InputNotConsumed), "InputNotConsumed mismatch");
class Compressor {
public:
static QByteArray DecompressZLIB(const QByteArray &compressedData) {
if (compressedData.isEmpty())
return QByteArray();
// Set up the inflate stream.
z_stream strm;
memset(&strm, 0, sizeof(strm));
// The inflate() function needs a non-const pointer; this is safe as we never modify the input.
strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(compressedData.data()));
strm.avail_in = static_cast<uInt>(compressedData.size());
// Use inflateInit(); if you want to support gzip streams, see note below.
int ret = inflateInit(&strm);
if (ret != Z_OK) {
qWarning() << "inflateInit failed:" << zError(ret);
return QByteArray();
}
QByteArray outArray;
char buffer[4096];
// Decompress until we reach the stream end.
do {
strm.next_out = reinterpret_cast<Bytef*>(buffer);
strm.avail_out = sizeof(buffer);
ret = inflate(&strm, Z_NO_FLUSH);
// Handle a special case: if inflate() returns Z_BUF_ERROR without
// having produced any output and with no further input, then we break out.
if (ret == Z_BUF_ERROR && strm.avail_in == 0) {
break;
}
if (ret != Z_OK && ret != Z_STREAM_END) {
qWarning() << "Error: ZLib inflate failed:" << zError(ret);
inflateEnd(&strm);
return QByteArray();
}
// Calculate number of bytes produced in this iteration.
int bytesProduced = sizeof(buffer) - strm.avail_out;
if (bytesProduced > 0)
outArray.append(buffer, bytesProduced);
} while (ret != Z_STREAM_END);
inflateEnd(&strm);
return outArray;
}
static QByteArray DecompressLZO(const QByteArray& input) {
lzokay::EResult error;
// Ensure the input QByteArray is valid
if (input.isEmpty()) {
qDebug() << "Input QByteArray is empty.";
return QByteArray();
}
// Step 1: Cast QByteArray to uint8_t*
const uint8_t *compressedData = reinterpret_cast<const uint8_t *>(input.constData());
std::size_t compressedSize = static_cast<std::size_t>(input.size());
// Step 2: Allocate a sufficiently large decompression buffer
// Use a large initial estimate if the decompressed size is unknown
std::size_t initialBufferSize = compressedSize * 20; // Arbitrary multiplier for decompression
std::unique_ptr<uint8_t[]> decompressed(new uint8_t[initialBufferSize]);
// Step 3: Attempt decompression
std::size_t decompressedSize = 0;
error = lzokay::decompress(
compressedData, compressedSize, // Input data and size
decompressed.get(), initialBufferSize, // Output buffer and initial size
decompressedSize // Actual decompressed size
);
// Step 4: Handle decompression errors
if (error != lzokay::EResult::Success) {
qDebug() << "Decompression failed with error code:" << static_cast<int>(error);
return QByteArray();
}
// Step 5: Return the decompressed data as a QByteArray
return QByteArray(reinterpret_cast<const char *>(decompressed.get()), decompressedSize);
}
static const int VECTOR_SIZE = 16; // 16 32-bit words
static const int NUM_OF_BLOCKS_PER_CHUNK = 8192;
//--------------------------------------------------------------------
// Helper functions (assuming littleendian order)
static void Convert32BitTo8Bit(quint32 value, quint8* array) {
array[0] = static_cast<quint8>(value >> 0);
array[1] = static_cast<quint8>(value >> 8);
array[2] = static_cast<quint8>(value >> 16);
array[3] = static_cast<quint8>(value >> 24);
}
static quint32 ConvertArrayTo32Bit(const QByteArray &array) {
return ((static_cast<quint32>(static_cast<uchar>(array[0])) << 0) |
(static_cast<quint32>(static_cast<uchar>(array[1])) << 8) |
(static_cast<quint32>(static_cast<uchar>(array[2])) << 16) |
(static_cast<quint32>(static_cast<uchar>(array[3])) << 24));
}
static quint32 Rotate(quint32 value, quint32 numBits) {
return (value << numBits) | (value >> (32 - numBits));
}
// Build the IV table from a 0x20byte feed. The table is 0xFB0 bytes.
static QByteArray InitIVTable(const QByteArray &feed) {
const int tableSize = 0xFB0;
QByteArray table;
table.resize(tableSize);
int ptr = 0;
for (int i = 0; i < 200; ++i) {
for (int x = 0; x < 5; ++x) {
if (static_cast<uchar>(feed.at(ptr)) == 0x00)
ptr = 0;
int base = i * 20 + x * 4;
table[base] = feed.at(ptr);
table[base + 1] = feed.at(ptr);
table[base + 2] = feed.at(ptr);
table[base + 3] = feed.at(ptr);
++ptr;
}
}
// Copy block numbers [1,0,0,0] into the last 16 bytes
QByteArray oneBlock;
oneBlock.append(char(1)); oneBlock.append(char(0)); oneBlock.append(char(0)); oneBlock.append(char(0));
table.replace(0xFA0, 4, oneBlock);
table.replace(0xFA4, 4, oneBlock);
table.replace(0xFA8, 4, oneBlock);
table.replace(0xFAC, 4, oneBlock);
return table;
}
// "unk" function as in the C# code.
static int unk(quint64 arg1, quint8 arg2) {
if (arg2 >= 0x40)
return 0;
return static_cast<int>(arg1 >> arg2);
}
// Compute the IV for a given section index using the IV table.
static QByteArray GetIV(const QByteArray &table, int index) {
int num1 = 0xFA0 + index;
int num2 = unk(0x51EB851FLL * num1, 0x20);
int adjust = ((num2 >> 6) + (num2 >> 31));
int startIndex = 20 * (num1 - 200 * adjust);
// Return 8 bytes from that location.
return table.mid(startIndex, 8);
}
// Update the IV table given the section's SHA1 hash.
static void UpdateIVTable(QByteArray &table, int index, const QByteArray &sectionHash) {
int blockNumIndex = index % 4;
int baseOffset = 0xFA0 + blockNumIndex * 4;
quint32 blockNumVal = (static_cast<uchar>(table.at(baseOffset)) ) |
(static_cast<uchar>(table.at(baseOffset + 1)) << 8 ) |
(static_cast<uchar>(table.at(baseOffset + 2)) << 16) |
(static_cast<uchar>(table.at(baseOffset + 3)) << 24);
int blockNum = blockNumVal * 4 + index;
int num2 = unk(0x51EB851FLL * blockNum, 0x20);
int adjust = ((num2 >> 6) + (num2 >> 31));
int startIndex = 20 * (blockNum - 200 * adjust) + 1;
int hashIndex = 0;
for (int x = 0; x < 4; ++x) {
table[startIndex - 1] = table.at(startIndex - 1) ^ sectionHash.at(hashIndex);
table[startIndex] = table.at(startIndex) ^ sectionHash.at(hashIndex + 1);
table[startIndex + 1] = table.at(startIndex + 1) ^ sectionHash.at(hashIndex + 2);
table[startIndex + 2] = table.at(startIndex + 2) ^ sectionHash.at(hashIndex + 3);
table[startIndex + 3] = table.at(startIndex + 3) ^ sectionHash.at(hashIndex + 4);
startIndex += 5;
hashIndex += 5;
}
}
static quint32 ToUInt32(const QByteArray &data, int offset) {
// Converts 4 bytes (starting at offset) from data into a 32-bit unsigned integer (little-endian)
return ((static_cast<quint32>(static_cast<uchar>(data[offset])) ) |
(static_cast<quint32>(static_cast<uchar>(data[offset+1])) << 8 ) |
(static_cast<quint32>(static_cast<uchar>(data[offset+2])) << 16) |
(static_cast<quint32>(static_cast<uchar>(data[offset+3])) << 24));
}
//--------------------------------------------------------------------
// Salsa20 decryption for one section.
// This function resets the counter for each section.
static QByteArray salsa20DecryptSection(const QByteArray &sectionData, const QByteArray &key, const QByteArray &iv, int blockSize = 64)
{
// Choose the appropriate constant based on key length.
QByteArray constants;
if (key.size() == 32)
constants = "expand 32-byte k";
else if (key.size() == 16)
constants = "expand 16-byte k";
else {
qWarning() << "Invalid key size:" << key.size() << "; expected 16 or 32 bytes.";
return QByteArray();
}
QVector<quint32> state(VECTOR_SIZE);
// Set state[0] using the first 4 bytes of the constant.
state[0] = ConvertArrayTo32Bit(constants.mid(0, 4));
// state[1] through state[4] come from the first 16 bytes of the key.
state[1] = ToUInt32(key, 0);
state[2] = ToUInt32(key, 4);
state[3] = ToUInt32(key, 8);
state[4] = ToUInt32(key, 12);
// state[5] comes from the next 4 bytes of the constant.
state[5] = ConvertArrayTo32Bit(constants.mid(4, 4));
// state[6] and state[7] come from the IV (which must be 8 bytes).
state[6] = ConvertArrayTo32Bit(iv.mid(0, 4));
state[7] = ConvertArrayTo32Bit(iv.mid(4, 4));
// state[8] and state[9] are the 64-bit block counter (start at 0).
state[8] = 0;
state[9] = 0;
// state[10] comes from the next 4 bytes of the constant.
state[10] = ConvertArrayTo32Bit(constants.mid(8, 4));
// For state[11] through state[14]:
// If the key is 32 bytes, use bytes 16..31; if 16 bytes, reuse the first 16 bytes.
if (key.size() == 32) {
state[11] = ToUInt32(key, 16);
state[12] = ToUInt32(key, 20);
state[13] = ToUInt32(key, 24);
state[14] = ToUInt32(key, 28);
} else { // key.size() == 16
state[11] = ToUInt32(key, 0);
state[12] = ToUInt32(key, 4);
state[13] = ToUInt32(key, 8);
state[14] = ToUInt32(key, 12);
}
// state[15] comes from the last 4 bytes of the constant.
state[15] = ConvertArrayTo32Bit(constants.mid(12, 4));
// Prepare the output buffer.
QByteArray output(sectionData.size(), Qt::Uninitialized);
int numBlocks = sectionData.size() / blockSize;
int remainder = sectionData.size() % blockSize;
// Process each full block.
for (int blockIndex = 0; blockIndex < numBlocks; ++blockIndex) {
QVector<quint32> x = state; // make a copy of the current state for this block
// Run 20 rounds (10 iterations) of Salsa20.
for (int round = 20; round > 0; round -= 2) {
x[4] ^= Rotate(x[0] + x[12], 7);
x[8] ^= Rotate(x[4] + x[0], 9);
x[12] ^= Rotate(x[8] + x[4], 13);
x[0] ^= Rotate(x[12] + x[8], 18);
x[9] ^= Rotate(x[5] + x[1], 7);
x[13] ^= Rotate(x[9] + x[5], 9);
x[1] ^= Rotate(x[13] + x[9], 13);
x[5] ^= Rotate(x[1] + x[13], 18);
x[14] ^= Rotate(x[10] + x[6], 7);
x[2] ^= Rotate(x[14] + x[10], 9);
x[6] ^= Rotate(x[2] + x[14], 13);
x[10] ^= Rotate(x[6] + x[2], 18);
x[3] ^= Rotate(x[15] + x[11], 7);
x[7] ^= Rotate(x[3] + x[15], 9);
x[11] ^= Rotate(x[7] + x[3], 13);
x[15] ^= Rotate(x[11] + x[7], 18);
x[1] ^= Rotate(x[0] + x[3], 7);
x[2] ^= Rotate(x[1] + x[0], 9);
x[3] ^= Rotate(x[2] + x[1], 13);
x[0] ^= Rotate(x[3] + x[2], 18);
x[6] ^= Rotate(x[5] + x[4], 7);
x[7] ^= Rotate(x[6] + x[5], 9);
x[4] ^= Rotate(x[7] + x[6], 13);
x[5] ^= Rotate(x[4] + x[7], 18);
x[11] ^= Rotate(x[10] + x[9], 7);
x[8] ^= Rotate(x[11] + x[10], 9);
x[9] ^= Rotate(x[8] + x[11], 13);
x[10] ^= Rotate(x[9] + x[8], 18);
x[12] ^= Rotate(x[15] + x[14], 7);
x[13] ^= Rotate(x[12] + x[15], 9);
x[14] ^= Rotate(x[13] + x[12], 13);
x[15] ^= Rotate(x[14] + x[13], 18);
}
// Produce the 64-byte keystream block by adding the original state.
QVector<quint8> keyStreamBlock(blockSize);
for (int i = 0; i < VECTOR_SIZE; ++i) {
x[i] += state[i];
Convert32BitTo8Bit(x[i], keyStreamBlock.data() + 4 * i);
}
// XOR the keystream block with the corresponding block of sectionData.
const uchar* inBlock = reinterpret_cast<const uchar*>(sectionData.constData()) + blockIndex * blockSize;
uchar* outBlock = reinterpret_cast<uchar*>(output.data()) + blockIndex * blockSize;
for (int j = 0; j < blockSize; ++j) {
outBlock[j] = inBlock[j] ^ keyStreamBlock[j];
}
// Increment the 64-bit block counter.
state[8]++;
if (state[8] == 0)
state[9]++;
}
// Process any remaining bytes.
if (remainder > 0) {
QVector<quint32> x = state;
for (int round = 20; round > 0; round -= 2) {
x[4] ^= Rotate(x[0] + x[12], 7);
x[8] ^= Rotate(x[4] + x[0], 9);
x[12] ^= Rotate(x[8] + x[4], 13);
x[0] ^= Rotate(x[12] + x[8], 18);
x[9] ^= Rotate(x[5] + x[1], 7);
x[13] ^= Rotate(x[9] + x[5], 9);
x[1] ^= Rotate(x[13] + x[9], 13);
x[5] ^= Rotate(x[1] + x[13], 18);
x[14] ^= Rotate(x[10] + x[6], 7);
x[2] ^= Rotate(x[14] + x[10], 9);
x[6] ^= Rotate(x[2] + x[14], 13);
x[10] ^= Rotate(x[6] + x[2], 18);
x[3] ^= Rotate(x[15] + x[11], 7);
x[7] ^= Rotate(x[3] + x[15], 9);
x[11] ^= Rotate(x[7] + x[3], 13);
x[15] ^= Rotate(x[11] + x[7], 18);
x[1] ^= Rotate(x[0] + x[3], 7);
x[2] ^= Rotate(x[1] + x[0], 9);
x[3] ^= Rotate(x[2] + x[1], 13);
x[0] ^= Rotate(x[3] + x[2], 18);
x[6] ^= Rotate(x[5] + x[4], 7);
x[7] ^= Rotate(x[6] + x[5], 9);
x[4] ^= Rotate(x[7] + x[6], 13);
x[5] ^= Rotate(x[4] + x[7], 18);
x[11] ^= Rotate(x[10] + x[9], 7);
x[8] ^= Rotate(x[11] + x[10], 9);
x[9] ^= Rotate(x[8] + x[11], 13);
x[10] ^= Rotate(x[9] + x[8], 18);
x[12] ^= Rotate(x[15] + x[14], 7);
x[13] ^= Rotate(x[12] + x[15], 9);
x[14] ^= Rotate(x[13] + x[12], 13);
x[15] ^= Rotate(x[14] + x[13], 18);
}
QVector<quint8> keyStreamBlock(blockSize);
for (int i = 0; i < VECTOR_SIZE; ++i) {
x[i] += state[i];
Convert32BitTo8Bit(x[i], keyStreamBlock.data() + 4 * i);
}
const uchar* inBlock = reinterpret_cast<const uchar*>(sectionData.constData()) + numBlocks * blockSize;
uchar* outBlock = reinterpret_cast<uchar*>(output.data()) + numBlocks * blockSize;
for (int j = 0; j < remainder; ++j)
outBlock[j] = inBlock[j] ^ keyStreamBlock[j];
}
return output;
}
};
#endif // COMPRESSOR_H

View File

@ -53,5 +53,39 @@
<file>icons/Icon_WAVFile.png</file>
<file>icons/Icon_MenuFile.png</file>
<file>icons/Icon_Image.png</file>
<file>icons/Icon_Model.png</file>
<file>icons/Icon_StringTable.png</file>
<file>icons/Icon_Sound.png</file>
<file>icons/Icon_Pause.png</file>
<file>icons/Icon_Play.png</file>
<file>icons/Icon_SkipBack.png</file>
<file>icons/Icon_SkipForward.png</file>
<file>icons/Icon_Stop.png</file>
<file>icons/Icon_Editor.png</file>
<file>icons/Icon_Views.png</file>
<file>icons/Icon_Tree.png</file>
<file>icons/Icon_Copy.png</file>
<file>icons/Icon_Cut.png</file>
<file>icons/Icon_Find.png</file>
<file>icons/Icon_NewFile.png</file>
<file>icons/Icon_Paste.png</file>
<file>icons/Icon_Save.png</file>
<file>icons/Icon_OpenFile.png</file>
<file>icons/Icon_COD2.png</file>
<file>icons/Icon_Material.png</file>
<file>icons/Icon_Animation.png</file>
<file>icons/Icon_BSP.png</file>
<file>icons/Icon_ColMapSp.png</file>
<file>icons/Icon_Effect.png</file>
<file>icons/Icon_GameMapSp.png</file>
<file>icons/Icon_Font.png</file>
<file>icons/Icon_FXMap.png</file>
<file>icons/Icon_LightDef.png</file>
<file>icons/Icon_Weapon.png</file>
<file>icons/Icon_RawFile.png</file>
<file>icons/Icon_Destructible.png</file>
<file>icons/Icon_PhysPreset.png</file>
<file>icons/Icon_Wii.png</file>
<file>icons/Icon_WiiU.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
data/icons/Icon_BSP.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
data/icons/Icon_COD2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
data/icons/Icon_Copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

BIN
data/icons/Icon_Cut.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
data/icons/Icon_Editor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

BIN
data/icons/Icon_Effect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
data/icons/Icon_FXMap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
data/icons/Icon_Find.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
data/icons/Icon_Font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
data/icons/Icon_Model.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
data/icons/Icon_NewFile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

BIN
data/icons/Icon_Paste.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

BIN
data/icons/Icon_Pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
data/icons/Icon_Play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
data/icons/Icon_RawFile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
data/icons/Icon_Save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

BIN
data/icons/Icon_Sound.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
data/icons/Icon_Stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Some files were not shown because too many files have changed in this diff Show More