Lotta new stuff.
23
XPlor.pro
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
After Width: | Height: | Size: 316 B |
BIN
data/icons/Icon_Cut.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
data/icons/Icon_Editor.png
Normal file
|
After Width: | Height: | Size: 210 B |
BIN
data/icons/Icon_Find.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
data/icons/Icon_Model.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
data/icons/Icon_NewFile.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
data/icons/Icon_OpenFile.png
Normal file
|
After Width: | Height: | Size: 317 B |
BIN
data/icons/Icon_Paste.png
Normal file
|
After Width: | Height: | Size: 537 B |
BIN
data/icons/Icon_Pause.png
Normal file
|
After Width: | Height: | Size: 213 B |
BIN
data/icons/Icon_Play.png
Normal file
|
After Width: | Height: | Size: 318 B |
BIN
data/icons/Icon_Save.png
Normal file
|
After Width: | Height: | Size: 371 B |
BIN
data/icons/Icon_SkipBack.png
Normal file
|
After Width: | Height: | Size: 488 B |
BIN
data/icons/Icon_SkipForward.png
Normal file
|
After Width: | Height: | Size: 532 B |
BIN
data/icons/Icon_Sound.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
data/icons/Icon_Stop.png
Normal file
|
After Width: | Height: | Size: 195 B |
BIN
data/icons/Icon_StringTable.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
data/icons/Icon_Tree.png
Normal file
|
After Width: | Height: | Size: 321 B |
BIN
data/icons/Icon_Views.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
15
enums.h
@ -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 {
|
||||||
|
|||||||
113
fastfile.cpp
@ -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,13 +31,24 @@ bool FastFile::Load(const QByteArray aData) {
|
|||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
company = pParseFFCompany(&fastFileStream);
|
if (fastFileStream.device()->peek(2).toHex() == "0000") {
|
||||||
fileType = pParseFFFileType(&fastFileStream);
|
company = COMPANY_INFINITY_WARD;
|
||||||
signage = pParseFFSignage(&fastFileStream);
|
fileType = FILETYPE_FAST_FILE;
|
||||||
magic = pParseFFMagic(&fastFileStream);
|
signage = SIGNAGE_UNSIGNED;
|
||||||
version = pParseFFVersion(&fastFileStream);
|
magic = 0;
|
||||||
platform = pCalculateFFPlatform();
|
version = 0;
|
||||||
game = pCalculateFFGame();
|
platform = "360";
|
||||||
|
game = "COD2";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
company = pParseFFCompany(&fastFileStream);
|
||||||
|
fileType = pParseFFFileType(&fastFileStream);
|
||||||
|
signage = pParseFFSignage(&fastFileStream);
|
||||||
|
magic = pParseFFMagic(&fastFileStream);
|
||||||
|
version = pParseFFVersion(&fastFileStream);
|
||||||
|
platform = pCalculateFFPlatform();
|
||||||
|
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; }
|
||||||
|
|||||||
64
fastfile.h
@ -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
@ -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
@ -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
@ -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
@ -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
|
||||||
@ -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);
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
@ -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
@ -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
@ -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
@ -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 && 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
@ -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
@ -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
36
stringtableviewer.cpp
Normal 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
@ -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
@ -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
@ -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()
|
||||||
|
|
||||||
|
|||||||
264
xtreewidget.cpp
@ -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;
|
||||||
|
|||||||
@ -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
@ -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
@ -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
|
||||||
287
zonefile.cpp
@ -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) {
|
||||||
size = pParseZoneSize(aZoneFileStream);
|
if (game != FF_GAME_COD2) {
|
||||||
pParseZoneUnknownsA(aZoneFileStream);
|
size = pParseZoneSize(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) {
|
||||||
pParseZoneUnknownsC(aZoneFileStream);
|
if (game == FF_GAME_COD2) {
|
||||||
if (tagCount > 1) {
|
|
||||||
tags = pParseZoneTags(aZoneFileStream, tagCount);
|
} else {
|
||||||
|
pParseZoneUnknownsC(aZoneFileStream);
|
||||||
}
|
}
|
||||||
|
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
|
||||||
aZoneFileStream->skipRawData(4 * (tagCount - 1));
|
if (game == FF_GAME_COD2) {
|
||||||
|
aZoneFileStream->skipRawData(4 * (tagCount + 1));
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
14
zonefile.h
@ -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);
|
||||||
|
|||||||