diff --git a/.gitignore b/.gitignore index 6700e2b..fb5ba92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /build/ /data/dlls/ /data/fastfiles/ -.pro.user +*.pro.user 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/DevILSDK/include/IL/DevIL.i b/DevILSDK/include/IL/DevIL.i new file mode 100644 index 0000000..820449d --- /dev/null +++ b/DevILSDK/include/IL/DevIL.i @@ -0,0 +1,13 @@ +%module DevIL +%{ +#include "il.h" +#include "ilu.h" +#include "ilut.h" +//#include "ilu_region.h" +%} + +%include "il.h" +%include "ilu.h" +%include "ilut.h" +//%include "ilu_region.h" + diff --git a/DevILSDK/include/IL/build-lua b/DevILSDK/include/IL/build-lua new file mode 100644 index 0000000..ed45659 --- /dev/null +++ b/DevILSDK/include/IL/build-lua @@ -0,0 +1,51 @@ +IL_INCLUDE_PATH="/usr/include" +IL_LIB_PATH="/usr/lib" +LUA_INCLUDE_PATH="/usr/include/lua5.1" +LUA_LIB_PATH="/usr/lib" +OSX=no + +echo "Building the lua binding!" + +export SWIG_FEATURES="-I$IL_INCLUDE_PATH" +swig -lua DevIL.i +if [ $? -ne 0 ] ; then + echo "swig Failed to build the lua interface" + exit 1 +fi + +compile() { + gcc luadevil.c "$1" -o luadevil "-L$LUA_LIB_PATH" "-I$LUA_INCLUDE_PATH" "-I$IL_LIB_PATH" -lIL -lILU -lILUT -llua5.1 &>/dev/null + err=$? + if [ "$OSX" = "no" ] ; then + gcc -shared "$1" -o DevIL.so "-L$LUA_LIB_PATH" "-I$LUA_INCLUDE_PATH" "-I$IL_LIB_PATH" -lIL -lILU -lILUT &>/dev/null + else + gcc -bundle -undefined dynamic_lookup "$1" -o DevIL.so "-L$LUA_LIB_PATH" "-I$LUA_INCLUDE_PATH" "-I$IL_LIB_PATH" -lIL -lILU -lILUT &>/dev/null + fi + return $err +} + +compile DevIL_wrap.c +if [ $? -ne 0 ] ; then + echo 'Failed compilation' + echo 'On some platform the file malloc.h is not present and produces a compilation error' + echo -n 'it can be removed safely, try [y/n] ? ' + while read i ; do + if [ "$i" = "y" ] ; then + sed 's/\#include\ \//' < DevIL_wrap.c > DevIL_wrap.mod.c + compile "DevIL_wrap.mod.c" + if [ $? -ne 0 ] ; then + echo 'still failing...' + exit 2 + fi + exit 0 + elif [ "$i" = "n" ] ; then + echo 'ok, failing...' + exit 3 + else + echo 'Unknown command [y/n] ? ' + fi + done +fi + +echo "ok!" +exit 0 diff --git a/DevILSDK/include/IL/build-python b/DevILSDK/include/IL/build-python new file mode 100644 index 0000000..bb16b6f --- /dev/null +++ b/DevILSDK/include/IL/build-python @@ -0,0 +1,17 @@ +#! /bin/bash + +IL_INCLUDE_PATH="/usr/local/include" +IL_LIB_PATH="/usr/local/lib" +PYTHON_INCLUDE_PATH="/usr/include/python2.5" + +swig "-I$IL_INCLUDE_PATH" -python -interface DevIL DevIL.i +if [ $? -ne 0 ] ; then + echo Error while building the swig interface + exit 1 +fi + +gcc -shared "-I$IL_INCLUDE_PATH" "-I$PYTHON_INCLUDE_PATH" "-L$IL_LIB_PATH" -lIL -lILU -lILUT DevIL_wrap.c -o DevIL.so +if [ $? -ne 0 ] ; then + echo Error while compiling the python module +fi +echo "DevIL.py and DevIL.so are ready" diff --git a/DevILSDK/include/IL/config.h.win b/DevILSDK/include/IL/config.h.win new file mode 100644 index 0000000..659f4ca --- /dev/null +++ b/DevILSDK/include/IL/config.h.win @@ -0,0 +1,79 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#define IL_USE_PRAGMA_LIBS // Links to only the libraries that are requested. +#define IL_INLINE_ASM 1 // Define if you can support at least some ASM + +// Supported images formats (IL) + +// #define IL_NO_BLP +// #define IL_NO_BMP +// #define IL_NO_CUT +// #define IL_NO_CHEAD +// #define IL_NO_DCX +// #define IL_NO_DDS +// #define IL_NO_DICOM +// #define IL_NO_DOOM +// #define IL_NO_EXR +// #define IL_NO_FITS +// #define IL_NO_FTX +// #define IL_NO_GIF +// #define IL_NO_HDR +// #define IL_NO_ICO +// #define IL_NO_ICNS +// #define IL_NO_IWI +// #define IL_NO_JP2 +// #define IL_NO_JPG +// #define IL_NO_LCMS +// #define IL_NO_LIF +// #define IL_NO_MDL +// #define IL_NO_MNG +// #define IL_NO_PCD +// #define IL_NO_PCX +// #define IL_NO_PIC +// #define IL_NO_PIX +// #define IL_NO_PNG +// #define IL_NO_PNM +// #define IL_NO_PSD +// #define IL_NO_PSP +// #define IL_NO_PXR +// #define IL_NO_RAW +// #define IL_NO_ROT +// #define IL_NO_SGI +// #define IL_NO_SUN +// #define IL_NO_TGA +// #define IL_NO_TIF +// #define IL_NO_TPL +// #define IL_NO_WAL +// #define IL_NO_WDP +// #define IL_NO_XPM + +#define IL_USE_JPEGLIB_UNMODIFIED 1 +#define IL_USE_DXTC_NVIDIA +#define IL_USE_DXTC_SQUISH + +//#define IL_NO_GAMES + +/* Supported api (ilut) */ + + +// +// sorry just +// cant get this one to work under windows +// have disabled for the now +// +// will look at it some more later +// +// Kriss +// +#undef ILUT_USE_ALLEGRO + +#undef ILUT_USE_DIRECTX8 +#define ILUT_USE_DIRECTX9 +#define ILUT_USE_DIRECTX10 +#define ILUT_USE_OPENGL +#define ILUT_USE_SDL +#define ILUT_USE_WIN32 + + +#endif /* __CONFIG_H__ */ diff --git a/DevILSDK/include/IL/devil_cpp_wrapper.hpp b/DevILSDK/include/IL/devil_cpp_wrapper.hpp new file mode 100644 index 0000000..95c7f77 --- /dev/null +++ b/DevILSDK/include/IL/devil_cpp_wrapper.hpp @@ -0,0 +1,952 @@ +#ifndef DEVIL_CPP_WRAPPER_HPP +#define DEVIL_CPP_WRAPPER_HPP + +#include // Probably only have to #include this one + +class ilImage +{ +public: + ilImage(); + ilImage(ILconst_string); + ilImage(const ilImage &); + virtual ~ilImage(); + + ILboolean Load(ILconst_string); + ILboolean Load(ILconst_string, ILenum); + ILboolean Save(ILconst_string); + ILboolean Save(ILconst_string, ILenum); + + // ImageLib functions + ILboolean ActiveImage(ILuint); + ILboolean ActiveLayer(ILuint); + ILboolean ActiveMipmap(ILuint); + ILboolean Clear(void); + void ClearColour(ILclampf, ILclampf, ILclampf, ILclampf); + ILboolean Convert(ILenum); + ILboolean Copy(ILuint); + ILboolean Default(void); + ILboolean Flip(void); + ILboolean SwapColours(void); + ILboolean Resize(ILuint, ILuint, ILuint); + ILboolean TexImage(ILuint, ILuint, ILuint, ILubyte, ILenum, ILenum, void*); + + // Image handling + void Bind(void) const; + void Bind(ILuint); + void Close(void) { this->Delete(); } + void Delete(void); + void iGenBind(); + ILenum PaletteAlphaIndex(); + + // Image characteristics + ILuint Width(void); + ILuint Height(void); + ILuint Depth(void); + ILubyte Bpp(void); + ILubyte Bitpp(void); + ILenum PaletteType(void); + ILenum Format(void); + ILenum Type(void); + ILuint NumImages(void); + ILuint NumMipmaps(void); + ILuint GetId(void) const; + ILenum GetOrigin(void); + ILubyte *GetData(void); + ILubyte *GetPalette(void); + + // Rendering + ILuint BindImage(void); + ILuint BindImage(ILenum); + + // Operators + ilImage& operator = (ILuint); + ilImage& operator = (const ilImage &); + +protected: + ILuint Id; + +private: + static int ilStartUp(); + static ILboolean ilStartedUp; +}; + +// ensure that init is called exactly once +int ilImage::ilStartUp() +{ + ilInit(); + iluInit(); + //ilutInit(); + return true; +} +ILboolean ilImage::ilStartedUp = ilStartUp(); + +class ilFilters +{ +public: + static ILboolean Alienify(ilImage &); + static ILboolean BlurAvg(ilImage &, ILuint Iter); + static ILboolean BlurGaussian(ilImage &, ILuint Iter); + static ILboolean Contrast(ilImage &, ILfloat Contrast); + static ILboolean EdgeDetectE(ilImage &); + static ILboolean EdgeDetectP(ilImage &); + static ILboolean EdgeDetectS(ilImage &); + static ILboolean Emboss(ilImage &); + static ILboolean Gamma(ilImage &, ILfloat Gamma); + static ILboolean Negative(ilImage &); + static ILboolean Noisify(ilImage &, ILubyte Factor); + static ILboolean Pixelize(ilImage &, ILuint PixSize); + static ILboolean Saturate(ilImage &, ILfloat Saturation); + static ILboolean Saturate(ilImage &, ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation); + static ILboolean ScaleColours(ilImage &, ILfloat r, ILfloat g, ILfloat b); + static ILboolean Sharpen(ilImage &, ILfloat Factor, ILuint Iter); +}; + +#ifdef ILUT_USE_OPENGL +class ilOgl +{ +public: + static void Init(void); + static GLuint BindTex(ilImage &); + static ILboolean Upload(ilImage &, ILuint); + static GLuint Mipmap(ilImage &); + static ILboolean Screen(void); + static ILboolean Screenie(void); +}; +#endif//ILUT_USE_OPENGL + + +#ifdef ILUT_USE_ALLEGRO +class ilAlleg +{ +public: + static void Init(void); + static BITMAP *Convert(ilImage &); +}; +#endif//ILUT_USE_ALLEGRO + + +#ifdef ILUT_USE_WIN32 +class ilWin32 +{ +public: + static void Init(void); + static HBITMAP Convert(ilImage &); + static ILboolean GetClipboard(ilImage &); + static void GetInfo(ilImage &, BITMAPINFO *Info); + static ILubyte *GetPadData(ilImage &); + static HPALETTE GetPal(ilImage &); + static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType); + static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType, ILenum Type); + static ILboolean SetClipboard(ilImage &); +}; +#endif//ILUT_USE_WIN32 + + +class ilValidate +{ +public: + static ILboolean Valid(ILenum, ILconst_string); + static ILboolean Valid(ILenum, FILE *); + static ILboolean Valid(ILenum, void *, ILuint); + +protected: + +private: + +}; + +class ilState +{ +public: + static ILboolean Disable(ILenum); + static ILboolean Enable(ILenum); + static void Get(ILenum, ILboolean &); + static void Get(ILenum, ILint &); + static ILboolean GetBool(ILenum); + static ILint GetInt(ILenum); + static const char *GetString(ILenum); + static ILboolean IsDisabled(ILenum); + static ILboolean IsEnabled(ILenum); + static ILboolean Origin(ILenum); + static void Pop(void); + static void Push(ILuint); + +protected: + +private: + +}; + + +class ilError +{ +public: + static void Check(void (*Callback)(const char*)); + static void Check(void (*Callback)(ILenum)); + static ILenum Get(void); + static const char *String(void); + static const char *String(ILenum); + +protected: + +private: + +}; + + +// +// ILIMAGE +// +ilImage::ilImage() +{ + this->Id = 0; + //this->iStartUp(); // This was commented out, but it needs to be somewhere... + this->iGenBind(); + return; +} + + +ilImage::ilImage(ILconst_string FileName) +{ + this->Id = 0; + //this->iStartUp(); // This was commented out, but it needs to be somewhere... + this->iGenBind(); + ilLoadImage(FileName); + return; +} + + +ilImage::ilImage(const ilImage &Image) +{ + this->Id = 0; + // this->iStartUp(); + this->iGenBind(); + *this = Image; + return; +} + + +ilImage::~ilImage() +{ + if (this->Id) + ilDeleteImages(1, &this->Id); + this->Id = 0; + return; +} + + +ILboolean ilImage::Load(ILconst_string FileName) +{ + this->iGenBind(); + return ilLoadImage(FileName); +} + + +ILboolean ilImage::Load(ILconst_string FileName, ILenum Type) +{ + this->iGenBind(); + return ilLoad(Type, FileName); +} + + +ILboolean ilImage::Save(ILconst_string FileName) +{ + this->iGenBind(); + return ilSaveImage(FileName); +} + + +ILboolean ilImage::Save(ILconst_string FileName, ILenum Type) +{ + this->iGenBind(); + return ilSave(Type, FileName); +} + + + +// +// ImageLib functions +// +ILboolean ilImage::ActiveImage(ILuint Number) +{ + if (this->Id) { + this->Bind(); + return ilActiveImage(Number); + } + return IL_FALSE; +} + + +ILboolean ilImage::ActiveLayer(ILuint Number) +{ + if (this->Id) { + this->Bind(); + return ilActiveLayer(Number); + } + return IL_FALSE; +} + + +ILboolean ilImage::ActiveMipmap(ILuint Number) +{ + if (this->Id) { + this->Bind(); + return ilActiveMipmap(Number); + } + return IL_FALSE; +} + + +ILboolean ilImage::Clear() +{ + if (this->Id) { + this->Bind(); + return ilClearImage(); + } + return IL_FALSE; +} + + +void ilImage::ClearColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha) +{ + ilClearColour(Red, Green, Blue, Alpha); + return; +} + + +ILboolean ilImage::Convert(ILenum NewFormat) +{ + if (this->Id) { + this->Bind(); + return ilConvertImage(NewFormat, IL_UNSIGNED_BYTE); + } + return IL_FALSE; +} + + +ILboolean ilImage::Copy(ILuint Src) +{ + if (this->Id) { + this->Bind(); + return ilCopyImage(Src); + } + return IL_FALSE; +} + + +ILboolean ilImage::Default() +{ + if (this->Id) { + this->Bind(); + return ilDefaultImage(); + } + return IL_FALSE; +} + + +ILboolean ilImage::Flip() +{ + if (this->Id) { + this->Bind(); + return iluFlipImage(); + } + return IL_FALSE; +} + + +ILboolean ilImage::SwapColours() +{ + if (this->Id) { + this->Bind(); + return iluSwapColours(); + } + return IL_FALSE; +} + + +ILboolean ilImage::Resize(ILuint Width, ILuint Height, ILuint Depth) +{ + if (this->Id) { + this->Bind(); + return iluScale(Width, Height, Depth); + } + return IL_FALSE; +} + + +ILboolean ilImage::TexImage(ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data) +{ + if (this->Id) { + this->Bind(); + return ilTexImage(Width, Height, Depth, Bpp, Format, Type, Data); + } + return IL_FALSE; +} + + + +// +// Image handling +// +void ilImage::Bind() const +{ + if (this->Id) + ilBindImage(this->Id); + return; +} + +// Note: Behaviour may be changed! +void ilImage::Bind(ILuint Image) +{ + if (this->Id == Image) + return; + this->Delete(); // Should we delete it? + this->Id = Image; + ilBindImage(this->Id); + return; +} + + +void ilImage::Delete() +{ + if (this->Id == 0) + return; + ilDeleteImages(1, &this->Id); + this->Id = 0; + return; +} + + + + +// +// Image characteristics +// +ILuint ilImage::Width() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_IMAGE_WIDTH); + } + return 0; +} + + +ILuint ilImage::Height() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_IMAGE_HEIGHT); + } + return 0; +} + +ILuint ilImage::Depth() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_IMAGE_DEPTH); + } + return 0; +} + +ILubyte ilImage::Bpp() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL); + } + return 0; +} + +ILubyte ilImage::Bitpp() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_IMAGE_BITS_PER_PIXEL); + } + return 0; +} + +ILenum ilImage::Format() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_IMAGE_FORMAT); + } + return 0; +} + +ILenum ilImage::PaletteType() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_PALETTE_TYPE); + } + return 0; +} + +ILenum ilImage::PaletteAlphaIndex() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_PNG_ALPHA_INDEX); + } + return 0; +} + +ILenum ilImage::Type() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_IMAGE_TYPE); + } + return 0; +} + +ILenum ilImage::NumImages() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_NUM_IMAGES); + } + return 0; +} + +ILenum ilImage::NumMipmaps() +{ + if (this->Id) { + this->Bind(); + return ilGetInteger(IL_NUM_MIPMAPS); + } + return 0; +} + +ILuint ilImage::GetId() const +{ + return this->Id; +} + +ILenum ilImage::GetOrigin(void) +{ + ILinfo Info; + + if (this->Id) { + this->Bind(); + iluGetImageInfo(&Info); + return Info.Origin; + } + return 0; +} + +ILubyte* ilImage::GetData() +{ + if (this->Id) { + this->Bind(); + return ilGetData(); + } + return 0; +} + +ILubyte* ilImage::GetPalette() +{ + if (this->Id) { + this->Bind(); + return ilGetPalette(); + } + return 0; +} + +// +// Private members +// +/*void ilImage::iStartUp() +{ + ilInit(); + iluInit(); + ilutInit(); + return; +}*/ + +void ilImage::iGenBind() +{ + if (this->Id == 0) { + ilGenImages(1, &this->Id); + } + ilBindImage(this->Id); + return; +} + +// +// Operators +// +ilImage& ilImage::operator = (ILuint Image) +{ + if (this->Id == 0) + this->Id = Image; + else { + this->Bind(); + ilCopyImage(Image); + } + + return *this; +} + +ilImage& ilImage::operator = (const ilImage &Image) +{ + if (Id == 0) + Id = Image.GetId(); + else { + Bind(); + ilCopyImage(Image.GetId()); + } + + return *this; +} + +// +// ILFILTERS +// +ILboolean ilFilters::Alienify(ilImage &Image) +{ + Image.Bind(); + return iluAlienify(); +} + +ILboolean ilFilters::BlurAvg(ilImage &Image, ILuint Iter) +{ + Image.Bind(); + return iluBlurAvg(Iter); +} + +ILboolean ilFilters::BlurGaussian(ilImage &Image, ILuint Iter) +{ + Image.Bind(); + return iluBlurGaussian(Iter); +} + +ILboolean ilFilters::Contrast(ilImage &Image, ILfloat Contrast) +{ + Image.Bind(); + return iluContrast(Contrast); +} + +ILboolean ilFilters::EdgeDetectE(ilImage &Image) +{ + Image.Bind(); + return iluEdgeDetectP(); +} + +ILboolean ilFilters::EdgeDetectP(ilImage &Image) +{ + Image.Bind(); + return iluEdgeDetectP(); +} + +ILboolean ilFilters::EdgeDetectS(ilImage &Image) +{ + Image.Bind(); + return iluEdgeDetectS(); +} + +ILboolean ilFilters::Emboss(ilImage &Image) +{ + Image.Bind(); + return iluEmboss(); +} + +ILboolean ilFilters::Gamma(ilImage &Image, ILfloat Gamma) +{ + Image.Bind(); + return iluGammaCorrect(Gamma); +} + +ILboolean ilFilters::Negative(ilImage &Image) +{ + Image.Bind(); + return iluNegative(); +} + +ILboolean ilFilters::Noisify(ilImage &Image, ILubyte Factor) +{ + Image.Bind(); + return iluNoisify(Factor); +} + +ILboolean ilFilters::Pixelize(ilImage &Image, ILuint PixSize) +{ + Image.Bind(); + return iluPixelize(PixSize); +} + +ILboolean ilFilters::Saturate(ilImage &Image, ILfloat Saturation) +{ + Image.Bind(); + return iluSaturate1f(Saturation); +} + +ILboolean ilFilters::Saturate(ilImage &Image, ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation) +{ + Image.Bind(); + return iluSaturate4f(r, g, b, Saturation); +} + +ILboolean ilFilters::ScaleColours(ilImage &Image, ILfloat r, ILfloat g, ILfloat b) +{ + Image.Bind(); + return iluScaleColours(r, g, b); +} + + +ILboolean ilFilters::Sharpen(ilImage &Image, ILfloat Factor, ILuint Iter) +{ + Image.Bind(); + return iluSharpen(Factor, Iter); +} + + +// +// ILOPENGL +// +#ifdef ILUT_USE_OPENGL +void ilOgl::Init() +{ + ilutRenderer(ILUT_OPENGL); + return; +} + + +GLuint ilOgl::BindTex(ilImage &Image) +{ + Image.Bind(); + return ilutGLBindTexImage(); +} + +ILboolean ilOgl::Upload(ilImage &Image, ILuint Level) +{ + Image.Bind(); + return ilutGLTexImage(Level); +} + + +GLuint ilOgl::Mipmap(ilImage &Image) +{ + Image.Bind(); + return ilutGLBuildMipmaps(); +} + +ILboolean ilOgl::Screen() +{ + return ilutGLScreen(); +} + + +ILboolean ilOgl::Screenie() +{ + return ilutGLScreenie(); +} +#endif//ILUT_USE_OPENGL + +// +// ILALLEGRO +// +#ifdef ILUT_USE_ALLEGRO +void ilAlleg::Init() +{ + ilutRenderer(IL_ALLEGRO); + return; +} + +BITMAP *ilAlleg::Convert(ilImage &Image, PALETTE Pal) +{ + Image.Bind(); + return ilutConvertToAlleg(Pal); +} +#endif//ILUT_USE_ALLEGRO + +// +// ILWIN32 +// +#ifdef ILUT_USE_WIN32 +void ilWin32::Init() +{ + ilutRenderer(ILUT_WIN32); + return; +} + +HBITMAP ilWin32::Convert(ilImage &Image) +{ + Image.Bind(); + return ilutConvertToHBitmap(GetDC(NULL)); +} + +ILboolean ilWin32::GetClipboard(ilImage &Image) +{ + Image.Bind(); + return ilutGetWinClipboard(); +} + +void ilWin32::GetInfo(ilImage &Image, BITMAPINFO *Info) +{ + Image.Bind(); + ilutGetBmpInfo(Info); + return; +} + +ILubyte* ilWin32::GetPadData(ilImage &Image) +{ + Image.Bind(); + return ilutGetPaddedData(); +} + +HPALETTE ilWin32::GetPal(ilImage &Image) +{ + Image.Bind(); + return ilutGetHPal(); +} + +ILboolean ilWin32::GetResource(ilImage &Image, HINSTANCE hInst, ILint ID, char *ResourceType) +{ + Image.Bind(); + return ilutLoadResource(hInst, ID, ResourceType, IL_TYPE_UNKNOWN); +} + +ILboolean ilWin32::GetResource(ilImage &Image, HINSTANCE hInst, ILint ID, char *ResourceType, ILenum Type) +{ + Image.Bind(); + return ilutLoadResource(hInst, ID, ResourceType, Type); +} + +ILboolean ilWin32::SetClipboard(ilImage &Image) +{ + Image.Bind(); + return ilutSetWinClipboard(); +} +#endif//ILUT_USE_WIN32 + +// +// ILVALIDATE +// +ILboolean ilValidate::Valid(ILenum Type, ILconst_string FileName) +{ + return ilIsValid(Type, FileName); +} + +ILboolean ilValidate::Valid(ILenum Type, FILE *File) +{ + return ilIsValidF(Type, File); +} + +ILboolean ilValidate::Valid(ILenum Type, void *Lump, ILuint Size) +{ + return ilIsValidL(Type, Lump, Size); +} + +// +// ILSTATE +// +ILboolean ilState::Disable(ILenum State) +{ + return ilDisable(State); +} + +ILboolean ilState::Enable(ILenum State) +{ + return ilEnable(State); +} + +void ilState::Get(ILenum Mode, ILboolean &Param) +{ + ilGetBooleanv(Mode, &Param); + return; +} + +void ilState::Get(ILenum Mode, ILint &Param) +{ + ilGetIntegerv(Mode, &Param); + return; +} + +ILboolean ilState::GetBool(ILenum Mode) +{ + return ilGetBoolean(Mode); +} + +ILint ilState::GetInt(ILenum Mode) +{ + return ilGetInteger(Mode); +} + +const char *ilState::GetString(ILenum StringName) +{ + return ilGetString(StringName); +} + +ILboolean ilState::IsDisabled(ILenum Mode) +{ + return ilIsDisabled(Mode); +} + +ILboolean ilState::IsEnabled(ILenum Mode) +{ + return ilIsEnabled(Mode); +} + +ILboolean ilState::Origin(ILenum Mode) +{ + return ilOriginFunc(Mode); +} + +void ilState::Pop() +{ + ilPopAttrib(); + return; +} + +void ilState::Push(ILuint Bits = IL_ALL_ATTRIB_BITS) +{ + ilPushAttrib(Bits); + return; +} + +// +// ILERROR +// +void ilError::Check(void (*Callback)(const char*)) +{ + static ILenum Error; + + while ((Error = ilGetError()) != IL_NO_ERROR) { + Callback(iluErrorString(Error)); + } + + return; +} + +void ilError::Check(void (*Callback)(ILenum)) +{ + static ILenum Error; + + while ((Error = ilGetError()) != IL_NO_ERROR) { + Callback(Error); + } + + return; +} + +ILenum ilError::Get() +{ + return ilGetError(); +} + +const char *ilError::String() +{ + return iluErrorString(ilGetError()); +} + +const char *ilError::String(ILenum Error) +{ + return iluErrorString(Error); +} + +#endif// DEVIL_CPP_WRAPPER_HPP diff --git a/DevILSDK/include/IL/devil_internal_exports.h b/DevILSDK/include/IL/devil_internal_exports.h new file mode 100644 index 0000000..fd07d06 --- /dev/null +++ b/DevILSDK/include/IL/devil_internal_exports.h @@ -0,0 +1,159 @@ +//----------------------------------------------------------------------------- +// +// ImageLib Sources +// Copyright (C) 2000-2017 by Denton Woods +// Last modified: 01/06/2009 +// +// Filename: IL/devil_internal_exports.h +// +// Description: Internal stuff for DevIL (IL, ILU and ILUT) +// +//----------------------------------------------------------------------------- + +#ifndef IL_EXPORTS_H +#define IL_EXPORTS_H + +#include "IL/il.h" + +#ifdef DEBUG + #include +#else + #define assert(x) +#endif + + +#ifdef NOINLINE + // No inlining. Treat all inline funcs as static. + // Functions will be replicated in all translation units + // use them. + #define STATIC_INLINE static +#else + #if defined(_MSC_VER) && !defined(__cplusplus) + // MSVC compiler uses __inline when compiling C (not C++) + #define STATIC_INLINE static __inline + #else + // Portable across C99, GNU89, C++... + #define STATIC_INLINE static inline + #endif +#endif // NOINLINE + + +#ifdef __cplusplus +extern "C" { +#endif + +#define IL_MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define IL_MIN(a,b) (((a) < (b)) ? (a) : (b)) + + +//! Basic Palette struct +typedef struct ILpal +{ + ILubyte* Palette; //!< the image palette (if any) + ILuint PalSize; //!< size of the palette (in bytes) + ILenum PalType; //!< the palette types in il.h (0x0500 range) +} ILpal; + + +//! The Fundamental Image structure +/*! Every bit of information about an image is stored in this internal structure.*/ +typedef struct ILimage +{ + ILuint Width; //!< the image's width + ILuint Height; //!< the image's height + ILuint Depth; //!< the image's depth + ILubyte Bpp; //!< bytes per pixel (now number of channels) + ILubyte Bpc; //!< bytes per channel + ILuint Bps; //!< bytes per scanline (components for IL) + ILubyte* Data; //!< the image data + ILuint SizeOfData; //!< the total size of the data (in bytes) + ILuint SizeOfPlane; //!< SizeOfData in a 2d image, size of each plane slice in a 3d image (in bytes) + ILenum Format; //!< image format (in IL enum style) + ILenum Type; //!< image type (in IL enum style) + ILenum Origin; //!< origin of the image + ILpal Pal; //!< palette details + ILuint Duration; //!< length of the time to display this "frame" + ILenum CubeFlags; //!< cube map flags for sides present in chain + struct ILimage* Mipmaps; //!< mipmapped versions of this image terminated by a NULL - usu. NULL + struct ILimage* Next; //!< next image in the chain - usu. NULL + struct ILimage* Faces; //!< next cubemap face in the chain - usu. NULL + struct ILimage* Layers; //!< subsequent layers in the chain - usu. NULL + ILuint* AnimList; //!< animation list + ILuint AnimSize; //!< animation list size + void* Profile; //!< colour profile + ILuint ProfileSize; //!< colour profile size + ILuint OffX; //!< x-offset of the image + ILuint OffY; //!< y-offset of the image + ILubyte* DxtcData; //!< compressed data + ILenum DxtcFormat; //!< compressed data format + ILuint DxtcSize; //!< compressed data size +} ILimage; + + +// Memory functions +ILAPI void* ILAPIENTRY ialloc(const ILsizei Size); +ILAPI void ILAPIENTRY ifree(const void *Ptr); +ILAPI void* ILAPIENTRY icalloc(const ILsizei Size, const ILsizei Num); +#ifdef ALTIVEC_GCC +ILAPI void* ILAPIENTRY ivec_align_buffer(void *buffer, const ILuint size); +#endif + +// Internal library functions in IL +ILAPI ILimage* ILAPIENTRY ilGetCurImage(void); +ILAPI void ILAPIENTRY ilSetCurImage(ILimage *Image); +ILAPI void ILAPIENTRY ilSetError(ILenum Error); +ILAPI void ILAPIENTRY ilSetPal(ILpal *Pal); + +// +// Utility functions +// +ILAPI ILubyte ILAPIENTRY ilGetBppFormat(ILenum Format); +ILAPI ILenum ILAPIENTRY ilGetFormatBpp(ILubyte Bpp); +ILAPI ILubyte ILAPIENTRY ilGetBpcType(ILenum Type); +ILAPI ILenum ILAPIENTRY ilGetTypeBpc(ILubyte Bpc); +ILAPI ILubyte ILAPIENTRY ilGetBppPal(ILenum PalType); +ILAPI ILenum ILAPIENTRY ilGetPalBaseType(ILenum PalType); +ILAPI ILuint ILAPIENTRY ilNextPower2(ILuint Num); +ILAPI ILenum ILAPIENTRY ilTypeFromExt(ILconst_string FileName); +ILAPI void ILAPIENTRY ilReplaceCurImage(ILimage *Image); +ILAPI void ILAPIENTRY iMemSwap(ILubyte *, ILubyte *, const ILuint); + +// +// Image functions +// +ILAPI void ILAPIENTRY iBindImageTemp (void); +ILAPI ILboolean ILAPIENTRY ilClearImage_ (ILimage *Image); +ILAPI void ILAPIENTRY ilCloseImage (ILimage *Image); +ILAPI void ILAPIENTRY ilClosePal (ILpal *Palette); +ILAPI ILpal* ILAPIENTRY iCopyPal (void); +ILAPI ILboolean ILAPIENTRY ilCopyImageAttr (ILimage *Dest, ILimage *Src); +ILAPI ILimage* ILAPIENTRY ilCopyImage_ (ILimage *Src); +ILAPI void ILAPIENTRY ilGetClear (void *Colours, ILenum Format, ILenum Type); +ILAPI ILuint ILAPIENTRY ilGetCurName (void); +ILAPI ILboolean ILAPIENTRY ilIsValidPal (ILpal *Palette); +ILAPI ILimage* ILAPIENTRY ilNewImage (ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILubyte Bpc); +ILAPI ILimage* ILAPIENTRY ilNewImageFull (ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); +ILAPI ILboolean ILAPIENTRY ilInitImage (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); +ILAPI ILboolean ILAPIENTRY ilResizeImage (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILubyte Bpc); +ILAPI ILboolean ILAPIENTRY ilTexImage_ (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); +ILAPI ILboolean ILAPIENTRY ilTexImageSurface_(ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); +ILAPI ILboolean ILAPIENTRY ilTexSubImage_ (ILimage *Image, void *Data); +ILAPI void* ILAPIENTRY ilConvertBuffer (ILuint SizeOfData, ILenum SrcFormat, ILenum DestFormat, ILenum SrcType, ILenum DestType, ILpal *SrcPal, void *Buffer); +ILAPI ILimage* ILAPIENTRY iConvertImage (ILimage *Image, ILenum DestFormat, ILenum DestType); +ILAPI ILpal* ILAPIENTRY iConvertPal (ILpal *Pal, ILenum DestFormat); +ILAPI ILubyte* ILAPIENTRY iGetFlipped (ILimage *Image); +ILAPI ILboolean ILAPIENTRY iMirror(); +ILAPI void ILAPIENTRY iFlipBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num); +ILubyte* iFlipNewBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num); +ILAPI void ILAPIENTRY iGetIntegervImage(ILimage *Image, ILenum Mode, ILint *Param); + +// Internal library functions in ILU +ILAPI ILimage* ILAPIENTRY iluRotate_(ILimage *Image, ILfloat Angle); +ILAPI ILimage* ILAPIENTRY iluRotate3D_(ILimage *Image, ILfloat x, ILfloat y, ILfloat z, ILfloat Angle); +ILAPI ILimage* ILAPIENTRY iluScale_(ILimage *Image, ILuint Width, ILuint Height, ILuint Depth); + +#ifdef __cplusplus +} +#endif + +#endif//IL_EXPORTS_H diff --git a/DevILSDK/include/IL/il.h b/DevILSDK/include/IL/il.h new file mode 100644 index 0000000..47dfcd7 --- /dev/null +++ b/DevILSDK/include/IL/il.h @@ -0,0 +1,645 @@ +//----------------------------------------------------------------------------- +// +// ImageLib Sources +// Copyright (C) 2000-2017 by Denton Woods +// Last modified: 03/07/2009 +// +// Filename: IL/il.h +// +// Description: The main include file for DevIL +// +//----------------------------------------------------------------------------- + +// Doxygen comment +/*! \file il.h + The main include file for DevIL +*/ + +#ifndef __il_h_ +#ifndef __IL_H__ + +#define __il_h_ +#define __IL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +//this define controls if floats and doubles are clamped to [0..1] +//during conversion. It takes a little more time, but it is the correct +//way of doing this. If you are sure your floats are always valid, +//you can undefine this value... +#define CLAMP_HALF 1 +#define CLAMP_FLOATS 1 +#define CLAMP_DOUBLES 1 + +/*#ifdef _WIN32_WCE + #define IL_NO_EXR + #define IL_NO_GIF + #define IL_NO_JP2 + #define IL_NO_JPG + #define IL_NO_MNG + #define IL_NO_PNG + #define IL_NO_TIF + #define IL_NO_LCMS +#endif //_WIN32_WCE + +#ifdef DJGPP + #define IL_NO_EXR + #define IL_NO_GIF + #define IL_NO_JP2 + #define IL_NO_JPG + #define IL_NO_MNG + #define IL_NO_PNG + #define IL_NO_TIF + #define IL_NO_LCMS +#endif //DJGPP*/ + +#ifdef _WIN32 + #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) + #if defined(_MSC_VER) || defined(__BORLANDC__) + #pragma comment(lib, "DevIL.lib") + #endif + #endif +#endif + +#if defined(RESTRICT_KEYWORD) && !defined(__cplusplus) +#define RESTRICT restrict +#define CONST_RESTRICT const restrict +#else +#define RESTRICT +#define CONST_RESTRICT const +#endif + +#include + +typedef unsigned int ILenum; +typedef unsigned char ILboolean; +typedef unsigned int ILbitfield; +typedef signed char ILbyte; +typedef signed short ILshort; +typedef int ILint; +typedef size_t ILsizei; +typedef unsigned char ILubyte; +typedef unsigned short ILushort; +typedef unsigned int ILuint; +typedef float ILfloat; +typedef float ILclampf; +typedef double ILdouble; +typedef double ILclampd; + +#ifdef _MSC_VER +typedef __int64 ILint64; +typedef unsigned __int64 ILuint64; +#else +typedef long long int ILint64; +typedef long long unsigned int ILuint64; +#endif + + +#include +#ifdef _UNICODE + #ifndef _WIN32_WCE + #include + #endif + //if we use a define instead of a typedef, + //ILconst_string works as intended + #define ILchar wchar_t + #define ILstring wchar_t* + #define ILconst_string wchar_t const * +#else + //if we use a define instead of a typedef, + //ILconst_string works as intended + #define ILchar char + #define ILstring char* + #define ILconst_string char const * +#endif //_UNICODE + +#define IL_FALSE 0 +#define IL_TRUE 1 + +// Matches OpenGL's right now. +//! Data formats \link Formats Formats\endlink +#define IL_COLOUR_INDEX 0x1900 +#define IL_COLOR_INDEX 0x1900 +#define IL_ALPHA 0x1906 +#define IL_RGB 0x1907 +#define IL_RGBA 0x1908 +#define IL_BGR 0x80E0 +#define IL_BGRA 0x80E1 +#define IL_LUMINANCE 0x1909 +#define IL_LUMINANCE_ALPHA 0x190A + +//! Data types \link Types Types\endlink +#define IL_BYTE 0x1400 +#define IL_UNSIGNED_BYTE 0x1401 +#define IL_SHORT 0x1402 +#define IL_UNSIGNED_SHORT 0x1403 +#define IL_INT 0x1404 +#define IL_UNSIGNED_INT 0x1405 +#define IL_FLOAT 0x1406 +#define IL_DOUBLE 0x140A +#define IL_HALF 0x140B + + +#define IL_MAX_BYTE SCHAR_MAX +#define IL_MAX_UNSIGNED_BYTE UCHAR_MAX +#define IL_MAX_SHORT SHRT_MAX +#define IL_MAX_UNSIGNED_SHORT USHRT_MAX +#define IL_MAX_INT INT_MAX +#define IL_MAX_UNSIGNED_INT UINT_MAX + +#define IL_LIMIT(x,m,M) (xM?M:x)) +#define IL_CLAMP(x) IL_LIMIT(x,0,1) + +#define IL_VENDOR 0x1F00 +#define IL_LOAD_EXT 0x1F01 +#define IL_SAVE_EXT 0x1F02 + + +// +// IL-specific #define's +// + +#define IL_VERSION_1_8_0 1 +#define IL_VERSION 180 + + +// Attribute Bits +#define IL_ORIGIN_BIT 0x00000001 +#define IL_FILE_BIT 0x00000002 +#define IL_PAL_BIT 0x00000004 +#define IL_FORMAT_BIT 0x00000008 +#define IL_TYPE_BIT 0x00000010 +#define IL_COMPRESS_BIT 0x00000020 +#define IL_LOADFAIL_BIT 0x00000040 +#define IL_FORMAT_SPECIFIC_BIT 0x00000080 +#define IL_ALL_ATTRIB_BITS 0x000FFFFF + + +// Palette types +#define IL_PAL_NONE 0x0400 +#define IL_PAL_RGB24 0x0401 +#define IL_PAL_RGB32 0x0402 +#define IL_PAL_RGBA32 0x0403 +#define IL_PAL_BGR24 0x0404 +#define IL_PAL_BGR32 0x0405 +#define IL_PAL_BGRA32 0x0406 + + +// Image types +#define IL_TYPE_UNKNOWN 0x0000 +#define IL_BMP 0x0420 //!< Microsoft Windows Bitmap - .bmp extension +#define IL_CUT 0x0421 //!< Dr. Halo - .cut extension +#define IL_DOOM 0x0422 //!< DooM walls - no specific extension +#define IL_DOOM_FLAT 0x0423 //!< DooM flats - no specific extension +#define IL_ICO 0x0424 //!< Microsoft Windows Icons and Cursors - .ico and .cur extensions +#define IL_JPG 0x0425 //!< JPEG - .jpg, .jpe and .jpeg extensions +#define IL_JFIF 0x0425 //!< +#define IL_ILBM 0x0426 //!< Amiga IFF (FORM ILBM) - .iff, .ilbm, .lbm extensions +#define IL_PCD 0x0427 //!< Kodak PhotoCD - .pcd extension +#define IL_PCX 0x0428 //!< ZSoft PCX - .pcx extension +#define IL_PIC 0x0429 //!< PIC - .pic extension +#define IL_PNG 0x042A //!< Portable Network Graphics - .png extension +#define IL_PNM 0x042B //!< Portable Any Map - .pbm, .pgm, .ppm and .pnm extensions +#define IL_SGI 0x042C //!< Silicon Graphics - .sgi, .bw, .rgb and .rgba extensions +#define IL_TGA 0x042D //!< TrueVision Targa File - .tga, .vda, .icb and .vst extensions +#define IL_TIF 0x042E //!< Tagged Image File Format - .tif and .tiff extensions +#define IL_CHEAD 0x042F //!< C-Style Header - .h extension +#define IL_RAW 0x0430 //!< Raw Image Data - any extension +#define IL_MDL 0x0431 //!< Half-Life Model Texture - .mdl extension +#define IL_WAL 0x0432 //!< Quake 2 Texture - .wal extension +#define IL_LIF 0x0434 //!< Homeworld Texture - .lif extension +#define IL_MNG 0x0435 //!< Multiple-image Network Graphics - .mng extension +#define IL_JNG 0x0435 //!< +#define IL_GIF 0x0436 //!< Graphics Interchange Format - .gif extension +#define IL_DDS 0x0437 //!< DirectDraw Surface - .dds extension +#define IL_DCX 0x0438 //!< ZSoft Multi-PCX - .dcx extension +#define IL_PSD 0x0439 //!< Adobe PhotoShop - .psd extension +#define IL_EXIF 0x043A //!< +#define IL_PSP 0x043B //!< PaintShop Pro - .psp extension +#define IL_PIX 0x043C //!< PIX - .pix extension +#define IL_PXR 0x043D //!< Pixar - .pxr extension +#define IL_XPM 0x043E //!< X Pixel Map - .xpm extension +#define IL_HDR 0x043F //!< Radiance High Dynamic Range - .hdr extension +#define IL_ICNS 0x0440 //!< Macintosh Icon - .icns extension +#define IL_JP2 0x0441 //!< Jpeg 2000 - .jp2 extension +#define IL_EXR 0x0442 //!< OpenEXR - .exr extension +#define IL_WDP 0x0443 //!< Microsoft HD Photo - .wdp and .hdp extension +#define IL_VTF 0x0444 //!< Valve Texture Format - .vtf extension +#define IL_WBMP 0x0445 //!< Wireless Bitmap - .wbmp extension +#define IL_SUN 0x0446 //!< Sun Raster - .sun, .ras, .rs, .im1, .im8, .im24 and .im32 extensions +#define IL_IFF 0x0447 //!< Interchange File Format - .iff extension +#define IL_TPL 0x0448 //!< Gamecube Texture - .tpl extension +#define IL_FITS 0x0449 //!< Flexible Image Transport System - .fit and .fits extensions +#define IL_DICOM 0x044A //!< Digital Imaging and Communications in Medicine (DICOM) - .dcm and .dicom extensions +#define IL_IWI 0x044B //!< Call of Duty Infinity Ward Image - .iwi extension +#define IL_BLP 0x044C //!< Blizzard Texture Format - .blp extension +#define IL_FTX 0x044D //!< Heavy Metal: FAKK2 Texture - .ftx extension +#define IL_ROT 0x044E //!< Homeworld 2 - Relic Texture - .rot extension +#define IL_TEXTURE 0x044F //!< Medieval II: Total War Texture - .texture extension +#define IL_DPX 0x0450 //!< Digital Picture Exchange - .dpx extension +#define IL_UTX 0x0451 //!< Unreal (and Unreal Tournament) Texture - .utx extension +#define IL_MP3 0x0452 //!< MPEG-1 Audio Layer 3 - .mp3 extension +#define IL_KTX 0x0453 //!< Khronos Texture - .ktx extension + + +#define IL_JASC_PAL 0x0475 //!< PaintShop Pro Palette + + +// Error Types +#define IL_NO_ERROR 0x0000 +#define IL_INVALID_ENUM 0x0501 +#define IL_OUT_OF_MEMORY 0x0502 +#define IL_FORMAT_NOT_SUPPORTED 0x0503 +#define IL_INTERNAL_ERROR 0x0504 +#define IL_INVALID_VALUE 0x0505 +#define IL_ILLEGAL_OPERATION 0x0506 +#define IL_ILLEGAL_FILE_VALUE 0x0507 +#define IL_INVALID_FILE_HEADER 0x0508 +#define IL_INVALID_PARAM 0x0509 +#define IL_COULD_NOT_OPEN_FILE 0x050A +#define IL_INVALID_EXTENSION 0x050B +#define IL_FILE_ALREADY_EXISTS 0x050C +#define IL_OUT_FORMAT_SAME 0x050D +#define IL_STACK_OVERFLOW 0x050E +#define IL_STACK_UNDERFLOW 0x050F +#define IL_INVALID_CONVERSION 0x0510 +#define IL_BAD_DIMENSIONS 0x0511 +#define IL_FILE_READ_ERROR 0x0512 // 05/12/2002: Addition by Sam. +#define IL_FILE_WRITE_ERROR 0x0512 + +#define IL_LIB_GIF_ERROR 0x05E1 +#define IL_LIB_JPEG_ERROR 0x05E2 +#define IL_LIB_PNG_ERROR 0x05E3 +#define IL_LIB_TIFF_ERROR 0x05E4 +#define IL_LIB_MNG_ERROR 0x05E5 +#define IL_LIB_JP2_ERROR 0x05E6 +#define IL_LIB_EXR_ERROR 0x05E7 +#define IL_UNKNOWN_ERROR 0x05FF + + +// Origin Definitions +#define IL_ORIGIN_SET 0x0600 +#define IL_ORIGIN_LOWER_LEFT 0x0601 +#define IL_ORIGIN_UPPER_LEFT 0x0602 +#define IL_ORIGIN_MODE 0x0603 + + +// Format and Type Mode Definitions +#define IL_FORMAT_SET 0x0610 +#define IL_FORMAT_MODE 0x0611 +#define IL_TYPE_SET 0x0612 +#define IL_TYPE_MODE 0x0613 + + +// File definitions +#define IL_FILE_OVERWRITE 0x0620 +#define IL_FILE_MODE 0x0621 + + +// Palette definitions +#define IL_CONV_PAL 0x0630 + + +// Load fail definitions +#define IL_DEFAULT_ON_FAIL 0x0632 + + +// Key colour and alpha definitions +#define IL_USE_KEY_COLOUR 0x0635 +#define IL_USE_KEY_COLOR 0x0635 +#define IL_BLIT_BLEND 0x0636 + + +// Interlace definitions +#define IL_SAVE_INTERLACED 0x0639 +#define IL_INTERLACE_MODE 0x063A + + +// Quantization definitions +#define IL_QUANTIZATION_MODE 0x0640 +#define IL_WU_QUANT 0x0641 +#define IL_NEU_QUANT 0x0642 +#define IL_NEU_QUANT_SAMPLE 0x0643 +#define IL_MAX_QUANT_INDEXS 0x0644 //XIX : ILint : Maximum number of colors to reduce to, default of 256. and has a range of 2-256 +#define IL_MAX_QUANT_INDICES 0x0644 // Redefined, since the above #define is misspelled + + +// Hints +#define IL_FASTEST 0x0660 +#define IL_LESS_MEM 0x0661 +#define IL_DONT_CARE 0x0662 +#define IL_MEM_SPEED_HINT 0x0665 +#define IL_USE_COMPRESSION 0x0666 +#define IL_NO_COMPRESSION 0x0667 +#define IL_COMPRESSION_HINT 0x0668 + + +// Compression +#define IL_NVIDIA_COMPRESS 0x0670 +#define IL_SQUISH_COMPRESS 0x0671 + + +// Subimage types +#define IL_SUB_NEXT 0x0680 +#define IL_SUB_MIPMAP 0x0681 +#define IL_SUB_LAYER 0x0682 + + +// Compression definitions +#define IL_COMPRESS_MODE 0x0700 +#define IL_COMPRESS_NONE 0x0701 +#define IL_COMPRESS_RLE 0x0702 +#define IL_COMPRESS_LZO 0x0703 +#define IL_COMPRESS_ZLIB 0x0704 + + +// File format-specific values +#define IL_TGA_CREATE_STAMP 0x0710 +#define IL_JPG_QUALITY 0x0711 +#define IL_PNG_INTERLACE 0x0712 +#define IL_TGA_RLE 0x0713 +#define IL_BMP_RLE 0x0714 +#define IL_SGI_RLE 0x0715 +#define IL_TGA_ID_STRING 0x0717 +#define IL_TGA_AUTHNAME_STRING 0x0718 +#define IL_TGA_AUTHCOMMENT_STRING 0x0719 +#define IL_PNG_AUTHNAME_STRING 0x071A +#define IL_PNG_TITLE_STRING 0x071B +#define IL_PNG_DESCRIPTION_STRING 0x071C +#define IL_TIF_DESCRIPTION_STRING 0x071D +#define IL_TIF_HOSTCOMPUTER_STRING 0x071E +#define IL_TIF_DOCUMENTNAME_STRING 0x071F +#define IL_TIF_AUTHNAME_STRING 0x0720 +#define IL_JPG_SAVE_FORMAT 0x0721 +#define IL_CHEAD_HEADER_STRING 0x0722 +#define IL_PCD_PICNUM 0x0723 +#define IL_PNG_ALPHA_INDEX 0x0724 // currently has no effect! +#define IL_JPG_PROGRESSIVE 0x0725 +#define IL_VTF_COMP 0x0726 + + +// DXTC definitions +#define IL_DXTC_FORMAT 0x0705 +#define IL_DXT1 0x0706 +#define IL_DXT2 0x0707 +#define IL_DXT3 0x0708 +#define IL_DXT4 0x0709 +#define IL_DXT5 0x070A +#define IL_DXT_NO_COMP 0x070B +#define IL_KEEP_DXTC_DATA 0x070C +#define IL_DXTC_DATA_FORMAT 0x070D +#define IL_3DC 0x070E +#define IL_RXGB 0x070F +#define IL_ATI1N 0x0710 +#define IL_DXT1A 0x0711 // Normally the same as IL_DXT1, except for nVidia Texture Tools. + +// Environment map definitions +#define IL_CUBEMAP_POSITIVEX 0x00000400 +#define IL_CUBEMAP_NEGATIVEX 0x00000800 +#define IL_CUBEMAP_POSITIVEY 0x00001000 +#define IL_CUBEMAP_NEGATIVEY 0x00002000 +#define IL_CUBEMAP_POSITIVEZ 0x00004000 +#define IL_CUBEMAP_NEGATIVEZ 0x00008000 +#define IL_SPHEREMAP 0x00010000 + + +// Values +#define IL_VERSION_NUM 0x0DE2 +#define IL_IMAGE_WIDTH 0x0DE4 +#define IL_IMAGE_HEIGHT 0x0DE5 +#define IL_IMAGE_DEPTH 0x0DE6 +#define IL_IMAGE_SIZE_OF_DATA 0x0DE7 +#define IL_IMAGE_BPP 0x0DE8 +#define IL_IMAGE_BYTES_PER_PIXEL 0x0DE8 +#define IL_IMAGE_BPP 0x0DE8 +#define IL_IMAGE_BITS_PER_PIXEL 0x0DE9 +#define IL_IMAGE_FORMAT 0x0DEA +#define IL_IMAGE_TYPE 0x0DEB +#define IL_PALETTE_TYPE 0x0DEC +#define IL_PALETTE_SIZE 0x0DED +#define IL_PALETTE_BPP 0x0DEE +#define IL_PALETTE_NUM_COLS 0x0DEF +#define IL_PALETTE_BASE_TYPE 0x0DF0 +#define IL_NUM_FACES 0x0DE1 +#define IL_NUM_IMAGES 0x0DF1 +#define IL_NUM_MIPMAPS 0x0DF2 +#define IL_NUM_LAYERS 0x0DF3 +#define IL_ACTIVE_IMAGE 0x0DF4 +#define IL_ACTIVE_MIPMAP 0x0DF5 +#define IL_ACTIVE_LAYER 0x0DF6 +#define IL_ACTIVE_FACE 0x0E00 +#define IL_CUR_IMAGE 0x0DF7 +#define IL_IMAGE_DURATION 0x0DF8 +#define IL_IMAGE_PLANESIZE 0x0DF9 +#define IL_IMAGE_BPC 0x0DFA +#define IL_IMAGE_OFFX 0x0DFB +#define IL_IMAGE_OFFY 0x0DFC +#define IL_IMAGE_CUBEFLAGS 0x0DFD +#define IL_IMAGE_ORIGIN 0x0DFE +#define IL_IMAGE_CHANNELS 0x0DFF + +# if defined __GNUC__ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) +// __attribute__((deprecated)) is supported by GCC 3.1 and later. +# define DEPRECATED(D) D __attribute__((deprecated)) +# elif defined _MSC_VER && _MSC_VER >= 1300 +// __declspec(deprecated) is supported by MSVC 7.0 and later. +# define DEPRECATED(D) __declspec(deprecated) D +# else +# define DEPRECATED (D) D +# endif + +// +// Section shamelessly modified from the glut header. +// + +// This is from Win32's +#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) || defined(__LCC__) + #define ILAPIENTRY __stdcall + #define IL_PACKSTRUCT +//#elif defined(linux) || defined(MACOSX) || defined(__CYGWIN__) //fix bug 840364 +#elif defined( __GNUC__ ) + // this should work for any of the above commented platforms + // plus any platform using GCC + #ifdef __MINGW32__ + #define ILAPIENTRY __stdcall + #else + #define ILAPIENTRY + #endif + #define IL_PACKSTRUCT __attribute__ ((packed)) +#else + #define ILAPIENTRY + #define IL_PACKSTRUCT +#endif + +// This is from Win32's and +#if defined(__LCC__) + #define ILAPI __stdcall +#elif defined(_WIN32) //changed 20031221 to fix bug 840421 + #ifdef IL_STATIC_LIB + #define ILAPI + #else + #ifdef _IL_BUILD_LIBRARY + #define ILAPI __declspec(dllexport) + #else + #define ILAPI __declspec(dllimport) + #endif + #endif +#elif __APPLE__ + #define ILAPI extern +#else + #define ILAPI +#endif + + +#define IL_SEEK_SET 0 +#define IL_SEEK_CUR 1 +#define IL_SEEK_END 2 +#define IL_EOF -1 + + +// Callback functions for file reading +typedef void* ILHANDLE; +typedef void (ILAPIENTRY *fCloseRProc)(ILHANDLE); +typedef ILboolean (ILAPIENTRY *fEofProc) (ILHANDLE); +typedef ILint (ILAPIENTRY *fGetcProc) (ILHANDLE); +typedef ILHANDLE (ILAPIENTRY *fOpenRProc) (ILconst_string); +typedef ILint (ILAPIENTRY *fReadProc) (void*, ILuint, ILuint, ILHANDLE); +typedef ILint (ILAPIENTRY *fSeekRProc) (ILHANDLE, ILint, ILint); +typedef ILint (ILAPIENTRY *fTellRProc) (ILHANDLE); + +// Callback functions for file writing +typedef void (ILAPIENTRY *fCloseWProc)(ILHANDLE); +typedef ILHANDLE (ILAPIENTRY *fOpenWProc) (ILconst_string); +typedef ILint (ILAPIENTRY *fPutcProc) (ILubyte, ILHANDLE); +typedef ILint (ILAPIENTRY *fSeekWProc) (ILHANDLE, ILint, ILint); +typedef ILint (ILAPIENTRY *fTellWProc) (ILHANDLE); +typedef ILint (ILAPIENTRY *fWriteProc) (const void*, ILuint, ILuint, ILHANDLE); + +// Callback functions for allocation and deallocation +typedef void* (ILAPIENTRY *mAlloc)(const ILsizei); +typedef void (ILAPIENTRY *mFree) (const void* CONST_RESTRICT); + +// Registered format procedures +typedef ILenum (ILAPIENTRY *IL_LOADPROC)(ILconst_string); +typedef ILenum (ILAPIENTRY *IL_SAVEPROC)(ILconst_string); + + +// ImageLib Functions +ILAPI ILboolean ILAPIENTRY ilActiveFace(ILuint Number); +ILAPI ILboolean ILAPIENTRY ilActiveImage(ILuint Number); +ILAPI ILboolean ILAPIENTRY ilActiveLayer(ILuint Number); +ILAPI ILboolean ILAPIENTRY ilActiveMipmap(ILuint Number); +ILAPI ILboolean ILAPIENTRY ilApplyPal(ILconst_string FileName); +ILAPI ILboolean ILAPIENTRY ilApplyProfile(ILstring InProfile, ILstring OutProfile); +ILAPI void ILAPIENTRY ilBindImage(ILuint Image); +ILAPI ILboolean ILAPIENTRY ilBlit(ILuint Source, ILint DestX, ILint DestY, ILint DestZ, ILuint SrcX, ILuint SrcY, ILuint SrcZ, ILuint Width, ILuint Height, ILuint Depth); +ILAPI ILboolean ILAPIENTRY ilClampNTSC(void); +ILAPI void ILAPIENTRY ilClearColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha); +ILAPI ILboolean ILAPIENTRY ilClearImage(void); +ILAPI ILuint ILAPIENTRY ilCloneCurImage(void); +ILAPI ILubyte* ILAPIENTRY ilCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DXTCFormat, ILuint *DXTCSize); +ILAPI ILboolean ILAPIENTRY ilCompressFunc(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilConvertImage(ILenum DestFormat, ILenum DestType); +ILAPI ILboolean ILAPIENTRY ilConvertPal(ILenum DestFormat); +ILAPI ILboolean ILAPIENTRY ilCopyImage(ILuint Src); +ILAPI ILuint ILAPIENTRY ilCopyPixels(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); +ILAPI ILuint ILAPIENTRY ilCreateSubImage(ILenum Type, ILuint Num); +ILAPI ILboolean ILAPIENTRY ilDefaultImage(void); +ILAPI void ILAPIENTRY ilDeleteImage(const ILuint Num); +ILAPI void ILAPIENTRY ilDeleteImages(ILsizei Num, const ILuint *Images); +ILAPI ILenum ILAPIENTRY ilDetermineType(ILconst_string FileName); +ILAPI ILenum ILAPIENTRY ilDetermineTypeF(ILHANDLE File); +ILAPI ILenum ILAPIENTRY ilDetermineTypeL(const void *Lump, ILuint Size); +ILAPI ILboolean ILAPIENTRY ilDisable(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilDxtcDataToImage(void); +ILAPI ILboolean ILAPIENTRY ilDxtcDataToSurface(void); +ILAPI ILboolean ILAPIENTRY ilEnable(ILenum Mode); +ILAPI void ILAPIENTRY ilFlipSurfaceDxtcData(void); +ILAPI ILboolean ILAPIENTRY ilFormatFunc(ILenum Mode); +ILAPI void ILAPIENTRY ilGenImages(ILsizei Num, ILuint *Images); +ILAPI ILuint ILAPIENTRY ilGenImage(void); +ILAPI ILubyte* ILAPIENTRY ilGetAlpha(ILenum Type); +ILAPI ILboolean ILAPIENTRY ilGetBoolean(ILenum Mode); +ILAPI void ILAPIENTRY ilGetBooleanv(ILenum Mode, ILboolean *Param); +ILAPI ILubyte* ILAPIENTRY ilGetData(void); +ILAPI ILuint ILAPIENTRY ilGetDXTCData(void *Buffer, ILuint BufferSize, ILenum DXTCFormat); +ILAPI ILenum ILAPIENTRY ilGetError(void); +ILAPI ILint ILAPIENTRY ilGetInteger(ILenum Mode); +ILAPI void ILAPIENTRY ilGetIntegerv(ILenum Mode, ILint *Param); +ILAPI ILuint ILAPIENTRY ilGetLumpPos(void); +ILAPI ILubyte* ILAPIENTRY ilGetPalette(void); +ILAPI ILconst_string ILAPIENTRY ilGetString(ILenum StringName); +ILAPI void ILAPIENTRY ilHint(ILenum Target, ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilInvertSurfaceDxtcDataAlpha(void); +ILAPI void ILAPIENTRY ilInit(void); +ILAPI ILboolean ILAPIENTRY ilImageToDxtcData(ILenum Format); +ILAPI ILboolean ILAPIENTRY ilIsDisabled(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilIsEnabled(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilIsImage(ILuint Image); +ILAPI ILboolean ILAPIENTRY ilIsValid(ILenum Type, ILconst_string FileName); +ILAPI ILboolean ILAPIENTRY ilIsValidF(ILenum Type, ILHANDLE File); +ILAPI ILboolean ILAPIENTRY ilIsValidL(ILenum Type, void *Lump, ILuint Size); +ILAPI void ILAPIENTRY ilKeyColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha); +ILAPI ILboolean ILAPIENTRY ilLoad(ILenum Type, ILconst_string FileName); +ILAPI ILboolean ILAPIENTRY ilLoadF(ILenum Type, ILHANDLE File); +ILAPI ILboolean ILAPIENTRY ilLoadImage(ILconst_string FileName); +ILAPI ILboolean ILAPIENTRY ilLoadL(ILenum Type, const void *Lump, ILuint Size); +ILAPI ILboolean ILAPIENTRY ilLoadPal(ILconst_string FileName); +ILAPI void ILAPIENTRY ilModAlpha(ILdouble AlphaValue); +ILAPI ILboolean ILAPIENTRY ilOriginFunc(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilOverlayImage(ILuint Source, ILint XCoord, ILint YCoord, ILint ZCoord); +ILAPI void ILAPIENTRY ilPopAttrib(void); +ILAPI void ILAPIENTRY ilPushAttrib(ILuint Bits); +ILAPI void ILAPIENTRY ilRegisterFormat(ILenum Format); +ILAPI ILboolean ILAPIENTRY ilRegisterLoad(ILconst_string Ext, IL_LOADPROC Load); +ILAPI ILboolean ILAPIENTRY ilRegisterMipNum(ILuint Num); +ILAPI ILboolean ILAPIENTRY ilRegisterNumFaces(ILuint Num); +ILAPI ILboolean ILAPIENTRY ilRegisterNumImages(ILuint Num); +ILAPI void ILAPIENTRY ilRegisterOrigin(ILenum Origin); +ILAPI void ILAPIENTRY ilRegisterPal(void *Pal, ILuint Size, ILenum Type); +ILAPI ILboolean ILAPIENTRY ilRegisterSave(ILconst_string Ext, IL_SAVEPROC Save); +ILAPI void ILAPIENTRY ilRegisterType(ILenum Type); +ILAPI ILboolean ILAPIENTRY ilRemoveLoad(ILconst_string Ext); +ILAPI ILboolean ILAPIENTRY ilRemoveSave(ILconst_string Ext); +ILAPI void ILAPIENTRY ilResetMemory(void); // Deprecated +ILAPI void ILAPIENTRY ilResetRead(void); +ILAPI void ILAPIENTRY ilResetWrite(void); +ILAPI ILboolean ILAPIENTRY ilSave(ILenum Type, ILconst_string FileName); +ILAPI ILuint ILAPIENTRY ilSaveF(ILenum Type, ILHANDLE File); +ILAPI ILboolean ILAPIENTRY ilSaveImage(ILconst_string FileName); +ILAPI ILuint ILAPIENTRY ilSaveL(ILenum Type, void *Lump, ILuint Size); +ILAPI ILboolean ILAPIENTRY ilSavePal(ILconst_string FileName); +ILAPI ILboolean ILAPIENTRY ilSetAlpha(ILdouble AlphaValue); +ILAPI ILboolean ILAPIENTRY ilSetData(void *Data); +ILAPI ILboolean ILAPIENTRY ilSetDuration(ILuint Duration); +ILAPI void ILAPIENTRY ilSetInteger(ILenum Mode, ILint Param); +ILAPI void ILAPIENTRY ilSetMemory(mAlloc, mFree); +ILAPI void ILAPIENTRY ilSetPixels(ILint XOff, ILint YOff, ILint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); +ILAPI void ILAPIENTRY ilSetRead(fOpenRProc, fCloseRProc, fEofProc, fGetcProc, fReadProc, fSeekRProc, fTellRProc); +ILAPI void ILAPIENTRY ilSetString(ILenum Mode, const char *String); +ILAPI void ILAPIENTRY ilSetWrite(fOpenWProc, fCloseWProc, fPutcProc, fSeekWProc, fTellWProc, fWriteProc); +ILAPI void ILAPIENTRY ilShutDown(void); +ILAPI ILboolean ILAPIENTRY ilSurfaceToDxtcData(ILenum Format); +ILAPI ILboolean ILAPIENTRY ilTexImage(ILuint Width, ILuint Height, ILuint Depth, ILubyte NumChannels, ILenum Format, ILenum Type, void *Data); +ILAPI ILboolean ILAPIENTRY ilTexImageDxtc(ILint w, ILint h, ILint d, ILenum DxtFormat, const ILubyte* data); +ILAPI ILenum ILAPIENTRY ilTypeFromExt(ILconst_string FileName); +ILAPI ILboolean ILAPIENTRY ilTypeFunc(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilLoadData(ILconst_string FileName, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); +ILAPI ILboolean ILAPIENTRY ilLoadDataF(ILHANDLE File, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); +ILAPI ILboolean ILAPIENTRY ilLoadDataL(void *Lump, ILuint Size, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); +ILAPI ILboolean ILAPIENTRY ilSaveData(ILconst_string FileName); + +// For all those weirdos that spell "colour" without the 'u'. +#define ilClearColor ilClearColour +#define ilKeyColor ilKeyColour + +#define imemclear(x,y) memset(x,0,y); + +#ifdef __cplusplus +} +#endif + +#endif // __IL_H__ +#endif // __il_h__ diff --git a/DevILSDK/include/IL/il_wrap.h b/DevILSDK/include/IL/il_wrap.h new file mode 100644 index 0000000..5cf9b0e --- /dev/null +++ b/DevILSDK/include/IL/il_wrap.h @@ -0,0 +1,205 @@ +#ifndef WRAPPER_H +#define WRAPPER_H + +/*#include +#include */ +#include // Probably only have to #include this one + +#ifdef _MSC_VER + #ifndef _IL_WRAP_BUILD_LIB + #pragma comment(lib, "il_wrap.lib") + #endif +#endif + +class ilImage +{ +public: + ilImage(); + ilImage(char *); + ilImage(const ilImage &); + virtual ~ilImage(); + + ILboolean Load(char *); + ILboolean Load(char *, ILenum); + ILboolean Save(char *); + ILboolean Save(char *, ILenum); + + + // ImageLib functions + ILboolean ActiveImage(ILuint); + ILboolean ActiveLayer(ILuint); + ILboolean ActiveMipmap(ILuint); + ILboolean Clear(void); + ILvoid ClearColour(ILclampf, ILclampf, ILclampf, ILclampf); + ILboolean Convert(ILenum); + ILboolean Copy(ILuint); + ILboolean Default(void); + ILboolean Flip(void); + ILboolean SwapColours(void); + ILboolean Resize(ILuint, ILuint, ILuint); + ILboolean TexImage(ILuint, ILuint, ILuint, ILubyte, ILenum, ILenum, ILvoid*); + + + // Image handling + ILvoid Bind(void) const; + ILvoid Bind(ILuint); + ILvoid Close(void) { this->Delete(); } + ILvoid Delete(void); + ILvoid iGenBind(); + ILenum PaletteAlphaIndex(); + + // Image characteristics + ILuint Width(void); + ILuint Height(void); + ILuint Depth(void); + ILubyte Bpp(void); + ILubyte Bitpp(void); + ILenum PaletteType(void); + ILenum Format(void); + ILenum Type(void); + ILuint NumImages(void); + ILuint NumMipmaps(void); + ILuint GetId(void) const; + ILenum GetOrigin(void); + ILubyte *GetData(void); + ILubyte *GetPalette(void); + + + // Rendering + ILuint BindImage(void); + ILuint BindImage(ILenum); + + + // Operators + ilImage& operator = (ILuint); + ilImage& operator = (const ilImage &); + + +protected: + ILuint Id; + +private: + ILvoid iStartUp(); + + +}; + + +class ilFilters +{ +public: + static ILboolean Alienify(ilImage &); + static ILboolean BlurAvg(ilImage &, ILuint Iter); + static ILboolean BlurGaussian(ilImage &, ILuint Iter); + static ILboolean Contrast(ilImage &, ILfloat Contrast); + static ILboolean EdgeDetectE(ilImage &); + static ILboolean EdgeDetectP(ilImage &); + static ILboolean EdgeDetectS(ilImage &); + static ILboolean Emboss(ilImage &); + static ILboolean Gamma(ilImage &, ILfloat Gamma); + static ILboolean Negative(ilImage &); + static ILboolean Noisify(ilImage &, ILubyte Factor); + static ILboolean Pixelize(ilImage &, ILuint PixSize); + static ILboolean Saturate(ilImage &, ILfloat Saturation); + static ILboolean Saturate(ilImage &, ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation); + static ILboolean ScaleColours(ilImage &, ILfloat r, ILfloat g, ILfloat b); + static ILboolean Sharpen(ilImage &, ILfloat Factor, ILuint Iter); +}; + + +#ifdef ILUT_USE_OPENGL +class ilOgl +{ +public: + static ILvoid Init(void); + static GLuint BindTex(ilImage &); + static ILboolean Upload(ilImage &, ILuint); + static GLuint Mipmap(ilImage &); + static ILboolean Screen(void); + static ILboolean Screenie(void); +}; +#endif//ILUT_USE_OPENGL + + +#ifdef ILUT_USE_ALLEGRO +class ilAlleg +{ +public: + static ILvoid Init(void); + static BITMAP *Convert(ilImage &); +}; +#endif//ILUT_USE_ALLEGRO + + +#ifdef ILUT_USE_WIN32 +class ilWin32 +{ +public: + static ILvoid Init(void); + static HBITMAP Convert(ilImage &); + static ILboolean GetClipboard(ilImage &); + static ILvoid GetInfo(ilImage &, BITMAPINFO *Info); + static ILubyte *GetPadData(ilImage &); + static HPALETTE GetPal(ilImage &); + static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType); + static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType, ILenum Type); + static ILboolean SetClipboard(ilImage &); +}; +#endif//ILUT_USE_WIN32 + + +class ilValidate +{ +public: + static ILboolean Valid(ILenum, char *); + static ILboolean Valid(ILenum, FILE *); + static ILboolean Valid(ILenum, ILvoid *, ILuint); + +protected: + +private: + +}; + + +class ilState +{ +public: + static ILboolean Disable(ILenum); + static ILboolean Enable(ILenum); + static ILvoid Get(ILenum, ILboolean &); + static ILvoid Get(ILenum, ILint &); + static ILboolean GetBool(ILenum); + static ILint GetInt(ILenum); + static const char *GetString(ILenum); + static ILboolean IsDisabled(ILenum); + static ILboolean IsEnabled(ILenum); + static ILboolean Origin(ILenum); + static ILvoid Pop(void); + static ILvoid Push(ILuint); + + +protected: + +private: + +}; + + +class ilError +{ +public: + static ILvoid Check(ILvoid (*Callback)(const char*)); + static ILvoid Check(ILvoid (*Callback)(ILenum)); + static ILenum Get(void); + static const char *String(void); + static const char *String(ILenum); + +protected: + +private: + +}; + + +#endif//WRAPPER_H diff --git a/DevILSDK/include/IL/ilu.h b/DevILSDK/include/IL/ilu.h new file mode 100644 index 0000000..30d33a4 --- /dev/null +++ b/DevILSDK/include/IL/ilu.h @@ -0,0 +1,198 @@ +//----------------------------------------------------------------------------- +// +// ImageLib Utility Sources +// Copyright (C) 2000-2017 by Denton Woods +// Last modified: 03/07/2009 +// +// Filename: IL/ilu.h +// +// Description: The main include file for ILU +// +//----------------------------------------------------------------------------- + +// Doxygen comment +/*! \file ilu.h + The main include file for ILU +*/ + +#ifndef __ilu_h_ +#ifndef __ILU_H__ + +#define __ilu_h_ +#define __ILU_H__ + +#include "DevILSDK/include/IL/il.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef _WIN32 + #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) + #if defined(_MSC_VER) || defined(__BORLANDC__) + #pragma comment(lib, "ILU.lib") + #endif + #endif +#endif + + +#define ILU_VERSION_1_8_0 1 +#define ILU_VERSION 180 + + +#define ILU_FILTER 0x2600 +#define ILU_NEAREST 0x2601 +#define ILU_LINEAR 0x2602 +#define ILU_BILINEAR 0x2603 +#define ILU_SCALE_BOX 0x2604 +#define ILU_SCALE_TRIANGLE 0x2605 +#define ILU_SCALE_BELL 0x2606 +#define ILU_SCALE_BSPLINE 0x2607 +#define ILU_SCALE_LANCZOS3 0x2608 +#define ILU_SCALE_MITCHELL 0x2609 + + +// Error types +#define ILU_INVALID_ENUM 0x0501 +#define ILU_OUT_OF_MEMORY 0x0502 +#define ILU_INTERNAL_ERROR 0x0504 +#define ILU_INVALID_VALUE 0x0505 +#define ILU_ILLEGAL_OPERATION 0x0506 +#define ILU_INVALID_PARAM 0x0509 + + +// Values +#define ILU_PLACEMENT 0x0700 +#define ILU_LOWER_LEFT 0x0701 +#define ILU_LOWER_RIGHT 0x0702 +#define ILU_UPPER_LEFT 0x0703 +#define ILU_UPPER_RIGHT 0x0704 +#define ILU_CENTER 0x0705 +#define ILU_CONVOLUTION_MATRIX 0x0710 + +#define ILU_VERSION_NUM IL_VERSION_NUM +#define ILU_VENDOR IL_VENDOR + + +// Languages +#define ILU_ENGLISH 0x0800 +#define ILU_ARABIC 0x0801 +#define ILU_DUTCH 0x0802 +#define ILU_JAPANESE 0x0803 +#define ILU_SPANISH 0x0804 +#define ILU_GERMAN 0x0805 +#define ILU_FRENCH 0x0806 +#define ILU_ITALIAN 0x0807 + + +// Filters +/* +#define ILU_FILTER_BLUR 0x0803 +#define ILU_FILTER_GAUSSIAN_3x3 0x0804 +#define ILU_FILTER_GAUSSIAN_5X5 0x0805 +#define ILU_FILTER_EMBOSS1 0x0807 +#define ILU_FILTER_EMBOSS2 0x0808 +#define ILU_FILTER_LAPLACIAN1 0x080A +#define ILU_FILTER_LAPLACIAN2 0x080B +#define ILU_FILTER_LAPLACIAN3 0x080C +#define ILU_FILTER_LAPLACIAN4 0x080D +#define ILU_FILTER_SHARPEN1 0x080E +#define ILU_FILTER_SHARPEN2 0x080F +#define ILU_FILTER_SHARPEN3 0x0810 +*/ + + +typedef struct ILinfo +{ + ILuint Id; // the image's id + ILubyte *Data; // the image's data + ILuint Width; // the image's width + ILuint Height; // the image's height + ILuint Depth; // the image's depth + ILubyte Bpp; // bytes per pixel (not bits) of the image + ILuint SizeOfData; // the total size of the data (in bytes) + ILenum Format; // image format (in IL enum style) + ILenum Type; // image type (in IL enum style) + ILenum Origin; // origin of the image + ILubyte *Palette; // the image's palette + ILenum PalType; // palette type + ILuint PalSize; // palette size + ILenum CubeFlags; // flags for what cube map sides are present + ILuint NumNext; // number of images following + ILuint NumMips; // number of mipmaps + ILuint NumLayers; // number of layers +} ILinfo; + + +typedef struct ILpointf { + ILfloat x; + ILfloat y; +} ILpointf; + +typedef struct ILpointi { + ILint x; + ILint y; +} ILpointi; + +ILAPI ILboolean ILAPIENTRY iluAlienify(void); +ILAPI ILboolean ILAPIENTRY iluBlurAvg(ILuint Iter); +ILAPI ILboolean ILAPIENTRY iluBlurGaussian(ILuint Iter); +ILAPI ILboolean ILAPIENTRY iluBuildMipmaps(void); +ILAPI ILuint ILAPIENTRY iluColoursUsed(void); +ILAPI ILboolean ILAPIENTRY iluCompareImage(ILuint Comp); +ILAPI ILboolean ILAPIENTRY iluContrast(ILfloat Contrast); +ILAPI ILboolean ILAPIENTRY iluCrop(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth); +ILAPI void ILAPIENTRY iluDeleteImage(ILuint Id); // Deprecated +ILAPI ILboolean ILAPIENTRY iluEdgeDetectE(void); +ILAPI ILboolean ILAPIENTRY iluEdgeDetectP(void); +ILAPI ILboolean ILAPIENTRY iluEdgeDetectS(void); +ILAPI ILboolean ILAPIENTRY iluEmboss(void); +ILAPI ILboolean ILAPIENTRY iluEnlargeCanvas(ILuint Width, ILuint Height, ILuint Depth); +ILAPI ILboolean ILAPIENTRY iluEnlargeImage(ILfloat XDim, ILfloat YDim, ILfloat ZDim); +ILAPI ILboolean ILAPIENTRY iluEqualize(void); +ILAPI ILboolean ILAPIENTRY iluEqualize2(void); +ILAPI ILconst_string ILAPIENTRY iluErrorString(ILenum Error); +ILAPI ILboolean ILAPIENTRY iluConvolution(ILint *matrix, ILint scale, ILint bias); +ILAPI ILboolean ILAPIENTRY iluFlipImage(void); +ILAPI ILboolean ILAPIENTRY iluGammaCorrect(ILfloat Gamma); +ILAPI ILuint ILAPIENTRY iluGenImage(void); // Deprecated +ILAPI void ILAPIENTRY iluGetImageInfo(ILinfo *Info); +ILAPI ILint ILAPIENTRY iluGetInteger(ILenum Mode); +ILAPI void ILAPIENTRY iluGetIntegerv(ILenum Mode, ILint *Param); +ILAPI ILstring ILAPIENTRY iluGetString(ILenum StringName); +ILAPI void ILAPIENTRY iluImageParameter(ILenum PName, ILenum Param); +ILAPI void ILAPIENTRY iluInit(void); +ILAPI ILboolean ILAPIENTRY iluInvertAlpha(void); +ILAPI ILuint ILAPIENTRY iluLoadImage(ILconst_string FileName); +ILAPI ILboolean ILAPIENTRY iluMirror(void); +ILAPI ILboolean ILAPIENTRY iluNegative(void); +ILAPI ILboolean ILAPIENTRY iluNoisify(ILclampf Tolerance); +ILAPI ILboolean ILAPIENTRY iluPixelize(ILuint PixSize); +ILAPI void ILAPIENTRY iluRegionfv(ILpointf *Points, ILuint n); +ILAPI void ILAPIENTRY iluRegioniv(ILpointi *Points, ILuint n); +ILAPI ILboolean ILAPIENTRY iluReplaceColour(ILubyte Red, ILubyte Green, ILubyte Blue, ILfloat Tolerance); +ILAPI ILboolean ILAPIENTRY iluRotate(ILfloat Angle); +ILAPI ILboolean ILAPIENTRY iluRotate3D(ILfloat x, ILfloat y, ILfloat z, ILfloat Angle); +ILAPI ILboolean ILAPIENTRY iluSaturate1f(ILfloat Saturation); +ILAPI ILboolean ILAPIENTRY iluSaturate4f(ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation); +ILAPI ILboolean ILAPIENTRY iluScale(ILuint Width, ILuint Height, ILuint Depth); +ILAPI ILboolean ILAPIENTRY iluScaleAlpha(ILfloat scale); +ILAPI ILboolean ILAPIENTRY iluScaleColours(ILfloat r, ILfloat g, ILfloat b); +ILAPI ILboolean ILAPIENTRY iluSepia(void); +ILAPI ILboolean ILAPIENTRY iluSetLanguage(ILenum Language); +ILAPI ILboolean ILAPIENTRY iluSharpen(ILfloat Factor, ILuint Iter); +ILAPI ILboolean ILAPIENTRY iluSwapColours(void); +ILAPI ILboolean ILAPIENTRY iluWave(ILfloat Angle); + +#define iluColorsUsed iluColoursUsed +#define iluSwapColors iluSwapColours +#define iluReplaceColor iluReplaceColour +#define iluScaleColor iluScaleColour + +#ifdef __cplusplus +} +#endif + +#endif // __ILU_H__ +#endif // __ilu_h_ diff --git a/DevILSDK/include/IL/ilu_region.h b/DevILSDK/include/IL/ilu_region.h new file mode 100644 index 0000000..b5b3adc --- /dev/null +++ b/DevILSDK/include/IL/ilu_region.h @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------------- +// +// ImageLib Utility Sources +// Copyright (C) 2000-2002 by Denton Woods +// Last modified: 07/09/2002 <--Y2K Compliant! =] +// +// Filename: src-ILU/src/ilu_region.h +// +// Description: Creates an image region. +// +//----------------------------------------------------------------------------- + +#ifndef ILU_REGION_H +#define ILU_REGION_H + +typedef struct Edge +{ + ILint yUpper; + ILfloat xIntersect, dxPerScan; + struct Edge *next; +} Edge; + + +#endif//ILU_REGION_H + diff --git a/DevILSDK/include/IL/ilut.h b/DevILSDK/include/IL/ilut.h new file mode 100644 index 0000000..8c1feda --- /dev/null +++ b/DevILSDK/include/IL/ilut.h @@ -0,0 +1,354 @@ +//----------------------------------------------------------------------------- +// +// ImageLib Utility Toolkit Sources +// Copyright (C) 2000-2017 by Denton Woods +// Last modified: 03/07/2009 +// +// Filename: IL/ilut.h +// +// Description: The main include file for ILUT +// +//----------------------------------------------------------------------------- + +// Doxygen comment +/*! \file ilut.h + The main include file for ILUT +*/ + +#ifndef __ilut_h_ +#ifndef __ILUT_H__ + +#define __ilut_h_ +#define __ILUT_H__ + +#include "DevILSDK/include/IL/il.h" +#include "DevILSDK/include/IL/ilu.h" + + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +#define ILUT_VERSION_1_8_0 1 +#define ILUT_VERSION 180 + + +// Attribute Bits +#define ILUT_OPENGL_BIT 0x00000001 +#define ILUT_D3D_BIT 0x00000002 +#define ILUT_ALL_ATTRIB_BITS 0x000FFFFF + + +// Error Types +#define ILUT_INVALID_ENUM 0x0501 +#define ILUT_OUT_OF_MEMORY 0x0502 +#define ILUT_INVALID_VALUE 0x0505 +#define ILUT_ILLEGAL_OPERATION 0x0506 +#define ILUT_INVALID_PARAM 0x0509 +#define ILUT_COULD_NOT_OPEN_FILE 0x050A +#define ILUT_STACK_OVERFLOW 0x050E +#define ILUT_STACK_UNDERFLOW 0x050F +#define ILUT_BAD_DIMENSIONS 0x0511 +#define ILUT_NOT_SUPPORTED 0x0550 + + +// State Definitions +#define ILUT_PALETTE_MODE 0x0600 +#define ILUT_OPENGL_CONV 0x0610 +#define ILUT_D3D_MIPLEVELS 0x0620 +#define ILUT_MAXTEX_WIDTH 0x0630 +#define ILUT_MAXTEX_HEIGHT 0x0631 +#define ILUT_MAXTEX_DEPTH 0x0632 +#define ILUT_GL_USE_S3TC 0x0634 +#define ILUT_D3D_USE_DXTC 0x0634 +#define ILUT_GL_GEN_S3TC 0x0635 +#define ILUT_D3D_GEN_DXTC 0x0635 +#define ILUT_S3TC_FORMAT 0x0705 +#define ILUT_DXTC_FORMAT 0x0705 +#define ILUT_D3D_POOL 0x0706 +#define ILUT_D3D_ALPHA_KEY_COLOR 0x0707 +#define ILUT_D3D_ALPHA_KEY_COLOUR 0x0707 +#define ILUT_FORCE_INTEGER_FORMAT 0x0636 + +//This new state does automatic texture target detection +//if enabled. Currently, only cubemap detection is supported. +//if the current image is no cubemap, the 2d texture is chosen. +#define ILUT_GL_AUTODETECT_TEXTURE_TARGET 0x0807 + + +// Values +#define ILUT_VERSION_NUM IL_VERSION_NUM +#define ILUT_VENDOR IL_VENDOR + +// The different rendering api's...more to be added later? +#define ILUT_OPENGL 0 +#define ILUT_ALLEGRO 1 +#define ILUT_WIN32 2 +#define ILUT_DIRECT3D8 3 +#define ILUT_DIRECT3D9 4 +#define ILUT_X11 5 +#define ILUT_DIRECT3D10 6 + + +#if (defined(_WIN32) || defined(_WIN64)) + #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) + #if defined(_MSC_VER) || defined(__BORLANDC__) + #pragma comment(lib, "ILUT.lib") + #endif + #endif + + #include +#endif + + + + +////////////// +// OpenGL +////////////// + +#ifdef ILUT_USE_OPENGL + #if defined(_MSC_VER) || defined(_WIN32) + //#define WIN32_LEAN_AND_MEAN + #include + #endif//_MSC_VER + + #ifdef __APPLE__ + #include + #include + #else + #include + #include + #endif//__APPLE__ +#endif + + +#ifdef ILUT_USE_WIN32 + //#define WIN32_LEAN_AND_MEAN + #ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include + #ifndef _WIN32_WCE + #include + #endif + #endif + #include +#endif + + +// +// If we can avoid including these in all cases thing tend to break less +// and we can keep all of them defined as available +// +// Kriss +// + +// ImageLib Utility Toolkit's Allegro Functions +#ifdef ILUT_USE_ALLEGRO +// #include +#endif//ILUT_USE_ALLEGRO + +#ifdef ILUT_USE_SDL +// #include +#endif + +#ifdef ILUT_USE_DIRECTX8 + #include +#endif//ILUT_USE_DIRECTX9 + +#ifdef ILUT_USE_DIRECTX9 + #include +#endif//ILUT_USE_DIRECTX9 + +#ifdef ILUT_USE_DIRECTX10 + #pragma warning(push) + #pragma warning(disable : 4201) // Disables 'nonstandard extension used : nameless struct/union' warning + #include + #include + #include + #pragma warning(pop) +#endif//ILUT_USE_DIRECTX10 + +#ifdef ILUT_USE_X11 + #include + #include +#ifdef ILUT_USE_XSHM + #include + #include + #include +#endif//ILUT_USE_XSHM +#endif//ILUT_USE_X11 + + + +//----------------------------------------------------------------------------- +// Functions +//----------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +// ImageLib Utility Toolkit Functions +ILAPI ILboolean ILAPIENTRY ilutDisable(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilutEnable(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilutGetBoolean(ILenum Mode); +ILAPI void ILAPIENTRY ilutGetBooleanv(ILenum Mode, ILboolean *Param); +ILAPI ILint ILAPIENTRY ilutGetInteger(ILenum Mode); +ILAPI void ILAPIENTRY ilutGetIntegerv(ILenum Mode, ILint *Param); +ILAPI ILstring ILAPIENTRY ilutGetString(ILenum StringName); +ILAPI void ILAPIENTRY ilutInit(void); +ILAPI ILboolean ILAPIENTRY ilutIsDisabled(ILenum Mode); +ILAPI ILboolean ILAPIENTRY ilutIsEnabled(ILenum Mode); +ILAPI void ILAPIENTRY ilutPopAttrib(void); +ILAPI void ILAPIENTRY ilutPushAttrib(ILuint Bits); +ILAPI void ILAPIENTRY ilutSetInteger(ILenum Mode, ILint Param); + +ILAPI ILboolean ILAPIENTRY ilutRenderer(ILenum Renderer); + + +// ImageLib Utility Toolkit's OpenGL Functions +#ifdef ILUT_USE_OPENGL + ILAPI GLuint ILAPIENTRY ilutGLBindTexImage(); + ILAPI GLuint ILAPIENTRY ilutGLBindMipmaps(void); + ILAPI ILboolean ILAPIENTRY ilutGLBuildMipmaps(void); + ILAPI GLuint ILAPIENTRY ilutGLLoadImage(ILstring FileName); + ILAPI ILboolean ILAPIENTRY ilutGLScreen(void); + ILAPI ILboolean ILAPIENTRY ilutGLScreenie(void); + ILAPI ILboolean ILAPIENTRY ilutGLSaveImage(ILstring FileName, GLuint TexID); + ILAPI ILboolean ILAPIENTRY ilutGLSubTex2D(GLuint TexID, ILuint XOff, ILuint YOff); + ILAPI ILboolean ILAPIENTRY ilutGLSubTex3D(GLuint TexID, ILuint XOff, ILuint YOff, ILuint ZOff); + ILAPI ILboolean ILAPIENTRY ilutGLSetTex2D(GLuint TexID); + ILAPI ILboolean ILAPIENTRY ilutGLSetTex3D(GLuint TexID); + ILAPI ILboolean ILAPIENTRY ilutGLTexImage(GLuint Level); + ILAPI ILboolean ILAPIENTRY ilutGLSubTex(GLuint TexID, ILuint XOff, ILuint YOff); + + ILAPI ILboolean ILAPIENTRY ilutGLSetTex(GLuint TexID); // Deprecated - use ilutGLSetTex2D. + ILAPI ILboolean ILAPIENTRY ilutGLSubTex(GLuint TexID, ILuint XOff, ILuint YOff); // Use ilutGLSubTex2D. +#endif//ILUT_USE_OPENGL + + +// ImageLib Utility Toolkit's Allegro Functions +#ifdef ILUT_USE_ALLEGRO + #ifdef __cplusplus + extern "C" { + #endif + #include + #ifdef __cplusplus + } + #endif + + ILAPI BITMAP* ILAPIENTRY ilutAllegLoadImage(ILstring FileName); + ILAPI BITMAP* ILAPIENTRY ilutConvertToAlleg(PALETTE Pal); +#endif//ILUT_USE_ALLEGRO + + +// ImageLib Utility Toolkit's SDL Functions +#ifdef ILUT_USE_SDL + ILAPI struct SDL_Surface* ILAPIENTRY ilutConvertToSDLSurface(unsigned int flags); + ILAPI struct SDL_Surface* ILAPIENTRY ilutSDLSurfaceLoadImage(ILstring FileName); + ILAPI ILboolean ILAPIENTRY ilutSDLSurfaceFromBitmap(struct SDL_Surface *Bitmap); +#endif//ILUT_USE_SDL + + +// ImageLib Utility Toolkit's BeOS Functions +#ifdef ILUT_USE_BEOS + ILAPI BBitmap ILAPIENTRY ilutConvertToBBitmap(void); +#endif//ILUT_USE_BEOS + + +// ImageLib Utility Toolkit's Win32 GDI Functions +#ifdef ILUT_USE_WIN32 + ILAPI HBITMAP ILAPIENTRY ilutConvertToHBitmap(HDC hDC); + ILAPI HBITMAP ILAPIENTRY ilutConvertSliceToHBitmap(HDC hDC, ILuint slice); + ILAPI void ILAPIENTRY ilutFreePaddedData(ILubyte *Data); + ILAPI void ILAPIENTRY ilutGetBmpInfo(BITMAPINFO *Info); + ILAPI HPALETTE ILAPIENTRY ilutGetHPal(void); + ILAPI ILubyte* ILAPIENTRY ilutGetPaddedData(void); + ILAPI ILboolean ILAPIENTRY ilutGetWinClipboard(void); + ILAPI ILboolean ILAPIENTRY ilutLoadResource(HINSTANCE hInst, ILint ID, ILstring ResourceType, ILenum Type); + ILAPI ILboolean ILAPIENTRY ilutSetHBitmap(HBITMAP Bitmap); + ILAPI ILboolean ILAPIENTRY ilutSetHPal(HPALETTE Pal); + ILAPI ILboolean ILAPIENTRY ilutSetWinClipboard(void); + ILAPI HBITMAP ILAPIENTRY ilutWinLoadImage(ILstring FileName, HDC hDC); + ILAPI ILboolean ILAPIENTRY ilutWinLoadUrl(ILstring Url); + ILAPI ILboolean ILAPIENTRY ilutWinPrint(ILuint XPos, ILuint YPos, ILuint Width, ILuint Height, HDC hDC); + ILAPI ILboolean ILAPIENTRY ilutWinSaveImage(ILstring FileName, HBITMAP Bitmap); +#endif//ILUT_USE_WIN32 + +// ImageLib Utility Toolkit's DirectX 8 Functions +#ifdef ILUT_USE_DIRECTX8 +// ILAPI void ILAPIENTRY ilutD3D8MipFunc(ILuint NumLevels); + ILAPI struct IDirect3DTexture8* ILAPIENTRY ilutD3D8Texture(struct IDirect3DDevice8 *Device); + ILAPI struct IDirect3DVolumeTexture8* ILAPIENTRY ilutD3D8VolumeTexture(struct IDirect3DDevice8 *Device); + ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFile(struct IDirect3DDevice8 *Device, char *FileName, struct IDirect3DTexture8 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFile(struct IDirect3DDevice8 *Device, char *FileName, struct IDirect3DVolumeTexture8 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFileInMemory(struct IDirect3DDevice8 *Device, void *Lump, ILuint Size, struct IDirect3DTexture8 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFileInMemory(struct IDirect3DDevice8 *Device, void *Lump, ILuint Size, struct IDirect3DVolumeTexture8 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFileHandle(struct IDirect3DDevice8 *Device, ILHANDLE File, struct IDirect3DTexture8 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFileHandle(struct IDirect3DDevice8 *Device, ILHANDLE File, struct IDirect3DVolumeTexture8 **Texture); + // These two are not tested yet. + ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromResource(struct IDirect3DDevice8 *Device, HMODULE SrcModule, char *SrcResource, struct IDirect3DTexture8 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromResource(struct IDirect3DDevice8 *Device, HMODULE SrcModule, char *SrcResource, struct IDirect3DVolumeTexture8 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D8LoadSurface(struct IDirect3DDevice8 *Device, struct IDirect3DSurface8 *Surface); +#endif//ILUT_USE_DIRECTX8 + +#ifdef ILUT_USE_DIRECTX9 + #pragma warning(push) + #pragma warning(disable : 4115) // Disables 'named type definition in parentheses' warning +// ILAPI void ILAPIENTRY ilutD3D9MipFunc(ILuint NumLevels); + ILAPI struct IDirect3DTexture9* ILAPIENTRY ilutD3D9Texture (struct IDirect3DDevice9* Device); + ILAPI struct IDirect3DVolumeTexture9* ILAPIENTRY ilutD3D9VolumeTexture (struct IDirect3DDevice9* Device); + ILAPI struct IDirect3DCubeTexture9* ILAPIENTRY ilutD3D9CubeTexture (struct IDirect3DDevice9* Device); + + ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DCubeTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DCubeTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DCubeTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DCubeTexture9 **Texture); + + ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DVolumeTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DVolumeTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DVolumeTexture9 **Texture); + + // These three are not tested yet. + ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DVolumeTexture9 **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D9LoadSurface(struct IDirect3DDevice9 *Device, struct IDirect3DSurface9 *Surface); + #pragma warning(pop) +#endif//ILUT_USE_DIRECTX9 + +#ifdef ILUT_USE_DIRECTX10 + ILAPI ID3D10Texture2D* ILAPIENTRY ilutD3D10Texture(ID3D10Device *Device); + ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFile(ID3D10Device *Device, ILconst_string FileName, ID3D10Texture2D **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFileInMemory(ID3D10Device *Device, void *Lump, ILuint Size, ID3D10Texture2D **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromResource(ID3D10Device *Device, HMODULE SrcModule, ILconst_string SrcResource, ID3D10Texture2D **Texture); + ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFileHandle(ID3D10Device *Device, ILHANDLE File, ID3D10Texture2D **Texture); +#endif//ILUT_USE_DIRECTX10 + + + +#ifdef ILUT_USE_X11 + ILAPI XImage * ILAPIENTRY ilutXCreateImage( Display* ); + ILAPI Pixmap ILAPIENTRY ilutXCreatePixmap( Display*,Drawable ); + ILAPI XImage * ILAPIENTRY ilutXLoadImage( Display*,char* ); + ILAPI Pixmap ILAPIENTRY ilutXLoadPixmap( Display*,Drawable,char* ); +#ifdef ILUT_USE_XSHM + ILAPI XImage * ILAPIENTRY ilutXShmCreateImage( Display*,XShmSegmentInfo* ); + ILAPI void ILAPIENTRY ilutXShmDestroyImage( Display*,XImage*,XShmSegmentInfo* ); + ILAPI Pixmap ILAPIENTRY ilutXShmCreatePixmap( Display*,Drawable,XShmSegmentInfo* ); + ILAPI void ILAPIENTRY ilutXShmFreePixmap( Display*,Pixmap,XShmSegmentInfo* ); + ILAPI XImage * ILAPIENTRY ilutXShmLoadImage( Display*,char*,XShmSegmentInfo* ); + ILAPI Pixmap ILAPIENTRY ilutXShmLoadPixmap( Display*,Drawable,char*,XShmSegmentInfo* ); +#endif//ILUT_USE_XSHM +#endif//ILUT_USE_X11 + + +#ifdef __cplusplus +} +#endif + +#endif // __ILUT_H__ +#endif // __ilut_h_ diff --git a/DevILSDK/include/IL/ilut_config.h b/DevILSDK/include/IL/ilut_config.h new file mode 100644 index 0000000..8b187a4 --- /dev/null +++ b/DevILSDK/include/IL/ilut_config.h @@ -0,0 +1,26 @@ +#ifndef __ILUT_CONFIG_H__ +#define __ILUT_CONFIG_H__ + +//#define IL_USE_PRAGMA_LIBS + +// Supported APIs (ILUT) + +// +// sorry just +// cant get this one to work under windows +// have disabled for the now +// +// will look at it some more later +// +// Kriss +// +#undef ILUT_USE_ALLEGRO + +#undef ILUT_USE_DIRECTX8 +//#define ILUT_USE_DIRECTX9 +//#define ILUT_USE_DIRECTX10 +#define ILUT_USE_OPENGL +//#define ILUT_USE_SDL +#define ILUT_USE_WIN32 + +#endif//__ILUT_CONFIG_H__ diff --git a/DevILSDK/include/IL/luadevil.c b/DevILSDK/include/IL/luadevil.c new file mode 100644 index 0000000..1094e1a --- /dev/null +++ b/DevILSDK/include/IL/luadevil.c @@ -0,0 +1,393 @@ +/* +** $Id: luadevil.c,v 1.1 2007-02-12 21:03:04 darkyojimbo Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define lua_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + + +static lua_State *globalL = NULL; + +static const char *progname = LUA_PROGNAME; + + + +static void lstop (lua_State *L, lua_Debug *ar) { + (void)ar; /* unused arg. */ + lua_sethook(L, NULL, 0, 0); + luaL_error(L, "interrupted!"); +} + + +static void laction (int i) { + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); +} + + +static void print_usage (void) { + fprintf(stderr, + "usage: %s [options] [script [args]].\n" + "Available options are:\n" + " -e stat execute string " LUA_QL("stat") "\n" + " -l name require library " LUA_QL("name") "\n" + " -i enter interactive mode after executing " LUA_QL("script") "\n" + " -v show version information\n" + " -- stop handling options\n" + " - execute stdin and stop handling options\n" + , + progname); + fflush(stderr); +} + + +static void l_message (const char *pname, const char *msg) { + if (pname) fprintf(stderr, "%s: ", pname); + fprintf(stderr, "%s\n", msg); + fflush(stderr); +} + + +static int report (lua_State *L, int status) { + if (status && !lua_isnil(L, -1)) { + const char *msg = lua_tostring(L, -1); + if (msg == NULL) msg = "(error object is not a string)"; + l_message(progname, msg); + lua_pop(L, 1); + } + return status; +} + + +static int traceback (lua_State *L) { + lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return 1; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) { + lua_pop(L, 2); + return 1; + } + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ + return 1; +} + + +static int docall (lua_State *L, int narg, int clear) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, traceback); /* push traceback function */ + lua_insert(L, base); /* put it under chunk and args */ + signal(SIGINT, laction); + status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); + signal(SIGINT, SIG_DFL); + lua_remove(L, base); /* remove traceback function */ + /* force a complete garbage collection in case of errors */ + if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); + return status; +} + + +static void print_version (void) { + l_message(NULL, LUA_RELEASE " " LUA_COPYRIGHT); +} + + +static int getargs (lua_State *L, char **argv, int n) { + int narg; + int i; + int argc = 0; + while (argv[argc]) argc++; /* count total number of arguments */ + narg = argc - (n + 1); /* number of arguments to the script */ + luaL_checkstack(L, narg + 3, "too many arguments to script"); + for (i=n+1; i < argc; i++) + lua_pushstring(L, argv[i]); + lua_createtable(L, narg, n + 1); + for (i=0; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i - n); + } + return narg; +} + + +static int dofile (lua_State *L, const char *name) { + int status = luaL_loadfile(L, name) || docall(L, 0, 1); + return report(L, status); +} + + +static int dostring (lua_State *L, const char *s, const char *name) { + int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1); + return report(L, status); +} + + +static int dolibrary (lua_State *L, const char *name) { + lua_getglobal(L, "require"); + lua_pushstring(L, name); + return report(L, lua_pcall(L, 1, 0, 0)); +} + + +static const char *get_prompt (lua_State *L, int firstline) { + const char *p; + lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2"); + p = lua_tostring(L, -1); + if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); + lua_pop(L, 1); /* remove global */ + return p; +} + + +static int incomplete (lua_State *L, int status) { + if (status == LUA_ERRSYNTAX) { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + const char *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); + if (strstr(msg, LUA_QL("")) == tp) { + lua_pop(L, 1); + return 1; + } + } + return 0; /* else... */ +} + + +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) + return 0; /* no input */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(L, status)) break; /* cannot try to add lines? */ + if (!pushline(L, 0)) /* no more input? */ + return -1; + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } + lua_saveline(L, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = loadline(L)) != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + fflush(stdout); + progname = oldprogname; +} + + +static int handle_script (lua_State *L, char **argv, int n) { + int status; + const char *fname; + int narg = getargs(L, argv, n); /* collect arguments */ + lua_setglobal(L, "arg"); + fname = argv[n]; + if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + fname = NULL; /* stdin */ + status = luaL_loadfile(L, fname); + lua_insert(L, -(narg+1)); + if (status == 0) + status = docall(L, narg, 0); + else + lua_pop(L, narg); + return report(L, status); +} + + +/* check that argument has no extra characters at the end */ +#define notail(x) {if ((x)[2] != '\0') return -1;} + + +static int collectargs (char **argv, int *pi, int *pv, int *pe) { + int i; + for (i = 1; argv[i] != NULL; i++) { + if (argv[i][0] != '-') /* not an option? */ + return i; + switch (argv[i][1]) { /* option */ + case '-': + notail(argv[i]); + return (argv[i+1] != NULL ? i+1 : 0); + case '\0': + return i; + case 'i': + notail(argv[i]); + *pi = 1; /* go through */ + case 'v': + notail(argv[i]); + *pv = 1; + break; + case 'e': + *pe = 1; /* go through */ + case 'l': + if (argv[i][2] == '\0') { + i++; + if (argv[i] == NULL) return -1; + } + break; + default: return -1; /* invalid option */ + } + } + return 0; +} + + +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + if (argv[i] == NULL) continue; + lua_assert(argv[i][0] == '-'); + switch (argv[i][1]) { /* option */ + case 'e': { + const char *chunk = argv[i] + 2; + if (*chunk == '\0') chunk = argv[++i]; + lua_assert(chunk != NULL); + if (dostring(L, chunk, "=(command line)") != 0) + return 1; + break; + } + case 'l': { + const char *filename = argv[i] + 2; + if (*filename == '\0') filename = argv[++i]; + lua_assert(filename != NULL); + if (dolibrary(L, filename)) + return 1; /* stop if file fails */ + break; + } + default: break; + } + } + return 0; +} + + +static int handle_luainit (lua_State *L) { + const char *init = getenv(LUA_INIT); + if (init == NULL) return 0; /* status OK */ + else if (init[0] == '@') + return dofile(L, init+1); + else + return dostring(L, init, "=" LUA_INIT); +} + + +struct Smain { + int argc; + char **argv; + int status; +}; + + +static int pmain (lua_State *L) { + struct Smain *s = (struct Smain *)lua_touserdata(L, 1); + char **argv = s->argv; + int script; + int has_i = 0, has_v = 0, has_e = 0; + globalL = L; + if (argv[0] && argv[0][0]) progname = argv[0]; + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ + luaL_openlibs(L); /* open libraries */ + lua_gc(L, LUA_GCRESTART, 0); + s->status = handle_luainit(L); + if (s->status != 0) return 0; + script = collectargs(argv, &has_i, &has_v, &has_e); + if (script < 0) { /* invalid args? */ + print_usage(); + s->status = 1; + return 0; + } + if (has_v) print_version(); + s->status = runargs(L, argv, (script > 0) ? script : s->argc); + if (s->status != 0) return 0; + if (script) + s->status = handle_script(L, argv, script); + if (s->status != 0) return 0; + if (has_i) + dotty(L); + else if (script == 0 && !has_e && !has_v) { + if (lua_stdin_is_tty()) { + print_version(); + dotty(L); + } + else dofile(L, NULL); /* executes stdin as a file */ + } + return 0; +} + + +int main (int argc, char **argv) { + int status; + struct Smain s; + lua_State *L = lua_open(); /* create state */ + printf("DevIL embedded lua interpreter\n"); +//@TODO: Where the heck is this defined? + //Devil_Init(L); + if (L == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + s.argc = argc; + s.argv = argv; + status = lua_cpcall(L, &pmain, &s); + report(L, status); + lua_close(L); + return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; +} + diff --git a/DevILSDK/include/IL/stamp-h.in b/DevILSDK/include/IL/stamp-h.in new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/DevILSDK/include/IL/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/DevILSDK/lib/x64/Release/DevIL.dll b/DevILSDK/lib/x64/Release/DevIL.dll new file mode 100644 index 0000000..51b3450 Binary files /dev/null and b/DevILSDK/lib/x64/Release/DevIL.dll differ diff --git a/DevILSDK/lib/x64/Release/DevIL.lib b/DevILSDK/lib/x64/Release/DevIL.lib new file mode 100644 index 0000000..504d364 Binary files /dev/null and b/DevILSDK/lib/x64/Release/DevIL.lib differ diff --git a/DevILSDK/lib/x64/Release/ILU.dll b/DevILSDK/lib/x64/Release/ILU.dll new file mode 100644 index 0000000..5959615 Binary files /dev/null and b/DevILSDK/lib/x64/Release/ILU.dll differ diff --git a/DevILSDK/lib/x64/Release/ILU.lib b/DevILSDK/lib/x64/Release/ILU.lib new file mode 100644 index 0000000..bc44ef7 Binary files /dev/null and b/DevILSDK/lib/x64/Release/ILU.lib differ diff --git a/DevILSDK/lib/x64/Release/ILUT.dll b/DevILSDK/lib/x64/Release/ILUT.dll new file mode 100644 index 0000000..4eaafcb Binary files /dev/null and b/DevILSDK/lib/x64/Release/ILUT.dll differ diff --git a/DevILSDK/lib/x64/Release/ILUT.lib b/DevILSDK/lib/x64/Release/ILUT.lib new file mode 100644 index 0000000..6bb2aad Binary files /dev/null and b/DevILSDK/lib/x64/Release/ILUT.lib differ diff --git a/DevILSDK/lib/x64/unicode/Release/DevIL.dll b/DevILSDK/lib/x64/unicode/Release/DevIL.dll new file mode 100644 index 0000000..f37e16d Binary files /dev/null and b/DevILSDK/lib/x64/unicode/Release/DevIL.dll differ diff --git a/DevILSDK/lib/x64/unicode/Release/DevIL.lib b/DevILSDK/lib/x64/unicode/Release/DevIL.lib new file mode 100644 index 0000000..1402f93 Binary files /dev/null and b/DevILSDK/lib/x64/unicode/Release/DevIL.lib differ diff --git a/DevILSDK/lib/x64/unicode/Release/ILU.dll b/DevILSDK/lib/x64/unicode/Release/ILU.dll new file mode 100644 index 0000000..6bc6413 Binary files /dev/null and b/DevILSDK/lib/x64/unicode/Release/ILU.dll differ diff --git a/DevILSDK/lib/x64/unicode/Release/ILU.lib b/DevILSDK/lib/x64/unicode/Release/ILU.lib new file mode 100644 index 0000000..a44cbd1 Binary files /dev/null and b/DevILSDK/lib/x64/unicode/Release/ILU.lib differ diff --git a/DevILSDK/lib/x64/unicode/Release/ILUT.dll b/DevILSDK/lib/x64/unicode/Release/ILUT.dll new file mode 100644 index 0000000..e560746 Binary files /dev/null and b/DevILSDK/lib/x64/unicode/Release/ILUT.dll differ diff --git a/DevILSDK/lib/x64/unicode/Release/ILUT.lib b/DevILSDK/lib/x64/unicode/Release/ILUT.lib new file mode 100644 index 0000000..49a0775 Binary files /dev/null and b/DevILSDK/lib/x64/unicode/Release/ILUT.lib differ diff --git a/DevILSDK/lib/x86/Release/DevIL.dll b/DevILSDK/lib/x86/Release/DevIL.dll new file mode 100644 index 0000000..1bd3822 Binary files /dev/null and b/DevILSDK/lib/x86/Release/DevIL.dll differ diff --git a/DevILSDK/lib/x86/Release/DevIL.lib b/DevILSDK/lib/x86/Release/DevIL.lib new file mode 100644 index 0000000..cb7de1e Binary files /dev/null and b/DevILSDK/lib/x86/Release/DevIL.lib differ diff --git a/DevILSDK/lib/x86/Release/ILU.dll b/DevILSDK/lib/x86/Release/ILU.dll new file mode 100644 index 0000000..2966069 Binary files /dev/null and b/DevILSDK/lib/x86/Release/ILU.dll differ diff --git a/DevILSDK/lib/x86/Release/ILU.lib b/DevILSDK/lib/x86/Release/ILU.lib new file mode 100644 index 0000000..5ea04cb Binary files /dev/null and b/DevILSDK/lib/x86/Release/ILU.lib differ diff --git a/DevILSDK/lib/x86/Release/ILUT.dll b/DevILSDK/lib/x86/Release/ILUT.dll new file mode 100644 index 0000000..0fa9deb Binary files /dev/null and b/DevILSDK/lib/x86/Release/ILUT.dll differ diff --git a/DevILSDK/lib/x86/Release/ILUT.lib b/DevILSDK/lib/x86/Release/ILUT.lib new file mode 100644 index 0000000..c78c6a4 Binary files /dev/null and b/DevILSDK/lib/x86/Release/ILUT.lib differ diff --git a/DevILSDK/lib/x86/unicode/Release/DevIL.dll b/DevILSDK/lib/x86/unicode/Release/DevIL.dll new file mode 100644 index 0000000..38b2017 Binary files /dev/null and b/DevILSDK/lib/x86/unicode/Release/DevIL.dll differ diff --git a/DevILSDK/lib/x86/unicode/Release/DevIL.lib b/DevILSDK/lib/x86/unicode/Release/DevIL.lib new file mode 100644 index 0000000..8669310 Binary files /dev/null and b/DevILSDK/lib/x86/unicode/Release/DevIL.lib differ diff --git a/DevILSDK/lib/x86/unicode/Release/ILU.dll b/DevILSDK/lib/x86/unicode/Release/ILU.dll new file mode 100644 index 0000000..7228e66 Binary files /dev/null and b/DevILSDK/lib/x86/unicode/Release/ILU.dll differ diff --git a/DevILSDK/lib/x86/unicode/Release/ILU.lib b/DevILSDK/lib/x86/unicode/Release/ILU.lib new file mode 100644 index 0000000..ab2231f Binary files /dev/null and b/DevILSDK/lib/x86/unicode/Release/ILU.lib differ diff --git a/DevILSDK/lib/x86/unicode/Release/ILUT.dll b/DevILSDK/lib/x86/unicode/Release/ILUT.dll new file mode 100644 index 0000000..c329aaf Binary files /dev/null and b/DevILSDK/lib/x86/unicode/Release/ILUT.dll differ diff --git a/DevILSDK/lib/x86/unicode/Release/ILUT.lib b/DevILSDK/lib/x86/unicode/Release/ILUT.lib new file mode 100644 index 0000000..0219ac0 Binary files /dev/null and b/DevILSDK/lib/x86/unicode/Release/ILUT.lib differ diff --git a/XPlor.ico b/XPlor.ico new file mode 100644 index 0000000..68c58cd Binary files /dev/null and b/XPlor.ico differ diff --git a/XPlor.pro b/XPlor.pro index c155886..0d07980 100644 --- a/XPlor.pro +++ b/XPlor.pro @@ -1,34 +1,72 @@ QT += core gui 3dcore 3drender 3dinput 3dextras +RC_ICONS = XPlor.ico + 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 += \ + aboutdialog.cpp \ + ddsfile.cpp \ + ddsviewer.cpp \ + fastfile.cpp \ + fastfileviewer.cpp \ + imagewidget.cpp \ + iwifile.cpp \ + iwiviewer.cpp \ + localstringviewer.cpp \ + lzokay.cpp \ main.cpp \ - mainwindow.cpp + mainwindow.cpp \ + modelviewer.cpp \ + iwifile.cpp \ + techsetviewer.cpp \ + xtreewidget.cpp \ + zonefile.cpp \ + zonefileviewer.cpp HEADERS += \ + aboutdialog.h \ + asset_structs.h \ + compressor.h \ + d3dbsp_structs.h \ + dds_structs.h \ + ddsfile.h \ + ddsviewer.h \ enums.h \ + fastfile.h \ + fastfileviewer.h \ + imagewidget.h \ + ipak_structs.h \ + iwifile.h \ + iwiviewer.h \ + localstringviewer.h \ + lzokay.hpp \ + lzx.h \ mainwindow.h \ - structs.h \ - utils.h + modelviewer.h \ + techsetviewer.h \ + utils.h \ + xtreewidget.h \ + iwifile.h \ + zonefile.h \ + zonefileviewer.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 + aboutdialog.ui \ + ddsviewer.ui \ + fastfileviewer.ui \ + imagewidget.ui \ + iwiviewer.ui \ + localstringviewer.ui \ + mainwindow.ui \ + techsetviewer.ui \ + zonefileviewer.ui RESOURCES += \ - Data.qrc + data/Data.qrc + +LIBS += -L$$PWD/DevILSDK/lib/x64/Unicode/Release -lDevIL +LIBS += -L$$PWD/DevILSDK/lib/x64/Unicode/Release -lILU +LIBS += -L$$PWD/DevILSDK/lib/x64/Unicode/Release -lILUT diff --git a/XPlor.pro.user b/XPlor.pro.user deleted file mode 100644 index b77ffa5..0000000 --- a/XPlor.pro.user +++ /dev/null @@ -1,269 +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 - 0 - 0 - 0 - - 0 - C:\Users\njohnson\Projects\XPlor\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Debug - C:/Users/njohnson/Projects/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 - - - C:\Users\njohnson\Projects\XPlor\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Release - C:/Users/njohnson/Projects/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 - - - 0 - C:\Users\njohnson\Projects\XPlor\build\Desktop_Qt_6_8_1_MSVC2022_64bit-Profile - C:/Users/njohnson/Projects/XPlor/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 - - ProjectExplorer.CustomExecutableRunConfiguration - - false - true - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/aboutdialog.cpp b/aboutdialog.cpp new file mode 100644 index 0000000..c3ba1b4 --- /dev/null +++ b/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/aboutdialog.h b/aboutdialog.h new file mode 100644 index 0000000..4474ece --- /dev/null +++ b/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/aboutdialog.ui b/aboutdialog.ui new file mode 100644 index 0000000..27665f5 --- /dev/null +++ b/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/asset_structs.h b/asset_structs.h new file mode 100644 index 0000000..f3bb206 --- /dev/null +++ b/asset_structs.h @@ -0,0 +1,346 @@ +#ifndef ASSET_STRUCTS_H +#define ASSET_STRUCTS_H + +#include "enums.h" + +#include +#include +#include + +struct LocalString { + QString string; + QString alias; +}; + +struct RawFile { + quint32 length; + QString path; + QString contents; +}; + +struct TechSet { + QString name; + bool hasShaders = false; + QVector pointers; +}; + +struct Shader { + quint32 shaderPtr; +}; + +struct XModelCollSurf_s +{ + float mins[3]; + float maxs[3]; + int boneIdx; + int contents; + int surfFlags; +}; + +struct XModelLodInfo +{ + float dist; + unsigned short numsurfs; + unsigned short surfIndex; + int partBits[5]; +}; + +struct XModelHighMipBounds +{ + float mins[3]; + float maxs[3]; +}; + +struct XModelStreamInfo +{ + XModelHighMipBounds *highMipBounds; +}; + +struct XBoneInfo +{ + float bounds[2][3]; + float offset[3]; + float radiusSquared; +}; + +struct Model { + quint32 namePtr; + quint8 tagCount; + quint8 rootTagCount; + quint8 surfCount; + quint8 unknownCount; + quint32 boneNamePtr; + quint32 parentListPtr; + quint32 quatsPtr; + quint32 transPtr; + quint32 partClassPtr; + quint32 baseMatPtr; + quint32 surfsPtr; + quint32 materialHandlesPtr; + + XModelLodInfo lodInfo[4]; + quint32 collSurfsPtr; + int numCollSurfs; + int contents; + quint32 boneInfoPtr; + float radius; + float mins[3]; + float maxs[3]; + short numLods; + short collLod; + quint32 streamInfoPtr; // is not loaded on ps3 + int memUsage; + char flags; + quint32 physPresetPtr; + quint32 physGeomsPtr; + + QString modelName; +}; + +struct Animation { + quint16 dataByteCount; + quint16 dataShortCount; + quint16 dataIntCount; + quint16 randomDataByteCount; + quint16 randomDataIntCount; + quint16 numframes; + bool isLooped; + bool isDelta; + quint8 noneRotatedBoneCount; + quint8 twoDRotatedBoneCount; + quint8 normalRotatedBoneCount; + quint8 twoDStaticRotatedBoneCount; + quint8 normalStaticRotatedBoneCount; + quint8 normalTranslatedBoneCount; + quint8 preciseTranslatedBoneCount; + quint8 staticTranslatedBoneCount; + quint8 noneTranslatedBoneCount; + quint8 totalBoneCount; + quint8 otherBoneCount1; + quint8 otherBoneCount2; + quint8 notifyCount; + quint8 assetType; + bool pad; + unsigned int randomDataShortCount; + unsigned int indexCount; + float frameRate; + float frequency; + quint32 boneIDsPtr; + quint32 dataBytePtr; + quint32 dataShortPtr; + quint32 dataIntPtr; + quint32 randomDataShortPtr; + quint32 randomDataBytePtr; + quint32 randomDataIntPtr; + quint32 longIndiciesPtr; + quint32 notificationsPtr; + quint32 deltaPartsPtr; + QString name; +}; + +struct StringTable { + quint32 columnCount; + quint32 rowCount; + QString name; +}; + +struct Image { + QString name; + QString materialName; + quint32 size1; + quint32 size2; + IMAGE_COMPRESSION compression; + quint32 unknowna; + quint32 unknownb; + quint32 unknownc; + quint32 unknownd; + quint32 unknowne; + quint32 unknownf; + quint32 unknowng; + quint32 unknownh; + quint32 unknowni; + quint32 unknownj; + quint32 unknownk; + quint32 unknownl; + quint32 unknownm; + quint32 unknown1; + quint32 unknown2; + quint32 unknown3; + quint32 unknown4; + quint32 unknown5; + quint32 unknown6; + quint32 unknown7; + quint32 unknown8; + quint32 unknown9; +}; + +struct Menu { + QString filePath; + QString name; + QString definition; + quint32 menuNamePtr; + QRectF rect; + MENU_H_ALIGNMENT hAlign; + MENU_V_ALIGNMENT vAlign; + QRectF clientRect; + MENU_H_ALIGNMENT hClientAlign; + MENU_V_ALIGNMENT vClientAlign; + quint32 groupPtr; + MENU_WINDOW_STYLE style; + MENU_WINDOW_BORDER border; + quint32 ownerDraw; + quint32 ownerDrawFlags; + float borderSize; + int staticFlags; + float dynamicFlags; + float nextTime; + QColor foregroundColor; + QColor backgroundColor; + QColor borderColor; + QColor outlineColor; + quint32 materialPtr; + quint32 fontPtr; + quint32 fullScreen; + quint32 itemCount; + quint32 fontIndex; + quint32 cursorItem; + quint32 fadeCycle; + float fadeClamp; + float fadeAmount; + float fadeInAmount; + float blurRadius; + quint32 onOpenPtr; + quint32 onFocusPtr; + quint32 onClosePtr; + quint32 onESCPtr; + quint32 onKeyPtr; + quint32 visibleExpCount; + quint32 expEntryPtr; + quint32 allowedBindingPtr; + quint32 soundNamePtr; + quint32 imageTrack; + QColor focusColor; + QColor disabledColor; + quint32 rectXExpCount; + quint32 rectXExpPtr; + quint32 rectYExpCount; + quint32 rectYExpPtr; + quint32 itemWindowDefNamePtr; + QRectF itemRect; + MENU_H_ALIGNMENT itemHAlignment; + MENU_V_ALIGNMENT itemVAlignment; + quint32 itemGroupPtr; + MENU_WINDOW_STYLE itemWindowStyle; + MENU_WINDOW_BORDER itemWindowBorder; + quint32 itemOwnerDraw; + quint32 itemOwnerDrawFlags; + float itemBorderSize; + int itemStaticFlags; + int itemDynamicFlags; + int itemNextTime; + QColor itemForegroundColor; + QColor itemBackgroundColor; + QColor itemBorderColor; + QColor itemOutlineColor; + quint32 itemMaterialPtr; + QRectF itemTextRect; + MENU_H_ALIGNMENT itemText_hAlign; + MENU_V_ALIGNMENT itemText_vAlign; + MENU_ITEM_TYPE itemType; + quint32 dataType; + quint32 alignment; + MENU_FONT_TYPE fontEnum; + quint32 textAlignMode; + float textalignx; + float textaligny; + float textscale; + MENU_ITEM_TEXTSTYLE textStyle; + int gameMsgWindowIndex; + int gameMsgWindowMode; + quint32 testPtr; + quint32 textSavegameInfo; + quint32 parentPtr; + quint32 mouseEnterText; + quint32 mouseExitText; + quint32 mouseEnter; + quint32 mouseExit; + quint32 action; + quint32 onAccept; + quint32 onFocus; + quint32 leaveFocus; + quint32 dvar; + quint32 dvarTest; + quint32 keyHandlerPtr; + quint32 enableDvarPtr; + quint32 dvarFlags; + quint32 focusSoundPtr; + float special; + quint32 cursorPos; + // itemDefData_t typeData; + // listBoxDef_s *listBox; + quint32 startPos; + quint32 endPos; + quint32 drawPadding; + float elementWidth, elementHeight; + quint32 elementStyle, numColumns; + //columnInfo_s columnInfo[16]; + quint32 doubleClickPtr; + int notselectable; + int noScrollBars; + int usePaging; + QColor itemSelectBorderColor; + QColor itemDisableColor; + QColor itemFocusColor; + quint32 selectIconPtr; + quint32 backgroundItemListboxPtr; + quint32 highlightTexturePtr; + // editFieldDef_s *editField; + float minVal; + float maxVal; + float defVal; + float range; + int maxChars; + int maxCharsGotoNext; + int maxPaintChars; + int paintOffset; + // multiDef_s *multi; + QVector dvarListPtrs; + QVector dvarStrPtrs; + QVector dvarValues; + quint32 count; + quint32 strDef; + quint32 enumDvarNamePtr; + quint32 dataPtr; + quint32 itemImageTrack; +}; + +struct MenuFile { + quint32 menuCount; + QVector menuDefs; +}; + +struct AssetMap { + QVector localStrings; + QVector rawFiles; + //QVector phyPresets; + QVector models; + //QVector rawFiles; + //QVector shaders; + QVector techSets; + QVector images; + //QVector sounds; + //QVector collMaps; + //QVector lightDefs; + //QVector uiMaps; + //QVector driverGlobals; + //QVector aiType; + //QVector effects; + QVector animations; + QVector stringTables; + QVector menuFiles; + //QVector weapons; + //QVector d3dbspDumps; + //QVector spMaps; +}; + +#endif // ASSET_STRUCTS_H diff --git a/compressor.h b/compressor.h new file mode 100644 index 0000000..459cbf3 --- /dev/null +++ b/compressor.h @@ -0,0 +1,410 @@ +#ifndef COMPRESSOR_H +#define COMPRESSOR_H + +#include "utils.h" +#include "QtZlib/zlib.h" +#include "lzokay.hpp" +#include "lzx.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + EResult_LookbehindOverrun = -4, + EResult_OutputOverrun = -3, + EResult_InputOverrun = -2, + EResult_Error = -1, + EResult_Success = 0, + EResult_InputNotConsumed = 1, +} lzokay_EResult; + +static_assert(EResult_LookbehindOverrun == lzokay_EResult(lzokay::EResult::LookbehindOverrun), "LookbehindOverrun mismatch"); +static_assert(EResult_OutputOverrun == lzokay_EResult(lzokay::EResult::OutputOverrun), "OutputOverrun mismatch"); +static_assert(EResult_InputOverrun == lzokay_EResult(lzokay::EResult::InputOverrun), "InputOverrun mismatch"); +static_assert(EResult_Error == lzokay_EResult(lzokay::EResult::Error), "Error mismatch"); +static_assert(EResult_Success == lzokay_EResult(lzokay::EResult::Success), "Success mismatch"); +static_assert(EResult_InputNotConsumed == lzokay_EResult(lzokay::EResult::InputNotConsumed), "InputNotConsumed mismatch"); + +class Compressor { +public: + static QByteArray DecompressZLIB(const QByteArray &compressedData) { + if (compressedData.isEmpty()) + return QByteArray(); + + // Set up the inflate stream. + z_stream strm; + memset(&strm, 0, sizeof(strm)); + // The inflate() function needs a non-const pointer; this is safe as we never modify the input. + strm.next_in = reinterpret_cast(const_cast(compressedData.data())); + strm.avail_in = static_cast(compressedData.size()); + + // Use inflateInit(); if you want to support gzip streams, see note below. + int ret = inflateInit(&strm); + if (ret != Z_OK) { + qWarning() << "inflateInit failed:" << zError(ret); + return QByteArray(); + } + + QByteArray outArray; + char buffer[4096]; + + // Decompress until we reach the stream end. + do { + strm.next_out = reinterpret_cast(buffer); + strm.avail_out = sizeof(buffer); + + ret = inflate(&strm, Z_NO_FLUSH); + // Handle a special case: if inflate() returns Z_BUF_ERROR without + // having produced any output and with no further input, then we break out. + if (ret == Z_BUF_ERROR && strm.avail_in == 0) { + break; + } + if (ret != Z_OK && ret != Z_STREAM_END) { + qWarning() << "Error: ZLib inflate failed:" << zError(ret); + inflateEnd(&strm); + return QByteArray(); + } + + // Calculate number of bytes produced in this iteration. + int bytesProduced = sizeof(buffer) - strm.avail_out; + if (bytesProduced > 0) + outArray.append(buffer, bytesProduced); + + } while (ret != Z_STREAM_END); + + inflateEnd(&strm); + return outArray; + } + + static QByteArray DecompressLZO(const QByteArray& input) { + lzokay::EResult error; + + // Ensure the input QByteArray is valid + if (input.isEmpty()) { + qDebug() << "Input QByteArray is empty."; + return QByteArray(); + } + + // Step 1: Cast QByteArray to uint8_t* + const uint8_t *compressedData = reinterpret_cast(input.constData()); + std::size_t compressedSize = static_cast(input.size()); + + // Step 2: Allocate a sufficiently large decompression buffer + // Use a large initial estimate if the decompressed size is unknown + std::size_t initialBufferSize = compressedSize * 20; // Arbitrary multiplier for decompression + std::unique_ptr decompressed(new uint8_t[initialBufferSize]); + + // Step 3: Attempt decompression + std::size_t decompressedSize = 0; + error = lzokay::decompress( + compressedData, compressedSize, // Input data and size + decompressed.get(), initialBufferSize, // Output buffer and initial size + decompressedSize // Actual decompressed size + ); + + // Step 4: Handle decompression errors + if (error != lzokay::EResult::Success) { + qDebug() << "Decompression failed with error code:" << static_cast(error); + return QByteArray(); + } + + // Step 5: Return the decompressed data as a QByteArray + return QByteArray(reinterpret_cast(decompressed.get()), decompressedSize); + } + + static const int VECTOR_SIZE = 16; // 16 32-bit words + static const int NUM_OF_BLOCKS_PER_CHUNK = 8192; + + //-------------------------------------------------------------------- + // Helper functions (assuming little–endian order) + + static void Convert32BitTo8Bit(quint32 value, quint8* array) { + array[0] = static_cast(value >> 0); + array[1] = static_cast(value >> 8); + array[2] = static_cast(value >> 16); + array[3] = static_cast(value >> 24); + } + + static quint32 ConvertArrayTo32Bit(const QByteArray &array) { + return ((static_cast(static_cast(array[0])) << 0) | + (static_cast(static_cast(array[1])) << 8) | + (static_cast(static_cast(array[2])) << 16) | + (static_cast(static_cast(array[3])) << 24)); + } + + static quint32 Rotate(quint32 value, quint32 numBits) { + return (value << numBits) | (value >> (32 - numBits)); + } + + // Build the IV table from a 0x20–byte feed. The table is 0xFB0 bytes. + static QByteArray InitIVTable(const QByteArray &feed) { + const int tableSize = 0xFB0; + QByteArray table; + table.resize(tableSize); + int ptr = 0; + for (int i = 0; i < 200; ++i) { + for (int x = 0; x < 5; ++x) { + if (static_cast(feed.at(ptr)) == 0x00) + ptr = 0; + int base = i * 20 + x * 4; + table[base] = feed.at(ptr); + table[base + 1] = feed.at(ptr); + table[base + 2] = feed.at(ptr); + table[base + 3] = feed.at(ptr); + ++ptr; + } + } + // Copy block numbers [1,0,0,0] into the last 16 bytes + QByteArray oneBlock; + oneBlock.append(char(1)); oneBlock.append(char(0)); oneBlock.append(char(0)); oneBlock.append(char(0)); + table.replace(0xFA0, 4, oneBlock); + table.replace(0xFA4, 4, oneBlock); + table.replace(0xFA8, 4, oneBlock); + table.replace(0xFAC, 4, oneBlock); + return table; + } + + // "unk" function as in the C# code. + static int unk(quint64 arg1, quint8 arg2) { + if (arg2 >= 0x40) + return 0; + return static_cast(arg1 >> arg2); + } + + // Compute the IV for a given section index using the IV table. + static QByteArray GetIV(const QByteArray &table, int index) { + int num1 = 0xFA0 + index; + int num2 = unk(0x51EB851FLL * num1, 0x20); + int adjust = ((num2 >> 6) + (num2 >> 31)); + int startIndex = 20 * (num1 - 200 * adjust); + // Return 8 bytes from that location. + return table.mid(startIndex, 8); + } + + // Update the IV table given the section's SHA1 hash. + static void UpdateIVTable(QByteArray &table, int index, const QByteArray §ionHash) { + int blockNumIndex = index % 4; + int baseOffset = 0xFA0 + blockNumIndex * 4; + quint32 blockNumVal = (static_cast(table.at(baseOffset)) ) | + (static_cast(table.at(baseOffset + 1)) << 8 ) | + (static_cast(table.at(baseOffset + 2)) << 16) | + (static_cast(table.at(baseOffset + 3)) << 24); + int blockNum = blockNumVal * 4 + index; + int num2 = unk(0x51EB851FLL * blockNum, 0x20); + int adjust = ((num2 >> 6) + (num2 >> 31)); + int startIndex = 20 * (blockNum - 200 * adjust) + 1; + int hashIndex = 0; + for (int x = 0; x < 4; ++x) { + table[startIndex - 1] = table.at(startIndex - 1) ^ sectionHash.at(hashIndex); + table[startIndex] = table.at(startIndex) ^ sectionHash.at(hashIndex + 1); + table[startIndex + 1] = table.at(startIndex + 1) ^ sectionHash.at(hashIndex + 2); + table[startIndex + 2] = table.at(startIndex + 2) ^ sectionHash.at(hashIndex + 3); + table[startIndex + 3] = table.at(startIndex + 3) ^ sectionHash.at(hashIndex + 4); + startIndex += 5; + hashIndex += 5; + } + } + + static quint32 ToUInt32(const QByteArray &data, int offset) { + // Converts 4 bytes (starting at offset) from data into a 32-bit unsigned integer (little-endian) + return ((static_cast(static_cast(data[offset])) ) | + (static_cast(static_cast(data[offset+1])) << 8 ) | + (static_cast(static_cast(data[offset+2])) << 16) | + (static_cast(static_cast(data[offset+3])) << 24)); + } + + //-------------------------------------------------------------------- + // Salsa20 decryption for one section. + // This function resets the counter for each section. + static QByteArray salsa20DecryptSection(const QByteArray §ionData, const QByteArray &key, const QByteArray &iv, int blockSize = 64) + { + // Choose the appropriate constant based on key length. + QByteArray constants; + if (key.size() == 32) + constants = "expand 32-byte k"; + else if (key.size() == 16) + constants = "expand 16-byte k"; + else { + qWarning() << "Invalid key size:" << key.size() << "; expected 16 or 32 bytes."; + return QByteArray(); + } + + QVector state(VECTOR_SIZE); + + // Set state[0] using the first 4 bytes of the constant. + state[0] = ConvertArrayTo32Bit(constants.mid(0, 4)); + + // state[1] through state[4] come from the first 16 bytes of the key. + state[1] = ToUInt32(key, 0); + state[2] = ToUInt32(key, 4); + state[3] = ToUInt32(key, 8); + state[4] = ToUInt32(key, 12); + + // state[5] comes from the next 4 bytes of the constant. + state[5] = ConvertArrayTo32Bit(constants.mid(4, 4)); + + // state[6] and state[7] come from the IV (which must be 8 bytes). + state[6] = ConvertArrayTo32Bit(iv.mid(0, 4)); + state[7] = ConvertArrayTo32Bit(iv.mid(4, 4)); + + // state[8] and state[9] are the 64-bit block counter (start at 0). + state[8] = 0; + state[9] = 0; + + // state[10] comes from the next 4 bytes of the constant. + state[10] = ConvertArrayTo32Bit(constants.mid(8, 4)); + + // For state[11] through state[14]: + // If the key is 32 bytes, use bytes 16..31; if 16 bytes, reuse the first 16 bytes. + if (key.size() == 32) { + state[11] = ToUInt32(key, 16); + state[12] = ToUInt32(key, 20); + state[13] = ToUInt32(key, 24); + state[14] = ToUInt32(key, 28); + } else { // key.size() == 16 + state[11] = ToUInt32(key, 0); + state[12] = ToUInt32(key, 4); + state[13] = ToUInt32(key, 8); + state[14] = ToUInt32(key, 12); + } + + // state[15] comes from the last 4 bytes of the constant. + state[15] = ConvertArrayTo32Bit(constants.mid(12, 4)); + + // Prepare the output buffer. + QByteArray output(sectionData.size(), Qt::Uninitialized); + int numBlocks = sectionData.size() / blockSize; + int remainder = sectionData.size() % blockSize; + + // Process each full block. + for (int blockIndex = 0; blockIndex < numBlocks; ++blockIndex) { + QVector x = state; // make a copy of the current state for this block + + // Run 20 rounds (10 iterations) of Salsa20. + for (int round = 20; round > 0; round -= 2) { + x[4] ^= Rotate(x[0] + x[12], 7); + x[8] ^= Rotate(x[4] + x[0], 9); + x[12] ^= Rotate(x[8] + x[4], 13); + x[0] ^= Rotate(x[12] + x[8], 18); + + x[9] ^= Rotate(x[5] + x[1], 7); + x[13] ^= Rotate(x[9] + x[5], 9); + x[1] ^= Rotate(x[13] + x[9], 13); + x[5] ^= Rotate(x[1] + x[13], 18); + + x[14] ^= Rotate(x[10] + x[6], 7); + x[2] ^= Rotate(x[14] + x[10], 9); + x[6] ^= Rotate(x[2] + x[14], 13); + x[10] ^= Rotate(x[6] + x[2], 18); + + x[3] ^= Rotate(x[15] + x[11], 7); + x[7] ^= Rotate(x[3] + x[15], 9); + x[11] ^= Rotate(x[7] + x[3], 13); + x[15] ^= Rotate(x[11] + x[7], 18); + + x[1] ^= Rotate(x[0] + x[3], 7); + x[2] ^= Rotate(x[1] + x[0], 9); + x[3] ^= Rotate(x[2] + x[1], 13); + x[0] ^= Rotate(x[3] + x[2], 18); + + x[6] ^= Rotate(x[5] + x[4], 7); + x[7] ^= Rotate(x[6] + x[5], 9); + x[4] ^= Rotate(x[7] + x[6], 13); + x[5] ^= Rotate(x[4] + x[7], 18); + + x[11] ^= Rotate(x[10] + x[9], 7); + x[8] ^= Rotate(x[11] + x[10], 9); + x[9] ^= Rotate(x[8] + x[11], 13); + x[10] ^= Rotate(x[9] + x[8], 18); + + x[12] ^= Rotate(x[15] + x[14], 7); + x[13] ^= Rotate(x[12] + x[15], 9); + x[14] ^= Rotate(x[13] + x[12], 13); + x[15] ^= Rotate(x[14] + x[13], 18); + } + + // Produce the 64-byte keystream block by adding the original state. + QVector keyStreamBlock(blockSize); + for (int i = 0; i < VECTOR_SIZE; ++i) { + x[i] += state[i]; + Convert32BitTo8Bit(x[i], keyStreamBlock.data() + 4 * i); + } + + // XOR the keystream block with the corresponding block of sectionData. + const uchar* inBlock = reinterpret_cast(sectionData.constData()) + blockIndex * blockSize; + uchar* outBlock = reinterpret_cast(output.data()) + blockIndex * blockSize; + for (int j = 0; j < blockSize; ++j) { + outBlock[j] = inBlock[j] ^ keyStreamBlock[j]; + } + // Increment the 64-bit block counter. + state[8]++; + if (state[8] == 0) + state[9]++; + } + + // Process any remaining bytes. + if (remainder > 0) { + QVector x = state; + for (int round = 20; round > 0; round -= 2) { + x[4] ^= Rotate(x[0] + x[12], 7); + x[8] ^= Rotate(x[4] + x[0], 9); + x[12] ^= Rotate(x[8] + x[4], 13); + x[0] ^= Rotate(x[12] + x[8], 18); + + x[9] ^= Rotate(x[5] + x[1], 7); + x[13] ^= Rotate(x[9] + x[5], 9); + x[1] ^= Rotate(x[13] + x[9], 13); + x[5] ^= Rotate(x[1] + x[13], 18); + + x[14] ^= Rotate(x[10] + x[6], 7); + x[2] ^= Rotate(x[14] + x[10], 9); + x[6] ^= Rotate(x[2] + x[14], 13); + x[10] ^= Rotate(x[6] + x[2], 18); + + x[3] ^= Rotate(x[15] + x[11], 7); + x[7] ^= Rotate(x[3] + x[15], 9); + x[11] ^= Rotate(x[7] + x[3], 13); + x[15] ^= Rotate(x[11] + x[7], 18); + + x[1] ^= Rotate(x[0] + x[3], 7); + x[2] ^= Rotate(x[1] + x[0], 9); + x[3] ^= Rotate(x[2] + x[1], 13); + x[0] ^= Rotate(x[3] + x[2], 18); + + x[6] ^= Rotate(x[5] + x[4], 7); + x[7] ^= Rotate(x[6] + x[5], 9); + x[4] ^= Rotate(x[7] + x[6], 13); + x[5] ^= Rotate(x[4] + x[7], 18); + + x[11] ^= Rotate(x[10] + x[9], 7); + x[8] ^= Rotate(x[11] + x[10], 9); + x[9] ^= Rotate(x[8] + x[11], 13); + x[10] ^= Rotate(x[9] + x[8], 18); + + x[12] ^= Rotate(x[15] + x[14], 7); + x[13] ^= Rotate(x[12] + x[15], 9); + x[14] ^= Rotate(x[13] + x[12], 13); + x[15] ^= Rotate(x[14] + x[13], 18); + } + QVector keyStreamBlock(blockSize); + for (int i = 0; i < VECTOR_SIZE; ++i) { + x[i] += state[i]; + Convert32BitTo8Bit(x[i], keyStreamBlock.data() + 4 * i); + } + const uchar* inBlock = reinterpret_cast(sectionData.constData()) + numBlocks * blockSize; + uchar* outBlock = reinterpret_cast(output.data()) + numBlocks * blockSize; + for (int j = 0; j < remainder; ++j) + outBlock[j] = inBlock[j] ^ keyStreamBlock[j]; + } + + return output; + } +}; + + +#endif // COMPRESSOR_H diff --git a/structs.h b/d3dbsp_structs.h similarity index 75% rename from structs.h rename to d3dbsp_structs.h index 443470e..488acc9 100644 --- a/structs.h +++ b/d3dbsp_structs.h @@ -1,5 +1,5 @@ -#ifndef STRUCTS_H -#define STRUCTS_H +#ifndef D3DBSP_STRUCTS_H +#define D3DBSP_STRUCTS_H #include @@ -16,4 +16,4 @@ struct LumpIndexEntry { quint32 length; }; -#endif // STRUCTS_H +#endif // D3DBSP_STRUCTS_H diff --git a/data/Data.qrc b/data/Data.qrc new file mode 100644 index 0000000..44abea1 --- /dev/null +++ b/data/Data.qrc @@ -0,0 +1,57 @@ + + + obj/defaultactor_LOD0.XMODEL_BIN + obj/defaultactor_LOD0.XMODEL_EXPORT + obj/defaultactor_LOD0.bin + obj/defaultactor_LOD0.cast + obj/defaultactor_LOD0.gltf + obj/defaultactor_LOD0.ma + obj/defaultactor_LOD0.mesh.ascii + obj/defaultactor_LOD0.obj + obj/defaultactor_LOD0.semodel + obj/defaultactor_LOD0.smd + obj/defaultactor_LOD0_BIND.mel + obj/defaultactor_LOD0_cosmetics.mel + obj/diffusemap.png + obj/mtl_body_default_character.mtl + obj/mtl_body_default_character_images.txt + obj/normalmap.png + + + d3dbsp/asset_viewer.d3dbsp + d3dbsp/barebones.d3dbsp + + + images/XPlor.png + images/copy.svg + images/cut.svg + images/multiple.png + images/new_file.svg + images/open_file.svg + images/open_folder.svg + images/paste.svg + images/refresh.svg + images/save.svg + + + icons/Icon_COD4.png + icons/Icon_COD5.png + icons/Icon_COD6.png + icons/Icon_COD7.png + icons/Icon_COD8.png + icons/Icon_COD9.png + icons/Icon_DDSFile.png + icons/Icon_FastFile.png + icons/Icon_IWIFile.png + icons/Icon_PC.png + icons/Icon_Playstation.png + icons/Icon_Xbox.png + icons/Icon_ZoneFile.png + icons/Icon_GSCFile.png + icons/Icon_StringFile.png + icons/Icon_TechSetFile.png + icons/Icon_WAVFile.png + icons/Icon_MenuFile.png + icons/Icon_Image.png + + diff --git a/data/icons/Icon_COD4.png b/data/icons/Icon_COD4.png new file mode 100644 index 0000000..fa0df53 Binary files /dev/null and b/data/icons/Icon_COD4.png differ diff --git a/data/icons/Icon_COD5.png b/data/icons/Icon_COD5.png new file mode 100644 index 0000000..81b926a Binary files /dev/null and b/data/icons/Icon_COD5.png differ diff --git a/data/icons/Icon_COD6.png b/data/icons/Icon_COD6.png new file mode 100644 index 0000000..aecb4b0 Binary files /dev/null and b/data/icons/Icon_COD6.png differ diff --git a/data/icons/Icon_COD7.png b/data/icons/Icon_COD7.png new file mode 100644 index 0000000..d237f37 Binary files /dev/null and b/data/icons/Icon_COD7.png differ diff --git a/data/icons/Icon_COD8.png b/data/icons/Icon_COD8.png new file mode 100644 index 0000000..57f6d45 Binary files /dev/null and b/data/icons/Icon_COD8.png differ diff --git a/data/icons/Icon_COD9.png b/data/icons/Icon_COD9.png new file mode 100644 index 0000000..ac82d59 Binary files /dev/null and b/data/icons/Icon_COD9.png differ diff --git a/data/icons/Icon_DDSFile.png b/data/icons/Icon_DDSFile.png new file mode 100644 index 0000000..d9aa7eb Binary files /dev/null and b/data/icons/Icon_DDSFile.png differ diff --git a/data/icons/Icon_FastFile.png b/data/icons/Icon_FastFile.png new file mode 100644 index 0000000..8221e33 Binary files /dev/null and b/data/icons/Icon_FastFile.png differ diff --git a/data/icons/Icon_GSCFile.png b/data/icons/Icon_GSCFile.png new file mode 100644 index 0000000..9a5fad0 Binary files /dev/null and b/data/icons/Icon_GSCFile.png differ diff --git a/data/icons/Icon_IWIFile.png b/data/icons/Icon_IWIFile.png new file mode 100644 index 0000000..0a9e2fd Binary files /dev/null and b/data/icons/Icon_IWIFile.png differ diff --git a/data/icons/Icon_Image.png b/data/icons/Icon_Image.png new file mode 100644 index 0000000..5f31b19 Binary files /dev/null and b/data/icons/Icon_Image.png differ diff --git a/data/icons/Icon_MenuFile.png b/data/icons/Icon_MenuFile.png new file mode 100644 index 0000000..7d40946 Binary files /dev/null and b/data/icons/Icon_MenuFile.png differ diff --git a/data/icons/Icon_PC.png b/data/icons/Icon_PC.png new file mode 100644 index 0000000..b71e03d Binary files /dev/null and b/data/icons/Icon_PC.png differ diff --git a/data/icons/Icon_Playstation.png b/data/icons/Icon_Playstation.png new file mode 100644 index 0000000..c706d53 Binary files /dev/null and b/data/icons/Icon_Playstation.png differ diff --git a/data/icons/Icon_StringFile.png b/data/icons/Icon_StringFile.png new file mode 100644 index 0000000..ac3e25f Binary files /dev/null and b/data/icons/Icon_StringFile.png differ diff --git a/data/icons/Icon_TechSetFile.png b/data/icons/Icon_TechSetFile.png new file mode 100644 index 0000000..96fc774 Binary files /dev/null and b/data/icons/Icon_TechSetFile.png differ diff --git a/data/icons/Icon_WAVFile.png b/data/icons/Icon_WAVFile.png new file mode 100644 index 0000000..f7e43e8 Binary files /dev/null and b/data/icons/Icon_WAVFile.png differ diff --git a/data/icons/Icon_Xbox.png b/data/icons/Icon_Xbox.png new file mode 100644 index 0000000..c25da9a Binary files /dev/null and b/data/icons/Icon_Xbox.png differ diff --git a/data/icons/Icon_ZoneFile.png b/data/icons/Icon_ZoneFile.png new file mode 100644 index 0000000..f9e8daf Binary files /dev/null and b/data/icons/Icon_ZoneFile.png differ diff --git a/data/images/XPlor.png b/data/images/XPlor.png new file mode 100644 index 0000000..babe14d Binary files /dev/null and b/data/images/XPlor.png differ diff --git a/data/images/copy.svg b/data/images/copy.svg new file mode 100644 index 0000000..f09d902 --- /dev/null +++ b/data/images/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/cut.svg b/data/images/cut.svg new file mode 100644 index 0000000..c563fb2 --- /dev/null +++ b/data/images/cut.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/multiple.png b/data/images/multiple.png new file mode 100644 index 0000000..a18bbb4 Binary files /dev/null and b/data/images/multiple.png differ diff --git a/data/images/new_file.svg b/data/images/new_file.svg new file mode 100644 index 0000000..7c19795 --- /dev/null +++ b/data/images/new_file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/open_file.svg b/data/images/open_file.svg new file mode 100644 index 0000000..ee0ee85 --- /dev/null +++ b/data/images/open_file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/open_folder.svg b/data/images/open_folder.svg new file mode 100644 index 0000000..3e7b372 --- /dev/null +++ b/data/images/open_folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/paste.svg b/data/images/paste.svg new file mode 100644 index 0000000..bb4e796 --- /dev/null +++ b/data/images/paste.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/refresh.svg b/data/images/refresh.svg new file mode 100644 index 0000000..4e6d30c --- /dev/null +++ b/data/images/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/images/save.svg b/data/images/save.svg new file mode 100644 index 0000000..4f76105 --- /dev/null +++ b/data/images/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dds_structs.h b/dds_structs.h new file mode 100644 index 0000000..9058a9a --- /dev/null +++ b/dds_structs.h @@ -0,0 +1,8 @@ +#ifndef DDS_STRUCTS_H +#define DDS_STRUCTS_H + +#include +#include + + +#endif // DDS_STRUCTS_H diff --git a/ddsfile.cpp b/ddsfile.cpp new file mode 100644 index 0000000..bae7cec --- /dev/null +++ b/ddsfile.cpp @@ -0,0 +1,345 @@ +#include "ddsfile.h" +#include "enums.h" +#include "iwifile.h" + +DDSPixelFormat DDSFile::CalculatePixelFormat(quint8 aIWIFormat) { + DDSPixelFormat ddsPixelFormat = {}; + ddsPixelFormat.size = 16; // Fixed + ddsPixelFormat.format = 0; + + switch (aIWIFormat) { + case IWI_FORMAT_ARGB32: + ddsPixelFormat.flags = DDPF_RGB | DDPF_ALPHAPIXELS; + ddsPixelFormat.rgbBitCount = 32; + ddsPixelFormat.rBitMask = 0x00ff0000; + ddsPixelFormat.gBitMask = 0x0000ff00; + ddsPixelFormat.bBitMask = 0x000000ff; + ddsPixelFormat.aBitMask = 0xff000000; + break; + case IWI_FORMAT_DXT1: + ddsPixelFormat.flags = DDPF_FOURCC; + ddsPixelFormat.format = 0x31545844; + break; + case IWI_FORMAT_DXT3: + ddsPixelFormat.flags = DDPF_FOURCC; + ddsPixelFormat.format = 0x33545844; + break; + case IWI_FORMAT_DXT5: + ddsPixelFormat.flags = DDPF_FOURCC; + ddsPixelFormat.format = 0x35545844; + break; + default: + qDebug() << "Error: Invalid IWI format: " << aIWIFormat; + return {}; + } + return ddsPixelFormat; +} + +void DDSFile::SetupExportDirs() { + QDir dir = QDir::currentPath(); + if (!dir.exists("exports/")) { + dir.mkdir("exports/"); + } + + if (!dir.exists("exports/iwi/")) { + dir.mkdir("exports/iwi/"); + } + if (!dir.exists("exports/dds/")) { + dir.mkdir("exports/dds/"); + } + if (!dir.exists("exports/png/")) { + dir.mkdir("exports/png/"); + } + if (!dir.exists("exports/jpg/")) { + dir.mkdir("exports/jpg/"); + } +} + +DDSFile::DDSFile() : + fileStem(), + header(), + mipmaps() { + +} + +QByteArray DDSFile::ReadDDSFile(const QString &aFilePath) { + if (!aFilePath.endsWith(".dds", Qt::CaseInsensitive)) { + qDebug() << "Error: Invalid filename " << aFilePath; + return {}; + } + + if (!QFile::exists(aFilePath)) { + qDebug() << "Error: File does not exist!"; + return {}; + } + + QFile file(aFilePath); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << "Error: Failed to read DDS file."; + return {}; + } + + const QByteArray ddsData = file.readAll(); + file.close(); + return ddsData; +} + +DDSFile::DDSFile(const QString &aFilePath) + : DDSFile(ReadDDSFile(aFilePath), aFilePath.split('.').first().split('/').last()) { +} + +DDSFile::DDSFile(const QByteArray aDDSData, const QString aFileStem) { + QDataStream ddsIn(aDDSData); + ddsIn.setByteOrder(QDataStream::LittleEndian); + + DDSHeader ddsHeader; + if (ddsIn.readRawData(reinterpret_cast(&ddsHeader), sizeof(DDSHeader)) != sizeof(DDSHeader)) { + qDebug() << "Error: Failed to read DDSHeader from QByteArray!"; + return; + } + + fileStem = aFileStem; + header = ddsHeader; + + // Ensure DevIL is initialized once globally + static bool devilInitialized = false; + if (!devilInitialized) { + ilInit(); + devilInitialized = true; + } + + // Generate and bind an image + ILuint imageID; + ilGenImages(1, &imageID); + ilBindImage(imageID); + + ilEnable(IL_ORIGIN_SET); + ilOriginFunc(IL_ORIGIN_UPPER_LEFT); + + // Load DDS file + if (!ilLoadL(IL_DDS, aDDSData.constData(), aDDSData.size())) { + ILuint devilError = ilGetError(); + qDebug() << "DevIL Error while loading DDS: " << devilError; + ilDeleteImages(1, &imageID); + return; + } + + // Get mipmap count + ILint numMipmaps = ilGetInteger(IL_NUM_MIPMAPS); + qDebug() << "Number of mipmaps: " << numMipmaps; + + // Loop over all mipmap levels (0 is the base image) + for (ILint level = 0; level <= numMipmaps; ++level) { + ilBindImage(imageID); + if (!ilActiveMipmap(level)) { + qDebug() << "DevIL failed to activate mipmap level" << level; + continue; + } + + // Get mipmap properties + int width = ilGetInteger(IL_IMAGE_WIDTH); + int height = ilGetInteger(IL_IMAGE_HEIGHT); + int depth = ilGetInteger(IL_IMAGE_DEPTH); + int format = ilGetInteger(IL_IMAGE_FORMAT); + int bpp = 0; + + switch (format) { + case IL_RGB: + bpp = 3; + break; + case IL_RGBA: + bpp = 4; + break; + default: + qDebug() << "Unsupported image format."; + continue; + } + + int dataSize = width * height * depth * bpp; + + ILubyte *data = ilGetData(); + if (!data) { + qDebug() << "Error: DevIL returned null data for mipmap level" << level; + continue; + } + + // Create a mipmap structure + DDSMipmap mipmap; + mipmap.width = width; + mipmap.height = height; + mipmap.data = QByteArray(reinterpret_cast(data), dataSize); + mipmap.size = dataSize; + + // Store in DDS file + mipmaps.append(mipmap); + } + + ilDeleteImages(1, &imageID); +} + +DDSFile::DDSFile(const DDSFile &ddsFile) : + fileStem(ddsFile.fileStem), + header(ddsFile.header), + mipmaps(ddsFile.mipmaps) { + +} + +DDSFile::DDSFile(const IWIFile &aIWIFile) + : DDSFile(IWItoDDSData(aIWIFile), aIWIFile.fileStem) { +} + +QByteArray DDSFile::IWItoDDSData(const IWIFile &aIWIFile) { + DDSHeader ddsHeader = {}; + ddsHeader.magic = 0x20534444; // 'DDS ' + ddsHeader.size = 124; + ddsHeader.flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE; + ddsHeader.height = aIWIFile.info.Height; + ddsHeader.width = aIWIFile.info.Width; + ddsHeader.depth = 0; + ddsHeader.mipMapCount = aIWIFile.mipmaps.size(); + + DDSPixelFormat ddsPixelFormat = CalculatePixelFormat(aIWIFile.info.Format); + if (ddsPixelFormat.flags & DDPF_FOURCC) { + ddsHeader.flags |= DDSD_LINEARSIZE; + } else { + ddsHeader.flags |= DDSD_PITCH; + } + ddsHeader.pixelFormat = ddsPixelFormat; + + // Calculate pitch/linear size + if (ddsPixelFormat.flags & DDPF_FOURCC) { + int blockSize = (ddsPixelFormat.format == 0x31545844) ? 8 : 16; + ddsHeader.pitchOrLinearSize = fmax(1, (ddsHeader.width + 3) / 4) * blockSize * (ddsHeader.height / 4); + } else { + ddsHeader.pitchOrLinearSize = ddsHeader.width * (ddsPixelFormat.rgbBitCount / 8); + } + + DDSCaps ddsCaps = {}; + ddsCaps.caps1 = DDSCAPS_TEXTURE; + ddsCaps.caps2 = 0; + ddsCaps.dDSX = 0; + ddsCaps.reserved = 0; + ddsHeader.caps = ddsCaps; + + QByteArray ddsData; + QDataStream out(&ddsData, QIODevice::WriteOnly); + out.setByteOrder(QDataStream::LittleEndian); + + // Write DDS header + out.writeRawData(reinterpret_cast(&ddsHeader), sizeof(DDSHeader)); + + for (auto mipmap : aIWIFile.mipmaps) { + if (!mipmap.data.size()) { continue; } + + // Write mipmap data + out.writeRawData(reinterpret_cast(mipmap.data.constData()), mipmap.data.size()); + } + + return ddsData; +} + +DDSFile &DDSFile::operator=(const DDSFile &other) { + if (this != &other) { + fileStem = other.fileStem; + header = other.header; + mipmaps = other.mipmaps; + } + return *this; +} + +// Write a DDS file from a DDSFile object +bool DDSFile::SaveDDS() { + SetupExportDirs(); + + QFile file("exports/dds/" + fileStem + ".dds"); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "Error: Unable to write DDS file" << fileStem + ".dds"; + return false; + } + + QDataStream out(&file); + out.setByteOrder(QDataStream::LittleEndian); + + // Write DDS Header + out.writeRawData(reinterpret_cast(&header), sizeof(DDSHeader)); + file.close(); + + qDebug() << "Successfully wrote DDS file: " << fileStem + ".dds"; + return true; +} + +bool DDSFile::SaveIWI() { + SetupExportDirs(); + + IWIFile iwiFile(*this); + if (!iwiFile.SaveIWI()) { + qDebug() << "Error: Unable to write IWI file" << fileStem + ".iwi"; + return false; + } + return true; +} + +bool DDSFile::SavePNG() { + SetupExportDirs(); + + int mipmapIndex = 1; + for (const DDSMipmap &mipmap : mipmaps) { + QString subFilePath = "exports/png/" + fileStem + ".png"; + if (mipmaps.size() > 1) { + subFilePath = "exports/png/" + fileStem + QString("_%1").arg(mipmapIndex) + ".png"; + } + + // Calculate bytes per line (stride) + int bytesPerPixel = 4; // Assuming RGBA8888 (4 bytes per pixel) + int bytesPerLine = mipmap.width * bytesPerPixel; + + QImage image(reinterpret_cast(mipmap.data.constData()), + mipmap.width, mipmap.height, bytesPerLine, QImage::Format_RGBA8888); + + if (image.isNull()) { + qDebug() << "Error: Failed to create QImage for mipmap" << mipmapIndex; + return false; + } + + if (!image.save(subFilePath)) { + qDebug() << "Error: Unable to save PNG file" << subFilePath; + return false; + } + + mipmapIndex++; + } + return true; +} + +bool DDSFile::SaveJPG() { + SetupExportDirs(); + + int mipmapIndex = 1; + for (const DDSMipmap &mipmap : mipmaps) { + QString subFilePath = "exports/jpg/" + fileStem + ".jpg"; + if (mipmaps.size() > 1) { + subFilePath = "exports/jpg/" + fileStem + QString("_%1").arg(mipmapIndex) + ".jpg"; + } + + // Calculate bytes per line (stride) + int bytesPerPixel = 4; // Assuming RGBA8888 (4 bytes per pixel) + int bytesPerLine = mipmap.width * bytesPerPixel; + + QImage image(reinterpret_cast(mipmap.data.constData()), + mipmap.width, mipmap.height, bytesPerLine, QImage::Format_RGBA8888); + + if (image.isNull()) { + qDebug() << "Error: Failed to create QImage for mipmap" << mipmapIndex; + return false; + } + + if (!image.save(subFilePath, "JPG")) { + qDebug() << "Error: Unable to save JPG file" << subFilePath; + return false; + } + + mipmapIndex++; + } + return true; +} + diff --git a/ddsfile.h b/ddsfile.h new file mode 100644 index 0000000..5ccf0c7 --- /dev/null +++ b/ddsfile.h @@ -0,0 +1,84 @@ +#ifndef DDSFILE_H +#define DDSFILE_H + +#include "enums.h" +#include +#include +#include +#include +#include +#include +#include +#include + +struct DDSPixelFormat { + quint32 size; + quint32 flags; + quint32 format; + quint32 rgbBitCount; + quint32 rBitMask; + quint32 gBitMask; + quint32 bBitMask; + quint32 aBitMask; +}; + +struct DDSCaps { + quint32 caps1; + quint32 caps2; + quint32 dDSX; + quint32 reserved; +}; + +struct DDSHeader { + quint32 magic; + quint32 size; + quint32 flags; + quint32 height; + quint32 width; + quint32 pitchOrLinearSize; + quint32 depth; + quint32 mipMapCount; + quint32 reserved1[11]; + DDSPixelFormat pixelFormat; + DDSCaps caps; + quint32 reserved2; +}; + +// Mipmap Structure +struct DDSMipmap { + quint32 size; + quint32 width; + quint32 height; + QByteArray data; +}; + +class IWIFile; + +// DDS File Class +class DDSFile { +public: + QString fileStem; + DDSHeader header; + QVector mipmaps; + + DDSFile(); + DDSFile(const QString &aFilePath); + DDSFile(const IWIFile &aIWIFile); + DDSFile(const QByteArray aDDSData, const QString aFileStem); + DDSFile(const DDSFile &ddsFile); + DDSFile& operator=(const DDSFile& other); + + bool SaveDDS(); + bool SaveIWI(); + bool SavePNG(); + bool SaveJPG(); + + void SetupExportDirs(); + static DDSPixelFormat CalculatePixelFormat(quint8 aIWIFormat); + +private: + static QByteArray ReadDDSFile(const QString &aFilePath); + QByteArray IWItoDDSData(const IWIFile &aIWIFile); +}; + +#endif // DDSFILE_H diff --git a/ddsviewer.cpp b/ddsviewer.cpp new file mode 100644 index 0000000..c9c31c5 --- /dev/null +++ b/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/ddsviewer.h b/ddsviewer.h new file mode 100644 index 0000000..f49bbc2 --- /dev/null +++ b/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/ddsviewer.ui b/ddsviewer.ui new file mode 100644 index 0000000..d7dc083 --- /dev/null +++ b/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/enums.h b/enums.h index 415bf63..8818afa 100644 --- a/enums.h +++ b/enums.h @@ -1,6 +1,83 @@ #ifndef ENUMS_H #define ENUMS_H +#include + +enum FF_PLATFORM { + FF_PLATFORM_NONE = 0x00, // No platform + FF_PLATFORM_XBOX = 0x01, // Xbox 360 + FF_PLATFORM_PS3 = 0x02, // Playstation 3 + FF_PLATFORM_PC = 0x03 // PC +}; + +enum FF_GAME { + FF_GAME_NONE = 0x00, // No game + FF_GAME_COD4 = 0x01, // Modern Warware 1 + FF_GAME_COD5 = 0x02, // World at War + FF_GAME_COD6 = 0x03, // Modern Warfare 2 + FF_GAME_COD7 = 0x04, // Black Ops 1 + FF_GAME_COD8 = 0x05, // Modern Warfare 3 + FF_GAME_COD9 = 0x06, // Black Ops 2 +}; + +enum IWI_VERSION { + IWI_VERSION_COD2 = 0x05, // 05 CoD2 + IWI_VERSION_COD4 = 0x06, // 06 CoD4 + IWI_VERSION_COD5 = 0x06, // 06 CoD5 + IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2 + IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3 + IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1 + IWI_VERSION_CODBO2 = 0x1B, // 27 CoDBO2 +}; + +enum IWI_FORMAT { + // IWI Format + IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32 + IWI_FORMAT_RGB24 = 0x02, // 02 RGB24 + IWI_FORMAT_GA16 = 0x03, // 03 GA16 + IWI_FORMAT_A8 = 0x04, // 04 A8 + IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1 + IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3 + IWI_FORMAT_DXT5 = 0x0D // 13 DXT5 +}; + +enum DDS_FLAGS { + DDSD_CAPS = 0x1, + DDSD_HEIGHT = 0x2, + DDSD_WIDTH = 0x4, + DDSD_PITCH = 0x8, + DDSD_PIXELFORMAT = 0x1000, + DDSD_MIPMAPCOUNT = 0x20000, + DDSD_LINEARSIZE = 0x80000, + DDSD_DEPTH = 0x800000 +}; + +enum DDS_PIXELFORMAT_FLAGS { + DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000 +}; + +enum DDS_CAPS_FLAGS { + DDSCAPS_COMPLEX = 0x8, + DDSCAPS_MIPMAP = 0x400000, + DDSCAPS_TEXTURE = 0x1000 +}; + +enum DDS_CAPS2_FLAGS { + DDSCAPS2_CUBEMAP = 0x200, // Indicates a cubemap. + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + DDSCAPS2_VOLUME = 0x200000 // Indicates that the texture is a volume texture. +}; + enum LUMP_TYPE { LUMP_MATERIALS = 0x0, @@ -98,4 +175,699 @@ enum BSPVERSION_TYPE BSPVERSION_COD_BO = 45 }; +enum FF_COMPANY { + COMPANY_NONE = 0x00, + COMPANY_INFINITY_WARD = 0x01, + COMPANY_TREYARCH = 0x02, + COMPANY_SLEDGEHAMMER = 0x03, + COMPANY_NEVERSOFT = 0x04 +}; + +enum FF_FILETYPE { + FILETYPE_NONE = 0x00, + FILETYPE_FAST_FILE = 0x01 +}; + +enum FF_SIGNAGE { + SIGNAGE_NONE = 0x00, + SIGNAGE_SIGNED = 0x01, + SIGNAGE_UNSIGNED = 0x02 +}; + +enum IMAGE_COMPRESSION { + COMPRESSION_NONE = 0x00, + COMPRESSION_DXT1 = 0x01, + COMPRESSION_DXT3 = 0x02, + COMPRESSION_DXT5 = 0x03 +}; +enum MENU_ITEM_TYPE { + ITEM_TYPE_TEXT = 0, // simple text + ITEM_TYPE_BUTTON = 1, // button, basically text with a border + ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped + ITEM_TYPE_CHECKBOX = 3, // check box + ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar + ITEM_TYPE_COMBO = 5, // drop down list + ITEM_TYPE_LISTBOX = 6, // scrollable list + ITEM_TYPE_MODEL = 7, // model + ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is + ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar + ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc. + ITEM_TYPE_YESNO = 11, // yes no dvar setting + ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated + ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar + ITEM_TYPE_BIND = 14, // bind + ITEM_TYPE_MENUMODEL = 15, // special menu model + ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename + ITEM_TYPE_DECIMALFIELD = 17, // editable text, associated with a dvar, which allows decimal input + ITEM_TYPE_UPREDITFIELD = 18, // editable text, associated with a dvar + ITEM_TYPE_GAME_MESSAGE_WINDOW = 19, // game message window + ITEM_TYPE_SCALEFORM = 20, // Flash movie for Scaleform GFx + ITEM_TYPE_BIND2 = 21, // bind2 +}; + +enum MENU_ITEM_H_ALIGN { + ITEM_ALIGN_LEFT = 0, // aligns left of text to left of containing rectangle + ITEM_ALIGN_CENTER = 1, // aligns center of text to center of containing rectangle + ITEM_ALIGN_RIGHT = 2, // aligns right of text to right of containing rectangle + ITEM_ALIGN_X_MASK = 3, +}; + +enum MENU_ITEM_V_ALIGN { + ITEM_ALIGN_LEGACY = 0, // aligns bottom of text to top of containing rectangle + ITEM_ALIGN_TOP = 4, // aligns top of text to top of containing rectangle + ITEM_ALIGN_MIDDLE = 8, // aligns middle of text to middle of containing rectangle + ITEM_ALIGN_BOTTOM = 12, // aligns bottom of text to bottom of containing rectangle + ITEM_ALIGN_Y_MASK = 12, +}; + +enum MENU_ITEM_ALIGN { + ITEM_ALIGN_LEGACY_LEFT = 0, + ITEM_ALIGN_LEGACY_CENTER = 1, + ITEM_ALIGN_LEGACY_RIGHT = 2, + ITEM_ALIGN_TOP_LEFT = 4, + ITEM_ALIGN_TOP_CENTER = 5, + ITEM_ALIGN_TOP_RIGHT = 6, + ITEM_ALIGN_MIDDLE_LEFT = 8, + ITEM_ALIGN_MIDDLE_CENTER = 9, + ITEM_ALIGN_MIDDLE_RIGHT = 10, + ITEM_ALIGN_BOTTOM_LEFT = 12, + ITEM_ALIGN_BOTTOM_CENTER = 13, + ITEM_ALIGN_BOTTOM_RIGHT = 14 +}; + +enum MENU_ITEM_TEXTSTYLE { + ITEM_TEXTSTYLE_NORMAL = 0, // normal text + ITEM_TEXTSTYLE_BLINK = 1, // fast blinking + ITEM_TEXTSTYLE_SHADOWED = 3, // drop shadow ( need a color for this ) + ITEM_TEXTSTYLE_SHADOWEDMORE = 6, // drop shadow ( need a color for this ) + ITEM_TEXTSTYLE_MONOSPACE = 128 +}; + +enum MENU_WINDOW_BORDER { + WINDOW_BORDER_NONE = 0, // no border + WINDOW_BORDER_FULL = 1, // full border based on border color ( single pixel ) + WINDOW_BORDER_HORZ = 2, // horizontal borders only + WINDOW_BORDER_VERT = 3, // vertical borders only + WINDOW_BORDER_KCGRADIENT = 4, // horizontal border using the gradient bars + WINDOW_BORDER_RAISED = 5, // darken the bottom and right sides of the border + WINDOW_BORDER_SUNKEN = 6 // darken the top and left sides of the border +}; + +enum MENU_WINDOW_STYLE { + WINDOW_STYLE_EMPTY = 0, // no background + WINDOW_STYLE_FILLED = 1, // filled with background color + WINDOW_STYLE_GRADIENT = 2, // gradient bar based on background color + WINDOW_STYLE_SHADER = 3, // shader based on background color + WINDOW_STYLE_TEAMCOLOR = 4, // team color + WINDOW_STYLE_DVAR_SHADER = 5, // draws the shader specified by the dvar + WINDOW_STYLE_LOADBAR = 6, // shader based on background color +}; + +enum MENU_MODE { + MODE_BOTTOMUP_ALIGN_TOP = 0, // text appears on bottom of list and moves up to specified Y coordinate as old text fades out + MODE_BOTTOMUP_ALIGN_BOTTOM = 1, // text appears on bottom of list and moves away from specified Y coordinate as new text pushes it up + MODE_TOPDOWN_ALIGN_TOP = 2, // text appears on top of list and moves away from specified Y coordinate as new text pushes it down + MODE_TOPDOWN_ALIGN_BOTTOM = 3 // text appears on top of list and moves down to specified Y coordinate as old text fades out +}; + +enum MENU_BOOL { + MENU_TRUE = 1, + MENU_FALSE = 0 +}; + +enum MENU_ORIENTATION { + HUD_VERTICAL = 0x00, + HUD_HORIZONTAL = 0x01 +}; + +enum MENU_RANGETYPE { + RANGETYPE_ABSOLUTE = 0, + RANGETYPE_RELATIVE = 1 +}; + +// list box element types +enum MENU_LIST_BOX { + LISTBOX_TEXT = 0x00, + LISTBOX_IMAGE = 0x01 +}; + +// list feeders +enum MENU_FEEDERS { + FEEDER_HEADS = 0x00, // model heads + FEEDER_MAPS = 0x01, // text maps based on game type + FEEDER_SERVERS = 0x02, // servers + FEEDER_CLAN_MEMBERS = 0x03, // clan names + FEEDER_ALLMAPS = 0x04, // all maps available, in graphic format + FEEDER_REDTEAM_LIST = 0x05, // red team members + FEEDER_BLUETEAM_LIST = 0x06, // blue team members + FEEDER_PLAYER_LIST = 0x07, // players + FEEDER_TEAM_LIST = 0x08, // team members for team voting + FEEDER_MODS = 0x09, // team members for team voting + FEEDER_DEMOS = 0x0a, // team members for team voting + FEEDER_SCOREBOARD = 0x0b, // team members for team voting + FEEDER_Q3HEADS = 0x0c, // model heads + FEEDER_SERVERSTATUS = 0x0d, // server status + FEEDER_FINDPLAYER = 0x0e, // find player + FEEDER_CINEMATICS = 0x0f, // cinematics + FEEDER_SAVEGAMES = 0x10, // savegames + FEEDER_PICKSPAWN = 0x11, // pickspawn + FEEDER_LOBBY_MEMBERS = 0x12, // list of players in your party + FEEDER_LOBBY_MEMBERS_TALK = 0x13, // icon for whether they are speaking or not + FEEDER_MUTELIST = 0x14, // list of musted players + FEEDER_PLAYERSTALKING = 0x15, // list of players who are currently talking + FEEDER_SPLITSCREENPLAYERS = 0x16, // list of all players who are playing splitscreen + FEEDER_LOBBY_MEMBERS_READY = 0x17, // icon for whether they are ready or not + FEEDER_PLAYER_PROFILES = 0x18, // player profiles + FEEDER_PARTY_MEMBERS = 0x19, // list of players in your party + FEEDER_PARTY_MEMBERS_TALK = 0x1a, // icon for whether they are speaking or not + FEEDER_PARTY_MEMBERS_READY = 0x1b, // icon for whether they are ready or not + FEEDER_PLAYLISTS = 0x1c, // list of all playlists + FEEDER_GAMEMODES = 0x1d, // list of all game type modes, including any player custom modes + FEEDER_CATEGORIES = 0x1e, // list of all categories + FEEDER_LEADERBOARD = 0x1f, // list of rows for a leaderboard + FEEDER_MYTEAM_MEMBERS = 0x20, // list of marine team members + FEEDER_MYTEAM_MEMBERS_TALK = 0x21, // icon for whether they are speaking + FEEDER_ENEMY_MEMBERS = 0x22, // list of opfor team members + FEEDER_ENEMY_MEMBERS_TALK = 0x23, // icon for whether they are speaking + FEEDER_LOBBY_MEMBERS_STAT = 0x24, // last round stats for lobby members + FEEDER_MYTEAM_MEMBERS_STAT = 0x25, // last round stats for marine team members + FEEDER_ENEMY_MEMBERS_STAT = 0x26, // last round stats for opfor team members + FEEDER_ONLINEFRIENDS = 0x27, // list of your online friends + FEEDER_LOBBY_MEMBERS_RANK = 0x28, // rank icon + FEEDER_PARTY_MEMBERS_RANK = 0x29, // rank icon + FEEDER_ENEMY_MEMBERS_RANK = 0x2a, // rank icon + FEEDER_MYTEAM_MEMBERS_RANK = 0x2b, // rank icon + FEEDER_TESTMAPS = 0x2c, // department test maps + FEEDER_SYSTEMLINK_LOBBY_MEMBERS = 0x2d, // list of players in a system link lobby + FEEDER_LOBBY_MEMBERS_CONTROLLER = 0x2e, // icon for controller quadrant for splitscreen + FEEDER_PARTY_MEMBERS_CONTROLLER = 0x2f, // icon for controller quadrant for splitscreen + FEEDER_MYTEAM_MEMBERS_SQUAD = 0x30, // squad icon + FEEDER_ENEMY_MEMBERS_SQUAD = 0x31, // squad icon + FEEDER_INGAME_SQUAD_MEMBERS = 0x32, // Squad members displayed in MP 'Pause' menu + FEEDER_INGAME_SQUAD_MEMBERS_FULL = 0x33, // Squad members' name, rank, talk, leader displayed in PC MP 'Pause' menu + FEEDER_INGAME_SQUAD_NAMES = 0x34, // Squad names displayed in MP 'Join Squad' menu + FEEDER_INGAME_SQUAD_NAMES2 = 0x35, // Squad names displayed in MP 'Pause' menu + FEEDER_INGAME_SQUAD_NAMES_FULL = 0x36, // Squad names, lock, invite displayed in PC MP 'Pause' menu + FEEDER_CUSTOM_GAMETYPES = 0x37, // list of all the gametypes for custom matches + FEEDER_INGAME_SQUAD_MEMBER_RANK = 0x38, // Squad members' rank displayed in MP 'Pause' menu + FEEDER_INGAME_SQUAD_MEMBER_TALK = 0x39, // Squad members' talk icon displayed in MP 'Pause' menu + FEEDER_INGAME_SQUAD_LOCKED = 0x3a, // Squad lock icon displayed in MP 'Pause' menu + FEEDER_INGAME_SQUAD_MEMBER_INVITED = 0x3b, // Squad invite icon displayed in MP 'Pause' menu + FEEDER_INGAME_SQUAD_INVITE = 0x3c, // Squad invite icon displayed in MP 'Join Squad' menu + FEEDER_INGAME_SQUAD_LEADER = 0x3d, // Squad leader icon displayled in MP 'Pause' menu + FEEDER_FRIENDS = 0x3e, // list of your friends + FEEDER_PENDINGFRIENDS = 0x3f, // list of your pending friends + FEEDER_INVITES = 0x40, // list of the game invites from your friends +}; + +// display flags +enum MENU_DISPLAY_FLAG { + CG_SHOW_BLUE_TEAM_HAS_REDFLAG = 0x00000001, + CG_SHOW_RED_TEAM_HAS_BLUEFLAG = 0x00000002, + CG_SHOW_ANYTEAMGAME = 0x00000004, + CG_SHOW_CTF = 0x00000020, + CG_SHOW_OBELISK = 0x00000040, + CG_SHOW_HEALTHCRITICAL = 0x00000080, + CG_SHOW_SINGLEPLAYER = 0x00000100, + CG_SHOW_TOURNAMENT = 0x00000200, + CG_SHOW_DURINGINCOMINGVOICE = 0x00000400, + CG_SHOW_IF_PLAYER_HAS_FLAG = 0x00000800, + CG_SHOW_LANPLAYONLY = 0x00001000, + CG_SHOW_MINED = 0x00002000, + CG_SHOW_HEALTHOK = 0x00004000, + CG_SHOW_TEAMINFO = 0x00008000, + CG_SHOW_NOTEAMINFO = 0x00010000, + CG_SHOW_OTHERTEAMHASFLAG = 0x00020000, + CG_SHOW_YOURTEAMHASENEMYFLAG = 0x00040000, + CG_SHOW_ANYNONTEAMGAME = 0x00080000, + CG_SHOW_TEXTASINT = 0x00200000, + CG_SHOW_HIGHLIGHTED = 0x00100000, + CG_SHOW_NOT_V_CLEAR = 0x02000000, + CG_SHOW_2DONLY = 0x10000000 +}; + +enum MENU_UI_FLAG{ + UI_SHOW_LEADER = 0x00000001, + UI_SHOW_NOTLEADER = 0x00000002, + UI_SHOW_FAVORITESERVERS = 0x00000004, + UI_SHOW_ANYNONTEAMGAME = 0x00000008, + UI_SHOW_ANYTEAMGAME = 0x00000010, + UI_SHOW_NEWHIGHSCORE = 0x00000020, + UI_SHOW_DEMOAVAILABLE = 0x00000040, + UI_SHOW_NEWBESTTIME = 0x00000080, + UI_SHOW_FFA = 0x00000100, + UI_SHOW_NOTFFA = 0x00000200, + UI_SHOW_NETANYNONTEAMGAME = 0x00000400, + UI_SHOW_NETANYTEAMGAME = 0x00000800, + UI_SHOW_NOTFAVORITESERVERS = 0x00001000 +}; + +// font types +enum MENU_FONT_TYPE{ + UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small + UI_FONT_NORMAL = 1, + UI_FONT_BIG = 2, + UI_FONT_SMALL = 3, + UI_FONT_BOLD = 4, + UI_FONT_CONSOLE = 5, + UI_FONT_OBJECTIVE = 6, + UI_FONT_MAX = 6, +}; + +// owner draw types +// ideally these should be done outside of this file but +// this makes it much easier for the macro expansion to +// convert them for the designers ( from the .menu files ) +enum MENU_OWNER_DRAW_TYPE { + CG_OWNERDRAW_BASE = 1, + CG_PLAYER_AMMO_VALUE = 5, + CG_PLAYER_AMMO_BACKDROP = 6, + CG_PLAYER_HEAT_VALUE = 7, + CG_PLAYER_STANCE = 20, + CG_SPECTATORS = 60, + CG_HOLD_BREATH_HINT = 71, + CG_CURSORHINT = 72, + CG_PLAYER_POWERUP = 73, + CG_PLAYER_HOLDABLE = 74, + CG_PLAYER_INVENTORY = 75, + CG_CURSORHINT_STATUS = 78, // like 'health' bar when pointing at a func_explosive + CG_PLAYER_BAR_HEALTH = 79, + CG_MANTLE_HINT = 80, + CG_PLAYER_WEAPON_NAME = 81, + CG_PLAYER_WEAPON_NAME_BACK = 82, + CG_CENTER_MESSAGE = 90, // for things like "You were killed by ..." + CG_TANK_BODY_DIR = 95, + CG_TANK_BARREL_DIR = 96, + CG_DEADQUOTE = 97, + CG_PLAYER_BAR_HEALTH_BACK = 98, + CG_MISSION_OBJECTIVE_HEADER = 99, + CG_MISSION_OBJECTIVE_LIST = 100, + CG_MISSION_OBJECTIVE_BACKDROP = 101, + CG_PAUSED_MENU_LINE = 102, + CG_OFFHAND_WEAPON_ICON_FRAG = 103, + CG_OFFHAND_WEAPON_ICON_SMOKEFLASH = 104, + CG_OFFHAND_WEAPON_AMMO_FRAG = 105, + CG_OFFHAND_WEAPON_AMMO_SMOKEFLASH = 106, + CG_OFFHAND_WEAPON_NAME_FRAG = 107, + CG_OFFHAND_WEAPON_NAME_SMOKEFLASH = 108, + CG_OFFHAND_WEAPON_SELECT_FRAG = 109, + CG_OFFHAND_WEAPON_SELECT_SMOKEFLASH = 110, + CG_SAVING = 111, + CG_PLAYER_LOW_HEALTH_OVERLAY = 112, + CG_INVALID_CMD_HINT = 113, + CG_PLAYER_SPRINT_METER = 114, + CG_PLAYER_SPRINT_BACK = 115, + CG_PLAYER_WEAPON_BACKGROUND = 116, + CG_PLAYER_WEAPON_AMMO_CLIP_GRAPHIC = 117, + CG_PLAYER_WEAPON_PRIMARY_ICON = 118, + CG_PLAYER_WEAPON_AMMO_STOCK = 119, + CG_PLAYER_WEAPON_LOW_AMMO_WARNING = 120, + CG_BATTLE_COMPASS_MARKERS = 122, + CG_BATTLE_FULLMAP_MARKERS = 123, + CG_SUCCESSFUL_CMD_HINT = 130, + CG_WAR_TEXT = 135, + CG_PLAYER_COMPASS_TICKERTAPE = 145, + CG_PLAYER_COMPASS_TICKERTAPE_NO_OBJ = 146, + CG_PLAYER_COMPASS_DOGS = 147, + CG_PLAYER_COMPASS_ARTILLERY_ICON = 148, + CG_PLAYER_COMPASS_SQUAD_OBJECTIVE = 149, + CG_PLAYER_COMPASS_PLAYER = 150, + CG_PLAYER_COMPASS_BACK = 151, + CG_PLAYER_COMPASS_POINTERS = 152, + CG_PLAYER_COMPASS_ACTORS = 153, + CG_PLAYER_COMPASS_TANKS = 154, + CG_PLAYER_COMPASS_HELICOPTERS = 155, + CG_PLAYER_COMPASS_PLANES = 156, + CG_PLAYER_COMPASS_AUTOMOBILES = 157, + CG_PLAYER_COMPASS_FRIENDS = 158, + CG_PLAYER_COMPASS_MAP = 159, + CG_PLAYER_COMPASS_NORTHCOORD = 160, + CG_PLAYER_COMPASS_EASTCOORD = 161, + CG_PLAYER_COMPASS_NCOORD_SCROLL = 162, + CG_PLAYER_COMPASS_ECOORD_SCROLL = 163, + CG_PLAYER_COMPASS_GOALDISTANCE = 164, + CG_PLAYER_ACTIONSLOT_DPAD = 165, + CG_PLAYER_ACTIONSLOT_1 = 166, + CG_PLAYER_ACTIONSLOT_2 = 167, + CG_PLAYER_ACTIONSLOT_3 = 168, + CG_PLAYER_ACTIONSLOT_4 = 169, + CG_PLAYER_COMPASS_ENEMIES = 170, + CG_PLAYER_FULLMAP_DOGS = 176, + CG_PLAYER_FULLMAP_VEHICLES = 177, + CG_PLAYER_FULLMAP_ARTILLERY_ICON = 178, + CG_PLAYER_FULLMAP_SQUAD_OBJECTIVE = 179, + CG_PLAYER_FULLMAP_BACK = 180, + CG_PLAYER_FULLMAP_MAP = 181, + CG_PLAYER_FULLMAP_POINTERS = 182, + CG_PLAYER_FULLMAP_PLAYER = 183, + CG_PLAYER_FULLMAP_ACTORS = 184, + CG_PLAYER_FULLMAP_FRIENDS = 185, + CG_PLAYER_FULLMAP_LOCATION_SELECTOR = 186, + CG_PLAYER_FULLMAP_BORDER = 187, + CG_PLAYER_FULLMAP_ENEMIES = 188, + CG_PLAYER_COMPASS = 189, + CG_VEHICLE_RETICLE = 190, + CG_HUD_TARGETS_VEHICLE = 191, + CG_HUD_TARGETS_JAVELIN = 192, + CG_TALKER1 = 193, + CG_TALKER2 = 194, + CG_TALKER3 = 195, + CG_TALKER4 = 196, + CG_FRIENDLYARROWS = 197, + CG_FRIENDLYNAMES = 198, + UI_OWNERDRAW_BASE = 200, + UI_HANDICAP = 200, + UI_EFFECTS = 201, + UI_PLAYERMODEL = 202, + UI_GAMETYPE = 205, + UI_SKILL = 207, + UI_NETSOURCE = 220, + UI_NETFILTER = 222, + UI_VOTE_KICK = 238, + UI_NETGAMETYPE = 245, + UI_SERVERREFRESHDATE = 247, + UI_SERVERMOTD = 248, + UI_GLINFO = 249, + UI_KEYBINDSTATUS = 250, + UI_JOINGAMETYPE = 253, + UI_MAPPREVIEW = 254, + UI_MENUMODEL = 257, + UI_SAVEGAME_SHOT = 258, + UI_SAVEGAMENAME = 262, + UI_SAVEGAMEINFO = 263, + UI_LOADPROFILING = 264, + UI_RECORDLEVEL = 265, + UI_AMITALKING = 266, + UI_TALKER1 = 267, + UI_TALKER2 = 268, + UI_TALKER3 = 269, + UI_TALKER4 = 270, + UI_PARTYSTATUS = 271, + UI_LOGGEDINUSER = 272, + UI_RESERVEDSLOTS = 273, + UI_PLAYLISTNAME = 274, + UI_PLAYLISTDESCRIPTION = 275, + UI_USERNAME = 276, + UI_CINEMATIC = 277, + UI_TOTALONLINE = 278, + UI_CATEGORYNAME = 279, + UI_CATEGORYDESCRIPTION = 280, + UI_PLAYLISTICON = 281, + UI_CATEGORYICON = 282, + UI_GAMETYPE_MAPNAME = 283, + CG_HUD_WAR_MOMENTUM_PROGRESS = 284, + CG_HUD_WAR_MOMENTUM_MULTIPLIER = 285, + CG_HUD_WAR_MOMENTUM_MULTIPLIER_DETAIL = 286, + CG_HUD_WAR_MOMENTUM_MULTIPLIER_BLITZKRIEG = 287, + CG_COMPETITIVE_MODE_SCORES = 288, + UI_LOAD_STATUS_SCREEN = 289, + UI_LEADERBOARD_GAMEMODE = 290, + CG_PLAYER_ACTIONSLOT_BACK_1 = 290, + CG_PLAYER_ACTIONSLOT_BACK_2 = 291, + CG_PLAYER_ACTIONSLOT_BACK_3 = 292, + CG_PLAYER_ACTIONSLOT_BACK_4 = 293, + CG_PLAYER_ACTIONSLOT_ARROW_1 = 294, + CG_PLAYER_ACTIONSLOT_ARROW_2 = 295, + CG_PLAYER_ACTIONSLOT_ARROW_3 = 296, + CG_PLAYER_ACTIONSLOT_ARROW_4 = 297, + UI_DIFFICULTY_INFO = 298, + UI_DIFFICULTY_ICON = 299, + UI_LOBBY_CHAT = 300 +}; + +// Edge relative placement values for rect->h_align and rect->v_align +enum MENU_H_ALIGNMENT { + HORIZONTAL_ALIGN_SUBLEFT = 0, // left edge of a 4:3 screen (safe area not included) + HORIZONTAL_ALIGN_LEFT = 1, // left viewable (safe area) edge + HORIZONTAL_ALIGN_CENTER = 2, // center of the screen (reticle) + HORIZONTAL_ALIGN_RIGHT = 3, // right viewable (safe area) edge + HORIZONTAL_ALIGN_FULLSCREEN = 4, // disregards safe area + HORIZONTAL_ALIGN_NOSCALE = 5, // uses exact parameters - neither adjusts for safe area nor scales for screen size + HORIZONTAL_ALIGN_TO640 = 6, // scales a real-screen resolution x down into the 0 - 640 range + HORIZONTAL_ALIGN_CENTER_SAFEAREA = 7, // center of the safearea + HORIZONTAL_ALIGN_MAX = HORIZONTAL_ALIGN_CENTER_SAFEAREA, + HORIZONTAL_ALIGN_DEFAULT = HORIZONTAL_ALIGN_SUBLEFT +}; + +enum MENU_V_ALIGNMENT { + VERTICAL_ALIGN_SUBTOP = 0, // top edge of the 4:3 screen (safe area not included) + VERTICAL_ALIGN_TOP = 1, // top viewable (safe area) edge + VERTICAL_ALIGN_CENTER = 2, // center of the screen (reticle) + VERTICAL_ALIGN_BOTTOM = 3, // bottom viewable (safe area) edge + VERTICAL_ALIGN_FULLSCREEN = 4, // disregards safe area + VERTICAL_ALIGN_NOSCALE = 5, // uses exact parameters - neither adjusts for safe area nor scales for screen size + VERTICAL_ALIGN_TO480 = 6, // scales a real-screen resolution y down into the 0 - 480 range + VERTICAL_ALIGN_CENTER_SAFEAREA = 7, // center of the save area + VERTICAL_ALIGN_MAX = VERTICAL_ALIGN_CENTER_SAFEAREA, + VERTICAL_ALIGN_DEFAULT = VERTICAL_ALIGN_SUBTOP +}; + +enum MENU_BUTTON { + BUTTON_A = 1, + BUTTON_B = 2, + BUTTON_X = 3, + BUTTON_Y = 4, + BUTTON_LSHLDR = 5, + BUTTON_RSHLDR = 6, + BUTTON_START = 14, + BUTTON_BACK = 15, + BUTTON_LSTICK = 16, + BUTTON_RSTICK = 17, + BUTTON_LTRIG = 18, + BUTTON_RTRIG = 19, + DPAD_UP = 20, + DPAD_DOWN = 21, + DPAD_LEFT = 22, + DPAD_RIGHT = 23, + APAD_UP = 28, + APAD_DOWN = 29, + APAD_LEFT = 30, + APAD_RIGHT = 31 +}; + +enum ASSET_TYPE { + ASSET_UNKNOWN = 0, + ASSET_ANIMATION = 4, // x_anim PARTIALLY VERIFIED + ASSET_MODEL = 5, // xmodel PARTIALLY VERIFIED + ASSET_MATERIAL = 6, // material VERIFIED + ASSET_BIK_FILE = 7, // .bik file PARTIALLY VERIFIED + ASSET_SOUND = 9, // loaded_sound VERIFIED + ASSET_COLLISION_MAP = 12, // collision_map PARTIALLY VERIFIED + ASSET_SHADER = 13, // shader PARTIALLY VERIFIED + ASSET_D3DBSP_DUMP = 17, // d3dbsp dump VERIFIED + ASSET_FONT = 20, // font PARTIALLY VERIFIED + ASSET_MENU = 21, // menu_file VERIFIED + ASSET_LOCAL_STRING = 23, // localized string VERIFIED + ASSET_WEAPON = 24, // weapon VERIFIED + ASSET_EFFECT = 26, // fx VERIFIED + ASSET_RAW_FILE = 32, // raw_file VERIFIED + ASSET_STRING_TABLE = 33 // string_table PARTIALLY VERIFIED +}; + +enum SHADER_TYPE { + SHADER_NONE = 0x00, + SHADER_PIXEL = 0x01, + SHADER_VERTEX = 0x02 +}; + +enum SHADER_OPCODE { + OPCODE_Nop, + OPCODE_Mov, + OPCODE_Add, + OPCODE_Sub, + OPCODE_Mad, + OPCODE_Mul, + OPCODE_Rcp, + OPCODE_Rsq, + OPCODE_Dp3, + OPCODE_Dp4, + OPCODE_Min, + OPCODE_Max, + OPCODE_Slt, + OPCODE_Sge, + OPCODE_Exp, + OPCODE_Log, + OPCODE_Lit, + OPCODE_Dst, + OPCODE_Lrp, + OPCODE_Frc, + OPCODE_M4x4, + OPCODE_M4x3, + OPCODE_M3x4, + OPCODE_M3x3, + OPCODE_M3x2, + OPCODE_Call, + OPCODE_CallNZ, + OPCODE_Loop, + OPCODE_Ret, + OPCODE_EndLoop, + OPCODE_Label, + OPCODE_Dcl, + OPCODE_Pow, + OPCODE_Crs, + OPCODE_Sgn, + OPCODE_Abs, + OPCODE_Nrm, + OPCODE_SinCos, + OPCODE_Rep, + OPCODE_EndRep, + OPCODE_If, + OPCODE_IfC, + OPCODE_Else, + OPCODE_Endif, + OPCODE_Break, + OPCODE_BreakC, + OPCODE_MovA, + OPCODE_DefB, + OPCODE_DefI, + OPCODE_TexCoord = 64, + OPCODE_TexKill, + OPCODE_Tex, + OPCODE_TexBem, + OPCODE_TexBeml, + OPCODE_TexReg2AR, + OPCODE_TexReg2GB, + OPCODE_TeXM3x2Pad, + OPCODE_TexM3x2Tex, + OPCODE_TeXM3x3Pad, + OPCODE_TexM3x3Tex, + OPCODE_TexM3x3Diff, + OPCODE_TexM3x3Spec, + OPCODE_TexM3x3VSpec, + OPCODE_ExpP, + OPCODE_LogP, + OPCODE_Cnd, + OPCODE_Def, + OPCODE_TexReg2RGB, + OPCODE_TexDP3Tex, + OPCODE_TexM3x2Depth, + OPCODE_TexDP3, + OPCODE_TexM3x3, + OPCODE_TexDepth, + OPCODE_Cmp, + OPCODE_Bem, + OPCODE_DP2Add, + OPCODE_DSX, + OPCODE_DSY, + OPCODE_TexLDD, + OPCODE_SetP, + OPCODE_TexLDL, + OPCODE_Breakp, + OPCODE_Phase = 0xFFFD, + OPCODE_Comment = 0xFFFE, + OPCODE_End = 0xFFFF +}; + +#define SECTION_TYPE_INFO 1 +#define SECTION_TYPE_DATA 2 + +#define IPAK_SECTION_ENTRY 1 +#define IPAK_SECTION_DATA 2 +#define IPAK_SECTION_METADATA 3 + +#define FORMAT_DXT1 0 +#define FORMAT_DXT3 1 +#define FORMAT_DXT5 2 +#define FORMAT_A8R8G8B8 3 + +// Change this depending on the platform +// PC +#define DEVMAP_LEVEL_FIRST "devmap intro_pac" +#define DEVMAP "devmap" +// Not PC +// #define DEVMAP_LEVEL_FIRST "map intro_pac" +// #define DEVMAP "map" + +// Remove this to restore full frontend instead of limited EPD frontend +#define COOP_EPD 0 + +// LDS - This enables a German SKU with Nazi Zombies enabled *SHOULD BE SET TO 0 IF NOT APPROVED* +#define GERMAN_ZOMBIE_BUILD 0 + +#define DEVMAP_LEVEL_TRAINING "devmap training" +#define LEVEL_FIRST "intro_pac" +#define LEVEL_TRAINING "training" +#define FIRST_PLAYABLE_CAMPAIGN_LEVEL "mak" +#define FIRST_PLAYABLE_ZOMBIE_LEVEL "nazi_zombie_prototype" + +// Size define for the hud compass +// These are used for both the dynamic & non-dynamic compass drawing +// If these are changed, the cgame should be recompiled +#define COMPASS_SIZE 160 +#define MINIMAP_X 11.5 +#define MINIMAP_Y 5 +#define MINIMAP_W 89.5 +#define MINIMAP_H 89.5 + +#define COMPASS_SIZE_MP 125 +#define MINIMAP_X_MP 0 +#define MINIMAP_Y_MP 12 +#define MINIMAP_W_MP 102 +#define MINIMAP_H_MP 102 + +#define FULLSCREEN 0 0 640 480 +#define FULLSCREEN_WIDE -107 0 854 480 + +// PC +#define ORIGIN_TITLE 30 34 +// Not PC +// #define ORIGIN_TITLE 0 0 + +#define ORIGIN_TITLE_SS 104 120 + +#define FONTSCALE_SMALL 0.3095 //0.3750 // <-- COD4 // COD5 --> 0.30952//0.35897//0.24138 //14 pt //0.2900 //0.2750 // 18 +#define FONTSCALE_LOBBY 0.26 // <--Slate // 0.3010 <-- Slate Compressed // 0.3750 // <-- COD4 CONDUIT ITC small +#define FONTSCALE_NORMAL 0.3810 //0.35897//0.4583 +#define FONTSCALE_BOLD 0.5476 //0.4583 +#define FONTSCALE_BIG 0.5476 //0.5833 +#define FONTSCALE_EXTRABIG 1 //1.0000 + +// new settings +#define TEXTSIZE_SMALL FONTSCALE_SMALL +#define TEXTSIZE_SMALL_SS (FONTSCALE_SMALL*2) +#define TEXTSIZE_DEFAULT FONTSCALE_NORMAL +#define TEXTSIZE_DEFAULT_SS (FONTSCALE_NORMAL*2) +#define TEXTSIZE_TITLE FONTSCALE_BIG +#define TEXTSIZE_TITLE_SS 1 + +#define TEXTSIZE_BOLD TEXTSIZE_DEFAULT +#define TEXTSIZE_BIG TEXTSIZE_TITLE + +//#define COLOR_TITLE 1 0.8 0.4 1 +#define COLOR_TITLE 1 1 1 1 +#define COLOR_HEADER 0.69 0.69 0.69 1 +#define COLOR_FOCUSED 0.95294 0.72156 0.21176 1 //1 0.788 0.129 1 +//#define COLOR_FOCUS_YELLOW 0.95294 0.72156 0.21176 1 +#define COLOR_UNFOCUSED 0.4823 0.4823 0.4823 1 +//#define COLOR_DISABLED 0.35 0.35 0.35 1 +#define COLOR_SAFEAREA 0 0 1 1 + +#define COLOR_INFO_YELLOW COLOR_FOCUSED//1 0.84706 0 1 +#define COLOR_TEXT 0.84313 0.84313 0.84313 1 +#define COLOR_DISABLED 0.34118 0.36863 0.37647 1 +#define COLOR_TITLEBAR 0.14510 0.16078 0.16862 0.3//1 +#define COLOR_RED_TEXT 0.69020 0.00784 0.00784 1 + +#define COLOR_FADEOUT 0.09412 0.09412 0.04912 0.65 + +#define COLOR_BODY_TEXT 0.62745 0.66667 0.67451 1 + +#define COLOR_USMC 0 0.0196 0.41 +#define COLOR_JPN 0.53 0.027 0.027 +#define COLOR_USSR 0.368 0.035 0.035 +#define COLOR_GER 0.937 0.9 0.607 + +#define DEFAULT_MP_CFG "default_mp.cfg" +#define SPLITSCREEN_MP_CFG "default_splitscreen.cfg" +#define SYSTEMLINK_MP_CFG "default_systemlink.cfg" +#define XBOXLIVE_MP_CFG "default_xboxlive.cfg" + +#define MAX_RANK int(tableLookup( "mp/rankTable.csv", 0, "maxrank", 1)) +#define MAX_PRESTIGE int(tableLookup( "mp/rankIconTable.csv", 0, "maxprestige", 1)) + +#define PRESTIGE_AVAIL (stat(2326) < MAX_PRESTIGE && stat(2301) == int(tableLookup("mp/rankTable.csv",0,MAX_RANK,7))) +#define PRESTIGE_NEXT (stat(2326) < MAX_PRESTIGE && stat(252) == MAX_RANK) +#define PRESTIGE_FINISH (stat(2326) == MAX_PRESTIGE) + +#define CAN_RANK_UP (stat(252) < MAX_RANK || stat(2326) < MAX_PRESTIGE) #endif // ENUMS_H diff --git a/fastfile.cpp b/fastfile.cpp new file mode 100644 index 0000000..4e57009 --- /dev/null +++ b/fastfile.cpp @@ -0,0 +1,374 @@ +#include "fastfile.h" +#include "compressor.h" + +#include +#include + +FastFile::FastFile() : + fileStem(), + company(), + fileType(), + signage(), + magic(), + version() { +} + +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) { + if (this != &other) { + fileStem = other.GetFileStem(); + company = other.GetCompany(); + fileType = other.GetFileType(); + signage = other.GetSignage(); + magic = other.GetMagic(); + version = other.GetVersion(); + zoneFile = other.zoneFile; + game = other.GetGame(); + platform = other.GetPlatform(); + } + return *this; +} + +bool FastFile::Load(const QByteArray aData) { + QByteArray decompressedData; + + // Create a QDataStream on the input data. + QDataStream fastFileStream(aData); + fastFileStream.setByteOrder(QDataStream::LittleEndian); + + // Parse header values. + company = pParseFFCompany(&fastFileStream); + fileType = pParseFFFileType(&fastFileStream); + signage = pParseFFSignage(&fastFileStream); + magic = pParseFFMagic(&fastFileStream); + version = pParseFFVersion(&fastFileStream); + platform = pCalculateFFPlatform(); + game = pCalculateFFGame(); + + if (game == "COD5") { + // 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"); + } + else if (game == "COD7" || game == "COD9") { + // For COD7/COD9, use BigEndian. + fastFileStream.setByteOrder(QDataStream::BigEndian); + if (platform == "PC") { + fastFileStream.setByteOrder(QDataStream::LittleEndian); + } + + // Select key based on game. + QByteArray key; + if (game == "COD7") { + fastFileStream.skipRawData(4); + if (platform == "360") { + key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d"); + } else if (platform == "PS3") { + key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A"); + // or + // key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370"); + } + } else if (game == "COD9") { + if (platform == "360") { + key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3"); + } else if (platform == "PC") { + key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"); + } + } + + // Read the 8-byte magic. + QByteArray fileMagic(8, Qt::Uninitialized); + fastFileStream.readRawData(fileMagic.data(), 8); + if (fileMagic != "PHEEBs71") { + qWarning() << "Invalid fast file magic!"; + return false; + } + fastFileStream.skipRawData(4); + + // Read IV table name (32 bytes). + QByteArray fileName(32, Qt::Uninitialized); + fastFileStream.readRawData(fileName.data(), 32); + + // Build the IV table from the fileName. + QByteArray ivTable = Compressor::InitIVTable(fileName); + + // Skip the RSA signature (256 bytes). + QByteArray rsaSignature(256, Qt::Uninitialized); + fastFileStream.readRawData(rsaSignature.data(), 256); + + // Now the stream should be positioned at 0x13C, where sections begin. + int sectionIndex = 0; + while (true) { + qint32 sectionSize = 0; + fastFileStream >> sectionSize; + qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize + << "Pos:" << fastFileStream.device()->pos(); + if (sectionSize == 0) + break; + + // Read the section data. + QByteArray sectionData; + sectionData.resize(sectionSize); + fastFileStream.readRawData(sectionData.data(), sectionSize); + + // Compute the IV for this section. + QByteArray iv = Compressor::GetIV(ivTable, sectionIndex); + + // Decrypt the section using Salsa20. + QByteArray decData = Compressor::salsa20DecryptSection(sectionData, key, iv); + + // Compute SHA1 hash of the decrypted data. + QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1); + + // Update the IV table based on the section hash. + Compressor::UpdateIVTable(ivTable, sectionIndex, sectionHash); + + // Build a compressed data buffer by prepending the two-byte zlib header. + QByteArray compressedData; + compressedData.append(char(0x78)); + compressedData.append(char(0x01)); + compressedData.append(decData); + + // For COD7, always decompress. + // For COD9, conditionally use DEFLATE (set useDeflateForCOD9 as needed). + if (game == "COD7") { + decompressedData.append(Compressor::DecompressZLIB(compressedData)); + } else if (game == "COD9") { + if (platform == "PC") { + decompressedData.append(Compressor::DecompressZLIB(compressedData)); + } else if (platform == "360") { + decompressedData.append(LZX::DecompressLZX(compressedData, compressedData.size())); + } + } else { + // If not decompressing, append the compressed buffer as-is. + decompressedData.append(compressedData); + } + + // Optionally write out test files for COD9. + if (game == "COD9") { + QFile testFile("exports/" + QString("%1.out").arg(sectionIndex)); + if(testFile.open(QIODevice::WriteOnly)) { + testFile.write(decompressedData); + testFile.close(); + } + } + + sectionIndex++; + } + + // For COD9, write out the complete decompressed zone for testing. + if (false && game == "COD9") { + QFile testFile("exports/test.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); + } + + return true; +} + + + +bool FastFile::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); + fileStem = 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; +} + +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) { + // Check for null datastream ptr + if (!afastFileStream) { return COMPANY_NONE; } + // Parse company + QByteArray companyData(2, Qt::Uninitialized); + afastFileStream->readRawData(companyData.data(), 2); + if (companyData == "IW") { + qDebug() << "Company found: 'INFINITY_WARD'"; + return COMPANY_INFINITY_WARD; + } else if (companyData == "TA") { + qDebug() << "Company found: 'TREYARCH'"; + return COMPANY_TREYARCH; + } else if (companyData == "Sl") { + qDebug() << "Company found: 'SLEDGEHAMMER'"; + return COMPANY_SLEDGEHAMMER; + } else if (companyData == "NX") { + qDebug() << "Company found: 'NEVERSOFT'"; + return COMPANY_NEVERSOFT; + } else { + qDebug() << QString("Failed to find company, found '%1'!").arg(companyData); + } + return COMPANY_NONE; +} + +FF_FILETYPE FastFile::pParseFFFileType(QDataStream *afastFileStream) { + // Parse filetype + QByteArray fileTypeData(2, Qt::Uninitialized); + afastFileStream->readRawData(fileTypeData.data(), 2); + if (fileTypeData == "ff") { + qDebug() << "File type found: 'FAST_FILE'"; + return FILETYPE_FAST_FILE; + } else { + qDebug() << "Failed to find file type!"; + } + return FILETYPE_NONE; +} + +FF_SIGNAGE FastFile::pParseFFSignage(QDataStream *afastFileStream) { + // Parse filetype + QByteArray signedData(1, Qt::Uninitialized); + afastFileStream->readRawData(signedData.data(), 1); + if (signedData == "u") { + qDebug() << "Found valid signage: Unsigned"; + return SIGNAGE_UNSIGNED; + } else if (signedData == "0" || signedData == "x") { + qDebug() << "Found valid signage: Signed"; + return SIGNAGE_SIGNED; + } else { + qDebug() << "Failed to determine signage of fastfile!"; + } + return SIGNAGE_NONE; +} + +QString FastFile::pParseFFMagic(QDataStream *afastFileStream) { + // Parse magic + QByteArray magicData(3, Qt::Uninitialized); + afastFileStream->readRawData(magicData.data(), 3); + if (magicData == "100") { + qDebug() << QString("Found valid magic: '%1'").arg(magicData); + return magicData; + } else { + qDebug() << "Magic invalid!"; + } + return ""; +} + +quint32 FastFile::pParseFFVersion(QDataStream *afastFileStream) { + // Parse version + quint32 version; + *afastFileStream >> version; + qDebug() << QString("Found version: '%1'").arg(version); + return version; +} + +QString FastFile::pCalculateFFPlatform() { + QString result = "NONE"; + switch (version) { + case 387: // PC World at War + case 473: // PC Black Ops 1 + case 1: // PC Modern Warfare 3 + case 147: // PC Black Ops 2 + result = "PC"; + break; + case 3640721408: // Xbox 360 Black Ops 1 + case 2449473536: // Xbox 360 Black Ops 2 + result = "360"; + break; + } + qDebug() << QString("Found platform: '%1'").arg(result); + return result; +} + +QString FastFile::pCalculateFFGame() { + QString result = "NONE"; + switch (version) { + case 387: // PC World at War + result = "COD5"; + break; + case 473: // PC Black Ops 1 + break; + case 3640721408: // Xbox 360 Black Ops 1 + result = "COD7"; + break; + case 1: // PC Modern Warfare 3 + result = "COD8"; + break; + case 147: // PC Black Ops 2 + case 2449473536: // Xbox 360 Black Ops 2 + result = "COD9"; + break; + } + qDebug() << QString("Found game: '%1'").arg(result); + return result; +} diff --git a/fastfile.h b/fastfile.h new file mode 100644 index 0000000..0277d1b --- /dev/null +++ b/fastfile.h @@ -0,0 +1,51 @@ +#ifndef FASTFILE_H +#define FASTFILE_H + +#include "enums.h" +#include "zonefile.h" + +#include +#include + +class FastFile +{ +public: + FastFile(); + ~FastFile(); + FastFile(const FastFile &aFastFile); + FastFile &operator=(const FastFile &other); + + bool Load(const QString aFilePath); + bool Load(const QByteArray aData); + + QString GetFileStem() const; + FF_COMPANY GetCompany() const; + FF_FILETYPE GetFileType() const; + FF_SIGNAGE GetSignage() const; + QString GetMagic() const; + quint32 GetVersion() const; + ZoneFile GetZoneFile() const; + QString GetGame() const; + QString GetPlatform() const; + +private: + QString fileStem; + FF_COMPANY company; + FF_FILETYPE fileType; + FF_SIGNAGE signage; + QString magic; + quint32 version; + ZoneFile zoneFile; + QString game; + QString platform; + + 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 diff --git a/fastfileviewer.cpp b/fastfileviewer.cpp new file mode 100644 index 0000000..8b883e8 --- /dev/null +++ b/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->GetFileStem()); + ui->comboBox_Company->setCurrentIndex(mFastFile->GetCompany()); + ui->comboBox_FileType->setCurrentIndex(mFastFile->GetFileType()); + ui->checkBox_Signed->setChecked(mFastFile->GetSignage() == SIGNAGE_SIGNED); + ui->lineEdit_Magic->setText(mFastFile->GetMagic()); + ui->spinBox_Version->setValue(mFastFile->GetVersion()); +} diff --git a/fastfileviewer.h b/fastfileviewer.h new file mode 100644 index 0000000..3fc36c1 --- /dev/null +++ b/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/fastfileviewer.ui b/fastfileviewer.ui new file mode 100644 index 0000000..52e4091 --- /dev/null +++ b/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/imagewidget.cpp b/imagewidget.cpp new file mode 100644 index 0000000..04af5c1 --- /dev/null +++ b/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/imagewidget.h b/imagewidget.h new file mode 100644 index 0000000..4de5a27 --- /dev/null +++ b/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/imagewidget.ui b/imagewidget.ui new file mode 100644 index 0000000..47b6206 --- /dev/null +++ b/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/ipak_structs.h b/ipak_structs.h new file mode 100644 index 0000000..44b996a --- /dev/null +++ b/ipak_structs.h @@ -0,0 +1,167 @@ +#ifndef IPAK_STRUCTS_H +#define IPAK_STRUCTS_H + +#include +#include +#include + +struct IPAKHeader +{ + QString magic; + quint32 magicInt; + QString version; + quint32 versionInt; + quint32 size; + quint32 sectionCount; + QString platform; + // Serial read method + friend QDataStream &operator>>(QDataStream &in, IPAKHeader &data) { + in.setByteOrder(QDataStream::LittleEndian); + in >> data.magicInt; + if (data.magicInt == 1262571593) { + in.setByteOrder(QDataStream::BigEndian); + data.platform = "Console"; + } else { + data.platform = "PC"; + } + in >> data.versionInt >> data.size >> data.sectionCount; + // Format magic into string + const char *magicChars = reinterpret_cast(&data.magicInt); + data.magic = QString::fromUtf8(magicChars, 4); + + // Format version into hex + data.version = QString::number(data.versionInt, 16).toUpper(); + return in; + } + // Serial write method + friend QDataStream &operator<<(QDataStream &out, const IPAKHeader &data) { + out.setByteOrder(QDataStream::LittleEndian); + if (data.magicInt == 1262571593) { + out.setByteOrder(QDataStream::BigEndian); + } + out << data.magicInt << data.version << data.size << data.sectionCount; + return out; + } +}; + +struct IPAKSection +{ + QString type; + quint32 typeInt; + quint32 offset; + quint32 size; + quint32 itemCount; + // Serial read method + friend QDataStream &operator>>(QDataStream &in, IPAKSection &data) { + in >> data.typeInt >> data.offset >> data.size >> data.itemCount; + // Format type into string + if (data.typeInt == 1) { + data.type = "Index"; + } else if (data.typeInt == 2) { + data.type = "Data"; + } else { + data.type = "Unknown"; + } + return in; + } + // Serial write method + friend QDataStream &operator<<(QDataStream &out, const IPAKSection &data) { + out << data.typeInt << data.offset << data.size << data.itemCount; + return out; + } +}; + +struct IPAKDataChunkCommand { + quint32 size; + bool compressed; + // Serial read method + friend QDataStream &operator>>(QDataStream &in, IPAKDataChunkCommand &data) { + quint32 sizeAndCompression; + in >> sizeAndCompression; + + data.size = sizeAndCompression & 0x00FFFFFF; + data.compressed = (sizeAndCompression >> 24) & 0x01; + + return in; + } + // Serial write method + friend QDataStream &operator<<(QDataStream &out, const IPAKDataChunkCommand &data) { + quint32 sanitizedSize = data.size & 0x00FFFFFF; + quint32 sanitizedCompressed = data.compressed & 0x01; + quint32 sizeAndCompression = (sanitizedCompressed << 24) | sanitizedSize; + + out << sizeAndCompression; + return out; + } +}; + +struct IPAKDataChunkHeader +{ + quint32 count; + quint32 offset; + QVector commands; + // Serial read method + friend QDataStream &operator>>(QDataStream &in, IPAKDataChunkHeader &data) { + quint32 countAndOffset; + in >> countAndOffset; + data.count = (countAndOffset >> 24) & 0xFF; + data.offset = countAndOffset & 0x00FFFFFF; + return in; + } + // Serial write method + friend QDataStream &operator<<(QDataStream &out, const IPAKDataChunkHeader &data) { + quint32 count = data.count & 0xFF; + quint32 offset = data.offset & 0x00FFFFFF; + out << ((count << 24) | offset); + return out; + } +}; + +struct IPAKIndexEntry +{ + quint32 dataHash; + quint32 nameHash; + quint32 offset; + quint32 size; + // Serial read method + friend QDataStream &operator>>(QDataStream &in, IPAKIndexEntry &data) { + in >> data.dataHash >> data.nameHash >> data.offset >> data.size; + return in; + } + // Serial write method + friend QDataStream &operator<<(QDataStream &out, const IPAKIndexEntry &data) { + out << data.dataHash << data.nameHash << data.offset << data.size; + return out; + } +}; + +struct IPAKDataChunkMetaData +{ + quint64 key; + QString name; + int format; + int offset; + int size; + int width; + int height; + int levels; + int mip; + // Serial read method + friend QDataStream &operator>>(QDataStream &in, IPAKDataChunkMetaData &data) { + in >> data.key; + in.readRawData(reinterpret_cast(data.name.data()), sizeof(60)); + in >> data.format >> data.offset >> data.size >> data.width + >> data.height >> data.levels >> data.mip; + return in; + } + // Serial write method + friend QDataStream &operator<<(QDataStream &out, const IPAKDataChunkMetaData &data) { + out << data.key; + out.writeRawData(reinterpret_cast(data.name.constData()), sizeof(60)); + out << data.format << data.offset << data.size << data.width + << data.height << data.levels << data.mip; + return out; + } +}; + +#endif // IPAK_STRUCTS_H diff --git a/iwifile.cpp b/iwifile.cpp new file mode 100644 index 0000000..4a96d1a --- /dev/null +++ b/iwifile.cpp @@ -0,0 +1,292 @@ +#include "iwifile.h" +#include "ddsfile.h" + +IWIFile::IWIFile() : + fileStem(), + header(), + info(), + mipmaps() { + +} + +IWIFile::IWIFile(const QString &aFilePath) : + fileStem(aFilePath.split('.').first().split('/').last()) { + + QFile file(aFilePath); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << "Error: Unable to open IWI file" << aFilePath; + return; + } + + QDataStream in(&file); + in.setByteOrder(QDataStream::LittleEndian); + + // Read header + in.readRawData(reinterpret_cast(&header), sizeof(IWIHeader)); + + if (!header.isSupported()) { + qDebug() << "Error: Unsupported IWI version!"; + return; + } + + // Adjust seek position for MW2/MW3 + if (header.Version == 0x08) { + file.seek(0x08); + } + + // Read info + in.readRawData(reinterpret_cast(&info), sizeof(IWIInfo)); + + // Determine offset array size + QVector offsets((header.Version == 0x1B) ? 8 : 4); + + if (header.Version == 0x0D || header.Version == 0x1B) { + file.seek(header.Version == 0x1B ? 0x20 : 0x10); + } + + // Read offsets + for (qint32 &offset : offsets) { + in >> offset; + } + + // Compute mipmaps + qint64 currentPos = file.pos(); + qint64 fileSize = file.size(); + QVector positions = QVector(); + + for (int i = 0; i < offsets.size(); i++) { + IWIMipmap m; + if (i == 0) { + m.offset = offsets[i]; + m.size = fileSize - offsets[i]; + } else if (i == offsets.size() - 1) { + m.offset = currentPos; + m.size = offsets[i] - currentPos; + } else { + m.offset = offsets[i]; + m.size = offsets[i - 1] - offsets[i]; + } + + quint64 pos = file.pos(); + + // Read mipmap + file.seek(m.offset); + m.data = file.read(m.size); + + file.seek(pos); + mipmaps.append(m); + } + + // Close file + file.close(); +} + +IWIFile::IWIFile(DDSFile &aDDSFile) { + // Ensure the DDS file has mipmaps + if (aDDSFile.mipmaps.isEmpty()) { + qDebug() << "Error: No mipmaps found in DDS file!"; + return; + } + + // Create IWIFile object + fileStem = aDDSFile.fileStem; + + // Set header (Magic & Version) + memcpy(header.Magic, "IWi", 3); + header.Version = 0x06; // Default to CoD4/CoD5 version + + // Set IWI Texture Info + info.Format = static_cast(aDDSFile.header.pixelFormat.format); + info.Width = aDDSFile.header.width; + info.Height = aDDSFile.header.height; + info.Depth = 1; // Default depth for 2D textures + info.Usage = 0; // No specific usage + + // Convert DDS mipmaps to IWI mipmaps + int offset = 28; // Standard offset start + for (const auto& ddsMipmap : aDDSFile.mipmaps) { + IWIMipmap iwiMipmap; + iwiMipmap.offset = offset; + iwiMipmap.size = ddsMipmap.data.size(); + iwiMipmap.data = ddsMipmap.data; + + offset += iwiMipmap.size; + mipmaps.append(iwiMipmap); + } +} + +IWIFile::IWIFile(const IWIFile &iwiFile) { + fileStem = iwiFile.fileStem; + header = iwiFile.header; + info = iwiFile.info; + mipmaps = iwiFile.mipmaps; +} + +IWIFile &IWIFile::operator=(const IWIFile &other) { + if (this != &other) { + fileStem = other.fileStem; + header = other.header; + info = other.info; + mipmaps = other.mipmaps; + } + return *this; +} + +IWIFile::~IWIFile() { + +} + +void IWIFile::SetupExportDirs() { + QDir dir = QDir::currentPath(); + if (!dir.exists("exports/")) { + dir.mkdir("exports/"); + } + + if (!dir.exists("exports/iwi/")) { + dir.mkdir("exports/iwi/"); + } + if (!dir.exists("exports/dds/")) { + dir.mkdir("exports/dds/"); + } + if (!dir.exists("exports/png/")) { + dir.mkdir("exports/png/"); + } + if (!dir.exists("exports/jpg/")) { + dir.mkdir("exports/jpg/"); + } +} + +bool IWIFile::SaveIWI() { + SetupExportDirs(); + QFile file("exports/iwi/" + fileStem + ".iwi"); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "Error: Unable to write IWI file " << fileStem + ".iwi"; + return false; + } + + QDataStream out(&file); + out.setByteOrder(QDataStream::LittleEndian); + + // Write IWI Header + out.writeRawData(reinterpret_cast(&header), sizeof(IWIHeader)); + + // Adjust seek position for MW2/MW3 + if (header.Version == 0x08) { + file.seek(0x08); + } + + // Write IWI Texture Info + out.writeRawData(reinterpret_cast(&info), sizeof(IWIInfo)); + + // Determine number of mipmaps based on version + QVector offsets((header.Version == 0x1B) ? 8 : 4); + qint32 currentOffset = file.pos() + (offsets.size() * sizeof(qint32)); + + // Compute offsets + for (int i = 0; i < offsets.size(); i++) { + offsets[i] = currentOffset; + if (mipmaps.size() && i < mipmaps.size()) { + currentOffset += mipmaps[i].size; + } + } + + // Seek and write offsets + if (header.Version == 0x0D || header.Version == 0x1B) { + file.seek(header.Version == 0x1B ? 0x20 : 0x10); + } + + for (const qint32 &offset : offsets) { + out << offset; + } + + for (auto mipmap : mipmaps) { + file.seek(mipmap.offset); + file.write(mipmap.data); + } + + file.close(); + + qDebug() << "Successfully wrote IWI file: " << fileStem + ".iwi"; + return true; +} + +bool IWIFile::SaveDDS() { + SetupExportDirs(); + QFile file("exports/dds/" + fileStem + ".dds"); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "Error: Unable to write DDS file " << fileStem + ".dds"; + return false; + } + + DDSHeader ddsHeader = {}; + ddsHeader.magic = 0x20534444; // 'DDS ' + ddsHeader.size = 124; + ddsHeader.flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE; + ddsHeader.height = info.Height; + ddsHeader.width = info.Width; + ddsHeader.depth = 0; + ddsHeader.mipMapCount = mipmaps.size(); + + DDSPixelFormat ddsPixelFormat = DDSFile::CalculatePixelFormat(info.Format); + if (ddsPixelFormat.flags & DDPF_FOURCC) { + ddsHeader.flags |= DDSD_LINEARSIZE; + } else { + ddsHeader.flags |= DDSD_PITCH; + } + ddsHeader.pixelFormat = ddsPixelFormat; + + // Calculate pitch/linear size + if (ddsPixelFormat.flags & DDPF_FOURCC) { + int blockSize = (ddsPixelFormat.format == 0x31545844) ? 8 : 16; + ddsHeader.pitchOrLinearSize = fmax(1, (ddsHeader.width + 3) / 4) * blockSize * (ddsHeader.height / 4); + } else { + ddsHeader.pitchOrLinearSize = ddsHeader.width * (ddsPixelFormat.rgbBitCount / 8); + } + + DDSCaps ddsCaps = {}; + ddsCaps.caps1 = DDSCAPS_TEXTURE; + ddsCaps.caps2 = 0; + ddsCaps.dDSX = 0; + ddsCaps.reserved = 0; + ddsHeader.caps = ddsCaps; + + QDataStream out(&file); + out.setByteOrder(QDataStream::LittleEndian); + + // Write DDS header + out.writeRawData(reinterpret_cast(&ddsHeader), sizeof(DDSHeader)); + + for (auto mipmap : mipmaps) { + if (!mipmap.data.size()) { continue; } + + // Write mipmap data + out.writeRawData(reinterpret_cast(mipmap.data.constData()), mipmap.data.size()); + } + file.close(); + + return true; +} + +bool IWIFile::SavePNG() { + DDSFile ddsFile(*this); + if (!ddsFile.SavePNG()) { + qDebug() << "Error: Failed to save PNG file: " << fileStem + ".png"; + return false; + } + return true; +} + +bool IWIFile::SaveJPG() { + DDSFile ddsFile(*this); + if (!ddsFile.SavePNG()) { + qDebug() << "Error: Failed to save JPG file: " << fileStem + ".jpg"; + return false; + } + return true; +} + +// Check if the IWI version is supported +bool IWIHeader::isSupported() const { + return (Magic[0] == 'I' && Magic[1] == 'W' && Magic[2] == 'i') && + supportedVersions.contains(Version); +} diff --git a/iwifile.h b/iwifile.h new file mode 100644 index 0000000..c1c4d2d --- /dev/null +++ b/iwifile.h @@ -0,0 +1,67 @@ +#ifndef IWIFILE_H +#define IWIFILE_H + +#include "qimage.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// Supported versions +static const QVector supportedVersions = { + 0x05, // CoD2 + 0x06, // CoD4, CoD5 + 0x08, // CoDMW2, CoDMW3 + 0x0D, // CoDBO1 + 0x1B // CoDBO2 +}; + +class DDSFile; + +struct IWIHeader { + char Magic[3]; + quint8 Version; + + bool isSupported() const; +}; + +struct IWIInfo { + quint8 Format; + quint8 Usage; + quint16 Width; + quint16 Height; + quint16 Depth; +}; + +struct IWIMipmap { + qint32 offset; + qint32 size; + QByteArray data; +}; + +class IWIFile { +public: + QString fileStem; + IWIHeader header; + IWIInfo info; + QVector mipmaps; + + IWIFile(); + IWIFile(const QString &aFilePath); + IWIFile(DDSFile &aDDSFile); + IWIFile(const IWIFile &iwiFile); + IWIFile& operator=(const IWIFile& other); + ~IWIFile(); + + bool SaveIWI(); + bool SaveDDS(); + bool SavePNG(); + bool SaveJPG(); + void SetupExportDirs(); +}; + +#endif // IWIFILE_H diff --git a/iwiviewer.cpp b/iwiviewer.cpp new file mode 100644 index 0000000..1fd2268 --- /dev/null +++ b/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/iwiviewer.h b/iwiviewer.h new file mode 100644 index 0000000..86f5105 --- /dev/null +++ b/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/iwiviewer.ui b/iwiviewer.ui new file mode 100644 index 0000000..657df71 --- /dev/null +++ b/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/localstringviewer.cpp b/localstringviewer.cpp new file mode 100644 index 0000000..8874da3 --- /dev/null +++ b/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->GetFileStem().section('.', 0, 0) + ".str"); + for (LocalString localStr : aZoneFile->GetAssetMap().localStrings) { + AddLocalString(localStr); + } +} diff --git a/localstringviewer.h b/localstringviewer.h new file mode 100644 index 0000000..b2c8566 --- /dev/null +++ b/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/localstringviewer.ui b/localstringviewer.ui new file mode 100644 index 0000000..bdd547e --- /dev/null +++ b/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/lzokay.cpp b/lzokay.cpp new file mode 100644 index 0000000..e2808b9 --- /dev/null +++ b/lzokay.cpp @@ -0,0 +1,647 @@ +#include "lzokay.hpp" +#include +#include +#include + +/* + * Based on documentation from the Linux sources: Documentation/lzo.txt + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/lzo.txt + */ + +namespace lzokay { + +#if _WIN32 +#define HOST_BIG_ENDIAN 0 +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define HOST_BIG_ENDIAN 1 +#else +#define HOST_BIG_ENDIAN 0 +#endif + +#if HOST_BIG_ENDIAN +static uint16_t get_le16(const uint8_t* p) { + uint16_t val = *reinterpret_cast(p); +#if __GNUC__ + return __builtin_bswap16(val); +#elif _WIN32 + return _byteswap_ushort(val); +#else + return (val = (val << 8) | ((val >> 8) & 0xFF)); +#endif +} +#else +static uint16_t get_le16(const uint8_t* p) { + return *reinterpret_cast(p); +} +#endif + +constexpr std::size_t Max255Count = std::size_t(~0) / 255 - 2; + +#define NEEDS_IN(count) \ +if (inp + (count) > inp_end) { \ + dst_size = outp - dst; \ + return EResult::InputOverrun; \ +} + +#define NEEDS_OUT(count) \ +if (outp + (count) > outp_end) { \ + dst_size = outp - dst; \ + return EResult::OutputOverrun; \ +} + +#define CONSUME_ZERO_BYTE_LENGTH \ +std::size_t offset; \ +{ \ + const uint8_t *old_inp = inp; \ + while (*inp == 0) ++inp; \ + offset = inp - old_inp; \ + if (offset > Max255Count) { \ + dst_size = outp - dst; \ + return EResult::Error; \ + } \ +} + +#define WRITE_ZERO_BYTE_LENGTH(length) \ +{ \ + std::size_t l; \ + for (l = length; l > 255; l -= 255) { *outp++ = 0; } \ + *outp++ = l; \ +} + +constexpr uint32_t M1MaxOffset = 0x0400; +constexpr uint32_t M2MaxOffset = 0x0800; +constexpr uint32_t M3MaxOffset = 0x4000; +constexpr uint32_t M4MaxOffset = 0xbfff; + +constexpr uint32_t M1MinLen = 2; +constexpr uint32_t M1MaxLen = 2; +constexpr uint32_t M2MinLen = 3; +constexpr uint32_t M2MaxLen = 8; +constexpr uint32_t M3MinLen = 3; +constexpr uint32_t M3MaxLen = 33; +constexpr uint32_t M4MinLen = 3; +constexpr uint32_t M4MaxLen = 9; + +constexpr uint32_t M1Marker = 0x0; +constexpr uint32_t M2Marker = 0x40; +constexpr uint32_t M3Marker = 0x20; +constexpr uint32_t M4Marker = 0x10; + +constexpr uint32_t MaxMatchByLengthLen = 34; /* Max M3 len + 1 */ + +EResult decompress(const uint8_t* src, std::size_t src_size, + uint8_t* dst, std::size_t init_dst_size, + std::size_t& dst_size) { + dst_size = init_dst_size; + + if (src_size < 3) { + dst_size = 0; + return EResult::InputOverrun; + } + + const uint8_t* inp = src; + const uint8_t* inp_end = src + src_size; + uint8_t* outp = dst; + uint8_t* outp_end = dst + dst_size; + uint8_t* lbcur; + std::size_t lblen; + std::size_t state = 0; + std::size_t nstate = 0; + + /* First byte encoding */ + if (*inp >= 22) { + /* 22..255 : copy literal string + * length = (byte - 17) = 4..238 + * state = 4 [ don't copy extra literals ] + * skip byte + */ + std::size_t len = *inp++ - uint8_t(17); + NEEDS_IN(len) + NEEDS_OUT(len) + for (std::size_t i = 0; i < len; ++i) + *outp++ = *inp++; + state = 4; + } else if (*inp >= 18) { + /* 18..21 : copy 0..3 literals + * state = (byte - 17) = 0..3 [ copy literals ] + * skip byte + */ + nstate = *inp++ - uint8_t(17); + state = nstate; + NEEDS_IN(nstate) + NEEDS_OUT(nstate) + for (std::size_t i = 0; i < nstate; ++i) + *outp++ = *inp++; + } + /* 0..17 : follow regular instruction encoding, see below. It is worth + * noting that codes 16 and 17 will represent a block copy from + * the dictionary which is empty, and that they will always be + * invalid at this place. + */ + + while (true) { + NEEDS_IN(1) + uint8_t inst = *inp++; + if (inst & 0xC0) { + /* [M2] + * 1 L L D D D S S (128..255) + * Copy 5-8 bytes from block within 2kB distance + * state = S (copy S literals after this block) + * length = 5 + L + * Always followed by exactly one byte : H H H H H H H H + * distance = (H << 3) + D + 1 + * + * 0 1 L D D D S S (64..127) + * Copy 3-4 bytes from block within 2kB distance + * state = S (copy S literals after this block) + * length = 3 + L + * Always followed by exactly one byte : H H H H H H H H + * distance = (H << 3) + D + 1 + */ + NEEDS_IN(1) + lbcur = outp - ((*inp++ << 3) + ((inst >> 2) & 0x7) + 1); + lblen = std::size_t(inst >> 5) + 1; + nstate = inst & uint8_t(0x3); + } else if (inst & M3Marker) { + /* [M3] + * 0 0 1 L L L L L (32..63) + * Copy of small block within 16kB distance (preferably less than 34B) + * length = 2 + (L ?: 31 + (zero_bytes * 255) + non_zero_byte) + * Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S + * distance = D + 1 + * state = S (copy S literals after this block) + */ + lblen = std::size_t(inst & uint8_t(0x1f)) + 2; + if (lblen == 2) { + CONSUME_ZERO_BYTE_LENGTH + NEEDS_IN(1) + lblen += offset * 255 + 31 + *inp++; + } + NEEDS_IN(2) + nstate = get_le16(inp); + inp += 2; + lbcur = outp - ((nstate >> 2) + 1); + nstate &= 0x3; + } else if (inst & M4Marker) { + /* [M4] + * 0 0 0 1 H L L L (16..31) + * Copy of a block within 16..48kB distance (preferably less than 10B) + * length = 2 + (L ?: 7 + (zero_bytes * 255) + non_zero_byte) + * Always followed by exactly one LE16 : D D D D D D D D : D D D D D D S S + * distance = 16384 + (H << 14) + D + * state = S (copy S literals after this block) + * End of stream is reached if distance == 16384 + */ + lblen = std::size_t(inst & uint8_t(0x7)) + 2; + if (lblen == 2) { + CONSUME_ZERO_BYTE_LENGTH + NEEDS_IN(1) + lblen += offset * 255 + 7 + *inp++; + } + NEEDS_IN(2) + nstate = get_le16(inp); + inp += 2; + lbcur = outp - (((inst & 0x8) << 11) + (nstate >> 2)); + nstate &= 0x3; + if (lbcur == outp) + break; /* Stream finished */ + lbcur -= 16384; + } else { + /* [M1] Depends on the number of literals copied by the last instruction. */ + if (state == 0) { + /* If last instruction did not copy any literal (state == 0), this + * encoding will be a copy of 4 or more literal, and must be interpreted + * like this : + * + * 0 0 0 0 L L L L (0..15) : copy long literal string + * length = 3 + (L ?: 15 + (zero_bytes * 255) + non_zero_byte) + * state = 4 (no extra literals are copied) + */ + std::size_t len = inst + 3; + if (len == 3) { + CONSUME_ZERO_BYTE_LENGTH + NEEDS_IN(1) + len += offset * 255 + 15 + *inp++; + } + /* copy_literal_run */ + NEEDS_IN(len) + NEEDS_OUT(len) + for (std::size_t i = 0; i < len; ++i) + *outp++ = *inp++; + state = 4; + continue; + } else if (state != 4) { + /* If last instruction used to copy between 1 to 3 literals (encoded in + * the instruction's opcode or distance), the instruction is a copy of a + * 2-byte block from the dictionary within a 1kB distance. It is worth + * noting that this instruction provides little savings since it uses 2 + * bytes to encode a copy of 2 other bytes but it encodes the number of + * following literals for free. It must be interpreted like this : + * + * 0 0 0 0 D D S S (0..15) : copy 2 bytes from <= 1kB distance + * length = 2 + * state = S (copy S literals after this block) + * Always followed by exactly one byte : H H H H H H H H + * distance = (H << 2) + D + 1 + */ + NEEDS_IN(1) + nstate = inst & uint8_t(0x3); + lbcur = outp - ((inst >> 2) + (*inp++ << 2) + 1); + lblen = 2; + } else { + /* If last instruction used to copy 4 or more literals (as detected by + * state == 4), the instruction becomes a copy of a 3-byte block from the + * dictionary from a 2..3kB distance, and must be interpreted like this : + * + * 0 0 0 0 D D S S (0..15) : copy 3 bytes from 2..3 kB distance + * length = 3 + * state = S (copy S literals after this block) + * Always followed by exactly one byte : H H H H H H H H + * distance = (H << 2) + D + 2049 + */ + NEEDS_IN(1) + nstate = inst & uint8_t(0x3); + lbcur = outp - ((inst >> 2) + (*inp++ << 2) + 2049); + lblen = 3; + } + } + if (lbcur < dst) { + dst_size = outp - dst; + return EResult::LookbehindOverrun; + } + NEEDS_IN(nstate) + NEEDS_OUT(lblen + nstate) + /* Copy lookbehind */ + for (std::size_t i = 0; i < lblen; ++i) + *outp++ = *lbcur++; + state = nstate; + /* Copy literal */ + for (std::size_t i = 0; i < nstate; ++i) + *outp++ = *inp++; + } + + dst_size = outp - dst; + if (lblen != 3) /* Ensure terminating M4 was encountered */ + return EResult::Error; + if (inp == inp_end) + return EResult::Success; + else if (inp < inp_end) + return EResult::InputNotConsumed; + else + return EResult::InputOverrun; +} + +struct State { + const uint8_t* src; + const uint8_t* src_end; + const uint8_t* inp; + uint32_t wind_sz; + uint32_t wind_b; + uint32_t wind_e; + uint32_t cycle1_countdown; + + const uint8_t* bufp; + uint32_t buf_sz; + + /* Access next input byte and advance both ends of circular buffer */ + void get_byte(uint8_t* buf) { + if (inp >= src_end) { + if (wind_sz > 0) + --wind_sz; + buf[wind_e] = 0; + if (wind_e < DictBase::MaxMatchLen) + buf[DictBase::BufSize + wind_e] = 0; + } else { + buf[wind_e] = *inp; + if (wind_e < DictBase::MaxMatchLen) + buf[DictBase::BufSize + wind_e] = *inp; + ++inp; + } + if (++wind_e == DictBase::BufSize) + wind_e = 0; + if (++wind_b == DictBase::BufSize) + wind_b = 0; + } + + uint32_t pos2off(uint32_t pos) const { + return wind_b > pos ? wind_b - pos : DictBase::BufSize - (pos - wind_b); + } +}; + +class DictImpl : public DictBase { +public: + struct Match3Impl : DictBase::Match3 { + static uint32_t make_key(const uint8_t* data) { + return ((0x9f5f * (((uint32_t(data[0]) << 5 ^ uint32_t(data[1])) << 5) ^ data[2])) >> 5) & 0x3fff; + } + + uint16_t get_head(uint32_t key) const { + return (chain_sz[key] == 0) ? uint16_t(UINT16_MAX) : head[key]; + } + + void init() { + std::fill(std::begin(chain_sz), std::end(chain_sz), 0); + } + + void remove(uint32_t pos, const uint8_t* b) { + --chain_sz[make_key(b + pos)]; + } + + void advance(State& s, uint32_t& match_pos, uint32_t& match_count, const uint8_t* b) { + uint32_t key = make_key(b + s.wind_b); + match_pos = chain[s.wind_b] = get_head(key); + match_count = chain_sz[key]++; + if (match_count > DictBase::MaxMatchLen) + match_count = DictBase::MaxMatchLen; + head[key] = uint16_t(s.wind_b); + } + + void skip_advance(State& s, const uint8_t* b) { + uint32_t key = make_key(b + s.wind_b); + chain[s.wind_b] = get_head(key); + head[key] = uint16_t(s.wind_b); + best_len[s.wind_b] = uint16_t(DictBase::MaxMatchLen + 1); + chain_sz[key]++; + } + }; + + struct Match2Impl : DictBase::Match2 { + static uint32_t make_key(const uint8_t* data) { + return uint32_t(data[0]) ^ (uint32_t(data[1]) << 8); + } + + void init() { + std::fill(std::begin(head), std::end(head), UINT16_MAX); + } + + void add(uint16_t pos, const uint8_t* b) { + head[make_key(b + pos)] = pos; + } + + void remove(uint32_t pos, const uint8_t* b) { + uint16_t& p = head[make_key(b + pos)]; + if (p == pos) + p = UINT16_MAX; + } + + bool search(State& s, uint32_t& lb_pos, uint32_t& lb_len, + uint32_t best_pos[MaxMatchByLengthLen], const uint8_t* b) const { + uint16_t pos = head[make_key(b + s.wind_b)]; + if (pos == UINT16_MAX) + return false; + if (best_pos[2] == 0) + best_pos[2] = pos + 1; + if (lb_len < 2) { + lb_len = 2; + lb_pos = pos; + } + return true; + } + }; + + void init(State& s, const uint8_t* src, std::size_t src_size) { + auto& match3 = static_cast(_storage->match3); + auto& match2 = static_cast(_storage->match2); + + s.cycle1_countdown = DictBase::MaxDist; + match3.init(); + match2.init(); + + s.src = src; + s.src_end = src + src_size; + s.inp = src; + s.wind_sz = uint32_t(std::min(src_size, std::size_t(MaxMatchLen))); + s.wind_b = 0; + s.wind_e = s.wind_sz; + std::copy_n(s.inp, s.wind_sz, _storage->buffer); + s.inp += s.wind_sz; + + if (s.wind_e == DictBase::BufSize) + s.wind_e = 0; + + if (s.wind_sz < 3) + std::fill_n(_storage->buffer + s.wind_b + s.wind_sz, 3, 0); + } + + void reset_next_input_entry(State& s, Match3Impl& match3, Match2Impl& match2) { + /* Remove match from about-to-be-clobbered buffer entry */ + if (s.cycle1_countdown == 0) { + match3.remove(s.wind_e, _storage->buffer); + match2.remove(s.wind_e, _storage->buffer); + } else { + --s.cycle1_countdown; + } + } + + void advance(State& s, uint32_t& lb_off, uint32_t& lb_len, + uint32_t best_off[MaxMatchByLengthLen], bool skip) { + auto& match3 = static_cast(_storage->match3); + auto& match2 = static_cast(_storage->match2); + + if (skip) { + for (uint32_t i = 0; i < lb_len - 1; ++i) { + reset_next_input_entry(s, match3, match2); + match3.skip_advance(s, _storage->buffer); + match2.add(uint16_t(s.wind_b), _storage->buffer); + s.get_byte(_storage->buffer); + } + } + + lb_len = 1; + lb_off = 0; + uint32_t lb_pos; + + uint32_t best_pos[MaxMatchByLengthLen] = {}; + uint32_t match_pos, match_count; + match3.advance(s, match_pos, match_count, _storage->buffer); + + int best_char = _storage->buffer[s.wind_b]; + uint32_t best_len = lb_len; + if (lb_len >= s.wind_sz) { + if (s.wind_sz == 0) + best_char = -1; + lb_off = 0; + match3.best_len[s.wind_b] = DictBase::MaxMatchLen + 1; + } else { + if (match2.search(s, lb_pos, lb_len, best_pos, _storage->buffer) && s.wind_sz >= 3) { + for (uint32_t i = 0; i < match_count; ++i, match_pos = match3.chain[match_pos]) { + auto ref_ptr = _storage->buffer + s.wind_b; + auto match_ptr = _storage->buffer + match_pos; + auto mismatch = std::mismatch(ref_ptr, ref_ptr + s.wind_sz, match_ptr); + auto match_len = uint32_t(mismatch.first - ref_ptr); + if (match_len < 2) + continue; + if (match_len < MaxMatchByLengthLen && best_pos[match_len] == 0) + best_pos[match_len] = match_pos + 1; + if (match_len > lb_len) { + lb_len = match_len; + lb_pos = match_pos; + if (match_len == s.wind_sz || match_len > match3.best_len[match_pos]) + break; + } + } + } + if (lb_len > best_len) + lb_off = s.pos2off(lb_pos); + match3.best_len[s.wind_b] = uint16_t(lb_len); + for (auto posit = std::begin(best_pos) + 2, offit = best_off + 2; + posit != std::end(best_pos); ++posit, ++offit) { + *offit = (*posit > 0) ? s.pos2off(*posit - 1) : 0; + } + } + + reset_next_input_entry(s, match3, match2); + + match2.add(uint16_t(s.wind_b), _storage->buffer); + + s.get_byte(_storage->buffer); + + if (best_char < 0) { + s.buf_sz = 0; + lb_len = 0; + /* Signal exit */ + } else { + s.buf_sz = s.wind_sz + 1; + } + s.bufp = s.inp - s.buf_sz; + } +}; + +static void find_better_match(const uint32_t best_off[MaxMatchByLengthLen], uint32_t& lb_len, uint32_t& lb_off) { + if (lb_len <= M2MinLen || lb_off <= M2MaxOffset) + return; + if (lb_off > M2MaxOffset && lb_len >= M2MinLen + 1 && lb_len <= M2MaxLen + 1 && + best_off[lb_len - 1] != 0 && best_off[lb_len - 1] <= M2MaxOffset) { + lb_len -= 1; + lb_off = best_off[lb_len]; + } else if (lb_off > M3MaxOffset && lb_len >= M4MaxLen + 1 && lb_len <= M2MaxLen + 2 && + best_off[lb_len - 2] && best_off[lb_len] <= M2MaxOffset) { + lb_len -= 2; + lb_off = best_off[lb_len]; + } else if (lb_off > M3MaxOffset && lb_len >= M4MaxLen + 1 && lb_len <= M3MaxLen + 1 && + best_off[lb_len - 1] != 0 && best_off[lb_len - 2] <= M3MaxOffset) { + lb_len -= 1; + lb_off = best_off[lb_len]; + } +} + +static EResult encode_literal_run(uint8_t*& outp, const uint8_t* outp_end, const uint8_t* dst, std::size_t& dst_size, + const uint8_t* lit_ptr, uint32_t lit_len) { + if (outp == dst && lit_len <= 238) { + NEEDS_OUT(1); + *outp++ = uint8_t(17 + lit_len); + } else if (lit_len <= 3) { + outp[-2] = uint8_t(outp[-2] | lit_len); + } else if (lit_len <= 18) { + NEEDS_OUT(1); + *outp++ = uint8_t(lit_len - 3); + } else { + NEEDS_OUT((lit_len - 18) / 255 + 2); + *outp++ = 0; + WRITE_ZERO_BYTE_LENGTH(lit_len - 18); + } + NEEDS_OUT(lit_len); + outp = std::copy_n(lit_ptr, lit_len, outp); + return EResult::Success; +} + +static EResult encode_lookback_match(uint8_t*& outp, const uint8_t* outp_end, const uint8_t* dst, std::size_t& dst_size, + uint32_t lb_len, uint32_t lb_off, uint32_t last_lit_len) { + if (lb_len == 2) { + lb_off -= 1; + NEEDS_OUT(2); + *outp++ = uint8_t(M1Marker | ((lb_off & 0x3) << 2)); + *outp++ = uint8_t(lb_off >> 2); + } else if (lb_len <= M2MaxLen && lb_off <= M2MaxOffset) { + lb_off -= 1; + NEEDS_OUT(2); + *outp++ = uint8_t((lb_len - 1) << 5 | ((lb_off & 0x7) << 2)); + *outp++ = uint8_t(lb_off >> 3); + } else if (lb_len == M2MinLen && lb_off <= M1MaxOffset + M2MaxOffset && last_lit_len >= 4) { + lb_off -= 1 + M2MaxOffset; + NEEDS_OUT(2); + *outp++ = uint8_t(M1Marker | ((lb_off & 0x3) << 2)); + *outp++ = uint8_t(lb_off >> 2); + } else if (lb_off <= M3MaxOffset) { + lb_off -= 1; + if (lb_len <= M3MaxLen) { + NEEDS_OUT(1); + *outp++ = uint8_t(M3Marker | (lb_len - 2)); + } else { + lb_len -= M3MaxLen; + NEEDS_OUT(lb_len / 255 + 2); + *outp++ = uint8_t(M3Marker); + WRITE_ZERO_BYTE_LENGTH(lb_len); + } + NEEDS_OUT(2); + *outp++ = uint8_t(lb_off << 2); + *outp++ = uint8_t(lb_off >> 6); + } else { + lb_off -= 0x4000; + if (lb_len <= M4MaxLen) { + NEEDS_OUT(1); + *outp++ = uint8_t(M4Marker | ((lb_off & 0x4000) >> 11) | (lb_len - 2)); + } else { + lb_len -= M4MaxLen; + NEEDS_OUT(lb_len / 255 + 2); + *outp++ = uint8_t(M4Marker | ((lb_off & 0x4000) >> 11)); + WRITE_ZERO_BYTE_LENGTH(lb_len); + } + NEEDS_OUT(2); + *outp++ = uint8_t(lb_off << 2); + *outp++ = uint8_t(lb_off >> 6); + } + return EResult::Success; +} + +EResult compress(const uint8_t* src, std::size_t src_size, + uint8_t* dst, std::size_t init_dst_size, + std::size_t& dst_size, DictBase& dict) { + EResult err; + State s; + auto& d = static_cast(dict); + dst_size = init_dst_size; + uint8_t* outp = dst; + uint8_t* outp_end = dst + dst_size; + uint32_t lit_len = 0; + uint32_t lb_off, lb_len; + uint32_t best_off[MaxMatchByLengthLen]; + d.init(s, src, src_size); + const uint8_t* lit_ptr = s.inp; + d.advance(s, lb_off, lb_len, best_off, false); + while (s.buf_sz > 0) { + if (lit_len == 0) + lit_ptr = s.bufp; + if (lb_len < 2 || (lb_len == 2 && (lb_off > M1MaxOffset || lit_len == 0 || lit_len >= 4)) || + (lb_len == 2 && outp == dst) || (outp == dst && lit_len == 0)) { + lb_len = 0; + } else if (lb_len == M2MinLen && lb_off > M1MaxOffset + M2MaxOffset && lit_len >= 4) { + lb_len = 0; + } + if (lb_len == 0) { + ++lit_len; + d.advance(s, lb_off, lb_len, best_off, false); + continue; + } + find_better_match(best_off, lb_len, lb_off); + if ((err = encode_literal_run(outp, outp_end, dst, dst_size, lit_ptr, lit_len)) < EResult::Success) + return err; + if ((err = encode_lookback_match(outp, outp_end, dst, dst_size, lb_len, lb_off, lit_len)) < EResult::Success) + return err; + lit_len = 0; + d.advance(s, lb_off, lb_len, best_off, true); + } + if ((err = encode_literal_run(outp, outp_end, dst, dst_size, lit_ptr, lit_len)) < EResult::Success) + return err; + + /* Terminating M4 */ + NEEDS_OUT(3); + *outp++ = M4Marker | 1; + *outp++ = 0; + *outp++ = 0; + + dst_size = outp - dst; + return EResult::Success; +} + +} diff --git a/lzokay.hpp b/lzokay.hpp new file mode 100644 index 0000000..522edd8 --- /dev/null +++ b/lzokay.hpp @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include + +namespace lzokay { + +enum class EResult { + LookbehindOverrun = -4, + OutputOverrun = -3, + InputOverrun = -2, + Error = -1, + Success = 0, + InputNotConsumed = 1, +}; + +class DictBase { +protected: + static constexpr uint32_t HashSize = 0x4000; + static constexpr uint32_t MaxDist = 0xbfff; + static constexpr uint32_t MaxMatchLen = 0x800; + static constexpr uint32_t BufSize = MaxDist + MaxMatchLen; + + /* List encoding of previous 3-byte data matches */ + struct Match3 { + uint16_t head[HashSize]; /* key -> chain-head-pos */ + uint16_t chain_sz[HashSize]; /* key -> chain-size */ + uint16_t chain[BufSize]; /* chain-pos -> next-chain-pos */ + uint16_t best_len[BufSize]; /* chain-pos -> best-match-length */ + }; + /* Encoding of 2-byte data matches */ + struct Match2 { + uint16_t head[1 << 16]; /* 2-byte-data -> head-pos */ + }; + + struct Data { + Match3 match3; + Match2 match2; + + /* Circular buffer caching enough data to access the maximum lookback + * distance of 48K + maximum match length of 2K. An additional 2K is + * allocated so the start of the buffer may be replicated at the end, + * therefore providing efficient circular access. + */ + uint8_t buffer[BufSize + MaxMatchLen]; + }; + using storage_type = Data; + storage_type* _storage; + DictBase() = default; + friend struct State; + friend EResult compress(const uint8_t* src, std::size_t src_size, + uint8_t* dst, std::size_t& dst_size, DictBase& dict); +}; +template class _Alloc = std::allocator> +class Dict : public DictBase { + _Alloc _allocator; +public: + Dict() { _storage = _allocator.allocate(1); } + ~Dict() { _allocator.deallocate(_storage, 1); } +}; + +EResult decompress(const uint8_t* src, std::size_t src_size, + uint8_t* dst, std::size_t dst_size, + std::size_t& out_size); +EResult compress(const uint8_t* src, std::size_t src_size, + uint8_t* dst, std::size_t dst_size, + std::size_t& out_size, DictBase& dict); +inline EResult compress(const uint8_t* src, std::size_t src_size, + uint8_t* dst, std::size_t dst_size, + std::size_t& out_size) { + Dict<> dict; + return compress(src, src_size, dst, dst_size, out_size, dict); +} + +constexpr std::size_t compress_worst_size(std::size_t s) { + return s + s / 16 + 64 + 3; +} + +} diff --git a/lzx.h b/lzx.h new file mode 100644 index 0000000..ee49541 --- /dev/null +++ b/lzx.h @@ -0,0 +1,120 @@ +#ifndef LZX_H +#define LZX_H + +#pragma once + +#include +#include +#include +#include + +namespace LZX { + +/*! + * \brief Decompresses LZX-compressed data. + * + * This function decodes a compressed QByteArray until there are no more + * bits available. (In a real LZX stream there is an end-of-stream marker; + * here we simply stop if a required field cannot be read.) + * + * \param compressedData The input LZX–compressed data. + * \param windowBits The log₂ of the sliding window size (default 15 → 32K). + * \return A QByteArray containing the decompressed data. + */ +static QByteArray DecompressLZX(const QByteArray &compressedData, uint32_t windowBits = 15) +{ + if (compressedData.isEmpty()) + return QByteArray(); + + // Calculate sliding window size. + const uint32_t windowSize = 1u << windowBits; + std::vector window(windowSize, 0); + uint32_t windowPos = 0; + + // Use a dynamic output buffer. + QByteArray outArray; + // Reserve an initial capacity. + outArray.reserve(1024); + + // --- Bitstream state --- + const uint8_t *inData = reinterpret_cast(compressedData.constData()); + size_t inSize = compressedData.size(); + size_t inPos = 0; + uint32_t bitBuffer = 0; + int bitsInBuffer = 0; + + // Lambda: Ensure at least 'count' bits are available. + auto ensureBits = [&](int count) -> bool { + while (bitsInBuffer < count) { + if (inPos < inSize) { + bitBuffer = (bitBuffer << 8) | inData[inPos++]; + bitsInBuffer += 8; + } else { + return false; + } + } + return true; + }; + + // Lambda: Get (and remove) 'count' bits from the bit buffer. + auto getBits = [&](int count) -> uint32_t { + if (!ensureBits(count)) + return 0; + uint32_t result = (bitBuffer >> (bitsInBuffer - count)) & ((1u << count) - 1); + bitsInBuffer -= count; + return result; + }; + + // --- Main decompression loop --- + // In this simplified placeholder format: + // - A flag bit of 1 means a literal byte follows (8 bits). + // - A flag bit of 0 means a match follows: first 4 bits for match length (plus base 2) + // then windowBits bits for the match offset (relative to the current sliding window). + while (true) { + // Try to read a flag bit; if not available, we assume the stream is complete. + if (!ensureBits(1)) + break; + uint32_t flag = getBits(1); + if (flag == 1) { + // Literal: next 8 bits form a literal byte. + if (!ensureBits(8)) { + qWarning() << "Unexpected end of input while reading literal."; + break; + } + uint8_t literal = static_cast(getBits(8)); + outArray.append(static_cast(literal)); + // Update the sliding window. + window[windowPos] = literal; + windowPos = (windowPos + 1) % windowSize; + } else { + // Match: first read a 4-bit match length (with a base of 2). + if (!ensureBits(4)) { + qWarning() << "Unexpected end of input while reading match length."; + break; + } + uint32_t matchLength = getBits(4) + 2; + // Then read the match offset (fixed number of bits equals windowBits). + if (!ensureBits(windowBits)) { + qWarning() << "Unexpected end of input while reading match offset."; + break; + } + uint32_t matchOffset = getBits(windowBits); + // Compute the source position in the sliding window. + uint32_t copyPos = (windowPos + windowSize - matchOffset) % windowSize; + // Copy matchLength bytes from the sliding window. + for (uint32_t i = 0; i < matchLength; i++) { + uint8_t byte = window[(copyPos + i) % windowSize]; + outArray.append(static_cast(byte)); + // Update the sliding window with the decompressed byte. + window[windowPos] = byte; + windowPos = (windowPos + 1) % windowSize; + } + } + } + + return outArray; +} + +} // namespace LZX + +#endif // LZX_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 8cd2ff6..8715004 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,189 +1,305 @@ #include "mainwindow.h" +#include "aboutdialog.h" +#include "fastfile.h" +#include "qheaderview.h" +#include "techsetviewer.h" #include "ui_mainwindow.h" +#include "compressor.h" +#include "dds_structs.h" +#include "iwifile.h" +#include "ddsfile.h" + +#include + +#include "DevILSDK/include/IL/il.h" MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent) - , ui(new Ui::MainWindow) { + : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); + setAcceptDrops(true); + mTypeMap = QMap(); mTypeOrder = QStringList(); mRawFileMap = QMap(); - mTreeMap = QMap(); + mImageMap = QMap(); + mTreeMap = QMap(); mStrTableMap = QMap>>(); mBSPVersion = 0; mDiskLumpCount = 0; mDiskLumpOrder = QVector(); mLumps = QMap(); + mTreeWidget = new XTreeWidget(this); - connect(ui->treeWidget_Scripts, &QTreeWidget::itemSelectionChanged, this, &MainWindow::ScriptSelected); - connect(ui->comboBox_StringTable, &QComboBox::currentTextChanged, this, &MainWindow::StrTableSelected); + //ModelViewer *mModelViewer = new ModelViewer(container); + //mModelViewer->setAcceptDrops(false); - // Initialize Asset Index Table - ui->tableWidget_Index->setColumnCount(3); - ui->tableWidget_Index->setHorizontalHeaderLabels({"Asset Type", "Asset Name", "Asset Count"}); - ui->tableWidget_Index->verticalHeader()->setVisible(false); - ui->tableWidget_Index->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->tableWidget_Index->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->tableWidget_Index->setSelectionMode(QAbstractItemView::SingleSelection); - ui->tableWidget_Index->setShowGrid(false); - ui->tableWidget_Index->setStyleSheet("QTableView {selection-background-color: red;}"); + ui->tabWidget->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->tabWidget, &QTabWidget::customContextMenuRequested, this, [this](const QPoint &pos) { + if (pos.isNull()) + return; - // Initialize Asset Order Table - ui->tableWidget_Order->setColumnCount(3); - ui->tableWidget_Order->setHorizontalHeaderLabels({"Asset Type", "Asset Name", "Asset Count"}); - ui->tableWidget_Order->verticalHeader()->setVisible(false); - ui->tableWidget_Order->setEditTriggers(QAbstractItemView::NoEditTriggers); - ui->tableWidget_Order->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->tableWidget_Order->setSelectionMode(QAbstractItemView::SingleSelection); - ui->tableWidget_Order->setShowGrid(false); - ui->tableWidget_Order->setStyleSheet("QTableView {selection-background-color: red;}"); + int tabIndex = ui->tabWidget->tabBar()->tabAt(pos); + QMenu *contextMenu = new QMenu(this); - Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow(); - view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f))); + QAction *closeAction = new QAction("Close"); + contextMenu->addAction(closeAction); + connect(closeAction, &QAction::triggered, this, [this, &tabIndex](bool checked) { + Q_UNUSED(checked); - QWidget *container = QWidget::createWindowContainer(view); - QSize screenSize = view->screen()->size(); - container->setMinimumSize(QSize(200, 100)); - container->setMaximumSize(screenSize); + ui->tabWidget->removeTab(tabIndex); + }); - QHBoxLayout *hLayout = new QHBoxLayout(ui->frame_Scene); - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->setAlignment(Qt::AlignTop); - hLayout->addWidget(container, 1); - hLayout->addLayout(vLayout); + QMenu *closeMultipleAction = new QMenu("Close Multiple Tabs"); - // Root entity - Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity(); + QAction *closeAllAction = new QAction("Close All"); + closeMultipleAction->addAction(closeAllAction); + connect(closeAllAction, &QAction::triggered, this, [this](bool checked) { + Q_UNUSED(checked); - // Camera - Qt3DRender::QCamera *cameraEntity = view->camera(); + ui->tabWidget->clear(); + }); - 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)); + QAction *closeAllButAction = new QAction("Close All BUT This"); + closeMultipleAction->addAction(closeAllButAction); + connect(closeAllButAction, &QAction::triggered, this, [this, &tabIndex](bool checked) { + Q_UNUSED(checked); - Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity); - Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity); - light->setColor("white"); - light->setIntensity(1); - lightEntity->addComponent(light); + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (i != tabIndex) { + ui->tabWidget->removeTab(i); + } + } + }); - Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity); - lightTransform->setTranslation(cameraEntity->position()); - lightEntity->addComponent(lightTransform); + 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 camera controls - Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity); - camController->setCamera(cameraEntity); + for (int i = 0; i < tabIndex; i++) { + ui->tabWidget->removeTab(i); + } + }); - // Set root object of the scene - view->setRootEntity(rootEntity); + QAction *closeRightAction = new QAction("Close All to the Right"); + closeMultipleAction->addAction(closeRightAction); + connect(closeRightAction, &QAction::triggered, this, [this, &tabIndex](bool checked) { + Q_UNUSED(checked); - // Load custom 3D model - Qt3DRender::QMesh *customMesh = new Qt3DRender::QMesh(); - customMesh->setSource(QUrl::fromLocalFile(":/obj/data/obj/defaultactor_LOD0.obj")); + for (int i = tabIndex + 1; i < ui->tabWidget->count(); i++) { + ui->tabWidget->removeTab(i); + } + }); - // Adjust the model transformation - Qt3DCore::QTransform *customTransform = new Qt3DCore::QTransform(); - customTransform->setRotationX(-90); - customTransform->setRotationY(-90); + contextMenu->addMenu(closeMultipleAction); - // Keep translation if necessary - customTransform->setTranslation(QVector3D(0.0f, -100.0f, -200.0f)); + QPoint pt(pos); + contextMenu->exec(ui->tabWidget->mapToGlobal(pt)); - Qt3DExtras::QNormalDiffuseMapMaterial *customMaterial = new Qt3DExtras::QNormalDiffuseMapMaterial(); + delete contextMenu; + }); - Qt3DRender::QTextureLoader *normalMap = new Qt3DRender::QTextureLoader(); - normalMap->setSource(QUrl::fromLocalFile(":/obj/data/obj/normalmap.png")); - customMaterial->setNormal(normalMap); + connect(ui->tabWidget, &QTabWidget::tabCloseRequested, this, [this](int index) { + ui->tabWidget->removeTab(index); + }); - Qt3DRender::QTextureLoader *diffuseMap = new Qt3DRender::QTextureLoader(); - diffuseMap->setSource(QUrl::fromLocalFile(":/obj/data/obj/diffusemap.png")); - customMaterial->setDiffuse(diffuseMap); + connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr rawFile) { + QPlainTextEdit *scriptEditor = new QPlainTextEdit(this); + scriptEditor->setAcceptDrops(false); - Qt3DCore::QEntity *m_torusEntity = new Qt3DCore::QEntity(rootEntity); - m_torusEntity->addComponent(customMesh); - m_torusEntity->addComponent(customMaterial); - m_torusEntity->addComponent(customTransform); + if (rawFile->contents.isEmpty()) { + scriptEditor->setPlainText("EMPTY"); + } else { + scriptEditor->setPlainText(rawFile->contents); + } - LoadFile_D3DBSP(":/d3dbsp/data/d3dbsp/barebones.d3dbsp"); + QString fileStem = rawFile->path.split('/').last(); + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (ui->tabWidget->tabText(i) == fileStem) { + return; + } + } + + ui->tabWidget->addTab(scriptEditor, 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) { + ImageWidget *mImageWidget = new ImageWidget(this); + mImageWidget->setAcceptDrops(false); + mImageWidget->SetImage(image); + + 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, [this](std::shared_ptr menu) { + Q_UNUSED(menu); + }); + + connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](std::shared_ptr ddsFile) { + DDSViewer *ddsViewer = new DDSViewer(this); + ddsViewer->setAcceptDrops(false); + ddsViewer->SetDDSFile(ddsFile); + + QString fileStem = ddsFile->fileStem + ".dds"; + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (ui->tabWidget->tabText(i) == fileStem) { + return; + } + } + + ui->tabWidget->addTab(ddsViewer, fileStem); + ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_DDSFile.png")); + ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); + }); + + connect(mTreeWidget, &XTreeWidget::IWIFileSelected, this, [this](std::shared_ptr iwiFile) { + IWIViewer *iwiViewer = new IWIViewer(this); + iwiViewer->setAcceptDrops(false); + iwiViewer->SetIWIFile(iwiFile); + + QString fileStem = iwiFile->fileStem + ".iwi"; + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (ui->tabWidget->tabText(i) == fileStem) { + return; + } + } + + ui->tabWidget->addTab(iwiViewer, fileStem); + ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_IWIFile.png")); + ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); + }); + + connect(mTreeWidget, &XTreeWidget::FastFileSelected, this, [this](std::shared_ptr aFastFile) { + FastFileViewer *fastFileViewer = new FastFileViewer(this); + fastFileViewer->setAcceptDrops(false); + fastFileViewer->SetFastFile(aFastFile); + + QString fileStem = aFastFile->GetFileStem(); + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (ui->tabWidget->tabText(i) == fileStem) { + return; + } + } + + ui->tabWidget->addTab(fastFileViewer, fileStem); + ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_FastFile.png")); + ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); + }); + + connect(mTreeWidget, &XTreeWidget::ZoneFileSelected, this, [this](std::shared_ptr aZoneFile) { + ZoneFileViewer *zoneFileViewer = new ZoneFileViewer(this); + zoneFileViewer->setAcceptDrops(false); + zoneFileViewer->SetZoneFile(aZoneFile); + + QString fileStem = aZoneFile->GetFileStem(); + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (ui->tabWidget->tabText(i) == fileStem) { + return; + } + } + + ui->tabWidget->addTab(zoneFileViewer, fileStem); + ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_ZoneFile.png")); + ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); + }); + + connect(mTreeWidget, &XTreeWidget::LocalStringSelected, this, [this](std::shared_ptr aZoneFile) { + LocalStringViewer *localStrViewer = new LocalStringViewer(this); + localStrViewer->setAcceptDrops(false); + localStrViewer->SetZoneFile(aZoneFile); + + QString fileStem = aZoneFile->GetFileStem() + ".str"; + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (ui->tabWidget->tabText(i) == fileStem) { + return; + } + } + + ui->tabWidget->addTab(localStrViewer, fileStem); + ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_String.png")); + ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); + }); + + connect(mTreeWidget, &XTreeWidget::TechSetSelected, this, [this](std::shared_ptr aTechSet) { + + TechSetViewer *techSetViewer = new TechSetViewer(this); + techSetViewer->setAcceptDrops(false); + techSetViewer->SetTechSet(aTechSet); + + QString fileStem = aTechSet->name; + for (int i = 0; i < ui->tabWidget->count(); i++) { + if (ui->tabWidget->tabText(i) == fileStem) { + return; + } + } + + ui->tabWidget->addTab(techSetViewer, aTechSet->name); + ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, QIcon(":/icons/icons/Icon_TechSetFile.png")); + ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1); + }); + + // Connect Help > About dialog + connect(ui->actionAbout, &QAction::triggered, this, [this](bool checked) { + Q_UNUSED(checked); + + AboutDialog *aboutDialog = new AboutDialog(this); + aboutDialog->exec(); + + delete aboutDialog; + }); + + connect(ui->actionOpen_Fast_File, &QAction::triggered, this, + [this](bool checked) { + Q_UNUSED(checked); + OpenFastFile(); + }); + connect(ui->actionOpen_Zone_File, &QAction::triggered, this, + [this](bool checked) { + Q_UNUSED(checked); + OpenZoneFile(); + }); + + QDockWidget *treeDockWidget = new QDockWidget(this); + treeDockWidget->setWidget(mTreeWidget); + addDockWidget(Qt::LeftDockWidgetArea, treeDockWidget); + + ui->toolBar->addAction(ui->actionNew_Fast_File); + ui->toolBar->addAction(ui->actionNew_Zone_File); + ui->toolBar->addAction(ui->actionOpen_Fast_File); + ui->toolBar->addAction(ui->actionOpen_Zone_File); + ui->toolBar->addAction(ui->actionOpen_Folder); + ui->toolBar->addAction(ui->actionSave); + ui->toolBar->addSeparator(); + ui->toolBar->addAction(ui->actionCut); + ui->toolBar->addAction(ui->actionCopy); + ui->toolBar->addAction(ui->actionPaste); + ui->toolBar->addSeparator(); + + ui->toolBar->addSeparator(); + + ui->toolBar->addSeparator(); + ui->toolBar->addAction(ui->actionFind_2); Reset(); } -MainWindow::~MainWindow() { - delete ui; -} +MainWindow::~MainWindow() { delete ui; } void MainWindow::Reset() { - // Reset tabwidget to 'General' tab - ui->tabWidget->setCurrentIndex(0); - - // Reset 'General' tab fields - ui->lineEdit_FastFile->clear(); - ui->comboBox_Company->setCurrentIndex(0); - ui->comboBox_FileType->setCurrentIndex(0); - ui->checkBox_Signed->setChecked(false); - ui->lineEdit_Magic->clear(); - ui->spinBox_Magic->clear(); - ui->spinBox_TagCount->clear(); - ui->spinBox_FileSize->clear(); - ui->spinBox_RecordCount->clear(); - - // Reset 'Unknowns' tab fields - ui->lineEdit_U1->clear(); - ui->spinBox_U1->clear(); - ui->lineEdit_U2->clear(); - ui->spinBox_U2->clear(); - ui->lineEdit_U3->clear(); - ui->spinBox_U3->clear(); - ui->lineEdit_U4->clear(); - ui->spinBox_U4->clear(); - ui->lineEdit_U5->clear(); - ui->spinBox_U5->clear(); - ui->lineEdit_U6->clear(); - ui->spinBox_U6->clear(); - ui->lineEdit_U7->clear(); - ui->spinBox_U7->clear(); - ui->lineEdit_U8->clear(); - ui->spinBox_U8->clear(); - ui->lineEdit_U9->clear(); - ui->spinBox_U9->clear(); - ui->lineEdit_U10->clear(); - ui->spinBox_U10->clear(); - ui->lineEdit_U11->clear(); - ui->spinBox_U11->clear(); - - // Reset 'Tags' tab fields - ui->listWidget_Tags->clear(); - - // Reset 'Localized Strings' tab fields - ui->listWidget_LocalString->clear(); - - // Reset 'Asset Index/Order' tab fields - ui->tableWidget_Index->clear(); - ui->tableWidget_Order->clear(); - - // Reset 'Raw Files' tab fields - ui->treeWidget_Scripts->clear(); - ui->plainTextEdit_Scripts->clear(); - - // Reset 'Tech Sets' tab fields - ui->listWidget_TechSets->clear(); - - // Reset 'Zone Dump' tab fields - ui->spinBox_DumpIndex->clear(); - ui->comboBox_DumpAsset->setCurrentIndex(0); - ui->plainTextEdit_ZoneDump->clear(); - - // Reset 'String Tables' tab fields - ui->comboBox_StringTable->setCurrentIndex(0); - ui->tableWidget_StringTable->clear(); - - // Reset '3D Scene' tab fields - ui->treeWidget_Models->clear(); + // Clear data tree + // mTreeWidget->clear(); // Reset class vars mTypeMap.clear(); @@ -195,62 +311,22 @@ void MainWindow::Reset() { mStrTableMap.clear(); } -void MainWindow::StrTableSelected(QString aStrTableName) { - ui->tableWidget_StringTable->clear(); +/* + OpenFastFile() - ui->tableWidget_StringTable->setColumnCount(2); - int entryIndex = 0; - for (auto strTableEntry : mStrTableMap[aStrTableName]) { - ui->tableWidget_StringTable->insertRow(ui->tableWidget_StringTable->rowCount() + 1); - ui->tableWidget_StringTable->setItem(entryIndex, 0, new QTableWidgetItem(strTableEntry.first)); - ui->tableWidget_StringTable->setItem(entryIndex, 1, new QTableWidgetItem(Utils::AssetTypeToString(strTableEntry.second))); - - entryIndex++; + Opens a file dialog in the steam folder, + and opens the selected file. +*/ +bool MainWindow::OpenFastFile(const QString aFastFilePath) { + FastFile fastFile; + if (!fastFile.Load(aFastFilePath)) { + qDebug() << "Error: Failed to load fast file!"; + return false; } -} + mTreeWidget->AddFastFile(std::make_shared(fastFile)); -void MainWindow::ScriptSelected() { - QTreeWidgetItem *selectedItem = ui->treeWidget_Scripts->selectedItems()[0]; - if (!selectedItem) { - qDebug() << "Attempted to load invalid tree item!"; - return; - } - - const QString itemName = selectedItem->text(0); - const QStringList scriptExts = {"gsc", "csc", "atr", "shock", "vision", "rmb"}; - if (!scriptExts.contains(itemName.split('.').last())) { - qDebug() << QString("Attempted to parse invalid raw file: %1!").arg(itemName); - return; - } - - ui->plainTextEdit_Scripts->clear(); - for (auto [scriptName, scriptContents] : mRawFileMap.asKeyValueRange()) { - if (scriptName.contains(itemName)) { - ui->plainTextEdit_Scripts->setPlainText(scriptContents); - return; - } - } -} - -QByteArray MainWindow::DecompressZLIB(QByteArray compressedData) { - QByteArray decompressedData; - uLongf decompressedSize = compressedData.size() * 4; - decompressedData.resize(static_cast(decompressedSize)); - - Bytef *destination = reinterpret_cast(decompressedData.data()); - uLongf *destLen = &decompressedSize; - const Bytef *source = reinterpret_cast(compressedData.data()); - uLong sourceLen = compressedData.size(); - - int result = uncompress(destination, destLen, source, sourceLen); - - if (result == Z_OK) { - decompressedData.resize(static_cast(decompressedSize)); - } else { - decompressedData.clear(); - qDebug() << QString("In DecompressZLIB: %1").arg(Utils::ZLibErrorToString(result)).toLatin1(); - } - return decompressedData; + // Open zone file after decompressing ff and writing + return false; } /* @@ -259,29 +335,13 @@ QByteArray MainWindow::DecompressZLIB(QByteArray compressedData) { Opens a file dialog in the steam folder, and opens the selected file. */ -QFile* MainWindow::OpenFastFile() { - // Reset dialog before opening new file - Reset(); - - // Open file dialog to steam apps - const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; - const QString fastFilePath = QFileDialog::getOpenFileName(this, "Open FastFile", steamPath, "FastFile (*.ff);;All Files (*.*)"); - if (!QFile::exists(fastFilePath)) { - QMessageBox::warning(this, "Warning!", QString("%1 does not exist!.").arg(fastFilePath)); - return nullptr; +bool MainWindow::OpenFastFile() { + const QString fastFileName = Utils::GetOpenFastFileName(); + if (!OpenFastFile(fastFileName)) { + qDebug() << "Failed to open Fast file!"; + return false; } - ui->lineEdit_FastFile->setText(fastFilePath); - - const QString fastFileStem = fastFilePath.split('/').last(); - setWindowTitle(QString("FastFile Wizard - %1").arg(fastFileStem)); - - // Check fastfile can be read - QFile *fastFile = new QFile(fastFilePath); - if (!fastFile->open(QIODevice::ReadOnly)) { - QMessageBox::warning(this, "Warning!", QString("%1 could not be read!.").arg(fastFilePath)); - return nullptr; - } - return fastFile; + return true; } /* @@ -290,884 +350,26 @@ QFile* MainWindow::OpenFastFile() { Opens a file dialog in the steam folder, and opens the selected file. */ -QFile* MainWindow::OpenZoneFile() { - // Reset dialog before opening new file - Reset(); +bool MainWindow::OpenZoneFile(const QString aZoneFilePath, bool fromFF) { + Q_UNUSED(fromFF); - // Open file dialog to steam apps - const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; - const QString zoneFilePath = QFileDialog::getOpenFileName(this, "Open ZoneFile", steamPath, "ZoneFile (*.zone);;All Files (*.*)"); - if (!QFile::exists(zoneFilePath)) { - QMessageBox::warning(this, "Warning!", QString("%1 does not exist!.").arg(zoneFilePath)); - return nullptr; + ZoneFile zoneFile; + if (!zoneFile.Load(aZoneFilePath)) { + qDebug() << "Error: Failed to load zone file!"; + return false; } - ui->lineEdit_ZoneFile->setText(zoneFilePath); + mTreeWidget->AddZoneFile(std::make_shared(zoneFile)); - const QString zoneFileStem = zoneFilePath.split('/').last(); - setWindowTitle(QString("FastFile Wizard - %1").arg(zoneFileStem)); + return true; +} - // Check fastfile can be read - QFile *zoneFile = new QFile(zoneFilePath); - if (!zoneFile->open(QIODevice::ReadOnly)) { - QMessageBox::warning(this, "Warning!", QString("%1 could not be read!.").arg(zoneFilePath)); - return nullptr; +bool MainWindow::OpenZoneFile() { + const QString zoneFileName = Utils::GetOpenZoneFileName(); + if (!OpenZoneFile(zoneFileName)) { + qDebug() << "Failed to open Zone file!"; + return false; } - return zoneFile; -} - -void MainWindow::ParseFFCompany(QDataStream *afastFileStream) { - // Check for null datastream ptr - if (!afastFileStream) { return; } - // Parse company - QByteArray companyData(2, Qt::Uninitialized); - afastFileStream->readRawData(companyData.data(), 2); - if (companyData == "IW") { - qDebug() << "Company found: 'INFINITY_WARD'"; - ui->comboBox_Company->setCurrentIndex(1); - } else if (companyData == "TA") { - qDebug() << "Company found: 'TREYARCH'"; - ui->comboBox_Company->setCurrentIndex(2); - } else if (companyData == "Sl") { - qDebug() << "Company found: 'SLEDGEHAMMER'"; - ui->comboBox_Company->setCurrentIndex(3); - } else if (companyData == "NX") { - qDebug() << "Company found: 'NEVERSOFT'"; - ui->comboBox_Company->setCurrentIndex(4); - } else { - qDebug() << QString("Failed to find company, found '%1'!").arg(companyData); - return; - } -} - -void MainWindow::ParseFFFileType(QDataStream *afastFileStream) { - // Parse filetype - QByteArray fileTypeData(2, Qt::Uninitialized); - afastFileStream->readRawData(fileTypeData.data(), 2); - if (fileTypeData == "ff") { - qDebug() << "File type found: 'FAST_FILE'"; - ui->comboBox_FileType->setCurrentIndex(1); - } else { - qDebug() << "Failed to find file type!"; - return; - } -} - -void MainWindow::ParseFFSignage(QDataStream *afastFileStream) { - // Parse filetype - QByteArray signedData(1, Qt::Uninitialized); - afastFileStream->readRawData(signedData.data(), 1); - if (signedData == "u") { - qDebug() << "Found valid signage: Unsigned"; - ui->checkBox_Signed->setChecked(false); - } else if (signedData == "0") { - qDebug() << "Found valid signage: Signed"; - ui->checkBox_Signed->setChecked(true); - } else { - qDebug() << "Failed to determine signage of fastfile!"; - return; - } -} - -void MainWindow::ParseFFMagic(QDataStream *afastFileStream) { - // Parse magic - QByteArray magicData(3, Qt::Uninitialized); - afastFileStream->readRawData(magicData.data(), 3); - if (magicData == "100") { - qDebug() << QString("Found valid magic: '%1'").arg(magicData); - ui->lineEdit_Magic->setText(magicData.toHex()); - ui->spinBox_Magic->setValue(magicData.toInt()); - } else { - qDebug() << "Magic invalid!"; - return; - } -} - -void MainWindow::ParseFFVersion(QDataStream *afastFileStream) { - // Parse version - quint32 version; - *afastFileStream >> version; - qDebug() << "Version:" << version; - if (version == 387) { - qDebug() << QString("Found valid version: '%1'").arg(version); - ui->spinBox_Version->setValue(version); - } else { - qDebug() << "Version invalid!"; - return; - } -} - -void MainWindow::ParseFFHeader(QFile *aFastFilePtr) { - // Open stream to fastfile - QDataStream afastFileStream(aFastFilePtr); - afastFileStream.setByteOrder(QDataStream::LittleEndian); - - ParseFFCompany(&afastFileStream); - ParseFFFileType(&afastFileStream); - ParseFFSignage(&afastFileStream); - ParseFFMagic(&afastFileStream); - ParseFFVersion(&afastFileStream); -} - -void MainWindow::ParseZoneHeader(QDataStream *aZoneFileStream) { - ParseZoneSize(aZoneFileStream); - ParseZoneUnknownsA(aZoneFileStream); - - ParseZoneTagCount(aZoneFileStream); - ParseZoneUnknownsB(aZoneFileStream); - - ParseZoneRecordCount(aZoneFileStream); - - if (mTagCount) { - ParseZoneUnknownsC(aZoneFileStream); - ParseZoneTags(aZoneFileStream); - } else { - aZoneFileStream->skipRawData(4); - } -} - -void MainWindow::ParseZoneSize(QDataStream *aZoneFileStream) { - // Byte 0-3: (unsigned int?) correlates to the fastfile's - // size after decompression minus 36 bytes (24h) - quint32 zoneFileSize; - *aZoneFileStream >> zoneFileSize; - if (zoneFileSize <= 0) { - qDebug() << "Tried to open empty zone file!"; - exit(-1); - } - zoneFileSize += 36; - ui->spinBox_FileSize->setValue(zoneFileSize); - - qDebug() << QString("Zone file size: '%1'").arg(zoneFileSize); -} - -/* - ParseZoneUnknownsA() - - Parses the 1st section of unknowns as hex vals and uint32s -*/ -void MainWindow::ParseZoneUnknownsA(QDataStream *aZoneFileStream) { - // Byte 4-7, 8-11, 12-15: unknown - QByteArray unknown1(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown1.data(), 4); - ui->lineEdit_U1->setText(unknown1.toHex()); - ui->spinBox_U1->setValue(unknown1.toUInt()); - - QByteArray unknown2(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown2.data(), 4); - ui->lineEdit_U2->setText(unknown2.toHex()); - ui->spinBox_U2->setValue(unknown2.toUInt()); - - QByteArray unknown3(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown3.data(), 4); - ui->lineEdit_U3->setText(unknown3.toHex()); - ui->spinBox_U3->setValue(unknown3.toUInt()); - - // Byte 16-19, 20-23: empty/unknown - QByteArray unknown4(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown4.data(), 4); - ui->lineEdit_U4->setText(unknown4.toHex()); - ui->spinBox_U4->setValue(unknown4.toUInt()); - - QByteArray unknown5(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown5.data(), 4); - ui->lineEdit_U5->setText(unknown5.toHex()); - ui->spinBox_U5->setValue(unknown5.toUInt()); - - // Byte 24-27: somehow related to the filesize, but smaller value - QByteArray unknown6(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown6.data(), 4); - ui->lineEdit_U6->setText(unknown6.toHex()); - ui->spinBox_U6->setValue(unknown6.toUInt()); - - // Byte 28-31, 32-35: unknown - QByteArray unknown7(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown7.data(), 4); - ui->lineEdit_U7->setText(unknown7.toHex()); - ui->spinBox_U7->setValue(unknown7.toUInt()); - - QByteArray unknown8(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown8.data(), 4); - ui->lineEdit_U8->setText(unknown8.toHex()); - ui->spinBox_U8->setValue(unknown8.toUInt()); - - qDebug() << QString("Unknowns A: '%1''%2''%3''%4''%5''%6''%7''%8'") - .arg(unknown1.toHex()) - .arg(unknown2.toHex()) - .arg(unknown3.toHex()) - .arg(unknown4.toHex()) - .arg(unknown5.toHex()) - .arg(unknown6.toHex()) - .arg(unknown7.toHex()) - .arg(unknown8.toHex()); -} - -/* - ParseZoneTagCount() - - Parses the number of string tags in the zone index -*/ -void MainWindow::ParseZoneTagCount(QDataStream *aZoneFileStream) { - // Byte 36-39: might indicate where the index record starts, - // calculation unknown - *aZoneFileStream >> mTagCount; - ui->spinBox_TagCount->setValue(mTagCount); - qDebug() << QString("Tag count: '%1'").arg(mTagCount); -} - -/* - ParseZoneRecordCount() - - Parses the number of records in the zone index -*/ -void MainWindow::ParseZoneRecordCount(QDataStream *aZoneFileStream) { - // Byte 44-47: (unsigned int) number of records - *aZoneFileStream >> mRecordCount; - ui->spinBox_RecordCount->setValue(mRecordCount); - qDebug() << QString("Record count: '%1'").arg(mRecordCount); -} - -/* - ParseZoneUnknownsB() - - Parses the 2nd section of unknowns as hex vals and uint32s -*/ -void MainWindow::ParseZoneUnknownsB(QDataStream *aZoneFileStream) { - // Byte 44-47: Unknown/empty? - QByteArray unknown9(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown9.data(), 4); - ui->lineEdit_U9->setText(unknown9.toHex()); - ui->spinBox_U9->setValue(unknown9.toUInt()); - - qDebug() << QString("Unknowns B: \n\t'%1'") - .arg(unknown9.toHex()); -} - -/* - ParseZoneUnknownsC() - - Parses the 3rd section of unknowns as hex vals and uint32s -*/ -void MainWindow::ParseZoneUnknownsC(QDataStream *aZoneFileStream) { - // Byte 40-43: Unknown/empty? - QByteArray unknown10(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown10.data(), 4); - ui->lineEdit_U10->setText(unknown10.toHex()); - ui->spinBox_U10->setValue(unknown10.toUInt()); - - // Byte 44-47: Unknown/empty? - QByteArray unknown11(4, Qt::Uninitialized); - aZoneFileStream->readRawData(unknown11.data(), 4); - ui->lineEdit_U11->setText(unknown11.toHex()); - ui->spinBox_U11->setValue(unknown11.toUInt()); - - qDebug() << QString("Unknowns C: \n\t'%1'\n\t'%2'") - .arg(unknown10.toHex()) - .arg(unknown11.toHex()); -} - -/* - ParseZoneTags() - - Parses the string tags ate the start of zone file -*/ -void MainWindow::ParseZoneTags(QDataStream *aZoneFileStream) { - // Byte 48-51: Repeated separators? ÿÿÿÿ x i - aZoneFileStream->skipRawData(4 * (mTagCount - 1)); - - // Parse tags/strings before index - QString zoneTag; - char zoneTagChar; - for (quint32 i = 0; i < mTagCount - 1; i++) { - *aZoneFileStream >> zoneTagChar; - while (zoneTagChar != 0) { - zoneTag += zoneTagChar; - *aZoneFileStream >> zoneTagChar; - } - ui->listWidget_Tags->addItem(zoneTag); - // qDebug() << "Tag: " << zoneTag; - zoneTag.clear(); - } -} - -/* - ParseZoneIndex() - - Parse the binary zone index data and populate table -*/ -void MainWindow::ParseZoneIndex(QDataStream *aZoneFileStream) { - // Don't parse if no records - if (!mRecordCount) { return; } - - // Track past assets and counts - int consecutiveIndex = 0; - int consecutiveCount = 0; - QString lastAssetType = ""; - - // Parse index & map found asset types - for (quint32 i = 0; i < mRecordCount; i++) { - // Skip record start - QByteArray rawAssetType(4, Qt::Uninitialized); - aZoneFileStream->readRawData(rawAssetType.data(), 4); - if (!mTypeMap.contains(rawAssetType.toHex())) { - mTypeMap[rawAssetType.toHex()] = 0; - } - mTypeMap[rawAssetType.toHex()]++; - mTypeOrder << rawAssetType.toHex(); - - // Skip separator - aZoneFileStream->skipRawData(4); - - // Get asset description from type - const QString assetType = rawAssetType.toHex(); - - // Set lastAsset as current if first run - if (lastAssetType.isEmpty()) { - lastAssetType = assetType; - } - - // Track counts or populate asset order table - if (lastAssetType == assetType) { - // Count consecutive assets - consecutiveCount++; - } else { - // Insert row and populate for the previous asset type - ui->tableWidget_Order->insertRow(consecutiveIndex); - ui->tableWidget_Order->setItem(consecutiveIndex, 0, new QTableWidgetItem(lastAssetType)); - ui->tableWidget_Order->setItem(consecutiveIndex, 1, new QTableWidgetItem(Utils::AssetTypeToString(lastAssetType))); - ui->tableWidget_Order->setItem(consecutiveIndex, 2, new QTableWidgetItem(QString::number(consecutiveCount))); - - // Update counts and asset type - consecutiveCount = 1; - consecutiveIndex++; - lastAssetType = assetType; - } - } -} - -void MainWindow::ParseAsset_LocalString(QDataStream *aZoneFileStream) { - // Skip separator - aZoneFileStream->skipRawData(8); - - // Parse local string asset contents - QString localStr; - char localStrChar; - *aZoneFileStream >> localStrChar; - while (localStrChar != 0) { - localStr += localStrChar; - *aZoneFileStream >> localStrChar; - } - - // Parse rawfile name - QString aliasName; - char aliasNameChar; - *aZoneFileStream >> aliasNameChar; - while (aliasNameChar != 0) { - aliasName += aliasNameChar; - *aZoneFileStream >> aliasNameChar; - } - // qDebug() << QString("%1 = %2").arg(aliasName).arg(localStr); - ui->listWidget_LocalString->addItem(QString("%1 = %2").arg(aliasName).arg(localStr)); -} - -void MainWindow::ParseAsset_RawFile(QDataStream *aZoneFileStream) { - // Skip start separator FF FF FF FF (pointer?) - aZoneFileStream->skipRawData(4); - - quint32 gscLength; - *aZoneFileStream >> gscLength; - - // Skip unknown 4 byte data - aZoneFileStream->skipRawData(4); - - // Parse rawfile path - QString rawFilePath; - char scriptPathChar; - *aZoneFileStream >> scriptPathChar; - while (scriptPathChar != 0) { - rawFilePath += scriptPathChar; - *aZoneFileStream >> scriptPathChar; - } - rawFilePath.replace(",", ""); - const QStringList pathParts = rawFilePath.split('/'); - if (pathParts.size() == 0) { - qDebug() << "Failed to parse ff path! " << rawFilePath; - exit(-1); - } else if (pathParts.size() == 1) { - const QString path = pathParts[0]; - QTreeWidgetItem *newRootItem = new QTreeWidgetItem(ui->treeWidget_Scripts); - newRootItem->setText(0, path); - } else { - const QString path = pathParts[0]; - QTreeWidgetItem *newRootItem; - if (mTreeMap.contains(path)) { - newRootItem = mTreeMap[path]; - } else { - newRootItem = new QTreeWidgetItem(ui->treeWidget_Scripts); - newRootItem->setText(0, path); - mTreeMap[path] = newRootItem; - } - - QTreeWidgetItem *parentItem = newRootItem; - for (int i = 1; i < pathParts.size(); i++) { - const QString path = pathParts[i]; - QTreeWidgetItem *newChildItem; - if (mTreeMap.contains(path)) { - newChildItem = mTreeMap[path]; - } else { - newChildItem = new QTreeWidgetItem(); - newChildItem->setText(0, path); - mTreeMap[path] = newChildItem; - } - parentItem->addChild(newChildItem); - parentItem = newChildItem; - } - } - - // Parse gsc contents - QString rawFileContents; - char rawFileContentsChar; - *aZoneFileStream >> rawFileContentsChar; - while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { - rawFileContents += rawFileContentsChar; - *aZoneFileStream >> rawFileContentsChar; - } - mRawFileMap[rawFilePath] = (rawFileContents.isEmpty()) ? ("EMPTY") : (rawFileContents); - // qDebug() << QString("%1: %2").arg(rawFilePath).arg(rawFileContents); -} - -void MainWindow::ParseAsset_PhysPreset(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_XModel(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_Material(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_PixelShader(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_TechSet(QDataStream *aZoneFileStream) { - aZoneFileStream->skipRawData(4); - // Parse techset name - QString techSetName; - char techSetNameChar; - *aZoneFileStream >> techSetNameChar; - while (techSetNameChar == 0) { - *aZoneFileStream >> techSetNameChar; - } - while (techSetNameChar != 0) { - techSetName += techSetNameChar; - *aZoneFileStream >> techSetNameChar; - } - techSetName.replace(",", ""); - ui->listWidget_TechSets->addItem(techSetName); - //qDebug() << "Tech Set: " << techSetName; -} - -void MainWindow::ParseAsset_Image(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_LoadedSound(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_ColMapMP(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_GameMapSP(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_GameMapMP(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_LightDef(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_UIMap(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_AIType(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_FX(QDataStream *aZoneFileStream) { - -} - -void MainWindow::ParseAsset_XAnim(QDataStream *aZoneFileStream) { - // Read in pointer to x_anim name - QByteArray namePtr(4, Qt::Uninitialized); - aZoneFileStream->readRawData(namePtr.data(), 4); - - // Read in counts - quint16 dataByteCount, dataShortCount, - dataIntCount, randomDataByteCount, - randomDataIntCount, numframes; - *aZoneFileStream >> dataByteCount >> dataShortCount >> - dataIntCount >> randomDataByteCount >> - randomDataIntCount >> numframes; - - // Read bool flags - bool isLooped, isDelta; - *aZoneFileStream >> isLooped >> isDelta; - - // Read in more counts - quint8 noneRotatedBoneCount, - twoDRotatedBoneCount, normalRotatedBoneCount, - twoDStaticRotatedBoneCount, normalStaticRotatedBoneCount, - normalTranslatedBoneCount, preciseTranslatedBoneCount, - staticTranslatedBoneCount, noneTranslatedBoneCount, - totalBoneCount, otherBoneCount1, otherBoneCount2; - *aZoneFileStream >> noneRotatedBoneCount >> - twoDRotatedBoneCount >> normalRotatedBoneCount >> - twoDStaticRotatedBoneCount >> normalStaticRotatedBoneCount >> - normalTranslatedBoneCount >> preciseTranslatedBoneCount >> - staticTranslatedBoneCount >> noneTranslatedBoneCount >> - totalBoneCount >> otherBoneCount1 >> otherBoneCount2; - - // Yet more counts - quint8 notifyCount, assetType; - *aZoneFileStream >> notifyCount >> assetType; - - // Read more bool flags - bool pad; - *aZoneFileStream >> pad; - - // Yet more more counts - unsigned int randomDataShortCount, indexCount; - *aZoneFileStream >> randomDataShortCount >> indexCount; - - // Read in floats - float frameRate, frequency; - *aZoneFileStream >> frameRate >> frequency; - - // Read in pointers - quint32 boneIDsPtr, dataBytePtr, dataShortPtr, dataIntPtr, - randomDataShortPtr, randomDataBytePtr, randomDataIntPtr, - longIndiciesPtr, notificationsPtr, deltaPartsPtr; - *aZoneFileStream >> boneIDsPtr >> dataBytePtr >> dataShortPtr - >> dataIntPtr >> randomDataShortPtr >> randomDataBytePtr - >> randomDataIntPtr >> longIndiciesPtr >> notificationsPtr - >> deltaPartsPtr; - - // Read in x_anim file name - QString xAnimName; - char xAnimNameChar; - *aZoneFileStream >> xAnimNameChar; - while (xAnimNameChar != 0) { - xAnimName += xAnimNameChar; - *aZoneFileStream >> xAnimNameChar; - } - - // Parse x_anim index header - QVector sectionLengths; - for (int i = 0; i < numframes; i++) { - quint8 sectionlength; - *aZoneFileStream >> sectionlength; - sectionLengths.push_back(sectionlength); - // Skip padding - aZoneFileStream->skipRawData(1); - } - // Skip unknown section - aZoneFileStream->skipRawData(2 * 8); -} - -void MainWindow::ParseAsset_MenuFile(QDataStream *aZoneFileStream) { - //MENU_FILE -} - -void MainWindow::ParseAsset_Weapon(QDataStream *aZoneFileStream) { - //WEAPON_FILE -} - -void MainWindow::ParseAsset_D3DBSP(QDataStream *aZoneFileStream) { - //D3DBSP_DUMP -} - -void MainWindow::ParseAsset_StringTable(QDataStream *aZoneFileStream) { - aZoneFileStream->skipRawData(4); - - quint32 columnCount, rowCount; - *aZoneFileStream >> columnCount >> rowCount; - columnCount = 0; - rowCount = 0; - - aZoneFileStream->skipRawData(4); - - QString stringTableName; - char stringTableNameChar; - *aZoneFileStream >> stringTableNameChar; - while (stringTableNameChar != 0) { - stringTableName += stringTableNameChar; - *aZoneFileStream >> stringTableNameChar; - } - ui->comboBox_StringTable->addItem(stringTableName); - - QVector tablePointers = QVector(); - for (quint32 i = 0; i < rowCount; i++) { - QByteArray pointerData(4, Qt::Uninitialized); - aZoneFileStream->readRawData(pointerData.data(), 4); - tablePointers.push_back(pointerData.toHex()); - - aZoneFileStream->skipRawData(4); - } - - for (const QString &pointerAddr : tablePointers) { - QString leadingContent = ""; - if (pointerAddr == "FFFFFFFF") { - char leadingContentChar; - *aZoneFileStream >> leadingContentChar; - while (leadingContentChar != 0) { - leadingContent += leadingContentChar; - *aZoneFileStream >> leadingContentChar; - } - } else { - leadingContent = pointerAddr; - } - - QString content; - char contentChar; - *aZoneFileStream >> contentChar; - while (contentChar != 0) { - content += contentChar; - *aZoneFileStream >> contentChar; - } - QPair tableEntry = QPair(); - tableEntry.first = leadingContent; - tableEntry.second = content; - if (!mStrTableMap.contains(stringTableName)) { - mStrTableMap[stringTableName] = QVector>(); - } - mStrTableMap[stringTableName].push_back(tableEntry); - } -} - -void MainWindow::on_pushButton_FastFile_clicked() { - // Try to prompt user to open fastfile - QFile *fastFile; - if (!(fastFile = OpenFastFile())) { - QMessageBox::warning(this, "Warning!", QString("Failed to open FastFile!.")); - return; - } - - // Parse data from fast file header - ParseFFHeader(fastFile); - - // Decompress fastfile and close - const QByteArray fastFileData = fastFile->readAll(); - const QByteArray decompressedData = DecompressZLIB(fastFileData); - // ui->plainTextEdit_ZoneDump->setPlainText(decompressedData.toHex()); - - const QString zoneFilePath = fastFile->fileName().replace(".ff", ".zone"); - fastFile->close(); - - // Check zone file is writeable - QFile *zoneFile = new QFile(zoneFilePath); - if (!zoneFile->open(QIODevice::ReadWrite)) { - qDebug() << QString("Zone file could not be written to: '%1'").arg(zoneFilePath); - return; - } - // Write zone data - zoneFile->write(decompressedData); - zoneFile->close(); - - // Open zone file as little endian stream - QDataStream zoneFileStream(decompressedData); - zoneFileStream.setByteOrder(QDataStream::LittleEndian); - - // Parse data from zone file header - ParseZoneHeader(&zoneFileStream); - ParseZoneIndex(&zoneFileStream); - - // Track current and consecutive assets - int assetIndex = 0; - - // Iterate asset types found in index - for (auto [assetType, assetCount] : mTypeMap.asKeyValueRange()) { - // Get asset description from type - QString assetStr = Utils::AssetTypeToString(assetType); - - // Insert row and populate - ui->tableWidget_Index->insertRow(assetIndex); - ui->tableWidget_Index->setItem(assetIndex, 0, new QTableWidgetItem(assetType)); - ui->tableWidget_Index->setItem(assetIndex, 1, new QTableWidgetItem(assetStr)); - ui->tableWidget_Index->setItem(assetIndex, 2, new QTableWidgetItem(QString::number(assetCount))); - - // Update count - assetIndex++; - } - - for (int i = 0; i < mTypeOrder.size(); i++) { - const QString typeHex = mTypeOrder[i]; - const QString typeStr = Utils::AssetTypeToString(typeHex); - - // qDebug() << "Parsing Asset of Type: " << typeHex; - if (typeStr == "LOCAL STRING") { // localized string asset - ParseAsset_LocalString(&zoneFileStream); - } else if (typeStr == "RAW FILE") { // gsc - ParseAsset_RawFile(&zoneFileStream); - } else if (typeStr == "PHYS PRESET") { // physpreset - ParseAsset_PhysPreset(&zoneFileStream); - } else if (typeStr == "MODEL") { // xmodel - ParseAsset_XModel(&zoneFileStream); - } else if (typeStr == "MATERIAL") { // material - ParseAsset_Material(&zoneFileStream); - } else if (typeStr == "SHADER") { // pixelshader - ParseAsset_PixelShader(&zoneFileStream); - } else if (typeStr == "TECH SET") { // techset include - ParseAsset_TechSet(&zoneFileStream); - } else if (typeStr == "IMAGE") { // image - ParseAsset_Image(&zoneFileStream); - } else if (typeStr == "SOUND") { // loaded_sound - ParseAsset_LoadedSound(&zoneFileStream); - } else if (typeStr == "COLLISION MAP") { // col_map_mp - ParseAsset_ColMapMP(&zoneFileStream); - } else if (typeStr == "MP MAP") { // game_map_sp - ParseAsset_GameMapSP(&zoneFileStream); - } else if (typeStr == "SP MAP") { // game_map_mp - ParseAsset_GameMapMP(&zoneFileStream); - } else if (typeStr == "LIGHT DEF") { // lightdef - ParseAsset_LightDef(&zoneFileStream); - } else if (typeStr == "UI MAP") { // ui_map - ParseAsset_UIMap(&zoneFileStream); - } else if (typeStr == "SND DRIVER GLOBALS") { // snddriverglobals - ParseAsset_SNDDriverGlobals(&zoneFileStream); - } else if (typeStr == "AI TYPE") { // aitype - ParseAsset_AIType(&zoneFileStream); - } else if (typeStr == "EFFECT") { // aitype - ParseAsset_FX(&zoneFileStream); - } else if (typeStr == "ANIMATION") { // aitype - ParseAsset_XAnim(&zoneFileStream); - } else if (typeStr == "STRING TABLE") { // string_table - ParseAsset_StringTable(&zoneFileStream); - } else if (typeStr == "MENU") { // string_table - ParseAsset_MenuFile(&zoneFileStream); - } else if (typeStr == "WEAPON") { // string_table - ParseAsset_Weapon(&zoneFileStream); - } else if (typeStr == "D3DBSP DUMP") { // string_table - ParseAsset_D3DBSP(&zoneFileStream); - } else if (typeStr != "UNKNOWN") { - qDebug() << "Found bad asset type!" << typeStr; - } - } - - // Close zone file - zoneFile->close(); - - // Clean up - delete zoneFile; - delete fastFile; -} - -void MainWindow::on_pushButton_FastFile_2_clicked() { - // Check zone file is writeable - QFile *zoneFile; - if (!(zoneFile = OpenZoneFile())) { - QMessageBox::warning(this, "Warning!", QString("Failed to open FastFile!.")); - return; - } - const QByteArray decompressedData = zoneFile->readAll(); - - // Open zone file as little endian stream - QDataStream zoneFileStream(decompressedData); - zoneFileStream.setByteOrder(QDataStream::LittleEndian); - - // Parse data from zone file header - ParseZoneHeader(&zoneFileStream); - ParseZoneIndex(&zoneFileStream); - - // Track current and consecutive assets - int assetIndex = 0; - - // Iterate asset types found in index - for (auto [assetType, assetCount] : mTypeMap.asKeyValueRange()) { - // Get asset description from type - QString assetStr = Utils::AssetTypeToString(assetType); - - // Insert row and populate - ui->tableWidget_Index->insertRow(assetIndex); - ui->tableWidget_Index->setItem(assetIndex, 0, new QTableWidgetItem(assetType)); - ui->tableWidget_Index->setItem(assetIndex, 1, new QTableWidgetItem(assetStr)); - ui->tableWidget_Index->setItem(assetIndex, 2, new QTableWidgetItem(QString::number(assetCount))); - - // Update count - assetIndex++; - } - - for (int i = 0; i < mTypeOrder.size(); i++) { - const QString typeHex = mTypeOrder[i]; - const QString typeStr = Utils::AssetTypeToString(typeHex); - - // qDebug() << "Parsing Asset of Type: " << typeHex; - if (typeStr == "LOCAL STRING") { // localized string asset - ParseAsset_LocalString(&zoneFileStream); - } else if (typeStr == "RAW FILE") { // gsc - ParseAsset_RawFile(&zoneFileStream); - } else if (typeStr == "PHYS PRESET") { // physpreset - ParseAsset_PhysPreset(&zoneFileStream); - } else if (typeStr == "MODEL") { // xmodel - ParseAsset_XModel(&zoneFileStream); - } else if (typeStr == "MATERIAL") { // material - ParseAsset_Material(&zoneFileStream); - } else if (typeStr == "SHADER") { // pixelshader - ParseAsset_PixelShader(&zoneFileStream); - } else if (typeStr == "TECH SET") { // techset include - ParseAsset_TechSet(&zoneFileStream); - } else if (typeStr == "IMAGE") { // image - ParseAsset_Image(&zoneFileStream); - } else if (typeStr == "SOUND") { // loaded_sound - ParseAsset_LoadedSound(&zoneFileStream); - } else if (typeStr == "COLLISION MAP") { // col_map_mp - ParseAsset_ColMapMP(&zoneFileStream); - } else if (typeStr == "MP MAP") { // game_map_sp - ParseAsset_GameMapSP(&zoneFileStream); - } else if (typeStr == "SP MAP") { // game_map_mp - ParseAsset_GameMapMP(&zoneFileStream); - } else if (typeStr == "LIGHT DEF") { // lightdef - ParseAsset_LightDef(&zoneFileStream); - } else if (typeStr == "UI MAP") { // ui_map - ParseAsset_UIMap(&zoneFileStream); - } else if (typeStr == "SND DRIVER GLOBALS") { // snddriverglobals - ParseAsset_SNDDriverGlobals(&zoneFileStream); - } else if (typeStr == "AI TYPE") { // aitype - ParseAsset_AIType(&zoneFileStream); - } else if (typeStr == "EFFECT") { // aitype - ParseAsset_FX(&zoneFileStream); - } else if (typeStr == "ANIMATION") { // aitype - ParseAsset_XAnim(&zoneFileStream); - } else if (typeStr == "STRING TABLE") { // string_table - ParseAsset_StringTable(&zoneFileStream); - } else if (typeStr == "MENU") { // string_table - ParseAsset_MenuFile(&zoneFileStream); - } else if (typeStr == "WEAPON") { // string_table - ParseAsset_Weapon(&zoneFileStream); - } else if (typeStr == "D3DBSP DUMP") { // string_table - ParseAsset_D3DBSP(&zoneFileStream); - } else if (typeStr != "UNKNOWN") { - qDebug() << "Found bad asset type!" << typeStr; - } - } - - // Close zone file - zoneFile->close(); - - // Clean up - delete zoneFile; + return true; } int MainWindow::LoadFile_D3DBSP(const QString aFilePath) { @@ -1195,11 +397,9 @@ int MainWindow::LoadFile_D3DBSP(const QString aFilePath) { // Assign diskLumpOrderSize mDiskLumpOrder.resize(mDiskLumpCount); - qDebug() << "BSP Version:" << mBSPVersion; - qDebug() << "Lump Count:" << mDiskLumpCount; - // Read Lump Index Entries - quint32 lumpOffset = sizeof(quint32) * 3 + sizeof(LumpIndexEntry) * mDiskLumpCount; + quint32 lumpOffset = + sizeof(quint32) * 3 + sizeof(LumpIndexEntry) * mDiskLumpCount; for (quint32 i = 0; i < mDiskLumpCount; i++) { LumpIndexEntry indexEntry; @@ -1212,7 +412,9 @@ int MainWindow::LoadFile_D3DBSP(const QString aFilePath) { lump.content.resize(indexEntry.length); lump.isEmpty = false; - qDebug() << "Lump Type:" << Utils::LumpTypeToString((LUMP_TYPE)indexEntry.type) << "Lump Size:" << indexEntry.length; + qDebug() << "Lump Type:" + << Utils::LumpTypeToString((LUMP_TYPE)indexEntry.type) + << "Lump Size:" << indexEntry.length; // Handle offsets and padding qint64 currentPos = file.pos(); @@ -1226,3 +428,292 @@ int MainWindow::LoadFile_D3DBSP(const QString aFilePath) { return 0; // Success } +struct Command { + quint32 size = 0; + bool compressed = false; +}; +quint32 DXT1 = 0x31545844; // 'DXT1' +quint32 DXT3 = 0x33545844; // 'DXT3' +quint32 DXT5 = 0x35545844; // 'DXT5' + +int MainWindow::LoadFile_IWI(const QString aFilePath) { + mTreeWidget->AddIWIFile(std::make_shared(aFilePath)); + + return 0; +} + +int MainWindow::LoadFile_DDSFiles(const QStringList aFilePaths) { + for (const QString &filePath : aFilePaths) { + if (!filePath.endsWith(".dds", Qt::CaseInsensitive)) { + qDebug() << "Error: Invalid filename " << filePath; + return -1; + } + mTreeWidget->AddDDSFile(std::make_shared(filePath)); + } + return 0; +} + +int MainWindow::LoadFile_DDS(const QString aFilePath) { + if (!aFilePath.endsWith(".dds", Qt::CaseInsensitive)) { + qDebug() << "Error: Invalid filename " << aFilePath; + return -1; + } + mTreeWidget->AddDDSFile(std::make_shared(aFilePath)); + return 0; +} + +int MainWindow::LoadFile_XSUB(const QString aFilePath) { + QFile file(aFilePath); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << "Error: Unable to open file" << aFilePath; + return 1; // ERR_FILE_NOT_FOUND + } + + QDataStream stream(&file); + stream.setByteOrder(QDataStream::LittleEndian); + + QByteArray magic(4, Qt::Uninitialized); + stream.readRawData(magic.data(), 4); + if (magic != "KAPI") { + qDebug() << "Wrong magic, invalid XSUB file!"; + return -1; + } + qDebug() << "Magic: " << magic; + + stream.skipRawData(5 * 4); + + quint32 fileSize; + stream >> fileSize; + qDebug() << "File Size: " << fileSize; + + return 0; // Success +} + +int MainWindow::LoadFile_IPAK(const QString aFilePath) { + QFile file(aFilePath); + if (!file.open(QIODevice::ReadOnly)) { + qDebug() << "Error: Unable to open file" << aFilePath; + return 1; // ERR_FILE_NOT_FOUND + } + + QDataStream stream(&file); + stream.setByteOrder(QDataStream::BigEndian); + + IPAKHeader header; + stream >> header; + + if (header.version == "50000") { + if (header.magic == "KAPI") { + stream.setByteOrder(QDataStream::LittleEndian); + } else if (header.magic == "IPAK") { + stream.setByteOrder(QDataStream::BigEndian); + } else { + qDebug() << "Invalid IPAK file!"; + return -1; + } + } else { + qDebug() << "Invalid IPAK file version!"; + return -1; + } + + qDebug() << "IPAK File " << "\n" + << "- Platform: " << header.platform << "\n" + << "- Magic: " << header.magic << "\n" + << "- Size: " << header.size << "\n" + << "- Version: " << header.version << "\n" + << "- Sections: " << header.sectionCount; + + QDir outputFolder = QDir(QDir::currentPath() + "/output"); + outputFolder.remove(QDir::currentPath() + "/output"); + outputFolder.mkdir(QDir::currentPath() + "/output"); + + QVector metas = QVector(); + + QVector entries = QVector(); + QVector sections = QVector(header.sectionCount); + for (uint i = 0; i < header.sectionCount; i++) { + IPAKSection currentSection; + stream >> currentSection; + sections << currentSection; + + qDebug() << " - IPAK Section " << i + 1 << "\n" + << " - Type: " << currentSection.type << " -> " << currentSection.typeInt << "\n" + << " - Offset: " << currentSection.offset << "\n" + << " - Item (IWI) Count: " << currentSection.itemCount << "\n" + << " - Size: " << currentSection.size; + + qint64 sectionPos = stream.device()->pos(); + stream.device()->seek(currentSection.offset); + + QString sectionType = currentSection.type; + if (sectionType == "Data") { + IPAKDataChunkHeader chunkHeader; + stream >> chunkHeader; + qDebug() << " - Chunk Header\n" + << " - Count: " << chunkHeader.count << "\n" + << " - Offset: " << chunkHeader.offset; + + for (uint j = 0; j < 31; j++) { + IPAKDataChunkCommand command; + stream >> command; + if (!command.size) { continue; } + chunkHeader.commands << command; + qDebug() << " - Command\n" + << " - Size: " << command.size << "\n" + << " - Compressed: " << command.compressed; + + } + for (uint j = 0; j < chunkHeader.count; j++) { + auto command = chunkHeader.commands[j]; + + qDebug() << "Reading from " << stream.device()->pos(); + QByteArray data = stream.device()->read(command.size); + qDebug() << " to " << stream.device()->pos(); + + QString outputFilePath = outputFolder.filePath(QString("%1.iwi").arg(j)); + if (command.compressed) { + data = Compressor::DecompressLZO(data); + } + QFile outputFile(outputFilePath); + if (!outputFile.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to extract IPAK file."; + } + qDebug() << " - File Name: " << outputFile.fileName(); + outputFile.write(data); + outputFile.close(); + } + + + qDebug() << stream.device()->pos(); + stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count)); + qDebug() << stream.device()->pos(); + } else if (sectionType == "Index") { + for (uint j = 0; j < currentSection.itemCount; j++) { + IPAKIndexEntry entry; + stream >> entry; + + if (entry.size == 0) { continue; } + + entries << entry; + + quint64 entryPos = stream.device()->pos(); + qDebug() << " - Index Entry " << j + 1 << "\n" + << " - Name Hash: " << entry.nameHash << "\n" + << " - Data Hash: " << entry.dataHash << "\n" + << " - Offset: " << entry.offset << "\n" + << " - Size: " << entry.size; + + stream.device()->seek(entry.offset); + + QByteArray sectionData(entry.size, Qt::Uninitialized); + stream.readRawData(sectionData.data(), entry.size); + + const QString entryKey = QString::number(entry.nameHash); + QFile outputFile(outputFolder.filePath(QString("%1.dds").arg(entryKey))); + if (!outputFile.open(QIODevice::WriteOnly)) { + qDebug() << "Failed to extract IPAK file."; + } + qDebug() << " - File Name: " << outputFile.fileName(); + outputFile.write(sectionData); + outputFile.close(); + + stream.device()->seek(entryPos); + } + } + stream.device()->seek(sectionPos); + qDebug() << stream.device()->pos(); + } + + return 0; // Success +} + +void MainWindow::dragEnterEvent(QDragEnterEvent *event) { + const QMimeData *mimeData = event->mimeData(); + bool goodDrag = true; + if (mimeData->hasUrls()) { + foreach (const QUrl url, mimeData->urls()) { + if (!url.toString().contains(".ff") && + !url.toString().contains(".zone") && + !url.toString().contains(".ipak") && + !url.toString().contains(".d3dbsp") && + !url.toString().contains(".lzoin") && + !url.toString().contains(".xsub") && + !url.toString().contains(".iwi") && + !url.toString().contains(".dds")) { + goodDrag = false; + } + } + } else { + goodDrag = false; + } + if (goodDrag) { + event->acceptProposedAction(); + } +} + +void MainWindow::dragMoveEvent(QDragMoveEvent *event) { + Q_UNUSED(event); +} + +void MainWindow::dragLeaveEvent(QDragLeaveEvent *event) { + Q_UNUSED(event); +} + +void MainWindow::dropEvent(QDropEvent *event) { + const QMimeData *mimeData = event->mimeData(); + if (mimeData->hasUrls()) { + QStringList ddsPaths = QStringList(); + foreach (const QUrl url, mimeData->urls()) { + const QString urlStr = url.toLocalFile(); + if (urlStr.contains(".zone")) { + OpenZoneFile(urlStr); + } else if (urlStr.contains(".ff")) { + OpenFastFile(urlStr); + } else if (urlStr.contains(".ipak")) { + qDebug() << "LoadFile_IPAK Returned: " << LoadFile_IPAK(urlStr); + } else if (urlStr.contains(".xsub")) { + qDebug() << "LoadFile_XSUB Returned: " << LoadFile_XSUB(urlStr); + } else if (urlStr.contains(".iwi")) { + qDebug() << "LoadFile_IWI Returned: " << LoadFile_IWI(urlStr); + } else if (urlStr.contains(".dds")) { + if (mimeData->urls().size() == 1) { + qDebug() << "LoadFile_DDS Returned: " << LoadFile_DDS(urlStr); + } else { + ddsPaths << urlStr; + } + } else if (urlStr.contains(".d3dbsp")) { + LoadFile_D3DBSP(urlStr); + } else if (urlStr.contains(".lzoin")) { + QFile lzoFile(urlStr); + if (!lzoFile.open(QIODevice::ReadOnly)) { + qDebug() << "LZO: Failed to read file!"; + continue; + } + QByteArray data = Compressor::DecompressLZO(lzoFile.readAll()); + lzoFile.close(); + + if (data.isEmpty()) { + qDebug() << "LZO: Decompressor gave empty result!"; + continue; + } + + QFile outputFile(url.toLocalFile().replace("lzoin", "lzoout")); + if (!outputFile.open(QIODevice::WriteOnly)) { + qDebug() << "LZO: Failed to write file!"; + continue; + } + outputFile.write(data); + outputFile.close(); + } else { + const QString ext = urlStr.split('.').last(); + ui->statusBar->showMessage( + QString("Can't display dropped file! .%1").arg(ext)); + } + } + if (ddsPaths.size() > 1) { + qDebug() << "LoadFile_DDSFiles Returned: " << LoadFile_DDSFiles(ddsPaths); + } + } else { + ui->statusBar->showMessage("Can't display dropped data!"); + } +} diff --git a/mainwindow.h b/mainwindow.h index cfee96c..d4ad802 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -1,9 +1,18 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include "enums.h" -#include "structs.h" -#include "utils.h" +#include "d3dbsp_structs.h" +#include "asset_structs.h" +#include "ddsviewer.h" +#include "fastfileviewer.h" +#include "ipak_structs.h" +#include "iwiviewer.h" +#include "localstringviewer.h" +#include "modelviewer.h" +#include "imagewidget.h" +#include "xtreewidget.h" +#include "zonefileviewer.h" +#include "techsetviewer.h" #include #include @@ -12,52 +21,9 @@ #include #include #include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#include - +#include +#include +#include #include QT_BEGIN_NAMESPACE @@ -75,59 +41,25 @@ public: ~MainWindow(); void Reset(); - QByteArray DecompressZLIB(QByteArray compressedData); - private slots: - void on_pushButton_FastFile_clicked(); - void on_pushButton_FastFile_2_clicked(); + bool OpenFastFile(const QString aFastFilePath); + bool OpenFastFile(); - QFile *OpenFastFile(); - QFile *OpenZoneFile(); - void ParseFFHeader(QFile *aFastFilePtr); - void ParseFFCompany(QDataStream *aFastFileStream); - void ParseFFFileType(QDataStream *afastFileStream); - void ParseFFSignage(QDataStream *afastFileStream); - void ParseFFMagic(QDataStream *afastFileStream); - void ParseFFVersion(QDataStream *afastFileStream); - - void ParseZoneHeader(QDataStream *aZoneFileStream); - void ParseZoneSize(QDataStream *aZoneFileStream); - - void ParseZoneUnknownsA(QDataStream *aZoneFileStream); - void ParseZoneUnknownsB(QDataStream *aZoneFileStream); - void ParseZoneUnknownsC(QDataStream *aZoneFileStream); - void ParseZoneTagCount(QDataStream *aZoneFileStream); - void ParseZoneRecordCount(QDataStream *aZoneFileStream); - void ParseZoneTags(QDataStream *aZoneFileStream); - void ParseZoneIndex(QDataStream *aZoneFileStream); - - void ParseAsset_LocalString(QDataStream *aZoneFileStream); - void ParseAsset_RawFile(QDataStream *aZoneFileStream); - void ParseAsset_PhysPreset(QDataStream *aZoneFileStream); - void ParseAsset_XModel(QDataStream *aZoneFileStream); - void ParseAsset_Material(QDataStream *aZoneFileStream); - void ParseAsset_PixelShader(QDataStream *aZoneFileStream); - void ParseAsset_TechSet(QDataStream *aZoneFileStream); - void ParseAsset_Image(QDataStream *aZoneFileStream); - void ParseAsset_LoadedSound(QDataStream *aZoneFileStream); - void ParseAsset_ColMapMP(QDataStream *aZoneFileStream); - void ParseAsset_GameMapSP(QDataStream *aZoneFileStream); - void ParseAsset_GameMapMP(QDataStream *aZoneFileStream); - void ParseAsset_LightDef(QDataStream *aZoneFileStream); - void ParseAsset_UIMap(QDataStream *aZoneFileStream); - void ParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream); - void ParseAsset_AIType(QDataStream *aZoneFileStream); - void ParseAsset_FX(QDataStream *aZoneFileStream); - void ParseAsset_XAnim(QDataStream *aZoneFileStream); - void ParseAsset_StringTable(QDataStream *aZoneFileStream); - void ParseAsset_MenuFile(QDataStream *aZoneFileStream); - void ParseAsset_Weapon(QDataStream *aZoneFileStream); - void ParseAsset_D3DBSP(QDataStream *aZoneFileStream); + bool OpenZoneFile(const QString aZoneFilePath, bool fromFF = false); + bool OpenZoneFile(); int LoadFile_D3DBSP(const QString aFilePath); + int LoadFile_IPAK(const QString aFilePath); + int LoadFile_XSUB(const QString aFilePath); + int LoadFile_IWI(const QString aFilePath); + int LoadFile_DDS(const QString aFilePath); + int LoadFile_DDSFiles(const QStringList aFilePaths); - void ScriptSelected(); - void StrTableSelected(QString aStrTableName); +protected: + void dragEnterEvent(QDragEnterEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; + void dropEvent(QDropEvent *event) override; private: Ui::MainWindow *ui; @@ -136,13 +68,14 @@ private: quint32 mTagCount; quint32 mRecordCount; QMap mRawFileMap; + QMap mImageMap; QMap mTreeMap; QMap>> mStrTableMap; + XTreeWidget *mTreeWidget; quint32 mBSPVersion; quint32 mDiskLumpCount; QVector mDiskLumpOrder; QMap mLumps; - }; #endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui index 0476b70..9ed5eb0 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,12 +6,18 @@ 0 0 - 850 - 628 + 986 + 692 + + + 550 + 300 + + - FastFile Wizard + XPlor QMainWindow { @@ -19,1060 +25,343 @@ } - - - - - true - - - - 14 - true - - - - WAW - PC - FastFile Viewer - - - Qt::AlignmentFlag::AlignCenter - - - - - - - true - - - Qt::Orientation::Horizontal - - - - + + - + + -1 + + true - - 0 + + true - - - General - - - - - - - - true - - - FastFile path... - - - - - - - true - - - Open .ff - - - - - - - - - - - true - - - ZoneFile path... - - - - - - - true - - - Open .zone - - - - - - - - - - - true - - - Company: - - - - - - - true - - - - Select Company - - - - - INFINITY_WARD - - - - - TREYARCH - - - - - SLEDGEHAMMER - - - - - NEVERSOFT - - - - - - - - - - - - true - - - File Type: - - - - - - - true - - - - Select File Type - - - - - FAST_FILE - - - - - - - - true - - - Signed - - - - - - - - - - - true - - - Magic: - - - - - - - true - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - true - - - Tag Count - - - - - - - true - - - 999999999 - - - - - - - - - - - true - - - File Size: - - - - - - - true - - - B - - - 999999999 - - - - - - - - - - - true - - - Version: - - - - - - - true - - - 999999999 - - - - - - - - - - - true - - - Record Count - - - - - - - true - - - 999999999 - - - - - - - - - Qt::Orientation::Vertical - - - - 17 - 242 - - - - - - - - - Unknowns - - - - - - - - Unknown 1: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 2: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 4: - - - - - - - - 0 - 0 - - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 3: - - - - - - - - 0 - 0 - - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 6: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 5: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 8: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 7: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 9: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 10: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - - - Unknown 11: - - - - - - - - 0 - 0 - - - - true - - - - - - - true - - - 999999999 - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - - Tags - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - true - - - - - - - - Localized Strings - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - Asset Index/Order - - - - - - Asset Index Table - - - - - - 3 - - - 50 - - - true - - - true - - - false - - - - - - - - - - This table shows the total asset counts per type. - - - - - - - - - - Qt::Orientation::Vertical - - - - - - - Asset Order Table - - - - - - 3 - - - 50 - - - true - - - true - - - false - - - - - - - - - - This table shows the consecutive asset counts in order. - - - - - - - - - - - Raw Files - - - - - - - 0 - 0 - - - - - 200 - 16777215 - - - - - 1 - - - - - - - - - 0 - 0 - - - - - - - - - Tech Sets - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - Zone Dump - - - - - - - - Select Asset: - - - - - - - - - - - - - - - - - - - String Tables - - - - - - - - String Table: - - - - - - - - - - - - - - - - 3D Scene - - - - - - - 200 - 16777215 - - - - - 1 - - - - - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - - - - - - - - true - - - < Back - - - - - - - true - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - true - - - Next > - - - - - + + + + 0 + 0 + 986 + 21 + + + + + File + + + + Recent... + + + + + + + + Import... + + + + + + + + + + + + + + + + + + + + + + Edit + + + + Undo History... + + + + + Redo History... + + + + + + + + + + + + + + + + + + + + + + Help + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + New + + + + + + + + New Fast File + + + + + + + + New Zone File + + + + + + + + Open Fast File + + + + + + + + Open Zone File + + + + + + + + Open Folder + + + + + + + + Save + + + + + + + + Save As + + + + + e + + + + + File + + + + + Folder + + + + + New File + + + + + New Fast File + + + + + New Zone File + + + + + From Clipboard + + + + + Material + + + + + Sound + + + + + + + + Undo + + + + + + + + Redo + + + + + + + + Cut + + + + + + + + Copy + + + + + + + + Paste + + + + + + + + Rename + + + + + Edit Value + + + + + Edit as Hex + + + + + + + + Delete + + + + + d + + + + + d + + + + + Clear Undo History + + + + + Find + + + + + + + + About + + + + + Change Icons + + + + + + + + Check for Updates + + + + + + + + Find + + diff --git a/modelviewer.cpp b/modelviewer.cpp new file mode 100644 index 0000000..27058b0 --- /dev/null +++ b/modelviewer.cpp @@ -0,0 +1,73 @@ +#include "modelviewer.h" + +ModelViewer::ModelViewer(QWidget *parent) + : QWidget{parent} { + Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow(); + view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f))); + + QWidget *container = QWidget::createWindowContainer(view); + QSize screenSize = view->screen()->size(); + container->setMinimumSize(QSize(200, 100)); + container->setMaximumSize(screenSize); + + 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); +} diff --git a/modelviewer.h b/modelviewer.h new file mode 100644 index 0000000..c56d376 --- /dev/null +++ b/modelviewer.h @@ -0,0 +1,53 @@ +#ifndef MODELVIEWER_H +#define MODELVIEWER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +// Qt3DCore includes +#include +#include +#include +#include +#include +#include +// Qt3DInput includes +#include +// Qt3DRender includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Qt3DExtras includes +#include +#include +#include +#include +#include +#include +#include + +class ModelViewer : public QWidget +{ + Q_OBJECT +public: + explicit ModelViewer(QWidget *parent = nullptr); + +signals: +}; + +#endif // MODELVIEWER_H diff --git a/techsetviewer.cpp b/techsetviewer.cpp new file mode 100644 index 0000000..81548b3 --- /dev/null +++ b/techsetviewer.cpp @@ -0,0 +1,25 @@ +#include "techsetviewer.h" +#include "ui_techsetviewer.h" + +TechSetViewer::TechSetViewer(QWidget *parent) + : QWidget(parent) + , ui(new Ui::TechSetViewer) +{ + ui->setupUi(this); +} + +TechSetViewer::~TechSetViewer() +{ + delete ui; +} + +void TechSetViewer::SetTechSet(std::shared_ptr aTechSet) { + ui->listWidget_Ptrs->clear(); + ui->label_Title->setText(aTechSet->name); + + int ptrIndex = 1; + for (auto ptr : aTechSet->pointers) { + ui->listWidget_Ptrs->addItem(QString("Pointer %1: %2").arg(ptrIndex).arg(ptr)); + ptrIndex++; + } +} diff --git a/techsetviewer.h b/techsetviewer.h new file mode 100644 index 0000000..20182cb --- /dev/null +++ b/techsetviewer.h @@ -0,0 +1,25 @@ +#ifndef TECHSETVIEWER_H +#define TECHSETVIEWER_H + +#include "asset_structs.h" +#include + +namespace Ui { +class TechSetViewer; +} + +class TechSetViewer : public QWidget +{ + Q_OBJECT + +public: + explicit TechSetViewer(QWidget *parent = nullptr); + ~TechSetViewer(); + + void SetTechSet(std::shared_ptr aTechSet); + +private: + Ui::TechSetViewer *ui; +}; + +#endif // TECHSETVIEWER_H diff --git a/techsetviewer.ui b/techsetviewer.ui new file mode 100644 index 0000000..fadd6d2 --- /dev/null +++ b/techsetviewer.ui @@ -0,0 +1,77 @@ + + + TechSetViewer + + + + 0 + 0 + 961 + 756 + + + + Form + + + + + + + Roboto + 16 + true + + + + Technique Set 0 + + + + + + + + + Unknown Pointers: + + + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Orientation::Vertical + + + + 20 + 363 + + + + + + + + + diff --git a/utils.h b/utils.h index 4a0bfc0..49c21dd 100644 --- a/utils.h +++ b/utils.h @@ -5,6 +5,8 @@ #include #include +#include +#include class Utils { public: @@ -35,18 +37,24 @@ public: return "TECH SET"; } else if (cleanedType == "18000000") { // weapon PARTIALLY VERIFIED return "WEAPON"; - } else if (cleanedType == "11000000") { // d3dbsp dump PARTIALLY VERIFIED - return "D3DBSP DUMP"; + } else if (cleanedType == "11000000") { // gfx map PARTIALLY VERIFIED + return "GFX MAP"; } else if (cleanedType == "12000000") { // light_def PARTIALLY VERIFIED return "LIGHT DEF"; } else if (cleanedType == "14000000") { // font PARTIALLY VERIFIED return "FONT"; } else if (cleanedType == "05000000") { // xmodel PARTIALLY VERIFIED return "MODEL"; - } else if (cleanedType == "0D000000") { // shader PARTIALLY VERIFIED - return "SHADER"; + } else if (cleanedType == "0D000000") { // d3dbsp PARTIALLY VERIFIED + return "D3DBSP"; + } else if (cleanedType == "06000000") { // image PARTIALLY VERIFIED + return "IMAGE"; + } else if (cleanedType == "0E000000") { // game map sp PARTIALLY VERIFIED + return "GAME MAP SP"; + } else if (cleanedType == "0B000000") { // col map sp PARTIALLY VERIFIED + return "COL MAP SP"; } - return "UNKNOWN"; + return aAssetType; } /* @@ -164,6 +172,138 @@ public: static quint32 PaddingSize(quint32 size) { return PadInt4(size) - size; } + + static QString GetOpenFastFileName(QWidget *parent = nullptr) { + // Open file dialog to steam apps + const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; + const QString fastFilePath = QFileDialog::getOpenFileName(parent, "Open Fast File", steamPath, "Fast File (*.ff);;All Files (*.*)"); + if (fastFilePath.isNull()) { + // User pressed cancel + return ""; + } else if (!QFile::exists(fastFilePath)) { + QMessageBox::warning(parent, "Warning!", QString("%1 does not exist!.").arg(fastFilePath)); + return ""; + } + return fastFilePath; + } + + static QString GetOpenZoneFileName(QWidget *parent = nullptr) { + // Open file dialog to steam apps + const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; + const QString zoneFilePath = QFileDialog::getOpenFileName(parent, "Open Zone File", steamPath, "Zone File (*.zone);;All Files (*.*)"); + if (zoneFilePath.isNull()) { + // User pressed cancel + return ""; + } else if (!QFile::exists(zoneFilePath)) { + QMessageBox::warning(parent, "Warning!", QString("%1 does not exist!.").arg(zoneFilePath)); + return nullptr; + } + return zoneFilePath; + } + + static QString CompanyEnumToStr(FF_COMPANY aCompany) { + switch (aCompany) { + case COMPANY_NONE: + return "None"; + case COMPANY_INFINITY_WARD: + return "Infinity Ward"; + case COMPANY_TREYARCH: + return "Treyarch"; + case COMPANY_SLEDGEHAMMER: + return "Sledgehammer"; + case COMPANY_NEVERSOFT: + return "Neversoft"; + } + return "None"; + } + + static QString FileTypeEnumToStr(FF_FILETYPE aFileType) { + switch (aFileType) { + case FILETYPE_NONE: + return "None"; + case FILETYPE_FAST_FILE: + return "Fast File"; + } + return "None"; + } + + static QString SignageEnumToStr(FF_SIGNAGE aSignage) { + switch (aSignage) { + case SIGNAGE_NONE: + return "None"; + case SIGNAGE_SIGNED: + return "Signed"; + case SIGNAGE_UNSIGNED: + return "Unsigned"; + } + return "None"; + } + + static QString MenuVAlignToStr(MENU_V_ALIGNMENT align) { + if (align == VERTICAL_ALIGN_SUBTOP) { + return "VERTICAL_ALIGN_SUBTOP"; + } else if (align == VERTICAL_ALIGN_TOP) { + return "VERTICAL_ALIGN_TOP"; + } else if (align == VERTICAL_ALIGN_CENTER) { + return "VERTICAL_ALIGN_CENTER"; + } else if (align == VERTICAL_ALIGN_BOTTOM) { + return "VERTICAL_ALIGN_BOTTOM"; + } else if (align == VERTICAL_ALIGN_FULLSCREEN) { + return "VERTICAL_ALIGN_FULLSCREEN"; + } else if (align == VERTICAL_ALIGN_NOSCALE) { + return "VERTICAL_ALIGN_NOSCALE"; + } else if (align == VERTICAL_ALIGN_TO480) { + return "VERTICAL_ALIGN_TO480"; + } else if (align == VERTICAL_ALIGN_CENTER_SAFEAREA) { + return "VERTICAL_ALIGN_CENTER_SAFEAREA"; + } else if (align == VERTICAL_ALIGN_MAX) { + return "VERTICAL_ALIGN_CENTER_SAFEAREA"; + } else if (align == VERTICAL_ALIGN_DEFAULT) { + return "VERTICAL_ALIGN_SUBTOP"; + } + return "VERTICAL_ALIGN_SUBTOP"; + } + + static QString MenuHAlignToStr(MENU_H_ALIGNMENT align) { + if (align == HORIZONTAL_ALIGN_SUBLEFT) { + return "HORIZONTAL_ALIGN_SUBLEFT"; + } else if (align == HORIZONTAL_ALIGN_LEFT) { + return "HORIZONTAL_ALIGN_LEFT"; + } else if (align == HORIZONTAL_ALIGN_CENTER) { + return "HORIZONTAL_ALIGN_CENTER"; + } else if (align == HORIZONTAL_ALIGN_RIGHT) { + return "HORIZONTAL_ALIGN_RIGHT"; + } else if (align == HORIZONTAL_ALIGN_FULLSCREEN) { + return "HORIZONTAL_ALIGN_FULLSCREEN"; + } else if (align == HORIZONTAL_ALIGN_NOSCALE) { + return "HORIZONTAL_ALIGN_NOSCALE"; + } else if (align == HORIZONTAL_ALIGN_TO640) { + return "HORIZONTAL_ALIGN_TO640"; + } else if (align == HORIZONTAL_ALIGN_CENTER_SAFEAREA) { + return "HORIZONTAL_ALIGN_CENTER_SAFEAREA"; + } else if (align == HORIZONTAL_ALIGN_MAX) { + return "HORIZONTAL_ALIGN_CENTER_SAFEAREA"; + } else if (align == HORIZONTAL_ALIGN_DEFAULT) { + return "HORIZONTAL_ALIGN_SUBLEFT"; + } + return "HORIZONTAL_ALIGN_SUBLEFT"; + } + + static QColor ColorFromNormalized(float r, float g, float b, float a) { + // Ensure values are clamped between 0 and 1 + r = qBound(0.0f, r, 1.0f); + g = qBound(0.0f, g, 1.0f); + b = qBound(0.0f, b, 1.0f); + a = qBound(0.0f, a, 1.0f); + + // Convert to 0-255 scale + int red = static_cast(r * 255); + int green = static_cast(g * 255); + int blue = static_cast(b * 255); + int alpha = static_cast(a * 255); + + return QColor(red, green, blue, alpha); + } }; #endif // UTILS_H diff --git a/xtreewidget.cpp b/xtreewidget.cpp new file mode 100644 index 0000000..691aba7 --- /dev/null +++ b/xtreewidget.cpp @@ -0,0 +1,508 @@ +#include "xtreewidget.h" +#include "qheaderview.h" +#include "qmenu.h" +#include "utils.h" + +XTreeWidget::XTreeWidget(QWidget *parent) + : QTreeWidget(parent) { + mFastFiles = QMap>(); + mZoneFiles = QMap>(); + mDDSFiles = QMap>(); + mIWIFiles = QMap>(); + + setContextMenuPolicy(Qt::CustomContextMenu); + setSelectionMode(QTreeWidget::SingleSelection); + setColumnCount(3); + setColumnWidth(0, 275); + setColumnWidth(1, 50); + setColumnWidth(2, 50); + header()->hide(); + setMinimumWidth(350); + + connect(this, &QTreeWidget::itemSelectionChanged, this, &XTreeWidget::ItemSelectionChanged); + connect(this, &XTreeWidget::customContextMenuRequested, this, &XTreeWidget::PrepareContextMenu); +} + +XTreeWidget::~XTreeWidget() { + +} + +void XTreeWidget::AddFastFile(std::shared_ptr aFastFile) { + QTreeWidgetItem *fastFileItem = new QTreeWidgetItem(this); + fastFileItem->setText(0, aFastFile->GetFileStem()); + fastFileItem->setIcon(0, QIcon(":/icons/icons/Icon_FastFile.png")); + if (aFastFile->GetPlatform() == "PC") { + fastFileItem->setIcon(1, QIcon(":/icons/icons/Icon_PC.png")); + } else if (aFastFile->GetPlatform() == "360") { + fastFileItem->setIcon(1, QIcon(":/icons/icons/Icon_Xbox.png")); + } + if (aFastFile->GetGame() == "COD4") { + fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD4.png")); + } else if (aFastFile->GetGame() == "COD5") { + fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD5.png")); + } else if (aFastFile->GetGame() == "COD6") { + fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD6.png")); + } else if (aFastFile->GetGame() == "COD7") { + fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD7.png")); + } else if (aFastFile->GetGame() == "COD8") { + fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD8.png")); + } else if (aFastFile->GetGame() == "COD9") { + fastFileItem->setIcon(2, QIcon(":/icons/icons/Icon_COD9.png")); + } + + AddZoneFile(std::make_shared(aFastFile->GetZoneFile()), fastFileItem); + + mFastFiles[aFastFile->GetFileStem().section(".", 0, 0)] = aFastFile; + + resizeColumnToContents(1); +} + +void XTreeWidget::AddZoneFile(std::shared_ptr aZoneFile, QTreeWidgetItem *aParentItem) { + QTreeWidgetItem *zoneItem; + if (aParentItem != nullptr) { + zoneItem = new QTreeWidgetItem(aParentItem); + } else { + zoneItem = new QTreeWidgetItem(this); + } + zoneItem->setIcon(0, QIcon(":/icons/icons/Icon_ZoneFile.png")); + zoneItem->setText(0, aZoneFile->GetFileStem()); + + auto assetMap = aZoneFile->GetAssetMap(); + + if (!assetMap.localStrings.isEmpty()) { + QTreeWidgetItem *localStrRoot = new QTreeWidgetItem(zoneItem); + localStrRoot->setText(0, "String Files"); + localStrRoot->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png")); + + QTreeWidgetItem *localStrItem = new QTreeWidgetItem(localStrRoot); + localStrItem->setText(0, aZoneFile->GetFileStem().section('.', 0, 0) + ".str"); + localStrItem->setIcon(0, QIcon(":/icons/icons/Icon_StringFile.png")); + } + + if (!assetMap.techSets.isEmpty()) { + QTreeWidgetItem *techSetRoot = new QTreeWidgetItem(zoneItem); + techSetRoot->setText(0, "Tech Sets"); + techSetRoot->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png")); + + for (TechSet techSet : assetMap.techSets) { + QTreeWidgetItem *techSetItem = new QTreeWidgetItem(techSetRoot); + techSetItem->setText(0, techSet.name); + techSetItem->setIcon(0, QIcon(":/icons/icons/Icon_TechSetFile.png")); + } + } + + if (!assetMap.rawFiles.isEmpty()) { + QTreeWidgetItem *rawFileRoot = new QTreeWidgetItem(zoneItem); + rawFileRoot->setText(0, "Raw Files"); + rawFileRoot->setIcon(0, QIcon(":/icons/icons/Icon_GSCFile.png")); + for (RawFile rawFile : assetMap.rawFiles) { + if (!rawFile.length) { continue; } + + QTreeWidgetItem *tempItem = rawFileRoot; + for (const QString &pathPart : rawFile.path.split('/')) { + bool childFound = false; + for (int i = 0; i < tempItem->childCount(); i++) { + QTreeWidgetItem *childItem = tempItem->child(i); + //qDebug() << "Child text: " << childItem->text(0); + if (childItem->text(0) == pathPart) { + tempItem = childItem; + + childFound = true; + break; + } + } + + if (pathPart.contains(".gsc")) { + QTreeWidgetItem *rawFileItem = new QTreeWidgetItem(tempItem); + rawFileItem->setText(0, pathPart); + + tempItem = rawFileItem; + } else if (!childFound) { + tempItem = new QTreeWidgetItem(tempItem); + tempItem->setText(0, pathPart); + } + + } + tempItem->setIcon(0, QIcon(":/icons/icons/Icon_GSCFile.png")); + } + } + + if (!assetMap.menuFiles.isEmpty()) { + QTreeWidgetItem *menuRoot = new QTreeWidgetItem(zoneItem); + menuRoot->setText(0, "Menu Files"); + menuRoot->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png")); + + int menuIndex = 1; + for (MenuFile menuFile : assetMap.menuFiles) { + QTreeWidgetItem *menuFileRoot = new QTreeWidgetItem(menuRoot); + menuFileRoot->setText(0, QString("Menu %1").arg(menuIndex)); + for (Menu menu : menuFile.menuDefs) { + QTreeWidgetItem *menuItem = new QTreeWidgetItem(menuFileRoot); + menuItem->setText(0, menu.name); + menuItem->setIcon(0, QIcon(":/icons/icons/Icon_MenuFile.png")); + } + menuIndex++; + } + } + + if (!assetMap.images.isEmpty()) { + QTreeWidgetItem *imageRoot = new QTreeWidgetItem(zoneItem); + imageRoot->setText(0, "Images"); + imageRoot->setIcon(0, QIcon(":/icons/icons/Icon_Image.png")); + + for (Image image : assetMap.images) { + QTreeWidgetItem *imageItem = new QTreeWidgetItem(imageRoot); + imageItem->setText(0, image.materialName); + imageItem->setIcon(0, QIcon(":/icons/icons/Icon_Image.png")); + } + } + + mZoneFiles[aZoneFile->GetFileStem().section(".", 0, 0)] = aZoneFile; +} + +void XTreeWidget::PrepareContextMenu(const QPoint &pos) { + auto activeItem = itemAt(pos); + if (!activeItem) { return; } + if (activeItem->text(0).isEmpty()) { return; } + + QString activeText = activeItem->text(0); + QMenu *contextMenu = new QMenu(this); + + if (activeText.contains(".dds")) { + const QString fileStem = activeText.replace(".dds", ""); + if (!mDDSFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in DDS map!"; + return; + } + + QAction *closeAction = new QAction("Close File"); + contextMenu->addAction(closeAction); + connect(closeAction, &QAction::triggered, this, [this, &fileStem, &activeItem](bool checked) { + Q_UNUSED(checked); + + mDDSFiles.remove(fileStem); + invisibleRootItem()->removeChild(activeItem); + }); + + QMenu *exportSubmenu = new QMenu("Export...", this); + contextMenu->addMenu(exportSubmenu); + + std::shared_ptr ddsFile = mDDSFiles[fileStem]; + + QAction *exportIWIAction = new QAction("Export as IWI"); + exportSubmenu->addAction(exportIWIAction); + connect(exportIWIAction, &QAction::triggered, this, [ddsFile](bool checked) { + Q_UNUSED(checked); + + ddsFile->SaveIWI(); + }); + + QAction *exportPNGAction = new QAction("Export as PNG"); + exportSubmenu->addAction(exportPNGAction); + connect(exportPNGAction, &QAction::triggered, this, [ddsFile](bool checked) { + Q_UNUSED(checked); + + ddsFile->SavePNG(); + }); + + QAction *exportJPGAction = new QAction("Export as JPG"); + exportSubmenu->addAction(exportJPGAction); + connect(exportJPGAction, &QAction::triggered, this, [ddsFile](bool checked) { + Q_UNUSED(checked); + + ddsFile->SaveJPG(); + }); + } else if (activeText.contains(".iwi")) { + const QString fileStem = activeText.replace(".iwi", ""); + if (!mIWIFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in IWI map!"; + return; + } + + QAction *closeAction = new QAction("Close File"); + contextMenu->addAction(closeAction); + connect(closeAction, &QAction::triggered, this, [this, &fileStem, &activeItem](bool checked) { + Q_UNUSED(checked); + + mIWIFiles.remove(fileStem); + invisibleRootItem()->removeChild(activeItem); + }); + + QMenu *exportSubmenu = new QMenu("Export...", this); + contextMenu->addMenu(exportSubmenu); + + std::shared_ptr iwiFile = mIWIFiles[fileStem]; + + QAction *exportDDSAction = new QAction("Export as DDS"); + exportSubmenu->addAction(exportDDSAction); + connect(exportDDSAction, &QAction::triggered, this, [iwiFile](bool checked) { + Q_UNUSED(checked); + + iwiFile->SaveDDS(); + }); + + QAction *exportPNGAction = new QAction("Export as PNG"); + exportSubmenu->addAction(exportPNGAction); + connect(exportPNGAction, &QAction::triggered, this, [iwiFile](bool checked) { + Q_UNUSED(checked); + + iwiFile->SavePNG(); + }); + + QAction *exportJPGAction = new QAction("Export as JPG"); + exportSubmenu->addAction(exportJPGAction); + connect(exportJPGAction, &QAction::triggered, this, [iwiFile](bool checked) { + Q_UNUSED(checked); + + iwiFile->SaveJPG(); + }); + } else if (activeText.contains(".ff")) { + 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); + + clear(); + }); + + QAction *closeAllButAction = new QAction("Close All BUT This"); + closeMultipleAction->addAction(closeAllButAction); + connect(closeAllButAction, &QAction::triggered, this, [this, &activeItem](bool checked) { + Q_UNUSED(checked); + + for (int i = 0; i < invisibleRootItem()->childCount(); i++) { + auto childItem = invisibleRootItem()->child(i); + if (childItem == activeItem) { continue; } + invisibleRootItem()->removeChild(childItem); + i--; + } + }); + + QAction *closeAboveAction = new QAction("Close All Above"); + closeMultipleAction->addAction(closeAboveAction); + connect(closeAboveAction, &QAction::triggered, this, [this, &activeItem](bool checked) { + Q_UNUSED(checked); + + for (int i = 0; i < invisibleRootItem()->childCount(); i++) { + auto childItem = invisibleRootItem()->child(i); + if (childItem == activeItem) { return; } + invisibleRootItem()->removeChild(childItem); + i--; + } + }); + + QAction *closeBelowAction = new QAction("Close All Below"); + closeMultipleAction->addAction(closeBelowAction); + connect(closeBelowAction, &QAction::triggered, this, [this, &activeItem](bool checked) { + Q_UNUSED(checked); + + bool ready = false; + for (int i = 0; i < invisibleRootItem()->childCount(); i++) { + auto childItem = invisibleRootItem()->child(i); + if (!ready && (childItem != activeItem)) { continue; } + if (childItem == activeItem) { + ready = true; + continue; + } + invisibleRootItem()->removeChild(childItem); + i--; + } + }); + + contextMenu->addMenu(closeMultipleAction); + const QString fileStem = activeText.replace(".ff", ""); + if (!mFastFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in Fast File map!"; + return; + } + + QAction *closeAction = new QAction("Close File"); + contextMenu->addAction(closeAction); + connect(closeAction, &QAction::triggered, this, [this, &fileStem, &activeItem](bool checked) { + Q_UNUSED(checked); + + mFastFiles.remove(fileStem); + invisibleRootItem()->removeChild(activeItem); + }); + + QMenu *exportSubmenu = new QMenu("Export...", this); + contextMenu->addMenu(exportSubmenu); + + std::shared_ptr fastFile = mFastFiles[fileStem]; + + QAction *exportDDSAction = new QAction("Export as Zone File"); + exportSubmenu->addAction(exportDDSAction); + connect(exportDDSAction, &QAction::triggered, this, [fastFile](bool checked) { + Q_UNUSED(checked); + + //fastFile->SaveZone(); + }); + } else if (activeText.contains(".zone")) { + const QString fileStem = activeText.replace(".zone", ""); + if (!mZoneFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in Zone File map!"; + return; + } + + QMenu *exportSubmenu = new QMenu("Export...", this); + contextMenu->addMenu(exportSubmenu); + + std::shared_ptr zoneFile = mZoneFiles[fileStem]; + + QAction *exportDDSAction = new QAction("Export as Fast File"); + exportSubmenu->addAction(exportDDSAction); + connect(exportDDSAction, &QAction::triggered, this, [zoneFile](bool checked) { + Q_UNUSED(checked); + + //zoneFile->SaveFastFile(); + }); + } + + QPoint pt(pos); + contextMenu->exec(mapToGlobal(pt)); + + delete contextMenu; +} + +void XTreeWidget::ItemSelectionChanged() { + if (selectedItems().isEmpty()) { return; } + + QTreeWidgetItem *selectedItem = selectedItems().first(); + if (!selectedItem) { return; } + if (selectedItem->text(0).isEmpty()) { return; } + QString selectedText = selectedItem->text(0); + const QString fileStem = selectedText.section(".", 0, 0); + + QTreeWidgetItem *parentItem = selectedItem->parent(); + + if (selectedText.contains(".dds")) { + if (!mDDSFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in DDS map!"; + return; + } + std::shared_ptr ddsFile = mDDSFiles[fileStem]; + emit DDSFileSelected(ddsFile); + } else if (selectedText.contains(".iwi")) { + if (!mIWIFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in IWI map!"; + return; + } + emit IWIFileSelected(mIWIFiles[fileStem]); + } else if (selectedText.contains(".ff")) { + if (!mFastFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in Fast File map!"; + return; + } + emit FastFileSelected(mFastFiles[fileStem]); + } else if (selectedText.contains(".zone")) { + if (!mZoneFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in Zone File map!"; + return; + } + emit ZoneFileSelected(mZoneFiles[fileStem]); + } else if (selectedText.contains(".str")) { + if (!mZoneFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in Zone File map!"; + return; + } + emit LocalStringSelected(mZoneFiles[fileStem]); + } else if (selectedText.contains(".gsc")) { + QTreeWidgetItem *zoneRoot = selectedItem; + if (!zoneRoot) { return; } + + while (!zoneRoot->text(0).contains(".zone")) { + zoneRoot = zoneRoot->parent(); + if (!zoneRoot) { return; } + } + + const QString fileStem = zoneRoot->text(0).section('.', 0, 0); + if (!mZoneFiles.contains(fileStem)) { + qDebug() << "Error: Could not find " << fileStem << " in Zone File map!"; + return; + } + + QVector rawFiles = mZoneFiles[fileStem]->GetAssetMap().rawFiles; + for (RawFile rawFile : rawFiles) { + if (rawFile.path.contains(selectedText)) { + emit RawFileSelected(std::make_shared(rawFile)); + return; + } + } + } else if (parentItem && (parentItem->text(0) == "Images")) { + QTreeWidgetItem *grandpaItem = parentItem->parent(); + if (grandpaItem && grandpaItem->text(0).contains(".zone")) { + const QString fileStem = grandpaItem->text(0).section('.', 0, 0); + QVector images = mZoneFiles[fileStem]->GetAssetMap().images; + for (Image image : images) { + if (image.materialName == selectedText) { + emit ImageSelected(std::make_shared(image)); + break; + } + } + } + } else if (parentItem && (parentItem->text(0) == "Tech Sets")) { + QTreeWidgetItem *grandpaItem = parentItem->parent(); + if (grandpaItem && grandpaItem->text(0).contains(".zone")) { + const QString fileStem = grandpaItem->text(0).section('.', 0, 0); + auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets; + for (auto techset : techsets) { + if (techset.name == selectedText) { + emit TechSetSelected(std::make_shared(techset)); + break; + } + } + } + } +} + +ZoneFile XTreeWidget::pFindZoneFile(const QString aFilePart) { + foreach (auto zoneFile, mZoneFiles) { + if (zoneFile->GetFileStem() == aFilePart) { + return *zoneFile.get(); + } + } + return ZoneFile(); +} + +FastFile XTreeWidget::pFindFastFile(const QString aFilePart) { + foreach (auto fastFile, mFastFiles) { + if (fastFile->GetFileStem() == aFilePart) { + return *fastFile.get(); + } + } + return FastFile(); +} + +void XTreeWidget::AddIWIFile(std::shared_ptr aIWIFile) { + const QString iwiFileName = QString(aIWIFile->fileStem + ".iwi"); + + for (int i = 0; i < invisibleRootItem()->childCount(); i++) { + auto iwiFileItem = invisibleRootItem()->child(i); + if (iwiFileItem->text(0) == iwiFileName) { + delete iwiFileItem; + } + } + + QTreeWidgetItem *iwiItem = new QTreeWidgetItem(this); + iwiItem->setIcon(0, QIcon(":/icons/icons/Icon_IWIFile.png")); + iwiItem->setText(0, iwiFileName); + mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile; +} + +void XTreeWidget::AddDDSFile(std::shared_ptr aDDSFile) { + const QString ddsFileName = QString(aDDSFile->fileStem + ".dds"); + + for (int i = 0; i < invisibleRootItem()->childCount(); i++) { + auto ddsFileItem = invisibleRootItem()->child(i); + if (ddsFileItem->text(0) == ddsFileName) { + delete ddsFileItem; + } + } + + QTreeWidgetItem *ddsItem = new QTreeWidgetItem(this); + ddsItem->setIcon(0, QIcon(":/icons/icons/Icon_DDSFile.png")); + ddsItem->setText(0, ddsFileName); + mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile; +} diff --git a/xtreewidget.h b/xtreewidget.h new file mode 100644 index 0000000..0d49910 --- /dev/null +++ b/xtreewidget.h @@ -0,0 +1,50 @@ +#ifndef XTREEWIDGET_H +#define XTREEWIDGET_H + +#include "d3dbsp_structs.h" +#include "asset_structs.h" +#include "ddsfile.h" +#include "iwifile.h" +#include "fastfile.h" +#include "zonefile.h" + +#include + +class XTreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + explicit XTreeWidget(QWidget *parent = nullptr); + ~XTreeWidget(); + + void AddFastFile(std::shared_ptr aFastFile); + void AddZoneFile(std::shared_ptr aZoneFile, QTreeWidgetItem *aParentItem = nullptr); + void AddIWIFile(std::shared_ptr aIWIFile); + void AddDDSFile(std::shared_ptr aDDSFile); + +signals: + void DDSFileSelected(std::shared_ptr aDDSFile); + void IWIFileSelected(std::shared_ptr aIWIFile); + void FastFileSelected(std::shared_ptr aFastFile); + void ZoneFileSelected(std::shared_ptr aZoneFile); + void LocalStringSelected(std::shared_ptr aZoneFile); + void RawFileSelected(std::shared_ptr aRawFile); + void ImageSelected(std::shared_ptr aImage); + void TechSetSelected(std::shared_ptr aZoneFile); + void MenuSelected(std::shared_ptr aMenu); + +protected: + void ItemSelectionChanged(); + void PrepareContextMenu(const QPoint &pos); + +private: + QMap> mFastFiles; + QMap> mZoneFiles; + QMap> mDDSFiles; + QMap> mIWIFiles; + + ZoneFile pFindZoneFile(const QString aFilePart); + FastFile pFindFastFile(const QString aFilePart); +}; + +#endif // XTREEWIDGET_H diff --git a/zonefile.cpp b/zonefile.cpp new file mode 100644 index 0000000..e423d78 --- /dev/null +++ b/zonefile.cpp @@ -0,0 +1,1089 @@ +#include "zonefile.h" +#include "utils.h" + +#include +#include +#include + +ZoneFile::ZoneFile() : + fileStem(), + size(), + tagCount(), + tags(), + recordCount(), + records(), + assetMap() { + +} + +ZoneFile::~ZoneFile() { + +} + +ZoneFile::ZoneFile(const ZoneFile &aZoneFile) { + fileStem = aZoneFile.fileStem; + size = aZoneFile.size; + tagCount = aZoneFile.tagCount; + tags = aZoneFile.tags; + recordCount = aZoneFile.recordCount; + records = aZoneFile.records; + assetMap = aZoneFile.assetMap; +} + +ZoneFile &ZoneFile::operator=(const ZoneFile &other) { + if (this != &other) { + fileStem = other.fileStem; + size = other.size; + tagCount = other.tagCount; + tags = other.tags; + recordCount = other.recordCount; + records = other.records; + assetMap = other.assetMap; + } + return *this; +} + +bool ZoneFile::Load(const QString aFilePath, FF_PLATFORM platform) { + Q_UNUSED(platform); + + if (aFilePath.isEmpty()) { + return false; + } + + fileStem = aFilePath.split('/').last(); + + // Check zone file can be read + QFile *zoneFileObj = new QFile(aFilePath); + if (!zoneFileObj->open(QIODevice::ReadOnly)) { + qDebug() << QString("Error: %1 could not be read!.").arg(aFilePath); + return false; + } else if (!Load(zoneFileObj->readAll())) { + qDebug() << "Error: Failed to load from zone data"; + return false; + } + + // Clean up zone file + zoneFileObj->close(); + delete zoneFileObj; + + return true; +} + +bool ZoneFile::Load(const QByteArray aFileData, const QString aFileStem, FF_PLATFORM platform) { + // Open zone file as little endian stream + QDataStream zoneFileStream(aFileData); + if (platform == FF_PLATFORM_PC) { + zoneFileStream.setByteOrder(QDataStream::LittleEndian); + } else { + zoneFileStream.setByteOrder(QDataStream::BigEndian); + } + + // Parse data from zone file header + pParseZoneHeader(&zoneFileStream); + fileStem = aFileStem; + records = + pParseZoneIndex(&zoneFileStream, recordCount); + assetMap = + pParseAssets(&zoneFileStream, records); + + return true; +} + +QString ZoneFile::GetFileStem() { + return fileStem; +} + +quint32 ZoneFile::GetSize() { + return size; +} + +quint32 ZoneFile::GetTagCount() { + return tagCount; +} + +QStringList ZoneFile::GetTags() { + return tags; +} + +quint32 ZoneFile::GetRecordCount() { + return recordCount; +} + +QStringList ZoneFile::GetRecords() { + return records; +} + +AssetMap ZoneFile::GetAssetMap() { + return assetMap; +} + +void ZoneFile::pParseZoneHeader(QDataStream *aZoneFileStream) { + size = pParseZoneSize(aZoneFileStream); + pParseZoneUnknownsA(aZoneFileStream); + + tagCount = pParseZoneTagCount(aZoneFileStream); + pParseZoneUnknownsB(aZoneFileStream); + + recordCount = pParseZoneRecordCount(aZoneFileStream); + + if (tagCount) { + pParseZoneUnknownsC(aZoneFileStream); + if (tagCount > 1) { + tags = pParseZoneTags(aZoneFileStream, tagCount); + } + } else { + aZoneFileStream->skipRawData(4); + } +} + +quint32 ZoneFile::pParseZoneSize(QDataStream *aZoneFileStream) { + quint32 zoneFileSize; + *aZoneFileStream >> zoneFileSize; + if (zoneFileSize <= 0) { + qDebug() << "Tried to open empty zone file!"; + exit(-1); + } + zoneFileSize += 36; + return zoneFileSize; +} + +/* + ParseZoneUnknownsA() + + Parses the 1st section of unknowns as hex vals and uint32s +*/ +void ZoneFile::pParseZoneUnknownsA(QDataStream *aZoneFileStream) { + // Byte 4-7, 8-11, 12-15: unknown + QByteArray unknown1(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown1.data(), 4); + + QByteArray unknown2(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown2.data(), 4); + + QByteArray unknown3(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown3.data(), 4); + + // Byte 16-19, 20-23: empty/unknown + QByteArray unknown4(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown4.data(), 4); + + QByteArray unknown5(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown5.data(), 4); + + // Byte 24-27: somehow related to the filesize, but smaller value + QByteArray unknown6(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown6.data(), 4); + + // Byte 28-31, 32-35: unknown + QByteArray unknown7(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown7.data(), 4); + + QByteArray unknown8(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown8.data(), 4); +} + +/* + ParseZoneTagCount() + + Parses the number of string tags in the zone index +*/ +quint32 ZoneFile::pParseZoneTagCount(QDataStream *aZoneFileStream) { + quint32 tagCount; + *aZoneFileStream >> tagCount; + return tagCount; +} + +/* + ParseZoneRecordCount() + + Parses the number of records in the zone index +*/ +quint32 ZoneFile::pParseZoneRecordCount(QDataStream *aZoneFileStream) { + quint32 recordCount; + *aZoneFileStream >> recordCount; + return recordCount; +} + +/* + ParseZoneUnknownsB() + + Parses the 2nd section of unknowns as hex vals and uint32s +*/ +void ZoneFile::pParseZoneUnknownsB(QDataStream *aZoneFileStream) { + // Byte 44-47: Unknown/empty? + QByteArray unknown9(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown9.data(), 4); +} + +/* + pParseZoneUnknownsC() + + Parses the 3rd section of unknowns as hex vals and uint32s +*/ +void ZoneFile::pParseZoneUnknownsC(QDataStream *aZoneFileStream) { + // Byte 40-43: Unknown/empty? + QByteArray unknown10(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown10.data(), 4); + + // Byte 44-47: Unknown/empty? + QByteArray unknown11(4, Qt::Uninitialized); + aZoneFileStream->readRawData(unknown11.data(), 4); +} + +/* + ParseZoneTags() + + Parses the string tags ate the start of zone file +*/ +QStringList ZoneFile::pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount) { + QStringList tags; + + // Byte 48-51: Repeated separators? ÿÿÿÿ x i + aZoneFileStream->skipRawData(4 * (tagCount - 1)); + + // Parse tags/strings before index + QString zoneTag; + char zoneTagChar; + for (quint32 i = 0; i < tagCount; i++) { + *aZoneFileStream >> zoneTagChar; + while (zoneTagChar != 0) { + zoneTag += zoneTagChar; + *aZoneFileStream >> zoneTagChar; + } + tags << zoneTag; + 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; +} + +/* + ParseZoneIndex() + + Parse the binary zone index data and populate table +*/ +QStringList ZoneFile::pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount) { + QStringList result; + + // Don't parse if no records + if (!recordCount) { return result; } + + // Parse index & map found asset types + for (quint32 i = 0; i <= recordCount; i++) { + // Skip record start + QByteArray rawAssetType(4, Qt::Uninitialized); + aZoneFileStream->readRawData(rawAssetType.data(), 4); + result << rawAssetType.toHex(); + + // Skip separator + aZoneFileStream->skipRawData(4); + } + return result; +} + +AssetMap ZoneFile::pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder) { + AssetMap result; + + aZoneFileStream->device()->seek(aZoneFileStream->device()->pos() - 8); + + for (int i = 0; i < assetOrder.size(); i++) { + const QString typeHex = assetOrder[i]; + const QString typeStr = Utils::AssetTypeToString(typeHex); + + if (typeStr == "LOCAL STRING") { // localized string asset + result.localStrings << pParseAsset_LocalString(aZoneFileStream); + } else if (typeStr == "RAW FILE") { // gsc + auto rawFile = pParseAsset_RawFile(aZoneFileStream); + if (rawFile.length) { + result.rawFiles << rawFile; + } + } else if (typeStr == "PHYS PRESET") { // physpreset + pParseAsset_PhysPreset(aZoneFileStream); + } else if (typeStr == "MODEL") { // xmodel + result.models << pParseAsset_Model(aZoneFileStream); + } else if (typeStr == "MATERIAL") { // material + pParseAsset_Material(aZoneFileStream); + } else if (typeStr == "SHADER") { // pixelshader + pParseAsset_Shader(aZoneFileStream); + } else if (typeStr == "TECH SET") { // techset include + result.techSets << pParseAsset_TechSet(aZoneFileStream); + } else if (typeStr == "IMAGE") { // image + result.images << pParseAsset_Image(aZoneFileStream); + } else if (typeStr == "SOUND") { // loaded_sound + pParseAsset_LoadedSound(aZoneFileStream); + } else if (typeStr == "COLLISION MAP") { // col_map_mp + pParseAsset_ColMapMP(aZoneFileStream); + } else if (typeStr == "MP MAP") { // game_map_sp + pParseAsset_GameMapSP(aZoneFileStream); + } else if (typeStr == "SP MAP") { // game_map_mp + pParseAsset_GameMapMP(aZoneFileStream); + } else if (typeStr == "LIGHT DEF") { // lightdef + pParseAsset_LightDef(aZoneFileStream); + } else if (typeStr == "UI MAP") { // ui_map + pParseAsset_UIMap(aZoneFileStream); + } else if (typeStr == "SND DRIVER GLOBALS") { // snddriverglobals + pParseAsset_SNDDriverGlobals(aZoneFileStream); + } else if (typeStr == "AI TYPE") { // aitype + pParseAsset_AIType(aZoneFileStream); + } else if (typeStr == "EFFECT") { // aitype + pParseAsset_FX(aZoneFileStream); + } else if (typeStr == "ANIMATION") { // aitype + result.animations << pParseAsset_Animation(aZoneFileStream); + } else if (typeStr == "STRING TABLE") { // string_table + result.stringTables << pParseAsset_StringTable(aZoneFileStream); + } else if (typeStr == "MENU") { // string_table + result.menuFiles << pParseAsset_MenuFile(aZoneFileStream); + } else if (typeStr == "WEAPON") { // string_table + pParseAsset_Weapon(aZoneFileStream); + } else if (typeStr == "D3DBSP DUMP") { // string_table + pParseAsset_D3DBSP(aZoneFileStream); + } else if (typeStr != "UNKNOWN") { + qDebug() << "Found bad asset type!" << typeStr; + } + } + return result; +} + +LocalString ZoneFile::pParseAsset_LocalString(QDataStream *aZoneFileStream) { + LocalString result; + + quint32 stringPtr, aliasPtr; + *aZoneFileStream >> stringPtr >> aliasPtr; + if (stringPtr == 4294967295) { + // Parse local string asset contents + QString localStr; + char localStrChar; + *aZoneFileStream >> localStrChar; + while (localStrChar != 0) { + result.string += localStrChar; + *aZoneFileStream >> localStrChar; + } + } else { + result.string = "String Ptr: " + QString::number(stringPtr); + } + + if (aliasPtr == 4294967295) { + // Parse rawfile name + QString aliasName; + char aliasNameChar; + *aZoneFileStream >> aliasNameChar; + while (aliasNameChar != 0) { + result.alias += aliasNameChar; + *aZoneFileStream >> aliasNameChar; + } + } else { + result.string = "Alias Ptr: " + QString::number(aliasPtr); + } + + return result; +} + +RawFile ZoneFile::pParseAsset_RawFile(QDataStream *aZoneFileStream) { + RawFile result; + + // Skip start separator FF FF FF FF (pointer?) + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.length; + + // Skip unknown 4 byte data + aZoneFileStream->skipRawData(4); + + // Parse rawfile path + char scriptPathChar; + *aZoneFileStream >> scriptPathChar; + while (scriptPathChar != 0) { + result.path += scriptPathChar; + *aZoneFileStream >> scriptPathChar; + } + result.path.replace(",", ""); + const QStringList pathParts = result.path.split('/'); + if (pathParts.size() == 0) { + qDebug() << "Failed to parse ff path! " << result.path; + exit(-1); + } + + // Parse gsc contents + char rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + while (rawFileContentsChar != 0 && rawFileContentsChar != -1) { + result.contents += rawFileContentsChar; + *aZoneFileStream >> rawFileContentsChar; + } + return result; +} + +void ZoneFile::pParseAsset_PhysPreset(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Model ZoneFile::pParseAsset_Model(QDataStream *aZoneFileStream) { + Model result; + + qDebug() << "Model Info:"; + + *aZoneFileStream >> result.namePtr >> result.tagCount >> result.rootTagCount + >> result.surfCount >> result.unknownCount >> result.boneNamePtr + >> result.parentListPtr >> result.quatsPtr >> result.transPtr + >> result.partClassPtr >> result.baseMatPtr + >> result.surfsPtr >> result.materialHandlesPtr; + + // Parse XModelLodInfo + for (int i = 1; i <= 4; i++) { + qDebug() << "- Lod Info " << i; + + quint32 intDist; + *aZoneFileStream >> intDist; + + std::memcpy(&result.lodInfo[i].dist, &intDist, sizeof(result.lodInfo[i].dist)); + *aZoneFileStream >> result.lodInfo[i].numsurfs >> result.lodInfo[i].surfIndex; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.lodInfo[i].partBits[0] + >> result.lodInfo[i].partBits[1] + >> result.lodInfo[i].partBits[2] + >> result.lodInfo[i].partBits[3]; + } + + *aZoneFileStream >> result.collSurfsPtr >> result.numCollSurfs >> result.contents >> result.boneInfoPtr; + + quint32 intRadius, intMins[3], intMaxs[3]; + *aZoneFileStream >> intRadius >> intMins[0] >> intMins[1] + >> intMins[2] >> intMaxs[0] >> intMaxs[1] >> intMaxs[2]; + + std::memcpy(&result.radius, &intRadius, sizeof(result.radius)); + + std::memcpy(&result.mins[0], &intMins[0], sizeof(result.mins[0])); + std::memcpy(&result.mins[1], &intMins[1], sizeof(result.mins[1])); + std::memcpy(&result.mins[2], &intMins[2], sizeof(result.mins[2])); + + std::memcpy(&result.maxs[0], &intMaxs[0], sizeof(result.maxs[0])); + std::memcpy(&result.maxs[1], &intMaxs[1], sizeof(result.maxs[2])); + std::memcpy(&result.maxs[2], &intMaxs[2], sizeof(result.maxs[3])); + + *aZoneFileStream >> result.numLods >> result.collLod >> result.streamInfoPtr + >> result.memUsage >> result.flags >> result.physPresetPtr >> result.physGeomsPtr; + + // Parse model name + char modelNameChar; + *aZoneFileStream >> modelNameChar; + while (modelNameChar == 0) { + *aZoneFileStream >> modelNameChar; + } + while (modelNameChar != 0) { + result.modelName += modelNameChar; + *aZoneFileStream >> modelNameChar; + } + return result; +} + +void ZoneFile::pParseAsset_Material(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Shader ZoneFile::pParseAsset_Shader(QDataStream *aZoneFileStream) { + Shader result = Shader(); + + quint8 minorVersion, majorVersion; + *aZoneFileStream >> minorVersion >> majorVersion; + + quint32 magic; + *aZoneFileStream >> magic; + + // Verify .fxc magic + if (magic != 65534 && magic != 65535) { return result; } + + SHADER_TYPE type = SHADER_NONE; + quint16 rawShaderType; + *aZoneFileStream >> rawShaderType; + if (rawShaderType == 65535) { // Pixel shader + type = SHADER_PIXEL; + } else if (rawShaderType == 65534) { // Vertex shader + type = SHADER_VERTEX; + } + Q_UNUSED(type); + + while (true) { + quint32 instructionToken; + *aZoneFileStream >> instructionToken; + + SHADER_OPCODE opCode = (SHADER_OPCODE)(instructionToken & 0xffff); + + int size; + if (opCode == OPCODE_End) { + break; + } else if (opCode == OPCODE_Comment) { + size = (int)((instructionToken >> 16) & 0x7FFF); + } else { + size = (int)((instructionToken >> 24) & 0x0f); + } + Q_UNUSED(size); + } + + + 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(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(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 result; + + for (int i = 1; i <= 62; i++) { + quint32 ptr; + *aZoneFileStream >> ptr; + + result.pointers << ptr; + } + qDebug() << aZoneFileStream->device()->pos(); + + // Parse techset name + char techSetNameChar; + *aZoneFileStream >> techSetNameChar; + while (techSetNameChar != 0) { + result.name += techSetNameChar; + *aZoneFileStream >> techSetNameChar; + } + result.name.replace(",", ""); + + return result; +} + +Image ZoneFile::pParseAsset_Image(QDataStream *aZoneFileStream) { + Image result; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknowna >> result.unknownb + >> result.unknownc >> result.unknownd + >> result.unknowne >> result.unknownf + >> result.unknowng; + + aZoneFileStream->skipRawData(15 * 4); + *aZoneFileStream >> result.unknownh >> result.unknowni; + + aZoneFileStream->skipRawData(4); + *aZoneFileStream >> result.unknownj; + + aZoneFileStream->skipRawData(4); + + char materialNameChar; + *aZoneFileStream >> materialNameChar; + while (materialNameChar != 0) { + result.materialName += materialNameChar; + *aZoneFileStream >> materialNameChar; + } + result.materialName.replace(",", ""); + + if (result.unknowna) { + *aZoneFileStream >> result.unknownk; + *aZoneFileStream >> result.unknownl; + *aZoneFileStream >> result.unknownm; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown1; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream >> result.unknown2 >> result.unknown3 + >> result.size1 >> result.size2 + >> result.unknown4 >> result.unknown5; + + aZoneFileStream->skipRawData(4); + + char imageNameChar; + *aZoneFileStream >> imageNameChar; + while (imageNameChar != 0) { + result.name += imageNameChar; + *aZoneFileStream >> imageNameChar; + } + + *aZoneFileStream >> result.unknown6 >> result.unknown7; + + QByteArray compressionData(8, Qt::Uninitialized); + aZoneFileStream->readRawData(compressionData.data(), 8); + if (compressionData.contains("DXT1")) { + result.compression = COMPRESSION_DXT1; + } else if (compressionData.contains("DXT3")) { + result.compression = COMPRESSION_DXT3; + } else if (compressionData.contains("DXT5")) { + result.compression = COMPRESSION_DXT5; + } else { + result.compression = COMPRESSION_NONE; + } + + *aZoneFileStream >> result.unknown8 >> result.unknown9; + } + + return result; +} + +void ZoneFile::pParseAsset_LoadedSound(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_ColMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_GameMapSP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_GameMapMP(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_LightDef(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_UIMap(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_AIType(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_FX(QDataStream *aZoneFileStream) { + Q_UNUSED(aZoneFileStream); +} + +Animation ZoneFile::pParseAsset_Animation(QDataStream *aZoneFileStream) { + Animation result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.dataByteCount + >> result.dataShortCount + >> result.dataIntCount + >> result.randomDataByteCount + >> result.randomDataIntCount + >> result.numframes + >> result.isLooped + >> result.isDelta + >> result.noneRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.twoDRotatedBoneCount + >> result.normalRotatedBoneCount + >> result.normalTranslatedBoneCount + >> result.preciseTranslatedBoneCount + >> result.staticTranslatedBoneCount + >> result.noneTranslatedBoneCount + >> result.totalBoneCount + >> result.otherBoneCount1 + >> result.otherBoneCount2 + >> result.notifyCount + >> result.assetType + >> result.pad + >> result.randomDataShortCount + >> result.indexCount + >> result.frameRate + >> result.frequency + >> result.boneIDsPtr + >> result.dataBytePtr + >> result.dataShortPtr + >> result.dataIntPtr + >> result.randomDataShortPtr + >> result.randomDataBytePtr + >> result.randomDataIntPtr + >> result.longIndiciesPtr + >> result.notificationsPtr + >> result.deltaPartsPtr; + + // Read in x_anim file name + QString xAnimName; + char xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + while (xAnimNameChar != 0) { + result.name += xAnimNameChar; + *aZoneFileStream >> xAnimNameChar; + } + + // Parse x_anim index header + QVector sectionLengths; + for (int i = 0; i < result.numframes; i++) { + quint8 sectionlength; + *aZoneFileStream >> sectionlength; + sectionLengths.push_back(sectionlength); + // Skip padding + aZoneFileStream->skipRawData(1); + } + // Skip unknown section + aZoneFileStream->skipRawData(2 * 8); + + return result; +} + +MenuFile ZoneFile::pParseAsset_MenuFile(QDataStream *aZoneFileStream) { + //MENU_FILE + MenuFile result; + + aZoneFileStream->skipRawData(4); // Separator + + // Parse menu def count + *aZoneFileStream >> result.menuCount; + + // Clearly misparsed, never have this much + if (result.menuCount > 1000) { + qDebug() << "Failure reported when parsing menu file."; + return result; + } + for (uint i = 0; i < result.menuCount; i++) { + Menu menu; + + aZoneFileStream->skipRawData(4); // Separator + + // Read in x_anim file name + char menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + while (menuFilepathChar != 0) { + menu.filePath += menuFilepathChar; + *aZoneFileStream >> menuFilepathChar; + } + aZoneFileStream->skipRawData(4); // Separator + + *aZoneFileStream >> menu.menuNamePtr; + + float menuRectX, menuRectY, menuRectWidth, menuRectHeight; + *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; + menu.rect = QRectF(menuRectX, menuRectY, menuRectWidth, menuRectHeight); + + quint32 hAlignInt, vAlignInt; + *aZoneFileStream >> hAlignInt >> vAlignInt; + menu.hAlign = (MENU_H_ALIGNMENT)hAlignInt; + menu.vAlign = (MENU_V_ALIGNMENT)vAlignInt; + + float rectClientX, rectClientY, rectClientWidth, rectClientHeight; + *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; + menu.clientRect = QRectF(rectClientX, rectClientY, rectClientWidth, rectClientHeight); + + quint32 hClientAlignInt, vClientAlignInt, styleInt, borderInt; + *aZoneFileStream >> hClientAlignInt >> vClientAlignInt >> menu.groupPtr + >> styleInt >> borderInt >> menu.ownerDraw >> menu.ownerDrawFlags + >> menu.borderSize >> menu.staticFlags >> menu.dynamicFlags >> menu.nextTime; + menu.hClientAlign = (MENU_H_ALIGNMENT)hClientAlignInt; + menu.vClientAlign = (MENU_V_ALIGNMENT)vClientAlignInt; + menu.style = (MENU_WINDOW_STYLE)styleInt; + menu.border = (MENU_WINDOW_BORDER)borderInt; + + float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, + backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, + borderColorR, borderColorG, borderColorB, borderColorA, + outlineColorR, outlineColorG, outlineColorB, outlineColorA; + *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA + >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA + >> borderColorR >> borderColorG >> borderColorB >> borderColorA + >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; + + menu.foregroundColor = QColor(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA); + menu.backgroundColor = QColor(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA); + menu.borderColor = QColor(borderColorR, borderColorG, borderColorB, borderColorA); + menu.outlineColor = QColor(outlineColorR, outlineColorG, outlineColorB, outlineColorA); + + *aZoneFileStream >> menu.materialPtr >> menu.fontPtr >> menu.fullScreen >> menu.itemCount + >> menu.fontIndex >> menu.cursorItem >> menu.fadeCycle >> menu.fadeClamp + >> menu.fadeAmount >> menu.fadeInAmount >> menu.blurRadius >> menu.onOpenPtr + >> menu.onFocusPtr >> menu.onClosePtr >> menu.onESCPtr >> menu.onKeyPtr + >> menu.visibleExpCount >> menu.expEntryPtr >> menu.allowedBindingPtr + >> menu.soundNamePtr >> menu.imageTrack; + + float focusColorR, focusColorG, focusColorB, focusColorA, + disabledColorR, disabledColorG, disabledColorB, disabledColorA; + *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA + >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; + menu.focusColor = QColor(focusColorR, focusColorG, focusColorB, focusColorA); + menu.disabledColor = QColor(disabledColorR, disabledColorG, disabledColorB, disabledColorA); + + *aZoneFileStream >> menu.rectXExpCount >> menu.rectXExpPtr >> menu.rectYExpCount >> menu.rectYExpPtr; + + aZoneFileStream->skipRawData(4); // Separator + + char menuDefNameChar; + int menuDefNameLen = 0; + *aZoneFileStream >> menuDefNameChar; + while (menuDefNameChar != 0 && menuDefNameLen < 30) { + menuDefNameLen++; + menu.name += menuDefNameChar; + *aZoneFileStream >> menuDefNameChar; + } + + char defStringChar; + int defStringLen = 0; + *aZoneFileStream >> defStringChar; + while (defStringChar != 0 && defStringLen < 30) { + defStringLen++; + menu.definition += defStringChar; + *aZoneFileStream >> defStringChar; + } + aZoneFileStream->skipRawData(4 * 10); + + *aZoneFileStream >> menu.itemWindowDefNamePtr; + + float itemRectX, itemRectY, itemRectWidth, itemRectHeight; + *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; + menu.itemRect = QRectF(itemRectX, itemRectY, itemRectWidth, itemRectHeight); + + *aZoneFileStream >> menu.itemHAlignment >> menu.itemVAlignment >> menu.itemGroupPtr + >> menu.itemWindowStyle >> menu.itemWindowBorder >> menu.itemOwnerDraw + >> menu.itemOwnerDrawFlags >> menu.itemBorderSize >> menu.itemStaticFlags + >> menu.itemDynamicFlags >> menu.itemNextTime; + + float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, + itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, + itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, + itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; + *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA + >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA + >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA + >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; + + menu.itemForegroundColor = QColor(itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA); + menu.itemBackgroundColor = QColor(itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA); + menu.itemBorderColor = QColor(itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA); + menu.itemOutlineColor = QColor(itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA); + + *aZoneFileStream >> menu.itemMaterialPtr; + + float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; + *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; + menu.itemTextRect = QRectF(itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight); + + quint32 hItemTextAlignInt, vItemTextAlignInt, itemType, fontTypeInt, textStyleInt; + *aZoneFileStream >> hItemTextAlignInt >> vItemTextAlignInt >> itemType >> menu.dataType + >> menu.alignment >> fontTypeInt >> menu.textAlignMode >> menu.textalignx >> menu.textaligny + >> menu.textscale >> textStyleInt >> menu.gameMsgWindowIndex >> menu.gameMsgWindowMode + >> menu.testPtr >> menu.textSavegameInfo >> menu.parentPtr; + menu.itemText_hAlign = (MENU_H_ALIGNMENT)hItemTextAlignInt; + menu.itemText_vAlign = (MENU_V_ALIGNMENT)vItemTextAlignInt; + menu.itemType = (MENU_ITEM_TYPE)itemType; + menu.fontEnum = (MENU_FONT_TYPE)fontTypeInt; + menu.textStyle = (MENU_ITEM_TEXTSTYLE)textStyleInt; + + *aZoneFileStream >> menu.mouseEnterText >> menu.mouseExitText >> menu.mouseEnter >> menu.mouseExit + >> menu.action >> menu.onAccept >> menu.onFocus >> menu.leaveFocus >> menu.dvar >> menu.dvarTest + >> menu.keyHandlerPtr >> menu.enableDvarPtr >> menu.dvarFlags >> menu.focusSoundPtr + >> menu.special >> menu.cursorPos; + + // itemDefData_t typeData; + + // listBoxDef_s *listBox; + + *aZoneFileStream >> menu.startPos >> menu.endPos >> menu.drawPadding; + + *aZoneFileStream >> menu.elementWidth >> menu.elementHeight; + + *aZoneFileStream >> menu.elementStyle >> menu.numColumns; + + //columnInfo_s columnInfo[16]; + + *aZoneFileStream >> menu.doubleClickPtr; + + + *aZoneFileStream >> menu.notselectable >> menu.noScrollBars >> menu.usePaging; + + float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, + itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, + itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA; + *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA + >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA + >> itemFocusColorR >> itemFocusColorG >> itemFocusColorB >> itemFocusColorA; + menu.itemSelectBorderColor = QColor(itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA); + menu.itemDisableColor = QColor(itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA); + menu.itemFocusColor = QColor(itemFocusColorR, itemFocusColorG, itemFocusColorB, itemFocusColorA); + + *aZoneFileStream >> menu.selectIconPtr >> menu.backgroundItemListboxPtr >> menu.highlightTexturePtr; + + // editFieldDef_s *editField; + + *aZoneFileStream >> menu.minVal >> menu.maxVal >> menu.defVal >> menu.range >> menu.maxChars + >> menu.maxCharsGotoNext >> menu.maxPaintChars >> menu.paintOffset; + + // multiDef_s *multi; + + for (int i = 0; i < 32; i++) { + quint32 dvarList; + *aZoneFileStream >> dvarList; + menu.dvarListPtrs.push_back(dvarList); + } + + for (int i = 0; i < 32; i++) { + quint32 dvarStr; + *aZoneFileStream >> dvarStr; + menu.dvarStrPtrs.push_back(dvarStr); + } + + for (int i = 0; i < 32; i++) { + float dvarValue; + *aZoneFileStream >> dvarValue; + menu.dvarValues.push_back(dvarValue); + } + + *aZoneFileStream >> menu.count >> menu.strDef >> menu.enumDvarNamePtr; + aZoneFileStream->skipRawData(4); + //>> menu.dataPtr + *aZoneFileStream >> menu.itemImageTrack; + + qDebug() << aZoneFileStream->device()->pos(); + + //statement_s visibleExp; + //statement_s textExp; + //statement_s materialExp; + //statement_s rectXExp; + //statement_s rectYExp; + //statement_s rectWExp; + //statement_s rectHExp; + //statement_s foreColorAExp; + result.menuDefs << menu; + } + return result; +} + +void ZoneFile::pParseAsset_Weapon(QDataStream *aZoneFileStream) { + //WEAPON_FILE + Q_UNUSED(aZoneFileStream); +} + +void ZoneFile::pParseAsset_D3DBSP(QDataStream *aZoneFileStream) { + //D3DBSP_DUMP + Q_UNUSED(aZoneFileStream); +} + +StringTable ZoneFile::pParseAsset_StringTable(QDataStream *aZoneFileStream) { + StringTable result; + + aZoneFileStream->skipRawData(4); + + *aZoneFileStream + >> result.columnCount + >> result.rowCount; + + // Todo fix this + result.columnCount = 0; + result.rowCount = 0; + + aZoneFileStream->skipRawData(4); + + QString stringTableName; + char stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + while (stringTableNameChar != 0) { + result.name += stringTableNameChar; + *aZoneFileStream >> stringTableNameChar; + } + + QVector tablePointers = QVector(); + for (quint32 i = 0; i < result.rowCount; i++) { + QByteArray pointerData(4, Qt::Uninitialized); + aZoneFileStream->readRawData(pointerData.data(), 4); + tablePointers.push_back(pointerData.toHex()); + + aZoneFileStream->skipRawData(4); + } + + for (const QString &pointerAddr : tablePointers) { + QString leadingContent = ""; + if (pointerAddr == "FFFFFFFF") { + char leadingContentChar; + *aZoneFileStream >> leadingContentChar; + while (leadingContentChar != 0) { + leadingContent += leadingContentChar; + *aZoneFileStream >> leadingContentChar; + } + } else { + leadingContent = pointerAddr; + } + + QString content; + char contentChar; + *aZoneFileStream >> contentChar; + while (contentChar != 0) { + content += contentChar; + *aZoneFileStream >> contentChar; + } + QPair tableEntry = QPair(); + tableEntry.first = leadingContent; + tableEntry.second = content; + //if (!mStrTableMap.contains(stringTableName)) { + // mStrTableMap[stringTableName] = QVector>(); + //} + //mStrTableMap[stringTableName].push_back(tableEntry); + } + return result; +} diff --git a/zonefile.h b/zonefile.h new file mode 100644 index 0000000..93d8cb7 --- /dev/null +++ b/zonefile.h @@ -0,0 +1,75 @@ +#ifndef ZONEFILE_H +#define ZONEFILE_H + +#include "asset_structs.h" + +#include + +class ZoneFile +{ +public: + ZoneFile(); + ~ZoneFile(); + ZoneFile(const ZoneFile &aZoneFile); + ZoneFile &operator=(const ZoneFile &other); + + 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); + + QString GetFileStem(); + quint32 GetSize(); + quint32 GetTagCount(); + QStringList GetTags(); + quint32 GetRecordCount(); + QStringList GetRecords(); + AssetMap GetAssetMap(); + +private slots: + void pParseZoneHeader(QDataStream *aZoneFileStream); + quint32 pParseZoneSize(QDataStream *aZoneFileStream); + void pParseZoneUnknownsA(QDataStream *aZoneFileStream); + quint32 pParseZoneTagCount(QDataStream *aZoneFileStream); + quint32 pParseZoneRecordCount(QDataStream *aZoneFileStream); + void pParseZoneUnknownsB(QDataStream *aZoneFileStream); + void pParseZoneUnknownsC(QDataStream *aZoneFileStream); + QStringList pParseZoneTags(QDataStream *aZoneFileStream, quint32 tagCount); + QStringList pParseZoneIndex(QDataStream *aZoneFileStream, quint32 recordCount); + AssetMap pParseAssets(QDataStream *aZoneFileStream, QStringList assetOrder); + LocalString pParseAsset_LocalString(QDataStream *aZoneFileStream); + RawFile pParseAsset_RawFile(QDataStream *aZoneFileStream); + void pParseAsset_PhysPreset(QDataStream *aZoneFileStream); + Model pParseAsset_Model(QDataStream *aZoneFileStream); + void pParseAsset_Material(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); + Image pParseAsset_Image(QDataStream *aZoneFileStream); + void pParseAsset_LoadedSound(QDataStream *aZoneFileStream); + void pParseAsset_ColMapMP(QDataStream *aZoneFileStream); + void pParseAsset_GameMapSP(QDataStream *aZoneFileStream); + void pParseAsset_GameMapMP(QDataStream *aZoneFileStream); + void pParseAsset_LightDef(QDataStream *aZoneFileStream); + void pParseAsset_UIMap(QDataStream *aZoneFileStream); + void pParseAsset_SNDDriverGlobals(QDataStream *aZoneFileStream); + void pParseAsset_AIType(QDataStream *aZoneFileStream); + void pParseAsset_FX(QDataStream *aZoneFileStream); + Animation pParseAsset_Animation(QDataStream *aZoneFileStream); + MenuFile pParseAsset_MenuFile(QDataStream *aZoneFileStream); + void pParseAsset_Weapon(QDataStream *aZoneFileStream); + void pParseAsset_D3DBSP(QDataStream *aZoneFileStream); + StringTable pParseAsset_StringTable(QDataStream *aZoneFileStream); + +private: + QString fileStem; + quint32 size; + quint32 tagCount; + QStringList tags; + quint32 recordCount; + QStringList records; + AssetMap assetMap; + QString platform; + QString game; +}; + +#endif // ZONEFILE_H diff --git a/zonefileviewer.cpp b/zonefileviewer.cpp new file mode 100644 index 0000000..c02a10c --- /dev/null +++ b/zonefileviewer.cpp @@ -0,0 +1,111 @@ +#include "zonefileviewer.h" +#include "ui_zonefileviewer.h" + +ZoneFileViewer::ZoneFileViewer(QWidget *parent) + : QWidget(parent) + , ui(new Ui::ZoneFileViewer) +{ + ui->setupUi(this); + + aZoneFile = nullptr; + + ui->tableWidget_RecordCounts->setColumnCount(2); + ui->tableWidget_RecordCounts->setHorizontalHeaderLabels({ "Asset", "Count" }); + ui->tableWidget_RecordCounts->horizontalHeader()->setStretchLastSection(true); + + ui->tableWidget_RecordOrder->setColumnCount(2); + ui->tableWidget_RecordOrder->setHorizontalHeaderLabels({ "Asset", "Count" }); + ui->tableWidget_RecordOrder->horizontalHeader()->setStretchLastSection(true); +} + +ZoneFileViewer::~ZoneFileViewer() +{ + delete ui; +} + +void ZoneFileViewer::SetZoneFile(std::shared_ptr aZoneFile) { + ui->tableWidget_RecordCounts->clear(); + ui->listWidget_Tags->clear(); + + const QStringList tags = aZoneFile->GetTags(); + ui->listWidget_Tags->addItems(tags); + ui->label_Title->setText(aZoneFile->GetFileStem()); + + if (tags.isEmpty()) { + ui->groupBox_Tags->hide(); + } else { + ui->groupBox_Tags->show(); + } + + QString lastAsset = ""; + int consecutiveCount = 1; + int consecutiveIndex = 0; + const QStringList records = aZoneFile->GetRecords(); + QMap recordCounts = QMap(); + for (const QString &record : records) { + if (record == "ffffffff") { break; } + if (!recordCounts.contains(record)) { + recordCounts[record] = 0; + } + recordCounts[record]++; + + QString assetType = Utils::AssetTypeToString(record); + if (lastAsset.isEmpty()) { + lastAsset = assetType; + } else if (lastAsset == assetType) { + consecutiveCount++; + } else { + ui->tableWidget_RecordOrder->setRowCount(consecutiveIndex + 1); + + QTableWidgetItem *recordStrItem = new QTableWidgetItem(lastAsset); + QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(consecutiveCount)); + + ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 0, recordStrItem); + ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 1, recordCountItem); + + consecutiveCount = 1; + consecutiveIndex++; + lastAsset = assetType; + } + } + ui->tableWidget_RecordOrder->setRowCount(consecutiveIndex + 1); + + QTableWidgetItem *recordStrItem = new QTableWidgetItem(lastAsset); + QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(consecutiveCount)); + + ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 0, recordStrItem); + ui->tableWidget_RecordOrder->setItem(consecutiveIndex, 1, recordCountItem); + + int recordIndex = 0; + for (const QString &record : recordCounts.keys()) { + int recordCount = recordCounts[record]; + QString assetType = Utils::AssetTypeToString(record); + + ui->tableWidget_RecordCounts->setRowCount(recordIndex + 1); + + QTableWidgetItem *recordCountStrItem = new QTableWidgetItem(assetType); + QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(recordCount)); + + ui->tableWidget_RecordCounts->setItem(recordIndex, 0, recordCountStrItem); + ui->tableWidget_RecordCounts->setItem(recordIndex, 1, recordCountItem); + + recordIndex++; + } + + auto assetMap = aZoneFile->GetAssetMap(); + for (LocalString localString : assetMap.localStrings) { + } + for (RawFile rawFile : assetMap.rawFiles) { + } + for (TechSet techSet : assetMap.techSets) { + } + for (Image image : assetMap.images) { + } + for (Animation animation : assetMap.animations) { + } + for (StringTable stringTable : assetMap.stringTables) { + } + for (MenuFile menuFile : assetMap.menuFiles) { + } + +} diff --git a/zonefileviewer.h b/zonefileviewer.h new file mode 100644 index 0000000..e335d2c --- /dev/null +++ b/zonefileviewer.h @@ -0,0 +1,27 @@ +#ifndef ZONEFILEVIEWER_H +#define ZONEFILEVIEWER_H + +#include "zonefile.h" +#include "utils.h" + +#include + +namespace Ui { +class ZoneFileViewer; +} + +class ZoneFileViewer : public QWidget +{ + Q_OBJECT + +public: + explicit ZoneFileViewer(QWidget *parent = nullptr); + ~ZoneFileViewer(); + + void SetZoneFile(std::shared_ptr aZoneFile); +private: + Ui::ZoneFileViewer *ui; + std::shared_ptr aZoneFile; +}; + +#endif // ZONEFILEVIEWER_H diff --git a/zonefileviewer.ui b/zonefileviewer.ui new file mode 100644 index 0000000..dbc14ad --- /dev/null +++ b/zonefileviewer.ui @@ -0,0 +1,140 @@ + + + ZoneFileViewer + + + + 0 + 0 + 942 + 445 + + + + + 942 + 445 + + + + Form + + + + + + + Roboto + 16 + true + + + + ZoneFile 0 + + + + + + + + + + + + 225 + 0 + + + + + Roboto + 9 + + + + Tags + + + + + + + + Search: + + + + + + + Search tags... + + + + + + + + + + + + + + + + 179 + 0 + + + + Record Counts + + + + + + + + + + + + + 179 + 0 + + + + Record Order + + + + + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + +