Skip to content

Commit

Permalink
Texture replacement cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-fadely committed Jan 3, 2016
1 parent a1d8b18 commit b6b27f6
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 41 deletions.
76 changes: 42 additions & 34 deletions SADXModLoader/TextureReplacement.cpp
Expand Up @@ -24,8 +24,8 @@ extern FileMap sadx_fileMap;
bool forceMipmaps = false;

DataPointer(bool, LoadingFile, 0x3ABDF68);
FunctionPointer(NJS_TEXMEMLIST*, GetGlobalTexture, (int gbix), 0x0077F5B0);
FunctionPointer(void, UnloadTextures, (NJS_TEXNAME** texName_pp), 0x00403290);
FunctionPointer(NJS_TEXMEMLIST*, GetCachedTexture, (int gbix), 0x0077F5B0);
FunctionPointer(Sint32, njReleaseTexture, (NJS_TEXLIST* texlist), 0x00403290);

#define TOMAPSTRING(a) { a, #a }

Expand Down Expand Up @@ -79,6 +79,13 @@ std::vector<std::wstring> TexturePackPaths;
std::unordered_map<std::wstring, vector<CustomTextureEntry>> entryCache;
static bool wasLoading = false;

void InitTextureReplacement()
{
WriteJump((void*)0x004210A0, LoadPVM_C);
WriteJump((void*)0x0077FC80, LoadPVRFile);
WriteJump((void*)0x004228E0, LoadPVR_wrapper);
}

#pragma region Index Parsing

