Lotta new stuff.

This commit is contained in:
= 2025-02-14 16:06:27 -05:00
parent 2df69cebce
commit 840f194195
49 changed files with 4961 additions and 403 deletions

View File

@ -1,4 +1,4 @@
QT += core gui 3dcore 3drender 3dinput 3dextras QT += core gui multimedia
RC_ICONS = XPlor.ico RC_ICONS = XPlor.ico
@ -11,6 +11,8 @@ SOURCES += \
ddsfile.cpp \ ddsfile.cpp \
ddsviewer.cpp \ ddsviewer.cpp \
fastfile.cpp \ fastfile.cpp \
fastfile_cod2.cpp \
fastfile_cod5.cpp \
fastfileviewer.cpp \ fastfileviewer.cpp \
imagewidget.cpp \ imagewidget.cpp \
iwifile.cpp \ iwifile.cpp \
@ -19,10 +21,13 @@ SOURCES += \
lzokay.cpp \ lzokay.cpp \
main.cpp \ main.cpp \
mainwindow.cpp \ mainwindow.cpp \
modelviewer.cpp \
iwifile.cpp \ iwifile.cpp \
preferenceeditor.cpp \
soundviewer.cpp \
stringtableviewer.cpp \
techsetviewer.cpp \ techsetviewer.cpp \
xtreewidget.cpp \ xtreewidget.cpp \
xtreewidgetitem.cpp \
zonefile.cpp \ zonefile.cpp \
zonefileviewer.cpp zonefileviewer.cpp
@ -36,6 +41,8 @@ HEADERS += \
ddsviewer.h \ ddsviewer.h \
enums.h \ enums.h \
fastfile.h \ fastfile.h \
fastfile_cod2.h \
fastfile_cod5.h \
fastfileviewer.h \ fastfileviewer.h \
imagewidget.h \ imagewidget.h \
ipak_structs.h \ ipak_structs.h \
@ -45,11 +52,14 @@ HEADERS += \
lzokay.hpp \ lzokay.hpp \
lzx.h \ lzx.h \
mainwindow.h \ mainwindow.h \
modelviewer.h \ preferenceeditor.h \
soundviewer.h \
stringtableviewer.h \
techsetviewer.h \ techsetviewer.h \
utils.h \ utils.h \
xtreewidget.h \ xtreewidget.h \
iwifile.h \ iwifile.h \
xtreewidgetitem.h \
zonefile.h \ zonefile.h \
zonefileviewer.h zonefileviewer.h
@ -61,11 +71,14 @@ FORMS += \
iwiviewer.ui \ iwiviewer.ui \
localstringviewer.ui \ localstringviewer.ui \
mainwindow.ui \ mainwindow.ui \
modelviewer.ui \
preferenceeditor.ui \
soundviewer.ui \
stringtableviewer.ui \
techsetviewer.ui \ techsetviewer.ui \
zonefileviewer.ui zonefileviewer.ui
RESOURCES += \ RESOURCES += data/data.qrc
data/Data.qrc
LIBS += -L$$PWD/DevILSDK/lib/x64/Unicode/Release -lDevIL 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 -lILU

View File

