diff --git a/Data.qrc b/Data.qrc
deleted file mode 100644
index 0325361..0000000
--- a/Data.qrc
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- data/obj/defaultactor_LOD0.bin
- data/obj/defaultactor_LOD0.cast
- data/obj/defaultactor_LOD0.gltf
- data/obj/defaultactor_LOD0.ma
- data/obj/defaultactor_LOD0.mesh.ascii
- data/obj/defaultactor_LOD0.obj
- data/obj/defaultactor_LOD0.semodel
- data/obj/defaultactor_LOD0.smd
- data/obj/defaultactor_LOD0.XMODEL_BIN
- data/obj/defaultactor_LOD0.XMODEL_EXPORT
- data/obj/defaultactor_LOD0_BIND.mel
- data/obj/defaultactor_LOD0_cosmetics.mel
- data/obj/mtl_body_default_character.mtl
- data/obj/mtl_body_default_character_images.txt
- data/obj/diffusemap.png
- data/obj/normalmap.png
-
-
- data/d3dbsp/asset_viewer.d3dbsp
- data/d3dbsp/barebones.d3dbsp
-
-
diff --git a/FastFile_WaW.pro b/FastFile_WaW.pro
deleted file mode 100644
index a7c6012..0000000
--- a/FastFile_WaW.pro
+++ /dev/null
@@ -1,35 +0,0 @@
-QT += core gui 3dcore 3drender 3dinput 3dextras
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-CONFIG += c++17
-
-# INCLUDEPATH += "C:/Program Files (x86)/Windows Kits/10/Include/10.0.26100.0/um"
-# LIBS += -L"C:/Program Files (x86)/Windows Kits/10/Lib/10.0.26100.0/um/x64" \
-# -ldxcompiler
-
-# You can make your code fail to compile if it uses deprecated APIs.
-# In order to do so, uncomment the following line.
-#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-
-SOURCES += \
- main.cpp \
- mainwindow.cpp
-
-HEADERS += \
- enums.h \
- mainwindow.h \
- structs.h \
- utils.h \
- bink.h
-
-FORMS += \
- mainwindow.ui
-
-# Default rules for deployment.
-qnx: target.path = /tmp/$${TARGET}/bin
-else: unix:!android: target.path = /opt/$${TARGET}/bin
-!isEmpty(target.path): INSTALLS += target
-
-RESOURCES += \
- Data.qrc
diff --git a/FastFile_WaW.pro.user b/FastFile_WaW.pro.user
deleted file mode 100644
index 4e96dc1..0000000
--- a/FastFile_WaW.pro.user
+++ /dev/null
@@ -1,271 +0,0 @@
-
-
-
-
-
- EnvironmentId
- {40d992cb-ac11-4385-a22b-016f1b4251a7}
-
-
- ProjectExplorer.Project.ActiveTarget
- 0
-
-
- ProjectExplorer.Project.EditorSettings
-
- true
- false
- true
-
- Cpp
-
- CppGlobal
-
-
-
- QmlJS
-
- QmlJSGlobal
-
-
- 2
- UTF-8
- false
- 4
- false
- 0
- 80
- true
- true
- 1
- 0
- false
- true
- false
- 2
- true
- true
- 0
- 8
- true
- false
- 1
- true
- true
- true
- *.md, *.MD, Makefile
- false
- true
- true
-
-
-
- ProjectExplorer.Project.PluginSettings
-
-
- true
- false
- true
- true
- true
- true
-
- false
-
-
- 0
- true
-
- true
- true
- Builtin.DefaultTidyAndClazy
- 16
- true
-
-
-
- true
-
-
-
-
- ProjectExplorer.Project.Target.0
-
- Desktop
- Desktop Qt 6.8.1 MSVC2022 64bit
- Desktop Qt 6.8.1 MSVC2022 64bit
- qt.qt6.681.win64_msvc2022_64_kit
- 1
- 0
- 0
-
- 0
- C:\Users\njohnson\Projects\FastFile_WaW\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Debug
- C:/Users/njohnson/Projects/FastFile_WaW/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Debug
-
-
- true
- QtProjectManager.QMakeBuildStep
- false
-
-
-
- true
- Qt4ProjectManager.MakeStep
-
- 2
- Build
- Build
- ProjectExplorer.BuildSteps.Build
-
-
-
- true
- Qt4ProjectManager.MakeStep
- clean
-
- 1
- Clean
- Clean
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Debug
- Qt4ProjectManager.Qt4BuildConfiguration
- 2
-
-
- C:\Users\njohnson\Projects\FastFile_WaW\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Release
- C:/Users/njohnson/Projects/FastFile_WaW/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Release
-
-
- true
- QtProjectManager.QMakeBuildStep
- false
-
-
-
- true
- Qt4ProjectManager.MakeStep
-
- 2
- Build
- Build
- ProjectExplorer.BuildSteps.Build
-
-
-
- true
- Qt4ProjectManager.MakeStep
- clean
-
- 1
- Clean
- Clean
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Release
- Qt4ProjectManager.Qt4BuildConfiguration
- 0
- 0
-
-
- 0
- C:\Users\njohnson\Projects\FastFile_WaW\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Profile
- C:/Users/njohnson/Projects/FastFile_WaW/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Profile
-
-
- true
- QtProjectManager.QMakeBuildStep
- false
-
-
-
- true
- Qt4ProjectManager.MakeStep
-
- 2
- Build
- Build
- ProjectExplorer.BuildSteps.Build
-
-
-
- true
- Qt4ProjectManager.MakeStep
- clean
-
- 1
- Clean
- Clean
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Profile
- Qt4ProjectManager.Qt4BuildConfiguration
- 0
- 0
- 0
-
- 3
-
-
- 0
- Deploy
- Deploy
- ProjectExplorer.BuildSteps.Deploy
-
- 1
-
- false
- ProjectExplorer.DefaultDeployConfiguration
-
- 1
-
- true
- true
- 0
- true
-
- 2
-
- false
- -e cpu-cycles --call-graph "dwarf,4096" -F 250
-
- Qt4ProjectManager.Qt4RunConfiguration:
- C:/Users/njohnson/Projects/FastFile_WaW/FastFile_WaW.pro
- false
- true
- true
- true
- C:/Users/njohnson/Projects/FastFile_WaW/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Release
-
- 1
-
-
-
- ProjectExplorer.Project.TargetCount
- 1
-
-
- ProjectExplorer.Project.Updater.FileVersion
- 22
-
-
- Version
- 22
-
-
diff --git a/XPlor.pro b/XPlor.pro
new file mode 100644
index 0000000..642f704
--- /dev/null
+++ b/XPlor.pro
@@ -0,0 +1,6 @@
+TEMPLATE = subdirs
+
+SUBDIRS += libs \
+ app \
+ tools \
+ tests
diff --git a/XPlor.pro.user.40d992c b/XPlor.pro.user.40d992c
new file mode 100644
index 0000000..861b133
--- /dev/null
+++ b/XPlor.pro.user.40d992c
@@ -0,0 +1,625 @@
+
+
+
+
+
+ EnvironmentId
+ {40d992cb-ac11-4385-a22b-016f1b4251a7}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 0
+ 80
+ true
+ true
+ 1
+ 0
+ false
+ true
+ false
+ 2
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+ false
+
+ Unchecked
+
+
+ 0
+ true
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 16
+ true
+
+
+
+ true
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 6.8.2 MSVC2022 64bit
+ Desktop Qt 6.8.2 MSVC2022 64bit
+ qt.qt6.682.win64_msvc2022_64_kit
+ 0
+ 0
+ 0
+
+ 0
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_2_MSVC2022_64bit-Debug
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_MSVC2022_64bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_2_MSVC2022_64bit-Release
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_MSVC2022_64bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_2_MSVC2022_64bit-Profile
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_MSVC2022_64bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+
+ Qt4ProjectManager.Qt4RunConfiguration:
+ G:/Projects/Qt/XPlor/app/app.pro
+ false
+ true
+ true
+ true
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_MSVC2022_64bit-Debug/app
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+
+ Qt4ProjectManager.Qt4RunConfiguration:
+ G:/Projects/Qt/XPlor/tests/tests.pro
+ false
+ true
+ true
+ true
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_MSVC2022_64bit-Debug/tests
+
+ 2
+
+
+
+ ProjectExplorer.Project.Target.1
+
+ Desktop
+ Desktop Qt 6.8.2 llvm-mingw 64-bit
+ Desktop Qt 6.8.2 llvm-mingw 64-bit
+ qt.qt6.682.win64_llvm_mingw_kit
+ 0
+ 0
+ 1
+
+ 0
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_llvm_mingw_64_bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Release
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_llvm_mingw_64_bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_2_llvm_mingw_64_bit-Profile
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_2_llvm_mingw_64_bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+
+ Qt4ProjectManager.Qt4RunConfiguration:
+ G:/Projects/Qt/XPlor/app/app.pro
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+
+ Qt4ProjectManager.Qt4RunConfiguration:
+ G:/Projects/Qt/XPlor/tests/tests.pro
+ false
+ true
+ true
+ true
+
+ 2
+
+
+
+ ProjectExplorer.Project.Target.2
+
+ Desktop
+ Desktop Qt 6.8.1 MSVC2022 64bit
+ Desktop Qt 6.8.1 MSVC2022 64bit
+ qt.qt6.681.win64_msvc2022_64_kit
+ 0
+ 0
+ 0
+
+ 0
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Debug
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ G:\Projects\Qt\XPlor\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Release
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+ 2
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+
+ Qt4ProjectManager.Qt4RunConfiguration:
+ G:/Projects/Qt/XPlor/app/app.pro
+ false
+ true
+ true
+ true
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Debug/app
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+
+ Qt4ProjectManager.Qt4RunConfiguration:
+ G:/Projects/Qt/XPlor/tests/tests.pro
+ false
+ true
+ true
+ true
+ G:/Projects/Qt/XPlor/build/Desktop_Qt_6_8_1_MSVC2022_64bit-Debug/tests
+
+ 2
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 3
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/LICENSE b/app/LICENSE
similarity index 100%
rename from LICENSE
rename to app/LICENSE
diff --git a/app/aboutdialog.cpp b/app/aboutdialog.cpp
new file mode 100644
index 0000000..c3ba1b4
--- /dev/null
+++ b/app/aboutdialog.cpp
@@ -0,0 +1,14 @@
+#include "aboutdialog.h"
+#include "ui_aboutdialog.h"
+
+AboutDialog::AboutDialog(QWidget *parent)
+ : QDialog(parent)
+ , ui(new Ui::AboutDialog)
+{
+ ui->setupUi(this);
+}
+
+AboutDialog::~AboutDialog()
+{
+ delete ui;
+}
diff --git a/app/aboutdialog.h b/app/aboutdialog.h
new file mode 100644
index 0000000..4474ece
--- /dev/null
+++ b/app/aboutdialog.h
@@ -0,0 +1,22 @@
+#ifndef ABOUTDIALOG_H
+#define ABOUTDIALOG_H
+
+#include
+
+namespace Ui {
+class AboutDialog;
+}
+
+class AboutDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AboutDialog(QWidget *parent = nullptr);
+ ~AboutDialog();
+
+private:
+ Ui::AboutDialog *ui;
+};
+
+#endif // ABOUTDIALOG_H
diff --git a/app/aboutdialog.ui b/app/aboutdialog.ui
new file mode 100644
index 0000000..27665f5
--- /dev/null
+++ b/app/aboutdialog.ui
@@ -0,0 +1,241 @@
+
+
+ AboutDialog
+
+
+
+ 0
+ 0
+ 350
+ 200
+
+
+
+
+ 350
+ 200
+
+
+
+
+ 350
+ 200
+
+
+
+ About XPlor
+
+
+ -
+
+
-
+
+
+
+ 80
+ 80
+
+
+
+
+ 80
+ 80
+
+
+
+
+
+
+ :/images/data/images/XPlor.png
+
+
+ true
+
+
+ Qt::AlignmentFlag::AlignCenter
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+ 16
+ false
+
+
+
+ XPlor v1.5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+
+
+
+ Copyright © 2024 RedLine Solutions LLC
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+
+
+
+ For more, check out redline.llc
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+ QSizePolicy::Policy::Fixed
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+
+
+
+ With Help From:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+
+
+
+ - Paging Red
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+
+
+
+ - ISOCheated
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+
+
+
+ - SureShotIan
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/app.ico b/app/app.ico
new file mode 100644
index 0000000..68c58cd
Binary files /dev/null and b/app/app.ico differ
diff --git a/app/app.pro b/app/app.pro
new file mode 100644
index 0000000..011daaf
--- /dev/null
+++ b/app/app.pro
@@ -0,0 +1,122 @@
+QT += core widgets gui multimedia
+
+RC_ICONS = app.ico
+
+SUBDIRS += app
+
+CONFIG += c++17
+
+SOURCES += \
+ aboutdialog.cpp \
+ ddsviewer.cpp \
+ fastfileviewer.cpp \
+ imagewidget.cpp \
+ iwiviewer.cpp \
+ localstringviewer.cpp \
+ main.cpp \
+ mainwindow.cpp \
+ materialviewer.cpp \
+ preferenceeditor.cpp \
+ soundviewer.cpp \
+ stringtableviewer.cpp \
+ techsetviewer.cpp \
+ xtreewidget.cpp \
+ xtreewidgetitem.cpp \
+ zonefileviewer.cpp
+
+HEADERS += \
+ aboutdialog.h \
+ d3dbsp_structs.h \
+ ddsviewer.h \
+ fastfileviewer.h \
+ imagewidget.h \
+ iwiviewer.h \
+ localstringviewer.h \
+ mainwindow.h \
+ materialviewer.h \
+ preferenceeditor.h \
+ soundviewer.h \
+ stringtableviewer.h \
+ techsetviewer.h \
+ xtreewidget.h \
+ xtreewidgetitem.h \
+ zonefileviewer.h
+
+FORMS += \
+ aboutdialog.ui \
+ ddsviewer.ui \
+ fastfileviewer.ui \
+ imagewidget.ui \
+ iwiviewer.ui \
+ localstringviewer.ui \
+ mainwindow.ui \
+ materialviewer.ui \
+ modelviewer.ui \
+ preferenceeditor.ui \
+ soundviewer.ui \
+ stringtableviewer.ui \
+ techsetviewer.ui \
+ zonefileviewer.ui
+
+RESOURCES += ../data/data.qrc
+
+app.depends += \
+ libs/core \
+ libs/compression \
+ libs/encryption \
+ libs/fastfile \
+ libs/ddsfile \
+ libs/ipakfile \
+ libs/iwifile \
+ libs/zonefile
+
+LIBS += \
+ -L$$PWD/../third_party/devil_sdk/lib/ -lDevIL -lILU -lILUT \
+ -L$$PWD/../third_party/zlib/lib/ -lzlib \
+ -L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
+ -L$$OUT_PWD/../libs/ -lcore \
+ -L$$OUT_PWD/../libs/ -lcompression \
+ -L$$OUT_PWD/../libs/ -lencryption \
+ -L$$OUT_PWD/../libs/ -lfastfile \
+ -L$$OUT_PWD/../libs/ -lddsfile \
+ -L$$OUT_PWD/../libs/ -lipakfile \
+ -L$$OUT_PWD/../libs/ -liwifile \
+ -L$$OUT_PWD/../libs/ -lzonefile
+
+INCLUDEPATH += \
+ $$PWD/../third_party/devil_sdk/include/ \
+ $$PWD/../third_party/zlib/include \
+ $$PWD/../third_party/xbox_sdk/include \
+ $$PWD/../libs/core \
+ $$PWD/../libs/compression \
+ $$PWD/../libs/encryption \
+ $$PWD/../libs/fastfile \
+ $$PWD/../libs/ddsfile \
+ $$PWD/../libs/ipakfile \
+ $$PWD/../libs/iwifile \
+ $$PWD/../libs/zonefile
+
+DEPENDPATH += \
+ $$PWD/../third_party/devil_sdk/include/ \
+ $$PWD/../third_party/zlib/include \
+ $$PWD/../third_party/xbox_sdk/include \
+ $$PWD/../libs/core \
+ $$PWD/../libs/compression \
+ $$PWD/../libs/encryption \
+ $$PWD/../libs/fastfile \
+ $$PWD/../libs/ddsfile \
+ $$PWD/../libs/ipakfile \
+ $$PWD/../libs/iwifile \
+ $$PWD/../libs/zonefile
+
+# Copy DLLs to Debug folder
+QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/zlib/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/xna/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
+
+# Copy DLLs to Release folder
+QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/zlib/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/xna/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
diff --git a/structs.h b/app/d3dbsp_structs.h
similarity index 88%
rename from structs.h
rename to app/d3dbsp_structs.h
index f1f1406..33017af 100644
--- a/structs.h
+++ b/app/d3dbsp_structs.h
@@ -1,5 +1,5 @@
-#ifndef STRUCTS_H
-#define STRUCTS_H
+#ifndef D3DBSP_STRUCTS_H
+#define D3DBSP_STRUCTS_H
#include
@@ -38,4 +38,4 @@ struct BINK {
uint32_t FrameChangePercent;
};
-#endif // STRUCTS_H
+#endif // D3DBSP_STRUCTS_H
diff --git a/app/ddsviewer.cpp b/app/ddsviewer.cpp
new file mode 100644
index 0000000..c9c31c5
--- /dev/null
+++ b/app/ddsviewer.cpp
@@ -0,0 +1,182 @@
+#include "ddsviewer.h"
+#include "enums.h"
+#include "ui_ddsviewer.h"
+
+DDSViewer::DDSViewer(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::DDSViewer)
+{
+ ui->setupUi(this);
+ mDDSFile = nullptr;
+}
+
+DDSViewer::~DDSViewer() {
+ delete ui;
+}
+
+void DDSViewer::SetDDSFile(std::shared_ptr aDDSFile) {
+ mDDSFile.swap(aDDSFile);
+
+ ui->label_Title->setText(mDDSFile->fileStem + ".dds");
+
+ char magicData[5];
+ magicData[0] = static_cast(mDDSFile->header.magic & 0xFF);
+ magicData[1] = static_cast((mDDSFile->header.magic >> 8) & 0xFF);
+ magicData[2] = static_cast((mDDSFile->header.magic >> 16) & 0xFF);
+ magicData[3] = static_cast((mDDSFile->header.magic >> 24) & 0xFF);
+ magicData[4] = '\0';
+
+ // If you’re using Qt and want a QString:
+ QString magicStr = QString::fromLatin1(magicData);
+ ui->lineEdit_Magic->setText(magicStr);
+ ui->spinBox_Size->setValue(mDDSFile->header.size);
+
+ ui->checkBox_CapsValid->setChecked((mDDSFile->header.flags & DDSD_CAPS) != 0);
+ ui->checkBox_HeightValid->setChecked((mDDSFile->header.flags & DDSD_HEIGHT) != 0);
+ ui->checkBox_WidthValid->setChecked((mDDSFile->header.flags & DDSD_WIDTH) != 0);
+ ui->checkBox_PitchValid->setChecked((mDDSFile->header.flags & DDSD_PITCH) != 0);
+ ui->checkBox_PFValid->setChecked((mDDSFile->header.flags & DDSD_PIXELFORMAT) != 0);
+ ui->checkBox_MipmapCountValid->setChecked((mDDSFile->header.flags & DDSD_MIPMAPCOUNT) != 0);
+ ui->checkBox_LinearSizeValid->setChecked((mDDSFile->header.flags & DDSD_LINEARSIZE) != 0);
+ ui->checkBox_DepthValid->setChecked((mDDSFile->header.flags & DDSD_DEPTH) != 0);
+
+ ui->spinBox_PLSize->setValue(mDDSFile->header.pitchOrLinearSize);
+ ui->spinBox_Depth->setValue(mDDSFile->header.depth);
+ ui->spinBox_Width->setValue(mDDSFile->header.width);
+ ui->spinBox_Height->setValue(mDDSFile->header.height);
+ ui->spinBox_MipmapCount->setValue(mDDSFile->header.mipMapCount);
+
+ ui->spinBox_Res1->setValue(mDDSFile->header.reserved1[0]);
+ ui->spinBox_Res2->setValue(mDDSFile->header.reserved1[1]);
+ ui->spinBox_Res3->setValue(mDDSFile->header.reserved1[2]);
+ ui->spinBox_Res4->setValue(mDDSFile->header.reserved1[3]);
+ ui->spinBox_Res5->setValue(mDDSFile->header.reserved1[4]);
+ ui->spinBox_Res6->setValue(mDDSFile->header.reserved1[5]);
+ ui->spinBox_Res7->setValue(mDDSFile->header.reserved1[6]);
+ ui->spinBox_Res8->setValue(mDDSFile->header.reserved1[7]);
+ ui->spinBox_Res9->setValue(mDDSFile->header.reserved1[8]);
+ ui->spinBox_Res10->setValue(mDDSFile->header.reserved1[9]);
+ ui->spinBox_Res11->setValue(mDDSFile->header.reserved1[10]);
+
+ ui->spinBox_Res12->setValue(mDDSFile->header.reserved2);
+
+ ui->spinBox_PF_Size->setValue(mDDSFile->header.pixelFormat.size);
+
+ ui->checkBox_PF_AlphaPxValid->setChecked((mDDSFile->header.pixelFormat.flags & DDPF_ALPHAPIXELS) != 0);
+ ui->checkBox_PF_AlphaOnlyValid->setChecked((mDDSFile->header.pixelFormat.flags & DDPF_ALPHA) != 0);
+ ui->checkBox_PF_FormatValid->setChecked((mDDSFile->header.pixelFormat.flags & DDPF_FOURCC) != 0);
+ ui->checkBox_PF_RGBValid->setChecked((mDDSFile->header.pixelFormat.flags & DDPF_RGB) != 0);
+ ui->checkBox_PF_YUVValid->setChecked((mDDSFile->header.pixelFormat.flags & DDPF_YUV) != 0);
+ ui->checkBox_PF_LuminanceValid->setChecked((mDDSFile->header.pixelFormat.flags & DDPF_LUMINANCE) != 0);
+
+ QString formatStr = QString::number(mDDSFile->header.pixelFormat.format);
+ switch (mDDSFile->header.pixelFormat.format) {
+ case IWI_FORMAT_ARGB32:
+ formatStr = "ARGB32";
+ break;
+ case IWI_FORMAT_RGB24:
+ formatStr = "RGB24";
+ break;
+ case IWI_FORMAT_GA16:
+ formatStr = "GA16";
+ break;
+ case IWI_FORMAT_A8:
+ formatStr = "A8";
+ break;
+ case IWI_FORMAT_DXT1:
+ formatStr = "DXT1";
+ break;
+ case IWI_FORMAT_DXT3:
+ formatStr = "DXT3";
+ break;
+ case IWI_FORMAT_DXT5:
+ formatStr = "DXT5";
+ break;
+ }
+ ui->lineEdit_PF_Format->setText(formatStr);
+ ui->spinBox_PF_RGBBitCount->setValue(mDDSFile->header.pixelFormat.rgbBitCount);
+ ui->spinBox_RedBitCount->setValue(mDDSFile->header.pixelFormat.rBitMask);
+ ui->spinBox_GreenBitCount->setValue(mDDSFile->header.pixelFormat.gBitMask);
+ ui->spinBox_BlueBitCount->setValue(mDDSFile->header.pixelFormat.bBitMask);
+ ui->spinBox_AlphaBitMask->setValue(mDDSFile->header.pixelFormat.aBitMask);
+
+ ui->checkBox_Caps1_TextureValid->setChecked((mDDSFile->header.caps.caps1 & DDSCAPS_TEXTURE) != 0);
+ ui->checkBox_Caps1_ComplexValid->setChecked((mDDSFile->header.caps.caps1 & DDSCAPS_COMPLEX) != 0);
+ ui->checkBox_Caps1_MipmapValid->setChecked((mDDSFile->header.caps.caps1 & DDSCAPS_MIPMAP) != 0);
+
+ ui->checkBox_Caps2_CubemapValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0);
+ ui->checkBox_Caps2_CMPXValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) != 0);
+ ui->checkBox_Caps2_CMNXValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) != 0);
+ ui->checkBox_Caps2_CMPYValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) != 0);
+ ui->checkBox_Caps2_CMNYValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) != 0);
+ ui->checkBox_Caps2_CMPZValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) != 0);
+ ui->checkBox_Caps2_CMNZValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) != 0);
+ ui->checkBox_Caps2_VolumeValid->setChecked((mDDSFile->header.caps.caps2 & DDSCAPS2_VOLUME) != 0);
+
+ ui->spinBox_Caps_DDSX->setValue(mDDSFile->header.caps.dDSX);
+ ui->spinBox_Caps_Res->setValue(mDDSFile->header.caps.reserved);
+
+ ui->comboBox_Mipmap->clear();
+ for (auto mipmap : mDDSFile->mipmaps) {
+ ui->comboBox_Mipmap->addItem(QString("%1x%2").arg(mipmap.width).arg(mipmap.height));
+ }
+
+ connect(ui->comboBox_Mipmap, &QComboBox::currentIndexChanged, this, &DDSViewer::MipmapIndexChanged);
+
+ if (!mDDSFile->mipmaps.empty()) {
+ MipmapIndexChanged(0);
+ }
+}
+
+void DDSViewer::MipmapIndexChanged(int aMipmapIndex) {
+ if (aMipmapIndex == -1) { return; }
+
+ auto mipmaps = mDDSFile->mipmaps;
+ auto mipmap = mipmaps[aMipmapIndex];
+
+ ui->spinBox_MipmapSize->setValue(mipmap.size);
+ ui->spinBox_MipmapWidth->setValue(mipmap.width);
+ ui->spinBox_MipmapHeight->setValue(mipmap.height);
+
+ // Validate Data
+ if (mipmap.size <= 0) {
+ qDebug() << "Error: Mipmap data is empty!";
+ return;
+ }
+ if (mipmap.width <= 0 || mipmap.height <= 0) {
+ qDebug() << "Error: Invalid mipmap dimensions!";
+ return;
+ }
+
+ // Ensure data size matches expected size
+ int bytesPerPixel = 4; // RGBA8888
+ quint32 expectedSize = mipmap.width * mipmap.height * bytesPerPixel;
+ if (mipmap.size < expectedSize) {
+ qDebug() << "Error: Mipmap data size mismatch! Expected:" << expectedSize << ", Got:" << mipmap.size;
+ return;
+ }
+
+ // Create QImage
+ const unsigned char* imageData = reinterpret_cast(mipmap.data.constData());
+ QImage image(reinterpret_cast(imageData),
+ mipmap.width, mipmap.height,
+ mipmap.width * bytesPerPixel, // Stride
+ QImage::Format_RGBA8888);
+
+ if (image.isNull()) {
+ qDebug() << "Error: QImage creation failed!";
+ return;
+ }
+
+ // Convert to QPixmap
+ QPixmap pixmap = QPixmap::fromImage(image);
+ if (pixmap.isNull()) {
+ qDebug() << "Error: QPixmap conversion failed!";
+ return;
+ }
+
+ // Scale and display
+ pixmap = pixmap.scaled(ui->label_Image->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ ui->label_Image->setPixmap(pixmap);
+}
+
diff --git a/app/ddsviewer.h b/app/ddsviewer.h
new file mode 100644
index 0000000..f49bbc2
--- /dev/null
+++ b/app/ddsviewer.h
@@ -0,0 +1,29 @@
+#ifndef DDSVIEWER_H
+#define DDSVIEWER_H
+
+#include "ddsfile.h"
+#include
+
+namespace Ui {
+class DDSViewer;
+}
+
+class DDSViewer : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit DDSViewer(QWidget *parent = nullptr);
+ ~DDSViewer();
+
+ void SetDDSFile(std::shared_ptr aDDSFile);
+
+private slots:
+ void MipmapIndexChanged(int aMipmapIndex);
+
+private:
+ Ui::DDSViewer *ui;
+ std::shared_ptr mDDSFile;
+};
+
+#endif // DDSVIEWER_H
diff --git a/app/ddsviewer.ui b/app/ddsviewer.ui
new file mode 100644
index 0000000..d7dc083
--- /dev/null
+++ b/app/ddsviewer.ui
@@ -0,0 +1,1712 @@
+
+
+ DDSViewer
+
+
+
+ 0
+ 0
+ 1326
+ 876
+
+
+
+ Form
+
+
+ -
+
+
+
+ Roboto
+ 16
+ true
+
+
+
+ DDS File 0
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Caps
+
+
+
-
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ D DSX:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Caps 2 Flags / Valid Data
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Cubemap Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Cubemap +X Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Cubemap -X Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Cubemap +Y Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Cubemap -Y Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Cubemap +Z Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Cubemap -Z Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Volume Valid
+
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Caps 1 Flags / Valid Data
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Complex Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Mipmap Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Texture Valid
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 78
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Header
+
+
+
-
+
+
-
+
+
-
+
+
-
+
+
+ false
+
+
+ Properties
+
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Magic:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Header Len:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ B
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Pitch/Linear Size:
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Depth:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Mipmap #:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Height:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Width:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Flags / Valid Data
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Caps Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Height Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Width Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Pitch Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Depth Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Linear Size Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Mipmap Count Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Pixel Format Valid
+
+
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Qt::Orientation::Vertical
+
+
+
+ -
+
+
-
+
+
+ false
+
+
+ Reserved Fields
+
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 1:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 2:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 3:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 4:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 5:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 6:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 7:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 8:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 9:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 10:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 11:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Reserved 12:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+ QSizePolicy::Policy::Ignored
+
+
+
+ 17
+ 118
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Mipmaps
+
+
+
-
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Select Mipmap:
+
+
+
+ -
+
+
+
+ 60
+ 0
+
+
+
+
+ Roboto
+ 9
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Properties
+
+
+
-
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Size:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Height:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Width:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Pixel Format
+
+
+
-
+
+
+ false
+
+
+ Properties
+
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Size:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Format:
+
+
+
+ -
+
+
+ false
+
+
+
+ 0
+ 0
+
+
+
+
+ Roboto
+ 9
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ RGB Bit #:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Red Bit Mask:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Blue Bit Mask:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Green Bit Mask:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Alpha Bit Mask:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Qt::Orientation::Vertical
+
+
+
+ -
+
+
+ false
+
+
+ Flags / Valid Data
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Alpha Pixels Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Alpha Only Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Format Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ RGB Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ YUV Valid
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Luminance Valid
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Preview
+
+
+
-
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 600
+ 600
+
+
+
+
+ 600
+ 600
+
+
+
+
+ Roboto
+ 9
+
+
+
+ border: 2px solid white;
+
+
+
+
+
+ Qt::AlignmentFlag::AlignCenter
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
diff --git a/app/fastfileviewer.cpp b/app/fastfileviewer.cpp
new file mode 100644
index 0000000..2fb29bb
--- /dev/null
+++ b/app/fastfileviewer.cpp
@@ -0,0 +1,27 @@
+#include "fastfileviewer.h"
+#include "asset_structs.h"
+#include "ui_fastfileviewer.h"
+
+FastFileViewer::FastFileViewer(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::FFViewer)
+ , mFastFile(nullptr)
+{
+ ui->setupUi(this);
+}
+
+FastFileViewer::~FastFileViewer()
+{
+ delete ui;
+}
+
+void FastFileViewer::SetFastFile(std::shared_ptr aFastFile) {
+ mFastFile.swap(aFastFile);
+
+ ui->label_Title->setText(mFastFile->GetStem() + ".ff");
+ ui->comboBox_Company->setCurrentIndex(mFastFile->GetCompany());
+ ui->comboBox_FileType->setCurrentIndex(mFastFile->GetType());
+ ui->checkBox_Signed->setChecked(mFastFile->GetSignage() == SIGNAGE_SIGNED);
+ ui->lineEdit_Magic->setText(mFastFile->GetMagic());
+ ui->spinBox_Version->setValue(mFastFile->GetVersion());
+}
diff --git a/app/fastfileviewer.h b/app/fastfileviewer.h
new file mode 100644
index 0000000..3fc36c1
--- /dev/null
+++ b/app/fastfileviewer.h
@@ -0,0 +1,26 @@
+#ifndef FASTFILEVIEWER_H
+#define FASTFILEVIEWER_H
+
+#include "asset_structs.h"
+#include "fastfile.h"
+#include
+
+namespace Ui {
+class FFViewer;
+}
+
+class FastFileViewer : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit FastFileViewer(QWidget *parent = nullptr);
+ ~FastFileViewer();
+
+ void SetFastFile(std::shared_ptr aFastFile);
+private:
+ Ui::FFViewer *ui;
+ std::shared_ptr mFastFile;
+};
+
+#endif // FASTFILEVIEWER_H
diff --git a/app/fastfileviewer.ui b/app/fastfileviewer.ui
new file mode 100644
index 0000000..52e4091
--- /dev/null
+++ b/app/fastfileviewer.ui
@@ -0,0 +1,197 @@
+
+
+ FFViewer
+
+
+
+ 0
+ 0
+ 428
+ 459
+
+
+
+ Form
+
+
+ -
+
+
+
+ Roboto
+ 16
+ true
+
+
+
+ FastFile 0
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ 400
+ 400
+
+
+
+
+ Roboto
+ 9
+
+
+
+ Header
+
+
+
-
+
+
+ Company:
+
+
+
+ -
+
+
+ false
+
+
-
+
+ None
+
+
+ -
+
+ Infinity Ward
+
+
+ -
+
+ Treyarch
+
+
+ -
+
+ Sledgehammer
+
+
+ -
+
+ Neversoft
+
+
+
+
+ -
+
+
+ File Type:
+
+
+
+ -
+
+
+ false
+
+
-
+
+ None
+
+
+ -
+
+ FastFile
+
+
+
+
+ -
+
+
+ Signed:
+
+
+
+ -
+
+
+ false
+
+
+ Is signed
+
+
+
+ -
+
+
+ Magic:
+
+
+
+ -
+
+
+ -
+
+
+ Version:
+
+
+
+ -
+
+
+ false
+
+
+ 10000
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 1
+
+
+
+
+
+
+
+
+
diff --git a/app/imagewidget.cpp b/app/imagewidget.cpp
new file mode 100644
index 0000000..04af5c1
--- /dev/null
+++ b/app/imagewidget.cpp
@@ -0,0 +1,28 @@
+#include "imagewidget.h"
+#include "ui_imagewidget.h"
+
+ImageWidget::ImageWidget(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::ImageWidget)
+{
+ ui->setupUi(this);
+}
+
+ImageWidget::~ImageWidget()
+{
+ delete ui;
+}
+
+void ImageWidget::SetImage(std::shared_ptr aImage)
+{
+ mImage = aImage;
+
+ ui->lineEdit_Name->setText(aImage->name);
+ ui->lineEdit_Role->setText(aImage->materialName);
+ ui->comboBox_Compression->setCurrentIndex(aImage->compression);
+}
+
+std::shared_ptr ImageWidget::GetImage()
+{
+ return mImage;
+}
diff --git a/app/imagewidget.h b/app/imagewidget.h
new file mode 100644
index 0000000..4de5a27
--- /dev/null
+++ b/app/imagewidget.h
@@ -0,0 +1,32 @@
+#ifndef IMAGEWIDGET_H
+#define IMAGEWIDGET_H
+
+#include "enums.h"
+#include "dds_structs.h"
+#include "d3dbsp_structs.h"
+#include "asset_structs.h"
+#include "ipak_structs.h"
+
+#include
+
+namespace Ui {
+class ImageWidget;
+}
+
+class ImageWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ImageWidget(QWidget *parent = nullptr);
+ ~ImageWidget();
+
+ void SetImage(std::shared_ptr aImage);
+ std::shared_ptr GetImage();
+
+private:
+ std::shared_ptr mImage;
+ Ui::ImageWidget *ui;
+};
+
+#endif // IMAGEWIDGET_H
diff --git a/app/imagewidget.ui b/app/imagewidget.ui
new file mode 100644
index 0000000..47b6206
--- /dev/null
+++ b/app/imagewidget.ui
@@ -0,0 +1,144 @@
+
+
+ ImageWidget
+
+
+
+ 0
+ 0
+ 589
+ 422
+
+
+
+ Form
+
+
+ -
+
+
-
+
+
-
+
+
+ Image Role:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ Name:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ Compression:
+
+
+
+ -
+
+
-
+
+ None
+
+
+ -
+
+ DXT1
+
+
+ -
+
+ DXT3
+
+
+ -
+
+ DXT5
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ -
+
+
-
+
+
+
+ 250
+ 250
+
+
+
+
+ 250
+ 250
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/iwiviewer.cpp b/app/iwiviewer.cpp
new file mode 100644
index 0000000..1fd2268
--- /dev/null
+++ b/app/iwiviewer.cpp
@@ -0,0 +1,98 @@
+#include "iwiviewer.h"
+#include "enums.h"
+#include "ui_iwiviewer.h"
+
+IWIViewer::IWIViewer(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::IWIViewer)
+{
+ ui->setupUi(this);
+}
+
+IWIViewer::~IWIViewer()
+{
+ delete ui;
+}
+
+void IWIViewer::SetIWIFile(std::shared_ptr aIWIFile) {
+ mIWIFile.swap(aIWIFile);
+
+ ui->label_Title->setText(mIWIFile->fileStem + ".iwi");
+
+ // If you’re using Qt and want a QString:
+ QString magicStr = QString::fromLatin1(mIWIFile->header.Magic, 3);
+ ui->lineEdit_Magic->setText(magicStr);
+
+ ui->spinBox_Version->setValue(mIWIFile->header.Version);
+ ui->spinBox_Depth->setValue(mIWIFile->info.Depth);
+ QString formatStr = "";
+ switch (mIWIFile->info.Format) {
+ case IWI_FORMAT_ARGB32:
+ formatStr = "ARGB32";
+ break;
+ case IWI_FORMAT_RGB24:
+ formatStr = "RGB24";
+ break;
+ case IWI_FORMAT_GA16:
+ formatStr = "GA16";
+ break;
+ case IWI_FORMAT_A8:
+ formatStr = "A8";
+ break;
+ case IWI_FORMAT_DXT1:
+ formatStr = "DXT1";
+ break;
+ case IWI_FORMAT_DXT3:
+ formatStr = "DXT3";
+ break;
+ case IWI_FORMAT_DXT5:
+ formatStr = "DXT5";
+ break;
+ }
+ ui->lineEdit_Format->setText(formatStr);
+ ui->spinBox_Height->setValue(mIWIFile->info.Height);
+ ui->spinBox_Width->setValue(mIWIFile->info.Width);
+ ui->spinBox_Usage->setValue(mIWIFile->info.Usage);
+
+ ui->comboBox_Mipmap->clear();
+ for (auto mipmap : mIWIFile->mipmaps) {
+ ui->comboBox_Mipmap->addItem(QString::number(mipmap.offset));
+ }
+
+ connect(ui->comboBox_Mipmap, &QComboBox::currentIndexChanged, this, &IWIViewer::MipmapIndexChanged);
+
+ if (!mIWIFile->mipmaps.empty()) {
+ MipmapIndexChanged(0);
+ }
+}
+
+void IWIViewer::MipmapIndexChanged(int aMipmapIndex) {
+ auto mipmaps = mIWIFile->mipmaps;
+
+ if (aMipmapIndex == -1) { return; }
+
+ auto mipmap = mipmaps[aMipmapIndex];
+ ui->spinBox_MipmapSize->setValue(mipmap.size);
+ ui->spinBox_MipmapOffset->setValue(mipmap.offset);
+
+ const unsigned char* imageData = reinterpret_cast(mipmap.data.constData());
+ QImage image(reinterpret_cast(imageData),
+ mIWIFile->info.Width, mIWIFile->info.Height,
+ QImage::Format_RGBA8888);
+
+ if (image.isNull()) {
+ qDebug() << "Error: QImage creation failed!";
+ return;
+ }
+
+ // Convert to QPixmap
+ QPixmap pixmap = QPixmap::fromImage(image);
+ if (pixmap.isNull()) {
+ qDebug() << "Error: QPixmap conversion failed!";
+ return;
+ }
+
+ // Scale and display
+ pixmap = pixmap.scaled(ui->label_Image->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ ui->label_Image->setPixmap(pixmap);
+}
diff --git a/app/iwiviewer.h b/app/iwiviewer.h
new file mode 100644
index 0000000..86f5105
--- /dev/null
+++ b/app/iwiviewer.h
@@ -0,0 +1,27 @@
+#ifndef IWIVIEWER_H
+#define IWIVIEWER_H
+
+#include "iwifile.h"
+#include
+
+namespace Ui {
+class IWIViewer;
+}
+
+class IWIViewer : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit IWIViewer(QWidget *parent = nullptr);
+ ~IWIViewer();
+
+ void MipmapIndexChanged(int aMipmapIndex);
+
+ void SetIWIFile(std::shared_ptr aIWIFile);
+private:
+ Ui::IWIViewer *ui;
+ std::shared_ptr mIWIFile;
+};
+
+#endif // IWIVIEWER_H
diff --git a/app/iwiviewer.ui b/app/iwiviewer.ui
new file mode 100644
index 0000000..657df71
--- /dev/null
+++ b/app/iwiviewer.ui
@@ -0,0 +1,548 @@
+
+
+ IWIViewer
+
+
+
+ 0
+ 0
+ 1246
+ 909
+
+
+
+ Form
+
+
+ -
+
+
+
+ Roboto
+ 16
+ true
+
+
+
+ IWI File 0
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Header
+
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Magic:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Version:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ B
+
+
+ 1000000000
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Info
+
+
+
-
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Depth:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Format
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Height:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Width:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+ -
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Usage
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Mipmaps
+
+
+
-
+
+
-
+
+
+
+ Roboto
+ 9
+
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Select Mipmap:
+
+
+
+ -
+
+
+
+ 60
+ 0
+
+
+
+
+ Roboto
+ 9
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Size:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Offset:
+
+
+
+ -
+
+
+ false
+
+
+
+ Roboto
+ 9
+
+
+
+ 1000000000
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ Roboto
+ 9
+
+
+
+ Preview
+
+
+
-
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 600
+ 600
+
+
+
+
+ 600
+ 600
+
+
+
+
+ Roboto
+ 9
+
+
+
+ border: 2px solid white;
+
+
+
+
+
+ Qt::AlignmentFlag::AlignCenter
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 116
+
+
+
+
+
+
+
+
+
diff --git a/app/localstringviewer.cpp b/app/localstringviewer.cpp
new file mode 100644
index 0000000..6550668
--- /dev/null
+++ b/app/localstringviewer.cpp
@@ -0,0 +1,59 @@
+#include "localstringviewer.h"
+#include "ui_localstringviewer.h"
+
+LocalStringViewer::LocalStringViewer(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::LocalStringViewer),
+ mVersion(),
+ mConfigPath(),
+ mFileNotes() {
+ ui->setupUi(this);
+
+ ui->tableWidget_Strings->setColumnCount(2);
+ ui->tableWidget_Strings->setColumnWidth(0, 200);
+ ui->tableWidget_Strings->horizontalHeader()->setStretchLastSection(true);
+}
+
+LocalStringViewer::~LocalStringViewer() {
+ delete ui;
+}
+
+void LocalStringViewer::SetVersion(quint32 aVersion) {
+ mVersion = aVersion;
+
+ ui->spinBox_Version->setValue(mVersion);
+}
+
+void LocalStringViewer::SetConfigPath(const QString aConfigPath) {
+ mConfigPath = aConfigPath;
+
+ ui->lineEdit_Config->setText(mConfigPath);
+}
+
+void LocalStringViewer::SetFileNotes(const QString aFileNotes) {
+ mFileNotes = aFileNotes;
+
+ ui->plainTextEdit_FileNotes->setPlainText(mFileNotes);
+}
+
+void LocalStringViewer::AddLocalString(LocalString aLocalString) {
+ mLocalStrings << aLocalString;
+
+ ui->tableWidget_Strings->setRowCount(mLocalStrings.size());
+
+ QTableWidgetItem *aliasItem = new QTableWidgetItem(aLocalString.alias);
+ QTableWidgetItem *stringItem = new QTableWidgetItem(aLocalString.string);
+
+ ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 0, aliasItem);
+ ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 1, stringItem);
+}
+
+void LocalStringViewer::SetZoneFile(std::shared_ptr aZoneFile) {
+ mLocalStrings.clear();
+ ui->tableWidget_Strings->clear();
+
+ ui->label_Title->setText(aZoneFile->GetStem().section('.', 0, 0) + ".str");
+ for (LocalString localStr : aZoneFile->GetAssetMap().localStrings) {
+ AddLocalString(localStr);
+ }
+}
diff --git a/app/localstringviewer.h b/app/localstringviewer.h
new file mode 100644
index 0000000..b2c8566
--- /dev/null
+++ b/app/localstringviewer.h
@@ -0,0 +1,34 @@
+#ifndef LOCALSTRINGVIEWER_H
+#define LOCALSTRINGVIEWER_H
+
+#include "asset_structs.h"
+#include "zonefile.h"
+#include
+
+namespace Ui {
+class LocalStringViewer;
+}
+
+class LocalStringViewer : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit LocalStringViewer(QWidget *parent = nullptr);
+ ~LocalStringViewer();
+
+ void SetVersion(quint32 aVersion);
+ void SetConfigPath(const QString aConfigPath);
+ void SetFileNotes(const QString aFileNotes);
+ void AddLocalString(LocalString aLocalString);
+ void SetZoneFile(std::shared_ptr aZoneFile);
+
+private:
+ Ui::LocalStringViewer *ui;
+ quint32 mVersion;
+ QString mConfigPath;
+ QString mFileNotes;
+ QVector mLocalStrings;
+};
+
+#endif // LOCALSTRINGVIEWER_H
diff --git a/app/localstringviewer.ui b/app/localstringviewer.ui
new file mode 100644
index 0000000..bdd547e
--- /dev/null
+++ b/app/localstringviewer.ui
@@ -0,0 +1,194 @@
+
+
+ LocalStringViewer
+
+
+
+ 0
+ 0
+ 841
+ 457
+
+
+
+
+ 841
+ 457
+
+
+
+ Form
+
+
+ -
+
+
+
+ Roboto
+ 16
+ true
+
+
+
+ LocalString File 0
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+ 325
+ 398
+
+
+
+
+ 325
+ 16777215
+
+
+
+
+ Roboto
+ 9
+
+
+
+ Header
+
+
+
-
+
+
+ File Notes:
+
+
+ Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop
+
+
+
+ -
+
+
+ Version:
+
+
+
+ -
+
+
+ false
+
+
+ C:\cod5\cod\cod5\bin\StringEd.cfg
+
+
+
+ -
+
+
+ Config:
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ false
+
+
+ 10000
+
+
+ 1
+
+
+
+ -
+
+
+ Files notes...
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 400
+ 400
+
+
+
+
+ Roboto
+ 9
+
+
+
+ Entries
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 0
+
+
+
+
+
+
+
+
+
diff --git a/main.cpp b/app/main.cpp
similarity index 100%
rename from main.cpp
rename to app/main.cpp
diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp
new file mode 100644
index 0000000..475cb32
--- /dev/null
+++ b/app/mainwindow.cpp
@@ -0,0 +1,902 @@
+#include "mainwindow.h"
+#include "aboutdialog.h"
+#include "fastfile.h"
+#include "materialviewer.h"
+#include "preferenceeditor.h"
+#include "soundviewer.h"
+#include "stringtableviewer.h"
+#include "techsetviewer.h"
+#include "ui_mainwindow.h"
+#include "compression.h"
+#include "iwifile.h"
+#include "ddsfile.h"
+#include "statusbarmanager.h"
+#include "ddsviewer.h"
+#include "fastfileviewer.h"
+#include "ipak_structs.h"
+#include "iwiviewer.h"
+#include "localstringviewer.h"
+#include "imagewidget.h"
+#include "xtreewidget.h"
+#include "zonefileviewer.h"
+#include "techsetviewer.h"
+#include "logmanager.h"
+
+#include
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent), ui(new Ui::MainWindow) {
+ ui->setupUi(this);
+
+ setAcceptDrops(true);
+
+ mTypeMap = QMap();
+ mTypeOrder = QStringList();
+ mRawFileMap = QMap();
+ mImageMap = QMap();
+ mTreeMap = QMap();
+ mStrTableMap = QMap>>();
+ mBSPVersion = 0;
+ mDiskLumpCount = 0;
+ mDiskLumpOrder = QVector();
+ mLumps = QMap();
+ mTreeWidget = new XTreeWidget(this);
+ mLogWidget = new QPlainTextEdit(this);
+
+ //ModelViewer *mModelViewer = new ModelViewer(container);
+ //mModelViewer->setAcceptDrops(false);
+
+ mProgressBar = new QProgressBar(this);
+ mProgressBar->setMaximum(100); // Default max value
+ mProgressBar->setVisible(false); // Initially hidden
+
+ connect(&StatusBarManager::instance(), &StatusBarManager::statusUpdated,
+ this, &MainWindow::HandleStatusUpdate);
+
+ connect(&StatusBarManager::instance(), &StatusBarManager::progressUpdated,
+ this, &MainWindow::HandleProgressUpdate);
+
+ connect(&LogManager::instance(), &LogManager::entryAdded,
+ this, &MainWindow::HandleLogEntry);
+
+ statusBar()->addPermanentWidget(mProgressBar);
+
+ connect(ui->actionPreferences, &QAction::triggered, this, [this](bool checked) {
+ Q_UNUSED(checked);
+
+ PreferenceEditor *prefEditor = new PreferenceEditor(this);
+ prefEditor->exec();
+ });
+
+ ui->tabWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->tabWidget, &QTabWidget::customContextMenuRequested, this, [this](const QPoint &pos) {
+ if (pos.isNull())
+ return;
+
+ int tabIndex = ui->tabWidget->tabBar()->tabAt(pos);
+ QMenu *contextMenu = new QMenu(this);
+
+ QAction *closeAction = new QAction("Close");
+ contextMenu->addAction(closeAction);
+ connect(closeAction, &QAction::triggered, this, [this, &tabIndex](bool checked) {
+ Q_UNUSED(checked);
+
+ ui->tabWidget->removeTab(tabIndex);
+ });
+
+ QMenu *closeMultipleAction = new QMenu("Close Multiple Tabs");
+
+ QAction *closeAllAction = new QAction("Close All");
+ closeMultipleAction->addAction(closeAllAction);
+ connect(closeAllAction, &QAction::triggered, this, [this](bool checked) {
+ Q_UNUSED(checked);
+
+ ui->tabWidget->clear();
+ });
+
+ QAction *closeAllButAction = new QAction("Close All BUT This");
+ closeMultipleAction->addAction(closeAllButAction);
+ connect(closeAllButAction, &QAction::triggered, this, [this, &tabIndex](bool checked) {
+ Q_UNUSED(checked);
+
+ for (int i = 0; i < ui->tabWidget->count(); i++) {
+ if (i != tabIndex) {
+ ui->tabWidget->removeTab(i);
+ }
+ }
+ });
+
+ QAction *closeLeftAction = new QAction("Close All to the Left");
+ closeMultipleAction->addAction(closeLeftAction);
+ connect(closeLeftAction, &QAction::triggered, this, [this, &tabIndex](bool checked) {
+ Q_UNUSED(checked);
+
+ for (int i = 0; i < tabIndex; i++) {
+ ui->tabWidget->removeTab(i);
+ }
+ });
+
+ QAction *closeRightAction = new QAction("Close All to the Right");
+ closeMultipleAction->addAction(closeRightAction);
+ connect(closeRightAction, &QAction::triggered, this, [this, &tabIndex](bool checked) {
+ Q_UNUSED(checked);
+
+ for (int i = tabIndex + 1; i < ui->tabWidget->count(); i++) {
+ ui->tabWidget->removeTab(i);
+ }
+ });
+
+ contextMenu->addMenu(closeMultipleAction);
+
+ QPoint pt(pos);
+ contextMenu->exec(ui->tabWidget->mapToGlobal(pt));
+
+ delete contextMenu;
+ });
+
+ connect(ui->tabWidget, &QTabWidget::tabCloseRequested, this, [this](int index) {
+ ui->tabWidget->removeTab(index);
+ });
+
+ connect(mTreeWidget, &XTreeWidget::Cleared, this, [this]() {
+ ui->tabWidget->clear();
+ });
+
+ connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr rawFile, const QString aParentName) {
+ QPlainTextEdit *scriptEditor = new QPlainTextEdit(this);
+ scriptEditor->setAcceptDrops(false);
+ scriptEditor->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
+
+ if (rawFile->contents.isEmpty()) {
+ scriptEditor->setPlainText("EMPTY");
+ } else {
+ scriptEditor->setPlainText(rawFile->contents);
+ }
+
+ QString fileStem = rawFile->path.split('/').last();
+ for (int i = 0; i < ui->tabWidget->count(); i++) {
+ if (ui->tabWidget->tabText(i) == fileStem) {
+ return;
+ }
+ }
+
+ QScrollArea *scrollArea = new QScrollArea(ui->tabWidget);
+ scrollArea->layout()->addWidget(scriptEditor);
+
+ ui->tabWidget->addTab(scrollArea, fileStem);
+ ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_GSCFile.png"));
+ ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
+ });
+
+ connect(mTreeWidget, &XTreeWidget::ImageSelected, this, [this](std::shared_ptr image, const QString aParentName) {
+ ImageWidget *mImageWidget = new ImageWidget(this);
+ mImageWidget->setAcceptDrops(false);
+ mImageWidget->SetImage(image);
+ mImageWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
+
+ QString fileStem = image->materialName;
+ for (int i = 0; i < ui->tabWidget->count(); i++) {
+ if (ui->tabWidget->tabText(i) == fileStem) {
+ return;
+ }
+ }
+
+ ui->tabWidget->addTab(mImageWidget, fileStem);
+ ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_Image.png"));
+ ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
+ });
+
+ connect(mTreeWidget, &XTreeWidget::MenuSelected, this, [](std::shared_ptr