/// <summary>
Expand Down Expand Up @@ -245,10 +252,10 @@ bool GetDDSHeader(const wstring& path, DDS_HEADER& header)
NJS_TEXMEMLIST* LoadTexture(const std::wstring& _path, uint32_t globalIndex, const std::string& name)
{
wstring path = _path + L"\\" + wstring(name.begin(), name.end());
NJS_TEXMEMLIST* texture = GetGlobalTexture(globalIndex);
NJS_TEXMEMLIST* texture = GetCachedTexture(globalIndex);

// GetGlobalTexture will only return null if over 2048 unique textures have been loaded.
// TODO: Add custom texture overflow vector with an access function similar to GetGlobalTexture.
// GetCachedTexture will only return null if over 2048 unique textures have been loaded.
// TODO: Add custom texture overflow vector with an access function similar to GetCachedTexture.
if (texture == nullptr)
{
PrintDebug("Failed to allocate global texture for gbix %u (likely exceeded max global texture limit)\n", globalIndex);
Expand Down Expand Up @@ -315,50 +322,50 @@ NJS_TEXMEMLIST* LoadTexture(const std::wstring& _path, CustomTextureEntry& entry

#pragma region PVM

FunctionPointer(Sint32, njLoadTexturePvmFile, (const char*, NJS_TEXLIST*), 0x0077FEB0);

/// <summary>
/// Replaces the specified PVM with a texture pack virtual PVM.
/// </summary>
/// <param name="pvmName">Name of the PVM without extension.</param>
/// <param name="texList">The tex list.</param>
/// <param name="filename">Name of the PVM without extension.</param>
/// <param name="texlist">The tex list.</param>
/// <returns><c>true</c> on success.</returns>
bool ReplacePVM(const std::wstring& pvmName, NJS_TEXLIST* texList)
bool ReplacePVM(const std::wstring& filename, NJS_TEXLIST* texlist)
{
if (texList == nullptr)
if (texlist == nullptr)
return false;

string pvmName_a(pvmName.begin(), pvmName.end());
string filename_a(filename.begin(), filename.end());

vector<CustomTextureEntry> customEntries;

if (!ParseIndex(pvmName + L'\\', customEntries))
if (!ParseIndex(filename + L'\\', customEntries))
return false;

texList->nbTexture = customEntries.size();
texlist->nbTexture = customEntries.size();
bool result = true;

for (uint32_t i = 0; i < texList->nbTexture; i++)
for (uint32_t i = 0; i < texlist->nbTexture; i++)
{
NJS_TEXMEMLIST* texture = LoadTexture(pvmName, customEntries[i]);;
NJS_TEXMEMLIST* texture = LoadTexture(filename, customEntries[i]);;

// I would just break here, but unloading the textures after that causes issues.
// TODO: Investigate that further. This is wasteful.
if (texture == nullptr && result)
result = false;

texList->textures[i].texaddr = (Uint32)texture;
texlist->textures[i].texaddr = (Uint32)texture;
}

if (!result)
UnloadTextures((NJS_TEXNAME**)&texList->textures);
njReleaseTexture(texlist);

return result;
}

FunctionPointer(signed int, LoadPVM_D_original, (const char*, NJS_TEXLIST*), 0x0077FEB0);

void __cdecl LoadPVM_C(const char* pvmName, NJS_TEXLIST* texList)
void __cdecl LoadPVM_C(const char* filename, NJS_TEXLIST* texlist)
{
string filename(pvmName);
string filename_str(filename);
CheckCache();
LoadingFile = true;

Expand All @@ -367,32 +374,39 @@ void __cdecl LoadPVM_C(const char* pvmName, NJS_TEXLIST* texList)
// the last entry containing the PVM name the game is trying to load.
for (size_t i = TexturePackPaths.size(); i-- > 0;)
{
wstring path = TexturePackPaths[i] + wstring(filename.begin(), filename.end());
wstring path = TexturePackPaths[i] + wstring(filename_str.begin(), filename_str.end());

if (!DirectoryExists(path))
continue;

// On success, the function is exited. Otherwise, the search continues.
if (ReplacePVM(path, texList))
if (ReplacePVM(path, texlist))
return;
}

// Default behavior.
// Loads real PVM archives if no texture packs were found or successfully loaded.
// TODO: Clean up.
if (FileExists(string(sadx_fileMap.replaceFile(("SYSTEM\\" + filename + ".PVM").c_str()))) || FileExists(string(sadx_fileMap.replaceFile(("SYSTEM\\" + filename).c_str()))))
if (FileExists(string(sadx_fileMap.replaceFile(("SYSTEM\\" + filename_str + ".PVM").c_str()))) || FileExists(string(sadx_fileMap.replaceFile(("SYSTEM\\" + filename_str).c_str()))))
{
LoadPVM_D_original(pvmName, texList);
njLoadTexturePvmFile(filename, texlist);
return;
}

PrintDebug("Unable to locate PVM: %s\n", pvmName);
PrintDebug("Unable to locate PVM: %s\n", filename);
}

#pragma endregion

#pragma region PVR

ThiscallFunctionPointer(int, DoSomethingWithPalette, (NJS_TEXPALETTE *pl), 0x78CF80);
FunctionPointer(NJS_TEXMEMLIST*, TexMemList_PixelFormat, (NJS_TEXINFO* info, Uint32 gbix), 0x0077F7F0);
FunctionPointer(NJS_TEXMEMLIST*, LoadPVR, (void* data, int gbix), 0x0077FBD0);
FunctionPointer(void*, LoadPVx, (const char*), 0x007929D0);
FunctionPointer(void, j__HeapFree_0, (LPVOID lpMem), 0x00792A70);
DataArray(NJS_TEXPALETTE*, unk_3CFC000, 0x3CFC000, 0);

/// <summary>
/// Loads texture pack replacement for specified PVR.
/// </summary>
Expand Down Expand Up @@ -435,13 +449,6 @@ bool ReplacePVR(const std::string& filename, NJS_TEXMEMLIST** tex)
return false;
}

ThiscallFunctionPointer(int, sub_78CF80, (void*), 0x78CF80);
FunctionPointer(NJS_TEXMEMLIST*, TexMemList_PixelFormat, (NJS_TEXINFO* info, Uint32 gbix), 0x0077F7F0);
FunctionPointer(NJS_TEXMEMLIST*, LoadPVR, (void* data, int gbix), 0x0077FBD0);
FunctionPointer(void*, LoadTextureFromFile, (const char*), 0x007929D0);
FunctionPointer(void, j__HeapFree_0, (LPVOID lpMem), 0x00792A70);
DataPointer(char, unk_3CFC000, 0x3CFC000);

signed int __cdecl LoadPVR_wrapper(NJS_TEXLIST* texlist)
{
CheckCache();
Expand All @@ -464,10 +471,11 @@ signed int __cdecl LoadPVRFile(NJS_TEXLIST* texlist)
if (entries->attr & NJD_TEXATTR_GLOBALINDEX)
gbix = entries->texaddr;

sub_78CF80(*((void**)&unk_3CFC000 + i));
DoSomethingWithPalette(unk_3CFC000[i]);
Uint32 attr = entries->attr;

// If already loaded, grab from memory. Otherwise, load from disk.
// If not already in memory, entries->filename is a string. Otherwise unknown.
if (attr & NJD_TEXATTR_TYPE_MEMORY)
{
if (attr & NJD_TEXATTR_GLOBALINDEX)
Expand All @@ -483,7 +491,7 @@ signed int __cdecl LoadPVRFile(NJS_TEXLIST* texlist)
continue;

filename += ".pvr";
void* data = LoadTextureFromFile(filename.c_str());
void* data = LoadPVx(filename.c_str());
memlist = LoadPVR(data, gbix);
j__HeapFree_0(data);
}
Expand Down
7 changes: 4 additions & 3 deletions SADXModLoader/TextureReplacement.h
Expand Up @@ -9,15 +9,16 @@ struct CustomTextureEntry
std::string name;
};

void InitTextureReplacement();

NJS_TEXMEMLIST* LoadTexture(const std::wstring& _path, CustomTextureEntry& entry);
NJS_TEXMEMLIST* LoadTexture(const std::wstring& _path, uint32_t globalIndex, const std::string& name);
bool ParseIndex(const std::wstring& path, std::vector<CustomTextureEntry>& entries);
std::vector<CustomTextureEntry> ParseIndex(const std::wstring& path);

signed int LoadPVR_wrapper(NJS_TEXLIST * texlist);
signed int LoadPVR_wrapper(NJS_TEXLIST* texlist);
signed int LoadPVRFile(NJS_TEXLIST* texlist);
signed int __cdecl LoadPVM_D(const char *pvmName, NJS_TEXLIST *texList);
void __cdecl LoadPVM_C(const char* pvmName, NJS_TEXLIST* texList);
void __cdecl LoadPVM_C(const char* filename, NJS_TEXLIST* texlist);

extern std::vector<std::wstring> TexturePackPaths;
extern bool forceMipmaps;
6 changes: 2 additions & 4 deletions SADXModLoader/dllmain.cpp
Expand Up @@ -1990,10 +1990,8 @@ static void __cdecl InitMods(void)
WriteJump((void *)0x40D0A0, (void *)ResumeSound_r);
WriteJump((void *)0x40CFF0, (void *)WMPClose_r);
WriteJump((void *)0x40D28A, (void *)WMPRelease_r);
// Texture pack stuff
WriteJump((void*)0x004210A0, LoadPVM_C);
WriteJump((void*)0x0077FC80, LoadPVRFile);
WriteJump((void*)0x004228E0, LoadPVR_wrapper);

InitTextureReplacement();

// Unprotect the .rdata section.
// TODO: Get .rdata address and length dynamically.
Expand Down

0 comments on commit b6b27f6

Please sign in to comment.