From 8a03c2b6a34e34aa566827df02c8153c1c76558c Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Thu, 14 May 2015 13:11:12 +0200 Subject: [PATCH] Fix materials and add image export. --- t5exp/T5.cpp | 56 +++++++++++++++++++++++++++++++++- t5exp/T5.h | 32 ++++++++++++++++++++ t5exp/XModelExport.cpp | 69 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 155 insertions(+), 2 deletions(-) diff --git a/t5exp/T5.cpp b/t5exp/T5.cpp index 6c1a86e..7833e45 100644 --- a/t5exp/T5.cpp +++ b/t5exp/T5.cpp @@ -3,4 +3,58 @@ Com_Printf_t Com_Printf = (Com_Printf_t)0x4126C0; DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x493A60; DB_LoadXAssets_t DB_LoadXAssets = (DB_LoadXAssets_t)0x4359A0; -SL_ConvertToString_t SL_ConvertToString = (SL_ConvertToString_t)0x624C70; \ No newline at end of file +FS_ReadFile_t FS_ReadFile = (FS_ReadFile_t)0x4BEDA0; +FS_FreeFile_t FS_FreeFile = (FS_FreeFile_t)0x4B54D0; +SL_ConvertToString_t SL_ConvertToString = (SL_ConvertToString_t)0x624C70; + +unsigned int R_HashString(const char* string) +{ + unsigned int hash = 0; + + while (*string) + { + hash = (*string | 0x20) ^ (33 * hash); + string++; + } + + return hash; +} + +#define VA_BUFFER_COUNT 4 +#define VA_BUFFER_SIZE 32768 + +static char vaBuffer[VA_BUFFER_COUNT][VA_BUFFER_SIZE]; +static int vaNextBufferIndex = 0; +static CRITICAL_SECTION ThreadSafe; +static bool Initialized = false; + +const char *va(const char *fmt, ...) +{ + va_list AP; + size_t Length = 0; + char *Destination = nullptr; + + if (!Initialized) + { + InitializeCriticalSection(&ThreadSafe); + Initialized = true; + } + + EnterCriticalSection(&ThreadSafe); + Destination = &vaBuffer[vaNextBufferIndex][0]; + vaNextBufferIndex = (vaNextBufferIndex + 1) % VA_BUFFER_COUNT; + + va_start(AP, fmt); + Length = _vsnprintf_s(Destination, VA_BUFFER_SIZE, _TRUNCATE, fmt, AP); + Destination[VA_BUFFER_SIZE - 1] = '\0'; + va_end(AP); + + if (Length < 0 || Length >= VA_BUFFER_SIZE) + { + // This is pretty bad. + MessageBoxA(NULL, "Attempted to overrun string in call to va()", "ZoneTool", NULL); + } + + LeaveCriticalSection(&ThreadSafe); + return Destination; +} \ No newline at end of file diff --git a/t5exp/T5.h b/t5exp/T5.h index 0b4ccce..18897c9 100644 --- a/t5exp/T5.h +++ b/t5exp/T5.h @@ -340,6 +340,29 @@ struct GfxStateBits unsigned int loadBits[2]; }; +struct GfxImageFileHeader +{ + char tag[3]; + char version; + char format; + char flags; + __int16 dimensions[3]; + float gamma; + int fileSizeForPicmip[8]; +}; + +struct GfxImageFileHeader_T6 +{ + char tag[3]; + char version; + char format; + char flags; + __int16 dimensions[3]; + float gamma; + char maxGlossForMip[16]; + int fileSizeForPicmip[8]; +}; + struct Material { MaterialInfo info; @@ -654,5 +677,14 @@ extern DB_FindXAssetHeader_t DB_FindXAssetHeader; typedef void(__cdecl * DB_LoadXAssets_t)(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); extern DB_LoadXAssets_t DB_LoadXAssets; +typedef int(__cdecl * FS_ReadFile_t)(const char *qpath, void **buffer); +extern FS_ReadFile_t FS_ReadFile; + +typedef void(__cdecl * FS_FreeFile_t)(void *buffer); +extern FS_FreeFile_t FS_FreeFile; + typedef const char *(__cdecl * SL_ConvertToString_t)(unsigned int stringValue, scriptInstance_t inst); extern SL_ConvertToString_t SL_ConvertToString; + +unsigned int R_HashString(const char* string); +const char *va(const char *fmt, ...); \ No newline at end of file diff --git a/t5exp/XModelExport.cpp b/t5exp/XModelExport.cpp index a4b6739..4e1738a 100644 --- a/t5exp/XModelExport.cpp +++ b/t5exp/XModelExport.cpp @@ -15,6 +15,63 @@ void fwritestr(FILE* file, const char* str) //fwrite(str, 1, 1, file); } +void Image_Export(GfxImage* image) +{ + _mkdir("raw"); + _mkdir("raw/images"); + + std::string _name = "images/"; + _name += image->name; + _name += ".iwi"; + + char* buffer; + int size = FS_ReadFile(_name.c_str(), (void**)&buffer); + + if (size) + { + _name = "raw/" + _name; + FILE* fp = fopen(_name.c_str(), "wb"); + + if (fp) + { + GfxImageFileHeader_T6 newHeader = { 0 }; + GfxImageFileHeader* header = (GfxImageFileHeader*)buffer; + memcpy(&newHeader, header, 16); + memcpy(newHeader.fileSizeForPicmip, header->fileSizeForPicmip, sizeof(newHeader.fileSizeForPicmip)); + + // Fix sizes + for (int i = 0; i < 8; i++) + { + int* size = &newHeader.fileSizeForPicmip[i]; + + if (*size) + { + *size -= sizeof(GfxImageFileHeader); + *size += sizeof(GfxImageFileHeader_T6); + } + } + + newHeader.version = 27; + + fwrite(&newHeader, sizeof(GfxImageFileHeader_T6), 1, fp); + fwrite(buffer + sizeof(GfxImageFileHeader), size - sizeof(GfxImageFileHeader), 1, fp); + + fclose(fp); + Com_Printf(0, "File '%s' written\n", _name.c_str()); + } + else + { + Com_Printf(0, "Unable to write file '%s'\n", _name.c_str()); + } + + FS_FreeFile(buffer); + } + else + { + Com_Printf(0, "Unable to read file '%s'\n", _name.c_str()); + } +} + void Write_TextureMaps(Material* material, FILE* fp, const char* map) { char first = *map; @@ -23,11 +80,13 @@ void Write_TextureMaps(Material* material, FILE* fp, const char* map) int count = -1; for (char i = 0; i < material->textureCount; i++) { - if (material->textureTable[i].nameStart == first && material->textureTable[i].nameEnd == last) + if (material->textureTable[i].nameStart == first && R_HashString(map) == material->textureTable[i].nameHash) { count++; fwritestr(fp, map); fwritestr(fp, " "); + fwritestr(fp, va("%d", count)); + fwritestr(fp, " "); fwritestr(fp, material->textureTable[i].u.image->name); fwritestr(fp, "\n"); } @@ -53,8 +112,16 @@ void Material_Export(Material* material) Write_TextureMaps(material, fp, "normalMap"); Write_TextureMaps(material, fp, "specularMap"); Write_TextureMaps(material, fp, "detailMap"); + Write_TextureMaps(material, fp, "colorTint"); + + fclose(fp); Com_Printf(0, "File '%s' written\n", _name.c_str()); + + for (int i = 0; i < material->textureCount; i++) + { + Image_Export(material->textureTable[i].u.image); + } } else {