@ -6,6 +6,7 @@
#include <QString> #include <QString>
#include <QColor> #include <QColor>
#include <QRectF> #include <QRectF>
#include <QMap>
struct LocalString { struct LocalString {
QString string; QString string;
@ -142,6 +143,8 @@ struct StringTable {
quint32 columnCount; quint32 columnCount;
quint32 rowCount; quint32 rowCount;
QString name; QString name;
QVector<QString> tablePointers;
QMap<QString, QString> content;
}; };
struct Image { struct Image {
@ -319,6 +322,20 @@ struct MenuFile {
QVector<Menu> menuDefs; QVector<Menu> menuDefs;
}; };
struct Sound {
QString path;
QString alias;
quint32 dataPtr;
quint32 dataLength;
QByteArray data;
};
struct SoundAsset {
QString name;
quint32 count;
QVector<Sound> sounds;
};
struct AssetMap { struct AssetMap {
QVector<LocalString> localStrings; QVector<LocalString> localStrings;
QVector<RawFile> rawFiles; QVector<RawFile> rawFiles;
@ -328,7 +345,7 @@ struct AssetMap {
//QVector<Shader> shaders; //QVector<Shader> shaders;
QVector<TechSet> techSets; QVector<TechSet> techSets;
QVector<Image> images; QVector<Image> images;
//QVector<Sound> sounds; QVector<SoundAsset> sounds;
//QVector<CollisionMap> collMaps; //QVector<CollisionMap> collMaps;
//QVector<LightDefinition> lightDefs; //QVector<LightDefinition> lightDefs;
//QVector<UiMap> uiMaps; //QVector<UiMap> uiMaps;

View File

@ -53,5 +53,23 @@
<file>icons/Icon_WAVFile.png</file> <file>icons/Icon_WAVFile.png</file>
<file>icons/Icon_MenuFile.png</file> <file>icons/Icon_MenuFile.png</file>
<file>icons/Icon_Image.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>
</qresource> </qresource>
</RCC> </RCC>

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

BIN
data/icons/Icon_Editor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

BIN
data/icons/Icon_Find.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 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

BIN
data/icons/Icon_Play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
data/icons/Icon_Tree.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

BIN
data/icons/Icon_Views.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

15
enums.h
View File

@ -12,12 +12,15 @@ enum FF_PLATFORM {
enum FF_GAME { enum FF_GAME {
FF_GAME_NONE = 0x00, // No game FF_GAME_NONE = 0x00, // No game
FF_GAME_COD4 = 0x01, // Modern Warware 1 FF_GAME_COD1 = 0x01, // Call of Duty
FF_GAME_COD5 = 0x02, // World at War FF_GAME_COD2 = 0x02, // Call of Duty 2
FF_GAME_COD6 = 0x03, // Modern Warfare 2 FF_GAME_COD3 = 0x03, // Call of Duty 3
FF_GAME_COD7 = 0x04, // Black Ops 1 FF_GAME_COD4 = 0x04, // Modern Warware 1
FF_GAME_COD8 = 0x05, // Modern Warfare 3 FF_GAME_COD5 = 0x05, // World at War
FF_GAME_COD9 = 0x06, // Black Ops 2 FF_GAME_COD6 = 0x06, // Modern Warfare 2
FF_GAME_COD7 = 0x07, // Black Ops 1
FF_GAME_COD8 = 0x08, // Modern Warfare 3
FF_GAME_COD9 = 0x09, // Black Ops 2
}; };
enum IWI_VERSION { enum IWI_VERSION {

View File

@ -4,42 +4,21 @@
#include <QFile> #include <QFile>
#include <QDebug> #include <QDebug>
FastFile::FastFile() :
fileStem(),
company(),
fileType(),
signage(),
magic(),
version() {
}
FastFile::~FastFile() { FastFile::~FastFile() {
} }
FastFile::FastFile(const FastFile &aFastFile) {
fileStem = aFastFile.GetFileStem();
company = aFastFile.GetCompany();
fileType = aFastFile.GetFileType();
signage = aFastFile.GetSignage();
magic = aFastFile.GetMagic();
version = aFastFile.GetVersion();
zoneFile = aFastFile.zoneFile;
game = aFastFile.GetGame();
platform = aFastFile.GetPlatform();
}
FastFile &FastFile::operator=(const FastFile &other) { FastFile &FastFile::operator=(const FastFile &other) {
if (this != &other) { if (this != &other) {
fileStem = other.GetFileStem(); mStem = other.GetStem();
company = other.GetCompany(); mType = other.GetType();
fileType = other.GetFileType(); mCompany = other.GetCompany();
signage = other.GetSignage(); mSignage = other.GetSignage();
magic = other.GetMagic(); mMagic = other.GetMagic();
version = other.GetVersion(); mVersion = other.GetVersion();
zoneFile = other.zoneFile; mZoneFile = other.GetZoneFile();
game = other.GetGame(); mGame = other.GetGame();
platform = other.GetPlatform(); mPlatform = other.GetPlatform();
} }
return *this; return *this;
} }
@ -52,6 +31,16 @@ bool FastFile::Load(const QByteArray aData) {
fastFileStream.setByteOrder(QDataStream::LittleEndian); fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values. // Parse header values.
if (fastFileStream.device()->peek(2).toHex() == "0000") {
company = COMPANY_INFINITY_WARD;
fileType = FILETYPE_FAST_FILE;
signage = SIGNAGE_UNSIGNED;
magic = 0;
version = 0;
platform = "360";
game = "COD2";
} else {
company = pParseFFCompany(&fastFileStream); company = pParseFFCompany(&fastFileStream);
fileType = pParseFFFileType(&fastFileStream); fileType = pParseFFFileType(&fastFileStream);
signage = pParseFFSignage(&fastFileStream); signage = pParseFFSignage(&fastFileStream);
@ -59,6 +48,7 @@ bool FastFile::Load(const QByteArray aData) {
version = pParseFFVersion(&fastFileStream); version = pParseFFVersion(&fastFileStream);
platform = pCalculateFFPlatform(); platform = pCalculateFFPlatform();
game = pCalculateFFGame(); game = pCalculateFFGame();
}
if (game == "COD5") { if (game == "COD5") {
// For COD5, simply decompress from offset 12. // For COD5, simply decompress from offset 12.
@ -189,6 +179,19 @@ bool FastFile::Load(const QByteArray aData) {
// Load the zone file with the decompressed data (using an Xbox platform flag). // Load the zone file with the decompressed data (using an Xbox platform flag).
zoneFile.Load(decompressedData, fileStem.section('.', 0, 0) + ".zone", FF_PLATFORM_XBOX); zoneFile.Load(decompressedData, fileStem.section('.', 0, 0) + ".zone", FF_PLATFORM_XBOX);
} else if (game == "COD2") {
Utils::ReadUntilHex(&fastFileStream, "78");
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
QByteArray decompressedData = Compressor::DecompressZLIB(compressedData);
QFile testFile("exports/" + fileStem.split('.')[0] + ".zone");
if(testFile.open(QIODevice::WriteOnly)) {
testFile.write(decompressedData);
testFile.close();
}
// Load the zone file with the decompressed data (using an Xbox platform flag).
zoneFile.Load(decompressedData, fileStem.section('.', 0, 0) + ".zone", FF_PLATFORM_XBOX, FF_GAME_COD2);
} }
return true; return true;
@ -222,42 +225,6 @@ bool FastFile::Load(const QString aFilePath) {
return true; return true;
} }
QString FastFile::GetFileStem() const {
return fileStem;
}
FF_COMPANY FastFile::GetCompany() const {
return company;
}
FF_FILETYPE FastFile::GetFileType() const {
return fileType;
}
FF_SIGNAGE FastFile::GetSignage() const {
return signage;
}
QString FastFile::GetMagic() const {
return magic;
}
quint32 FastFile::GetVersion() const {
return version;
}
ZoneFile FastFile::GetZoneFile() const {
return zoneFile;
}
QString FastFile::GetGame() const {
return game;
}
QString FastFile::GetPlatform() const {
return platform;
}
FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream) { FF_COMPANY FastFile::pParseFFCompany(QDataStream *afastFileStream) {
// Check for null datastream ptr // Check for null datastream ptr
if (!afastFileStream) { return COMPANY_NONE; } if (!afastFileStream) { return COMPANY_NONE; }

View File

@ -10,42 +10,42 @@
class FastFile class FastFile
{ {
public: public:
FastFile(); virtual ~FastFile();
~FastFile(); virtual FastFile &operator=(const FastFile &other);
FastFile(const FastFile &aFastFile);
FastFile &operator=(const FastFile &other);
bool Load(const QString aFilePath); virtual bool Load(const QString aFilePath) = 0;
bool Load(const QByteArray aData); virtual bool Load(const QByteArray aData) = 0;
QString GetFileStem() const; virtual QString GetStem() const { return mStem; }
FF_COMPANY GetCompany() const; virtual FF_FILETYPE GetType() const { return mType; }
FF_FILETYPE GetFileType() const; virtual FF_COMPANY GetCompany() const { return mCompany; }
FF_SIGNAGE GetSignage() const; virtual FF_SIGNAGE GetSignage() const { return mSignage; }
QString GetMagic() const; virtual QString GetMagic() const { return mMagic; }
quint32 GetVersion() const; virtual quint32 GetVersion() const { return mVersion; }
ZoneFile GetZoneFile() const; virtual ZoneFile GetZoneFile() const { return mZoneFile; }
QString GetGame() const; virtual QString GetGame() const { return mGame; }
QString GetPlatform() const; virtual QString GetPlatform() const { return mPlatform; }
virtual void SetStem(const QString aStem) { mStem = aStem; }
virtual void SetType(const FF_FILETYPE aType) { mType = aType; }
virtual void SetCompany(const FF_COMPANY aCompany) { mCompany = aCompany; }
virtual void SetSignage(const FF_SIGNAGE aSignage) { mSignage = aSignage; }
virtual void SetMagic(const QString aMagic) { mMagic = aMagic; }
virtual void SetVersion(const quint32 aVersion) { mVersion = aVersion; }
virtual void SetZoneFile(const ZoneFile aZoneFile) { mZoneFile = aZoneFile; }
virtual void SetGame(const QString aGame) { mGame = aGame; }
virtual void SetPlatform(const QString aPlatform) { mPlatform = aPlatform; }
private: private:
QString fileStem; QString mStem;
FF_COMPANY company; FF_FILETYPE mType;
FF_FILETYPE fileType; FF_COMPANY mCompany;
FF_SIGNAGE signage; FF_SIGNAGE mSignage;
QString magic; QString mMagic;
quint32 version; quint32 mVersion;
ZoneFile zoneFile; ZoneFile mZoneFile;
QString game; QString mGame;
QString platform; QString mPlatform;
QString pCalculateFFGame();
QString pCalculateFFPlatform();
QString pParseFFMagic(QDataStream *afastFileStream);
FF_SIGNAGE pParseFFSignage(QDataStream *afastFileStream);
FF_FILETYPE pParseFFFileType(QDataStream *afastFileStream);
FF_COMPANY pParseFFCompany(QDataStream *afastFileStream);
quint32 pParseFFVersion(QDataStream *afastFileStream);
}; };
#endif // FASTFILE_H #endif // FASTFILE_H

70
fastfile_cod2.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "fastfile_cod2.h"
#include <QFile>
#include <QDebug>
FastFile_COD2::FastFile_COD2() {
}
FastFile_COD2::~FastFile_COD2() {
}
FastFile &FastFile_COD2::operator=(const FastFile &other) {
}
bool FastFile_COD2::Load(const QString aFilePath) {
if (aFilePath.isEmpty()) {
return false;
}
// Check fastfile can be read
QFile *file = new QFile(aFilePath);
if (!file->open(QIODevice::ReadOnly)) {
qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath);
return false;
}
// Decompress fastfile and close
const QString fastFileStem = aFilePath.section("/", -1, -1);
SetStem(fastFileStem);
if (!Load(file->readAll())) {
qDebug() << "Error: Failed to load fastfile: " << fastFileStem;
return false;
}
file->close();
// Open zone file after decompressing ff and writing
return true;
}
bool FastFile_COD2::Load(const QByteArray aData) {
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(COMPANY_INFINITY_WARD);
SetType(FILETYPE_FAST_FILE);
SetSignage(SIGNAGE_UNSIGNED);
SetMagic(0);
SetVersion(0);
SetPlatform("360");
SetGame("COD2");
Utils::ReadUntilHex(&fastFileStream, "78");
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
QByteArray decompressedData = Compressor::DecompressZLIB(compressedData);
QFile testFile("exports/" + GetStem().split('.')[0] + ".zone");
if(testFile.open(QIODevice::WriteOnly)) {
testFile.write(decompressedData);
testFile.close();
}
// Load the zone file with the decompressed data (using an Xbox platform flag).
zoneFile.Load(decompressedData, GetStem().section('.', 0, 0) + ".zone", FF_PLATFORM_XBOX, FF_GAME_COD2);
}

18
fastfile_cod2.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef FASTFILE_COD2_H
#define FASTFILE_COD2_H
#include "fastfile.h"
class FastFile_COD2 : public FastFile
{
public:
FastFile_COD2();
~FastFile_COD2();
FastFile &operator=(const FastFile &other) override;
bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override;
};
#endif // FASTFILE_COD2_H

72
fastfile_cod5.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "fastfile_cod5.h"
#include <QFile>
#include <QDebug>
FastFile_COD5::FastFile_COD5() {
}
FastFile_COD5::~FastFile_COD5() {
}
FastFile &FastFile_COD5::operator=(const FastFile &other) {
}
bool FastFile_COD5::Load(const QString aFilePath) {
if (aFilePath.isEmpty()) {
return false;
}
// Check fastfile can be read
QFile *file = new QFile(aFilePath);
if (!file->open(QIODevice::ReadOnly)) {
qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath);
return false;
}
// Decompress fastfile and close
const QString fastFileStem = aFilePath.section("/", -1, -1);
SetStem(fastFileStem);
if (!Load(file->readAll())) {
qDebug() << "Error: Failed to load fastfile: " << fastFileStem;
return false;
}
file->close();
// Open zone file after decompressing ff and writing
return true;
}
bool FastFile_COD5::Load(const QByteArray aData) {
QByteArray decompressedData;
// Create a QDataStream on the input data.
QDataStream fastFileStream(aData);
fastFileStream.setByteOrder(QDataStream::LittleEndian);
// Parse header values.
SetCompany(pParseFFCompany(&fastFileStream));
fileType = pParseFFFileType(&fastFileStream);
signage = pParseFFSignage(&fastFileStream);
magic = pParseFFMagic(&fastFileStream);
version = pParseFFVersion(&fastFileStream);
platform = pCalculateFFPlatform();
game = pCalculateFFGame();
// For COD5, simply decompress from offset 12.
decompressedData = Compressor::DecompressZLIB(aData.mid(12));
QFile testFile("exports/" + fileStem.section('.', 0, 0) + ".zone");
if(testFile.open(QIODevice::WriteOnly)) {
testFile.write(decompressedData);
testFile.close();
}
zoneFile.Load(decompressedData, fileStem.section('.', 0, 0) + ".zone");
return true;
}

18
fastfile_cod5.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef FASTFILE_COD5_H
#define FASTFILE_COD5_H
#include "fastfile.h"
class FastFile_COD5 : public FastFile
{
public:
FastFile_COD5();
~FastFile_COD5();
FastFile &operator=(const FastFile &other) override;
bool Load(const QString aFilePath) override;
bool Load(const QByteArray aData) override;
};
#endif // FASTFILE_COD5_H

View File

@ -1,7 +1,10 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "aboutdialog.h" #include "aboutdialog.h"
#include "fastfile.h" #include "fastfile.h"
#include "preferenceeditor.h"
#include "qheaderview.h" #include "qheaderview.h"
#include "soundviewer.h"
#include "stringtableviewer.h"
#include "techsetviewer.h" #include "techsetviewer.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "compressor.h" #include "compressor.h"
@ -34,6 +37,11 @@ MainWindow::MainWindow(QWidget *parent)
//ModelViewer *mModelViewer = new ModelViewer(container); //ModelViewer *mModelViewer = new ModelViewer(container);
//mModelViewer->setAcceptDrops(false); //mModelViewer->setAcceptDrops(false);
connect(ui->actionPreferences, &QAction::triggered, this, [this](bool checked = false) {
PreferenceEditor *prefEditor = new PreferenceEditor(this);
prefEditor->exec();
});
ui->tabWidget->setContextMenuPolicy(Qt::CustomContextMenu); ui->tabWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tabWidget, &QTabWidget::customContextMenuRequested, this, [this](const QPoint &pos) { connect(ui->tabWidget, &QTabWidget::customContextMenuRequested, this, [this](const QPoint &pos) {
if (pos.isNull()) if (pos.isNull())
@ -104,6 +112,10 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->removeTab(index); ui->tabWidget->removeTab(index);
}); });
connect(mTreeWidget, &XTreeWidget::Cleared, this, [this]() {
ui->tabWidget->clear();
});
connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr<RawFile> rawFile) { connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr<RawFile> rawFile) {
QPlainTextEdit *scriptEditor = new QPlainTextEdit(this); QPlainTextEdit *scriptEditor = new QPlainTextEdit(this);
scriptEditor->setAcceptDrops(false); scriptEditor->setAcceptDrops(false);
@ -250,6 +262,51 @@ MainWindow::MainWindow(QWidget *parent)
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
}); });
connect(mTreeWidget, &XTreeWidget::StrTableSelected, this, [this](std::shared_ptr<StringTable> aStrTable) {
StringTableViewer *strTableViewer = new StringTableViewer(this);
strTableViewer->setAcceptDrops(false);
strTableViewer->SetStringTable(aStrTable);
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) {
SoundViewer *soundViewer = new SoundViewer(this);
soundViewer->setAcceptDrops(false);
soundViewer->SetSound(aSound);
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::TabSelected, this, [this](QString tabName) {
for (int i = 0; i < ui->tabWidget->count(); i++) {
if (ui->tabWidget->tabText(i) == tabName) {
ui->tabWidget->setCurrentIndex(i);
break;
}
}
});
// Connect Help > About dialog // Connect Help > About dialog
connect(ui->actionAbout, &QAction::triggered, this, [this](bool checked) { connect(ui->actionAbout, &QAction::triggered, this, [this](bool checked) {
Q_UNUSED(checked); Q_UNUSED(checked);

View File

@ -58,17 +58,11 @@
<property name="title"> <property name="title">
<string>Recent...</string> <string>Recent...</string>
</property> </property>
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentOpenRecent"/>
</property>
</widget> </widget>
<widget class="QMenu" name="menuImport"> <widget class="QMenu" name="menuImport">
<property name="title"> <property name="title">
<string>Import...</string> <string>Import...</string>
</property> </property>
<property name="icon">
<iconset theme="QIcon::ThemeIcon::FolderNew"/>
</property>
</widget> </widget>
<addaction name="actionNew_File_2"/> <addaction name="actionNew_File_2"/>
<addaction name="actionNew_Fast_File"/> <addaction name="actionNew_Fast_File"/>
@ -114,6 +108,8 @@
<addaction name="menuUndo_History"/> <addaction name="menuUndo_History"/>
<addaction name="menuRedo_History"/> <addaction name="menuRedo_History"/>
<addaction name="actionClear_Undo_History"/> <addaction name="actionClear_Undo_History"/>
<addaction name="separator"/>
<addaction name="actionPreferences"/>
</widget> </widget>
<widget class="QMenu" name="menuHelp"> <widget class="QMenu" name="menuHelp">
<property name="title"> <property name="title">
@ -140,7 +136,8 @@
<widget class="QStatusBar" name="statusBar"/> <widget class="QStatusBar" name="statusBar"/>
<action name="actionNew_File_2"> <action name="actionNew_File_2">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>New</string> <string>New</string>
@ -148,7 +145,8 @@
</action> </action>
<action name="actionNew_Fast_File"> <action name="actionNew_Fast_File">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>New Fast File</string> <string>New Fast File</string>
@ -156,7 +154,8 @@
</action> </action>
<action name="actionNew_Zone_File"> <action name="actionNew_Zone_File">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>New Zone File</string> <string>New Zone File</string>
@ -164,7 +163,8 @@
</action> </action>
<action name="actionOpen_Fast_File"> <action name="actionOpen_Fast_File">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Open Fast File</string> <string>Open Fast File</string>
@ -172,7 +172,8 @@
</action> </action>
<action name="actionOpen_Zone_File"> <action name="actionOpen_Zone_File">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Open Zone File</string> <string>Open Zone File</string>
@ -180,7 +181,8 @@
</action> </action>
<action name="actionOpen_Folder"> <action name="actionOpen_Folder">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Open Folder</string> <string>Open Folder</string>
@ -188,16 +190,14 @@
</action> </action>
<action name="actionSave"> <action name="actionSave">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Save</string> <string>Save</string>
</property> </property>
</action> </action>
<action name="actionSave_As"> <action name="actionSave_As">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::DocumentSaveAs"/>
</property>
<property name="text"> <property name="text">
<string>Save As</string> <string>Save As</string>
</property> </property>
@ -248,24 +248,19 @@
</property> </property>
</action> </action>
<action name="actionUndo"> <action name="actionUndo">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditUndo"/>
</property>
<property name="text"> <property name="text">
<string>Undo</string> <string>Undo</string>
</property> </property>
</action> </action>
<action name="actionRedo"> <action name="actionRedo">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditRedo"/>
</property>
<property name="text"> <property name="text">
<string>Redo</string> <string>Redo</string>
</property> </property>
</action> </action>
<action name="actionCut"> <action name="actionCut">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Cut</string> <string>Cut</string>
@ -273,7 +268,8 @@
</action> </action>
<action name="actionCopy"> <action name="actionCopy">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Copy</string> <string>Copy</string>
@ -281,16 +277,14 @@
</action> </action>
<action name="actionPaste"> <action name="actionPaste">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Paste</string> <string>Paste</string>
</property> </property>
</action> </action>
<action name="actionRename"> <action name="actionRename">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::MailMessageNew"/>
</property>
<property name="text"> <property name="text">
<string>Rename</string> <string>Rename</string>
</property> </property>
@ -306,9 +300,6 @@
</property> </property>
</action> </action>
<action name="actionDelete"> <action name="actionDelete">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::EditDelete"/>
</property>
<property name="text"> <property name="text">
<string>Delete</string> <string>Delete</string>
</property> </property>
@ -334,9 +325,6 @@
</property> </property>
</action> </action>
<action name="actionAbout"> <action name="actionAbout">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::HelpAbout"/>
</property>
<property name="text"> <property name="text">
<string>About</string> <string>About</string>
</property> </property>
@ -347,22 +335,27 @@
</property> </property>
</action> </action>
<action name="actionCheck_for_Updates"> <action name="actionCheck_for_Updates">
<property name="icon">
<iconset theme="QIcon::ThemeIcon::SyncSynchronizing"/>
</property>
<property name="text"> <property name="text">
<string>Check for Updates</string> <string>Check for Updates</string>
</property> </property>
</action> </action>
<action name="actionFind_2"> <action name="actionFind_2">
<property name="icon"> <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>
<property name="text"> <property name="text">
<string>Find</string> <string>Find</string>
</property> </property>
</action> </action>
<action name="actionPreferences">
<property name="text">
<string>Preferences...</string>
</property>
</action>
</widget> </widget>
<resources/> <resources>
<include location="data/data.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -1,73 +1,14 @@
#include "modelviewer.h" #include "modelviewer.h"
#include "ui_modelviewer.h"
ModelViewer::ModelViewer(QWidget *parent) ModelViewer::ModelViewer(QWidget *parent)
: QWidget{parent} { : QWidget(parent)
Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow(); , ui(new Ui::ModelViewer)
view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f))); {
ui->setupUi(this);
QWidget *container = QWidget::createWindowContainer(view); }
QSize screenSize = view->screen()->size();
container->setMinimumSize(QSize(200, 100)); ModelViewer::~ModelViewer()
container->setMaximumSize(screenSize); {
delete ui;
QHBoxLayout *hLayout = new QHBoxLayout(this);
QVBoxLayout *vLayout = new QVBoxLayout();
vLayout->setAlignment(Qt::AlignTop);
hLayout->addWidget(container, 1);
hLayout->addLayout(vLayout);
// Root entity
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
// Camera
Qt3DRender::QCamera *cameraEntity = view->camera();
cameraEntity->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
cameraEntity->setPosition(QVector3D(0, 0, 50.0f)); // Move farther along Z-axis
cameraEntity->setUpVector(QVector3D(0, 1, 0));
cameraEntity->setViewCenter(QVector3D(0, 0, 0));
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor("white");
light->setIntensity(1);
lightEntity->addComponent(light);
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(cameraEntity->position());
lightEntity->addComponent(lightTransform);
// For camera controls
Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity);
camController->setCamera(cameraEntity);
// Set root object of the scene
view->setRootEntity(rootEntity);
// Load custom 3D model
Qt3DRender::QMesh *customMesh = new Qt3DRender::QMesh();
customMesh->setSource(QUrl::fromLocalFile(":/obj/data/obj/defaultactor_LOD0.obj"));
// Adjust the model transformation
Qt3DCore::QTransform *customTransform = new Qt3DCore::QTransform();
customTransform->setRotationX(-90);
customTransform->setRotationY(-90);
// Keep translation if necessary
customTransform->setTranslation(QVector3D(0.0f, -100.0f, -200.0f));
Qt3DExtras::QNormalDiffuseMapMaterial *customMaterial = new Qt3DExtras::QNormalDiffuseMapMaterial();
Qt3DRender::QTextureLoader *normalMap = new Qt3DRender::QTextureLoader();
normalMap->setSource(QUrl::fromLocalFile(":/obj/data/obj/normalmap.png"));
customMaterial->setNormal(normalMap);
Qt3DRender::QTextureLoader *diffuseMap = new Qt3DRender::QTextureLoader();
diffuseMap->setSource(QUrl::fromLocalFile(":/obj/data/obj/diffusemap.png"));
customMaterial->setDiffuse(diffuseMap);
Qt3DCore::QEntity *m_torusEntity = new Qt3DCore::QEntity(rootEntity);
m_torusEntity->addComponent(customMesh);
m_torusEntity->addComponent(customMaterial);
m_torusEntity->addComponent(customTransform);
} }

View File

@ -1,53 +1,22 @@
#ifndef MODELVIEWER_H #ifndef MODELVIEWER_H
#define MODELVIEWER_H #define MODELVIEWER_H
#include <QApplication>
#include <QWidget> #include <QWidget>
#include <QHBoxLayout>
#include <QCheckBox>
#include <QCommandLinkButton>
#include <QScreen>
#include <QHBoxLayout>
#include <QVBoxLayout>
// Qt3DCore includes namespace Ui {
#include <QEntity> class ModelViewer;
#include <QTransform> }
#include <QAspectEngine>
#include <qtransform.h>
#include <qaspectengine.h>
#include <qentity.h>
// Qt3DInput includes
#include <QInputAspect>
// Qt3DRender includes
#include <QRenderAspect>
#include <QGeometryRenderer>
#include <QCamera>
#include <QCameraLens>
#include <QMesh>
#include <QTechnique>
#include <QMaterial>
#include <QEffect>
#include <QTexture>
#include <QRenderPass>
#include <QSceneLoader>
#include <QPointLight>
// Qt3DExtras includes
#include <Qt3DWindow>
#include <QFirstPersonCameraController>
#include <QNormalDiffuseMapMaterial>
#include <QForwardRenderer>
#include <QPhongMaterial>
#include <QSphereMesh>
#include <QTorusMesh>
class ModelViewer : public QWidget class ModelViewer : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ModelViewer(QWidget *parent = nullptr); explicit ModelViewer(QWidget *parent = nullptr);
~ModelViewer();
signals: private:
Ui::ModelViewer *ui;
}; };
#endif // MODELVIEWER_H #endif // MODELVIEWER_H

624
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
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
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
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
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
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
soundviewer.ui Normal file

File diff suppressed because it is too large Load Diff

36
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
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
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>

68
utils.h
View File

@ -10,6 +10,74 @@
class Utils { class Utils {
public: public:
static bool ReadUntilString(QDataStream* stream, const QString& targetString) {
if (!stream || targetString.isEmpty()) {
return false; // Invalid input
}
QByteArray buffer;
QByteArray targetBytes = targetString.toUtf8(); // Handle multibyte characters
const int targetLength = targetBytes.size();
qDebug() << targetBytes << targetLength;
// Read as unsigned bytes to handle all possible values (0-255)
unsigned char byte;
while (!stream->atEnd()) {
// Read one byte at a time
*stream >> byte;
buffer.append(static_cast<char>(byte)); // Append as char for QByteArray
// Keep buffer size limited to the target length
if (buffer.size() > targetLength) {
buffer.remove(0, 1);
}
// Check if the buffer matches the target string in raw bytes
if (buffer == targetBytes) {
// Backup to the start of the matched string
stream->device()->seek(stream->device()->pos() - targetLength);
return true;
}
}
// Target string not found
return false;
}
static bool ReadUntilHex(QDataStream* stream, const QString& hexString) {
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
return false; // Invalid input
}
// Convert hex string to byte array
QByteArray targetBytes = QByteArray::fromHex(hexString.toUtf8());
const int targetLength = targetBytes.size();
QByteArray buffer;
unsigned char byte;
while (!stream->atEnd()) {
// Read one byte at a time
*stream >> byte;
buffer.append(static_cast<char>(byte)); // Append as char for QByteArray
// Keep buffer size limited to the target length
if (buffer.size() > targetLength) {
buffer.remove(0, 1);
}
// Check if the buffer matches the target byte sequence
if (buffer == targetBytes) {
// Backup to the start of the matched sequence
stream->device()->seek(stream->device()->pos() - targetLength);
return true;
}
}
// Target sequence not found
return false;
}
/* /*
AssetTypeToString() AssetTypeToString()

View File

@ -13,11 +13,20 @@ XTreeWidget::XTreeWidget(QWidget *parent)
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
setSelectionMode(QTreeWidget::SingleSelection); setSelectionMode(QTreeWidget::SingleSelection);
setColumnCount(3); setColumnCount(3);
setColumnWidth(0, 275);
setColumnWidth(1, 50);
setColumnWidth(2, 50);
header()->hide(); header()->hide();
setMinimumWidth(350); 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, &QTreeWidget::itemSelectionChanged, this, &XTreeWidget::ItemSelectionChanged); connect(this, &QTreeWidget::itemSelectionChanged, this, &XTreeWidget::ItemSelectionChanged);
connect(this, &XTreeWidget::customContextMenuRequested, this, &XTreeWidget::PrepareContextMenu); connect(this, &XTreeWidget::customContextMenuRequested, this, &XTreeWidget::PrepareContextMenu);
@ -28,7 +37,7 @@ XTreeWidget::~XTreeWidget() {
} }
void XTreeWidget::AddFastFile(std::shared_ptr<FastFile> aFastFile) { void XTreeWidget::AddFastFile(std::shared_ptr<FastFile> aFastFile) {
QTreeWidgetItem *fastFileItem = new QTreeWidgetItem(this); XTreeWidgetItem *fastFileItem = new XTreeWidgetItem(this);
fastFileItem->setText(0, aFastFile->GetFileStem()); fastFileItem->setText(0, aFastFile->GetFileStem());
fastFileItem->setIcon(0, QIcon(":/icons/icons/Icon_FastFile.png")); fastFileItem->setIcon(0, QIcon(":/icons/icons/Icon_FastFile.png"));
if (aFastFile->GetPlatform() == "PC") { if (aFastFile->GetPlatform() == "PC") {
@ -55,14 +64,15 @@ void XTreeWidget::AddFastFile(std::shared_ptr<FastFile> aFastFile) {
mFastFiles[aFastFile->GetFileStem().section(".", 0, 0)] = aFastFile; mFastFiles[aFastFile->GetFileStem().section(".", 0, 0)] = aFastFile;
resizeColumnToContents(1); resizeColumnToContents(1);
setSortingEnabled(true);
} }
void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, QTreeWidgetItem *aParentItem) { void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem) {
QTreeWidgetItem *zoneItem; XTreeWidgetItem *zoneItem;
if (aParentItem != nullptr) { if (aParentItem != nullptr) {
zoneItem = new QTreeWidgetItem(aParentItem); zoneItem = new XTreeWidgetItem(aParentItem);
} else { } else {
zoneItem = new QTreeWidgetItem(this); zoneItem = new XTreeWidgetItem(this);
} }
zoneItem->setIcon(0, QIcon(":/icons/icons/Icon_ZoneFile.png")); zoneItem->setIcon(0, QIcon(":/icons/icons/Icon_ZoneFile.png"));
zoneItem->setText(0, aZoneFile->GetFileStem()); zoneItem->setText(0, aZoneFile->GetFileStem());
@ -70,40 +80,39 @@ void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, QTreeWidgetIt
auto assetMap = aZoneFile->GetAssetMap(); auto assetMap = aZoneFile->GetAssetMap();
if (!assetMap.localStrings.isEmpty()) { if (!assetMap.localStrings.isEmpty()) {
QTreeWidgetItem *localStrRoot = new QTreeWidgetItem(zoneItem); XTreeWidgetItem *localStrRoot = new XTreeWidgetItem(zoneItem);
localStrRoot->setText(0, "String Files"); localStrRoot->setText(0, "String Files");
localStrRoot->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png")); localStrRoot->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png"));
QTreeWidgetItem *localStrItem = new QTreeWidgetItem(localStrRoot); XTreeWidgetItem *localStrItem = new XTreeWidgetItem(localStrRoot);
localStrItem->setText(0, aZoneFile->GetFileStem().section('.', 0, 0) + ".str"); localStrItem->setText(0, aZoneFile->GetFileStem().section('.', 0, 0) + ".str");
localStrItem->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png")); localStrItem->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png"));
} }
if (!assetMap.techSets.isEmpty()) { if (!assetMap.techSets.isEmpty()) {
QTreeWidgetItem *techSetRoot = new QTreeWidgetItem(zoneItem); XTreeWidgetItem *techSetRoot = new XTreeWidgetItem(zoneItem);
techSetRoot->setText(0, "Tech Sets"); techSetRoot->setText(0, "Tech Sets");
techSetRoot->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png")); techSetRoot->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png"));
for (TechSet techSet : assetMap.techSets) { for (TechSet techSet : assetMap.techSets) {
QTreeWidgetItem *techSetItem = new QTreeWidgetItem(techSetRoot); XTreeWidgetItem *techSetItem = new XTreeWidgetItem(techSetRoot);
techSetItem->setText(0, techSet.name); techSetItem->setText(0, techSet.name);
techSetItem->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png")); techSetItem->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png"));
} }
} }
if (!assetMap.rawFiles.isEmpty()) { if (!assetMap.rawFiles.isEmpty()) {
QTreeWidgetItem *rawFileRoot = new QTreeWidgetItem(zoneItem); XTreeWidgetItem *rawFileRoot = new XTreeWidgetItem(zoneItem);
rawFileRoot->setText(0, "Raw Files"); rawFileRoot->setText(0, "Raw Files");
rawFileRoot->setIcon(0, QIcon(":/icons/icons/Icon_GSCFile.png")); rawFileRoot->setIcon(0, QIcon(":/icons/icons/Icon_GSCFile.png"));
for (RawFile rawFile : assetMap.rawFiles) { for (RawFile rawFile : assetMap.rawFiles) {
if (!rawFile.length) { continue; } if (!rawFile.length) { continue; }
QTreeWidgetItem *tempItem = rawFileRoot; XTreeWidgetItem *tempItem = rawFileRoot;
for (const QString &pathPart : rawFile.path.split('/')) { for (const QString &pathPart : rawFile.path.split('/')) {
bool childFound = false; bool childFound = false;
for (int i = 0; i < tempItem->childCount(); i++) { for (int i = 0; i < tempItem->childCount(); i++) {
QTreeWidgetItem *childItem = tempItem->child(i); XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(tempItem->child(i));
//qDebug() << "Child text: " << childItem->text(0);
if (childItem->text(0) == pathPart) { if (childItem->text(0) == pathPart) {
tempItem = childItem; tempItem = childItem;
@ -113,12 +122,12 @@ void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, QTreeWidgetIt
} }
if (pathPart.contains(".gsc")) { if (pathPart.contains(".gsc")) {
QTreeWidgetItem *rawFileItem = new QTreeWidgetItem(tempItem); XTreeWidgetItem *rawFileItem = new XTreeWidgetItem(tempItem);
rawFileItem->setText(0, pathPart); rawFileItem->setText(0, pathPart);
tempItem = rawFileItem; tempItem = rawFileItem;
} else if (!childFound) { } else if (!childFound) {
tempItem = new QTreeWidgetItem(tempItem); tempItem = new XTreeWidgetItem(tempItem);
tempItem->setText(0, pathPart); tempItem->setText(0, pathPart);
} }
@ -128,16 +137,16 @@ void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, QTreeWidgetIt
} }
if (!assetMap.menuFiles.isEmpty()) { if (!assetMap.menuFiles.isEmpty()) {
QTreeWidgetItem *menuRoot = new QTreeWidgetItem(zoneItem); XTreeWidgetItem *menuRoot = new XTreeWidgetItem(zoneItem);
menuRoot->setText(0, "Menu Files"); menuRoot->setText(0, "Menu Files");
menuRoot->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png")); menuRoot->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png"));
int menuIndex = 1; int menuIndex = 1;
for (MenuFile menuFile : assetMap.menuFiles) { for (MenuFile menuFile : assetMap.menuFiles) {
QTreeWidgetItem *menuFileRoot = new QTreeWidgetItem(menuRoot); XTreeWidgetItem *menuFileRoot = new XTreeWidgetItem(menuRoot);
menuFileRoot->setText(0, QString("Menu %1").arg(menuIndex)); menuFileRoot->setText(0, QString("Menu %1").arg(menuIndex));
for (Menu menu : menuFile.menuDefs) { for (Menu menu : menuFile.menuDefs) {
QTreeWidgetItem *menuItem = new QTreeWidgetItem(menuFileRoot); XTreeWidgetItem *menuItem = new XTreeWidgetItem(menuFileRoot);
menuItem->setText(0, menu.name); menuItem->setText(0, menu.name);
menuItem->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png")); menuItem->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png"));
} }
@ -146,17 +155,81 @@ void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, QTreeWidgetIt
} }
if (!assetMap.images.isEmpty()) { if (!assetMap.images.isEmpty()) {
QTreeWidgetItem *imageRoot = new QTreeWidgetItem(zoneItem); XTreeWidgetItem *imageRoot = new XTreeWidgetItem(zoneItem);
imageRoot->setText(0, "Images"); imageRoot->setText(0, "Images");
imageRoot->setIcon(0, QIcon(":/icons/icons/Icon_Image.png")); imageRoot->setIcon(0, QIcon(":/icons/icons/Icon_Image.png"));
for (Image image : assetMap.images) { for (Image image : assetMap.images) {
QTreeWidgetItem *imageItem = new QTreeWidgetItem(imageRoot); XTreeWidgetItem *imageItem = new XTreeWidgetItem(imageRoot);
imageItem->setText(0, image.materialName); imageItem->setText(0, image.materialName);
imageItem->setIcon(0, QIcon(":/icons/icons/Icon_Image.png")); 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.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->GetFileStem().section(".", 0, 0)] = aZoneFile; mZoneFiles[aZoneFile->GetFileStem().section(".", 0, 0)] = aZoneFile;
} }
@ -265,6 +338,8 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
Q_UNUSED(checked); Q_UNUSED(checked);
clear(); clear();
emit Cleared();
}); });
QAction *closeAllButAction = new QAction("Close All BUT This"); QAction *closeAllButAction = new QAction("Close All BUT This");
@ -358,6 +433,98 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
//zoneFile->SaveFastFile(); //zoneFile->SaveFastFile();
}); });
} 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); QPoint pt(pos);
@ -369,13 +536,15 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
void XTreeWidget::ItemSelectionChanged() { void XTreeWidget::ItemSelectionChanged() {
if (selectedItems().isEmpty()) { return; } if (selectedItems().isEmpty()) { return; }
QTreeWidgetItem *selectedItem = selectedItems().first(); XTreeWidgetItem *selectedItem = dynamic_cast<XTreeWidgetItem*>(selectedItems().first());
if (!selectedItem) { return; } if (!selectedItem) { return; }
if (selectedItem->text(0).isEmpty()) { return; } if (selectedItem->text(0).isEmpty()) { return; }
QString selectedText = selectedItem->text(0); QString selectedText = selectedItem->text(0);
emit TabSelected(selectedText);
const QString fileStem = selectedText.section(".", 0, 0); const QString fileStem = selectedText.section(".", 0, 0);
QTreeWidgetItem *parentItem = selectedItem->parent(); XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(selectedItem->parent());
if (selectedText.contains(".dds")) { if (selectedText.contains(".dds")) {
if (!mDDSFiles.contains(fileStem)) { if (!mDDSFiles.contains(fileStem)) {
@ -409,11 +578,11 @@ void XTreeWidget::ItemSelectionChanged() {
} }
emit LocalStringSelected(mZoneFiles[fileStem]); emit LocalStringSelected(mZoneFiles[fileStem]);
} else if (selectedText.contains(".gsc")) { } else if (selectedText.contains(".gsc")) {
QTreeWidgetItem *zoneRoot = selectedItem; XTreeWidgetItem *zoneRoot = selectedItem;
if (!zoneRoot) { return; } if (!zoneRoot) { return; }
while (!zoneRoot->text(0).contains(".zone")) { while (!zoneRoot->text(0).contains(".zone")) {
zoneRoot = zoneRoot->parent(); zoneRoot = dynamic_cast<XTreeWidgetItem*>(zoneRoot->parent());
if (!zoneRoot) { return; } if (!zoneRoot) { return; }
} }
@ -431,7 +600,7 @@ void XTreeWidget::ItemSelectionChanged() {
} }
} }
} else if (parentItem && (parentItem->text(0) == "Images")) { } else if (parentItem && (parentItem->text(0) == "Images")) {
QTreeWidgetItem *grandpaItem = parentItem->parent(); XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) { if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0); const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
QVector<Image> images = mZoneFiles[fileStem]->GetAssetMap().images; QVector<Image> images = mZoneFiles[fileStem]->GetAssetMap().images;
@ -443,7 +612,7 @@ void XTreeWidget::ItemSelectionChanged() {
} }
} }
} else if (parentItem && (parentItem->text(0) == "Tech Sets")) { } else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
QTreeWidgetItem *grandpaItem = parentItem->parent(); XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) { if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0); const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets; auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets;
@ -454,6 +623,39 @@ void XTreeWidget::ItemSelectionChanged() {
} }
} }
} }
} else if (parentItem && (parentItem->text(0) == "String Tables")) {
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
QVector<StringTable> strTables = mZoneFiles[fileStem]->GetAssetMap().stringTables;
for (StringTable strTable : strTables) {
if (strTable.name == selectedText) {
emit StrTableSelected(std::make_shared<StringTable>(strTable));
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));
break;
}
}
}
}
} }
} }
@ -485,7 +687,7 @@ void XTreeWidget::AddIWIFile(std::shared_ptr<IWIFile> aIWIFile) {
} }
} }
QTreeWidgetItem *iwiItem = new QTreeWidgetItem(this); XTreeWidgetItem *iwiItem = new XTreeWidgetItem(this);
iwiItem->setIcon(0, QIcon(":/icons/icons/Icon_IWIFile.png")); iwiItem->setIcon(0, QIcon(":/icons/icons/Icon_IWIFile.png"));
iwiItem->setText(0, iwiFileName); iwiItem->setText(0, iwiFileName);
mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile; mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile;
@ -501,7 +703,7 @@ void XTreeWidget::AddDDSFile(std::shared_ptr<DDSFile> aDDSFile) {
} }
} }
QTreeWidgetItem *ddsItem = new QTreeWidgetItem(this); XTreeWidgetItem *ddsItem = new XTreeWidgetItem(this);
ddsItem->setIcon(0, QIcon(":/icons/icons/Icon_DDSFile.png")); ddsItem->setIcon(0, QIcon(":/icons/icons/Icon_DDSFile.png"));
ddsItem->setText(0, ddsFileName); ddsItem->setText(0, ddsFileName);
mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile; mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile;

View File

@ -6,6 +6,7 @@
#include "ddsfile.h" #include "ddsfile.h"
#include "iwifile.h" #include "iwifile.h"
#include "fastfile.h" #include "fastfile.h"
#include "xtreewidgetitem.h"
#include "zonefile.h" #include "zonefile.h"
#include <QTreeWidget> #include <QTreeWidget>
@ -18,7 +19,7 @@ public:
~XTreeWidget(); ~XTreeWidget();
void AddFastFile(std::shared_ptr<FastFile> aFastFile); void AddFastFile(std::shared_ptr<FastFile> aFastFile);
void AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, QTreeWidgetItem *aParentItem = nullptr); void AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem = nullptr);
void AddIWIFile(std::shared_ptr<IWIFile> aIWIFile); void AddIWIFile(std::shared_ptr<IWIFile> aIWIFile);
void AddDDSFile(std::shared_ptr<DDSFile> aDDSFile); void AddDDSFile(std::shared_ptr<DDSFile> aDDSFile);
@ -31,7 +32,11 @@ signals:
void RawFileSelected(std::shared_ptr<RawFile> aRawFile); void RawFileSelected(std::shared_ptr<RawFile> aRawFile);
void ImageSelected(std::shared_ptr<Image> aImage); void ImageSelected(std::shared_ptr<Image> aImage);
void TechSetSelected(std::shared_ptr<TechSet> aZoneFile); void TechSetSelected(std::shared_ptr<TechSet> aZoneFile);
void StrTableSelected(std::shared_ptr<StringTable> aStrTable);
void MenuSelected(std::shared_ptr<Menu> aMenu); void MenuSelected(std::shared_ptr<Menu> aMenu);
void SoundSelected(std::shared_ptr<Sound> aSound);
void TabSelected(const QString aTabName);
void Cleared();
protected: protected:
void ItemSelectionChanged(); void ItemSelectionChanged();

37
xtreewidgetitem.cpp Normal file
View File

@ -0,0 +1,37 @@
#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) {
if ((this->childCount() > 0) != (otherItem->childCount() > 0))
return this->childCount() <= 0; // true if this item is a group and other is not
}
// 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
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

@ -69,7 +69,9 @@ bool ZoneFile::Load(const QString aFilePath, FF_PLATFORM platform) {
return true; return true;
} }
bool ZoneFile::Load(const QByteArray aFileData, const QString aFileStem, FF_PLATFORM platform) { bool ZoneFile::Load(const QByteArray aFileData, const QString aFileStem, FF_PLATFORM platform, FF_GAME game) {
fileStem = aFileStem;
// Open zone file as little endian stream // Open zone file as little endian stream
QDataStream zoneFileStream(aFileData); QDataStream zoneFileStream(aFileData);
if (platform == FF_PLATFORM_PC) { if (platform == FF_PLATFORM_PC) {
@ -79,12 +81,11 @@ bool ZoneFile::Load(const QByteArray aFileData, const QString aFileStem, FF_PLAT
} }
// Parse data from zone file header // Parse data from zone file header
pParseZoneHeader(&zoneFileStream); pParseZoneHeader(&zoneFileStream, game);
fileStem = aFileStem;
records = records =
pParseZoneIndex(&zoneFileStream, recordCount); pParseZoneIndex(&zoneFileStream, recordCount, game);
assetMap = assetMap =
pParseAssets(&zoneFileStream, records); pParseAssets(&zoneFileStream, records, game);
return true; return true;
} }
@ -117,23 +118,66 @@ AssetMap ZoneFile::GetAssetMap() {
return assetMap; return assetMap;
} }
void ZoneFile::pParseZoneHeader(QDataStream *aZoneFileStream) { void ZoneFile::pParseZoneHeader(QDataStream *aZoneFileStream, FF_GAME game) {
if (game != FF_GAME_COD2) {
size = pParseZoneSize(aZoneFileStream); size = pParseZoneSize(aZoneFileStream);
pParseZoneUnknownsA(aZoneFileStream); pParseZoneUnknownsA(aZoneFileStream);
}
tagCount = pParseZoneTagCount(aZoneFileStream); tagCount = pParseZoneTagCount(aZoneFileStream);
pParseZoneUnknownsB(aZoneFileStream);
quint32 extraCount;
if (game == FF_GAME_COD2) {
aZoneFileStream->skipRawData(4);
*aZoneFileStream >> extraCount;
qDebug() << "Extra Count: " << extraCount;
aZoneFileStream->skipRawData(4);
} else {
pParseZoneUnknownsB(aZoneFileStream);
}
recordCount = pParseZoneRecordCount(aZoneFileStream); recordCount = pParseZoneRecordCount(aZoneFileStream);
if (tagCount) { if (tagCount) {
if (game == FF_GAME_COD2) {
} else {
pParseZoneUnknownsC(aZoneFileStream); pParseZoneUnknownsC(aZoneFileStream);
if (tagCount > 1) {
tags = pParseZoneTags(aZoneFileStream, tagCount);
} }
tags = pParseZoneTags(aZoneFileStream, tagCount, game);
} else { } else {
aZoneFileStream->skipRawData(4); aZoneFileStream->skipRawData(4);
} }
int thingCount = 0;
if (game == FF_GAME_COD2) {
if (extraCount != 4294967295) {
qDebug() << "Pre Pos: " << aZoneFileStream->device()->pos();
for (int i = 0; i < extraCount; i++) {
quint32 thing;
*aZoneFileStream >> thing;
if (thing == 4294967295) {
thingCount++;
}
}
qDebug() << "Post Pos: " << aZoneFileStream->device()->pos();
qDebug() << "Thing Count: " << thingCount;
QStringList tags2;
QString tag;
char zoneTagChar;
for (quint32 i = 0; i < thingCount; i++) {
*aZoneFileStream >> zoneTagChar;
while (zoneTagChar != 0) {
tag += zoneTagChar;
*aZoneFileStream >> zoneTagChar;
}
tags2 << tag;
tag.clear();
}
qDebug() << tags2;
}
}
} }
quint32 ZoneFile::pParseZoneSize(QDataStream *aZoneFileStream) { quint32 ZoneFile::pParseZoneSize(QDataStream *aZoneFileStream) {
@ -235,11 +279,15 @@ void ZoneFile::pParseZoneUnknownsC(QDataStream *aZoneFileStream) {
Parses the string tags ate the start of zone file Parses the string tags ate the start of zone file
*/ */
QStringList ZoneFile::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { QStringList ZoneFile::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount, FF_GAME game) {
QStringList tags; QStringList tags;
// Byte 48-51: Repeated separators? ÿÿÿÿ x i // Byte 48-51: Repeated separators? ÿÿÿÿ x i
if (game == FF_GAME_COD2) {
aZoneFileStream->skipRawData(4 * (tagCount + 1));
} else {
aZoneFileStream->skipRawData(4 * (tagCount - 1)); aZoneFileStream->skipRawData(4 * (tagCount - 1));
}
// Parse tags/strings before index // Parse tags/strings before index
QString zoneTag; QString zoneTag;
@ -252,9 +300,6 @@ QStringList ZoneFile::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCo
} }
tags << zoneTag; tags << zoneTag;
zoneTag.clear(); zoneTag.clear();
qDebug() << "Peek: " << aZoneFileStream->device()->peek(8) << aZoneFileStream->device()->peek(8).contains(QByteArray::fromHex("FFFFFFFF"));
if (aZoneFileStream->device()->peek(8).contains(QByteArray::fromHex("FFFFFFFF"))) { break; }
} }
return tags; return tags;
} }
@ -264,12 +309,16 @@ QStringList ZoneFile::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCo
Parse the binary zone index data and populate table Parse the binary zone index data and populate table
*/ */
QStringList ZoneFile::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { QStringList ZoneFile::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount, FF_GAME game) {
QStringList result; QStringList result;
// Don't parse if no records // Don't parse if no records
if (!recordCount) { return result; } if (!recordCount) { return result; }
if (aZoneFileStream->device()->peek(4).toHex().contains("ffff")) {
aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 2);
}
// Parse index & map found asset types // Parse index & map found asset types
for (quint32 i = 0; i <= recordCount; i++) { for (quint32 i = 0; i <= recordCount; i++) {
// Skip record start // Skip record start
@ -283,7 +332,7 @@ QStringList ZoneFile::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 reco
return result; return result;
} }
AssetMap ZoneFile::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { AssetMap ZoneFile::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder, FF_GAME game) {
AssetMap result; AssetMap result;
aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8);
@ -312,7 +361,7 @@ AssetMap ZoneFile::pParseAssets(QDataStream *aZoneFileStream, QStringList assetO
} else if (typeStr == "IMAGE") { // image } else if (typeStr == "IMAGE") { // image
result.images << pParseAsset_Image(aZoneFileStream); result.images << pParseAsset_Image(aZoneFileStream);
} else if (typeStr == "SOUND") { // loaded_sound } else if (typeStr == "SOUND") { // loaded_sound
pParseAsset_LoadedSound(aZoneFileStream); result.sounds << pParseAsset_Sound(aZoneFileStream);
} else if (typeStr == "COLLISION MAP") { // col_map_mp } else if (typeStr == "COLLISION MAP") { // col_map_mp
pParseAsset_ColMapMP(aZoneFileStream); pParseAsset_ColMapMP(aZoneFileStream);
} else if (typeStr == "MP MAP") { // game_map_sp } else if (typeStr == "MP MAP") { // game_map_sp
@ -527,74 +576,6 @@ Shader ZoneFile::pParseAsset_Shader(QDataStream *aZoneFileStream) {
return result; return result;
} }
bool ZoneFile::pReadUntilString(QDataStream* stream, const QString& targetString) {
if (!stream || targetString.isEmpty()) {
return false; // Invalid input
}
QByteArray buffer;
QByteArray targetBytes = targetString.toUtf8(); // Handle multibyte characters
const int targetLength = targetBytes.size();
qDebug() << targetBytes << targetLength;
// Read as unsigned bytes to handle all possible values (0-255)
unsigned char byte;
while (!stream->atEnd()) {
// Read one byte at a time
*stream >> byte;
buffer.append(static_cast<char>(byte)); // Append as char for QByteArray
// Keep buffer size limited to the target length
if (buffer.size() > targetLength) {
buffer.remove(0, 1);
}
// Check if the buffer matches the target string in raw bytes
if (buffer == targetBytes) {
// Backup to the start of the matched string
stream->device()->seek(stream->device()->pos() - targetLength);
return true;
}
}
// Target string not found
return false;
}
bool ZoneFile::pReadUntilHex(QDataStream* stream, const QString& hexString) {
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
return false; // Invalid input
}
// Convert hex string to byte array
QByteArray targetBytes = QByteArray::fromHex(hexString.toUtf8());
const int targetLength = targetBytes.size();
QByteArray buffer;
unsigned char byte;
while (!stream->atEnd()) {
// Read one byte at a time
*stream >> byte;
buffer.append(static_cast<char>(byte)); // Append as char for QByteArray
// Keep buffer size limited to the target length
if (buffer.size() > targetLength) {
buffer.remove(0, 1);
}
// Check if the buffer matches the target byte sequence
if (buffer == targetBytes) {
// Backup to the start of the matched sequence
stream->device()->seek(stream->device()->pos() - targetLength);
return true;
}
}
// Target sequence not found
return false;
}
TechSet ZoneFile::pParseAsset_TechSet(QDataStream *aZoneFileStream) { TechSet ZoneFile::pParseAsset_TechSet(QDataStream *aZoneFileStream) {
TechSet result; TechSet result;
@ -687,8 +668,121 @@ Image ZoneFile::pParseAsset_Image(QDataStream *aZoneFileStream) {
return result; return result;
} }
void ZoneFile::pParseAsset_LoadedSound(QDataStream *aZoneFileStream) { SoundAsset ZoneFile::pParseAsset_Sound(QDataStream *aZoneFileStream) {
Q_UNUSED(aZoneFileStream); SoundAsset result;
qDebug() << aZoneFileStream->device()->pos();
QByteArray rootNamePtr(4, Qt::Uninitialized);
aZoneFileStream->readRawData(rootNamePtr.data(), 4);
qDebug() << "Root name ptr: " << (QString)rootNamePtr.toHex();
aZoneFileStream->skipRawData(4);
*aZoneFileStream >> result.count;
if (rootNamePtr.toHex() == "ffffffff") {
// Read in sound file name
char soundNameChar;
*aZoneFileStream >> soundNameChar;
while (soundNameChar != 0) {
result.name += soundNameChar;
*aZoneFileStream >> soundNameChar;
}
}
int tagCount = 0;
int resultCount = 0;
for (int i = 0; i < result.count; i++) {
aZoneFileStream->skipRawData(12);
QByteArray tagPtr(4, Qt::Uninitialized);
aZoneFileStream->readRawData(tagPtr.data(), 4);
if (tagPtr.toHex() == "ffffffff") {
qDebug() << "Tag Ptr: " << tagPtr.toHex();
tagCount++;
}
aZoneFileStream->skipRawData(4);
QByteArray pathPtr(4, Qt::Uninitialized);
aZoneFileStream->readRawData(pathPtr.data(), 4);
if (pathPtr.toHex() == "ffffffff") {
qDebug() << "Path Ptr: " << pathPtr.toHex();
resultCount++;
}
aZoneFileStream->skipRawData(160);
}
for (int i = 0; i < tagCount; i++) {
// Read in tag?
QString tag;
char tagChar;
*aZoneFileStream >> tagChar;
while (tagChar != 0) {
tag += tagChar;
*aZoneFileStream >> tagChar;
}
qDebug() << "Tag: " << tag;
}
for (int i = 0; i < resultCount; i++) {
Sound sound;
if (aZoneFileStream->device()->peek(12).toHex().contains("ffffffff00000000")) {
aZoneFileStream->skipRawData(12);
}
aZoneFileStream->skipRawData(8);
qDebug() << "- " << aZoneFileStream->device()->pos();
QByteArray aliasPtr(4, Qt::Uninitialized);
aZoneFileStream->readRawData(aliasPtr.data(), 4);
QByteArray namePtr(4, Qt::Uninitialized);
aZoneFileStream->readRawData(namePtr.data(), 4);
*aZoneFileStream >> sound.dataLength;
qDebug() << "- Data length: " << sound.dataLength;
if (aliasPtr.toHex() == "ffffffff") {
// Read in sound alias name
char soundAliasChar;
*aZoneFileStream >> soundAliasChar;
while (soundAliasChar != 0) {
sound.alias += soundAliasChar;
*aZoneFileStream >> soundAliasChar;
}
qDebug() << "- Alias: " << sound.alias;
}
if (aZoneFileStream->device()->peek(4) == "RIFF") {
sound.path = sound.alias;
sound.alias = "";
} else if (namePtr.toHex() == "ffffffff") {
// Read in sound file path
char soundPathChar;
*aZoneFileStream >> soundPathChar;
while (soundPathChar != 0) {
sound.path += soundPathChar;
*aZoneFileStream >> soundPathChar;
}
sound.path.replace(",", "");
qDebug() << "- Path: " << sound.path;
}
if (sound.dataLength) {
QByteArray data(sound.dataLength, Qt::Uninitialized);
aZoneFileStream->readRawData(data.data(), sound.dataLength);
sound.data = data;
}
result.sounds.append(sound);
}
qDebug() << "- " << aZoneFileStream->device()->pos();
return result;
} }
void ZoneFile::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { void ZoneFile::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) {
@ -1048,16 +1142,15 @@ StringTable ZoneFile::pParseAsset_StringTable(QDataStream *aZoneFileStream) {
*aZoneFileStream >> stringTableNameChar; *aZoneFileStream >> stringTableNameChar;
} }
QVector<QString> tablePointers = QVector<QString>();
for (quint32 i = 0; i < result.rowCount; i++) { for (quint32 i = 0; i < result.rowCount; i++) {
QByteArray pointerData(4, Qt::Uninitialized); QByteArray pointerData(4, Qt::Uninitialized);
aZoneFileStream->readRawData(pointerData.data(), 4); aZoneFileStream->readRawData(pointerData.data(), 4);
tablePointers.push_back(pointerData.toHex()); result.tablePointers.push_back(pointerData.toHex());
aZoneFileStream->skipRawData(4); aZoneFileStream->skipRawData(4);
} }
for (const QString &pointerAddr : tablePointers) { for (const QString &pointerAddr : result.tablePointers) {
QString leadingContent = ""; QString leadingContent = "";
if (pointerAddr == "FFFFFFFF") { if (pointerAddr == "FFFFFFFF") {
char leadingContentChar; char leadingContentChar;
@ -1077,13 +1170,7 @@ StringTable ZoneFile::pParseAsset_StringTable(QDataStream *aZoneFileStream) {
content += contentChar; content += contentChar;
*aZoneFileStream >> contentChar; *aZoneFileStream >> contentChar;
} }
QPair<QString, QString> tableEntry = QPair<QString, QString>(); result.content[leadingContent] = content;
tableEntry.first = leadingContent;
tableEntry.second = content;
//if (!mStrTableMap.contains(stringTableName)) {
// mStrTableMap[stringTableName] = QVector<QPair<QString, QString>>();
//}
//mStrTableMap[stringTableName].push_back(tableEntry);
} }
return result; return result;
} }

View File

@ -14,7 +14,7 @@ public:
ZoneFile &operator=(const ZoneFile &other); ZoneFile &operator=(const ZoneFile &other);
bool Load(const QString aFilePath, FF_PLATFORM platform = FF_PLATFORM_PC); bool Load(const QString aFilePath, FF_PLATFORM platform = FF_PLATFORM_PC);
bool Load(const QByteArray aFileData, const QString aFileStem, FF_PLATFORM platform = FF_PLATFORM_PC); bool Load(const QByteArray aFileData, const QString aFileStem, FF_PLATFORM platform = FF_PLATFORM_NONE, FF_GAME game = FF_GAME_NONE);
QString GetFileStem(); QString GetFileStem();
quint32 GetSize(); quint32 GetSize();
@ -25,27 +25,25 @@ public:
AssetMap GetAssetMap(); AssetMap GetAssetMap();
private slots: private slots:
void pParseZoneHeader(QDataStream *aZoneFileStream); void pParseZoneHeader(QDataStream *aZoneFileStream, FF_GAME game);
quint32 pParseZoneSize(QDataStream *aZoneFileStream); quint32 pParseZoneSize(QDataStream *aZoneFileStream);
void pParseZoneUnknownsA(QDataStream *aZoneFileStream); void pParseZoneUnknownsA(QDataStream *aZoneFileStream);
quint32 pParseZoneTagCount(QDataStream *aZoneFileStream); quint32 pParseZoneTagCount(QDataStream *aZoneFileStream);
quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream); quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream);
void pParseZoneUnknownsB(QDataStream *aZoneFileStream); void pParseZoneUnknownsB(QDataStream *aZoneFileStream);
void pParseZoneUnknownsC(QDataStream *aZoneFileStream); void pParseZoneUnknownsC(QDataStream *aZoneFileStream);
QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount); QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount, FF_GAME game);
QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount); QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount, FF_GAME game);
AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder); AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder, FF_GAME game);
LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream); LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream);
RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream); RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream);
void pParseAsset_PhysPreset(QDataStream *aZoneFileStream); void pParseAsset_PhysPreset(QDataStream *aZoneFileStream);
Model pParseAsset_Model(QDataStream *aZoneFileStream); Model pParseAsset_Model(QDataStream *aZoneFileStream);
void pParseAsset_Material(QDataStream *aZoneFileStream); void pParseAsset_Material(QDataStream *aZoneFileStream);
Shader pParseAsset_Shader(QDataStream *aZoneFileStream); Shader pParseAsset_Shader(QDataStream *aZoneFileStream);
bool pReadUntilString(QDataStream* stream, const QString& targetString);
bool pReadUntilHex(QDataStream* stream, const QString& hexString);
TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream); TechSet pParseAsset_TechSet(QDataStream *aZoneFileStream);
Image pParseAsset_Image(QDataStream *aZoneFileStream); Image pParseAsset_Image(QDataStream *aZoneFileStream);
void pParseAsset_LoadedSound(QDataStream *aZoneFileStream); SoundAsset pParseAsset_Sound(QDataStream *aZoneFileStream);
void pParseAsset_ColMapMP(QDataStream *aZoneFileStream); void pParseAsset_ColMapMP(QDataStream *aZoneFileStream);
void pParseAsset_GameMapSP(QDataStream *aZoneFileStream); void pParseAsset_GameMapSP(QDataStream *aZoneFileStream);
void pParseAsset_GameMapMP(QDataStream *aZoneFileStream); void pParseAsset_GameMapMP(QDataStream *aZoneFileStream);