diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml index 2cde215..724dad1 100644 --- a/.github/workflows/cd.yaml +++ b/.github/workflows/cd.yaml @@ -26,66 +26,14 @@ jobs: with: fetch-depth: 0 - - name: Config - run: echo "DXSDK_DIR=DXSDK" >> $GITHUB_ENV - shell: bash - - - name: Cache - id: cache - uses: actions/cache@v1 - with: - path: DXSDK - key: DXSDK - - - name: Cache create - if: steps.cache.outputs.cache-hit != 'true' - run: | - curl -L https://download.microsoft.com/download/a/e/7/ae743f1f-632b-4809-87a9-aa1bb3458e31/DXSDK_Jun10.exe -o _DX2010_.exe - 7z x _DX2010_.exe DXSDK/Include - 7z x _DX2010_.exe DXSDK/Lib/x86 - shell: bash - - - name: Echo cache - run: echo ${{ env.DXSDK_DIR }} - - - name: List dxsdk files - run: | - cd DXSDK - ls - cd Include - ls - cd ../Lib/x86 - ls - - - name: Copy DirectX headers to project include directory - run: Copy-Item -Path "${{ env.DXSDK_DIR }}/Include/*" -Destination header/ -Recurse -Force - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} - shell: pwsh - - - name: Ensure Lib directory exists and copy DirectX libraries - run: | - $libDir = "Lib/" - if (-Not (Test-Path -Path $libDir)) { - New-Item -ItemType Directory -Path $libDir - } - Copy-Item -Path "${{ env.DXSDK_DIR }}/Lib/x86/*" -Destination $libDir -Recurse -Force - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} - shell: pwsh - - name: Setup MSBuild.exe uses: microsoft/setup-msbuild@v1.3.1 - name: Build CMake Files run: cmake -S . -B build -A Win32 - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} - name: Build binaries run: cmake --build build --config Release - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} - name: Retrieve version id: set_version diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f6fab07..c51f101 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,64 +29,11 @@ jobs: with: fetch-depth: 0 - #https://stackoverflow.com/questions/61037714/how-to-install-an-old-version-of-the-direct-x-api-in-github-actions - - name: Config - run: echo "DXSDK_DIR=DXSDK" >> $GITHUB_ENV - shell: bash - - - name: Cache - id: cache - uses: actions/cache@v1 - with: - path: DXSDK - key: DXSDK - - - name: Cache create - if: steps.cache.outputs.cache-hit != 'true' - run: | - curl -L https://download.microsoft.com/download/a/e/7/ae743f1f-632b-4809-87a9-aa1bb3458e31/DXSDK_Jun10.exe -o _DX2010_.exe - 7z x _DX2010_.exe DXSDK/Include - 7z x _DX2010_.exe DXSDK/Lib/x86 - shell: bash - - - name: Echo cache - run: echo ${{ env.DXSDK_DIR }} - - - name: List dxsdk files - run: | - cd DXSDK - ls - cd Include - ls - cd ../Lib/x86 - ls - - - name: Copy DirectX headers to project include directory - run: Copy-Item -Path "${{ env.DXSDK_DIR }}/Include/*" -Destination header/ -Recurse -Force - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} - shell: pwsh - - - name: Ensure Lib directory exists and copy DirectX libraries - run: | - $libDir = "Lib/" - if (-Not (Test-Path -Path $libDir)) { - New-Item -ItemType Directory -Path $libDir - } - Copy-Item -Path "${{ env.DXSDK_DIR }}/Lib/x86/*" -Destination $libDir -Recurse -Force - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} - shell: pwsh - - name: Setup MSBuild.exe uses: microsoft/setup-msbuild@v1.3.1 - name: Build CMake Files run: cmake -S . -B build -A Win32 - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} - name: Build binaries run: cmake --build build --config Release - env: - DXSDK_DIR: ${{ env.DXSDK_DIR }} diff --git a/CMakeLists.txt b/CMakeLists.txt index dbcd022..1315e5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,8 +16,8 @@ if(${CLEAN} MATCHES "ON") endif() set(VERSION_MAJOR 1) -set(VERSION_MINOR 5) -set(VERSION_PATCH 8) +set(VERSION_MINOR 6) +set(VERSION_PATCH 0) set(VERSION_TWEAK 0) set(VERSION_RC "${CMAKE_CURRENT_BINARY_DIR}/version.rc") @@ -31,22 +31,6 @@ set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/bin/install) add_compile_options(/MP /permissive-) -find_library(D3D9_LIB NAMES d3d9 PATHS $ENV{DXSDK_DIR}/lib/x86 NO_DEFAULT_PATH) -find_library(D3DX9_LIB NAMES d3dx9 PATHS $ENV{DXSDK_DIR}/lib/x86 NO_DEFAULT_PATH) -find_library(DXGUID_LIB NAMES dxguid PATHS $ENV{DXSDK_DIR}/lib/x86 NO_DEFAULT_PATH) - -if(NOT D3D9_LIB) - find_library(D3D9_LIB NAMES d3d9 PATHS ${CMAKE_SOURCE_DIR}/Lib) -endif() - -if(NOT D3DX9_LIB) - find_library(D3DX9_LIB NAMES d3dx9 PATHS ${CMAKE_SOURCE_DIR}/Lib) -endif() - -if(NOT DXGUID_LIB) - find_library(DXGUID_LIB NAMES dxguid PATHS ${CMAKE_SOURCE_DIR}/Lib) -endif() - list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") include(libzippp) include(minhook) @@ -57,25 +41,23 @@ add_library(gMod SHARED) file(GLOB SOURCES "header/*.h" "source/*.cpp" + "modules/*.ixx" ${VERSION_RC} ) target_include_directories(gMod PRIVATE "header" ${CMAKE_INSTALL_PREFIX}/include - $ENV{DXSDK_DIR}/Include ) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES}) target_sources(gMod PRIVATE ${SOURCES}) target_link_libraries(gMod PRIVATE - ${D3D9_LIB} - ${D3DX9_LIB} - ${DXGUID_LIB} + dxguid libzippp - psapi - minhook - directxtex + psapi + minhook + directxtex ) target_link_options(gMod PRIVATE "$<$:/NODEFAULTLIB:LIBCMT>" diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4ac3fe --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +Requirements: +- DirectX SDK (June 2010) +- Visual Studio 2022 +- CMake 3.16+, integrated into the Developer Powershell for VS 2022 + +Compile: +- cmake -B build +- cmake --open build +- compile + +*Usage is primarily intended with GW Launcher or Daybreak, but it can be used without.* + +**Usage with manual gMod.dll injection:** +- Create a file called modlist.txt in either the Guild Wars (Gw.exe) folder, or the gMod.dll folder. +- Inject gMod.dll before d3d9.dll is loaded. + +**Usage without dll injection:** +- Create a file called modlist.txt in the Guild Wars (Gw.exe) folder. +- Place gMod.dll in the Guild Wars folder +- Rename gMod.dll to d3d9.dll +- Launch Guild Wars + +**Format of the modlist.txt file:** + + +Each line in the modlist.txt is the full path to a mod you want to load (eg. `D:\uMod\Borderless Cartography Made Easy 2015 1.3.tpf`) +gMod will load all these files on startup diff --git a/README.txt b/README.txt deleted file mode 100644 index d405f21..0000000 --- a/README.txt +++ /dev/null @@ -1,14 +0,0 @@ -Requirements: -- DirectX SDK (June 2010) -- Visual Studio 2022 -- CMake 3.16+, integrated into the Developer Powershell for VS 2022 - -Compile: -- cmake -B build -- cmake --open build -- compile - -Usage: -- Create a file called modlist.txt in either the Guild Wars (Gw.exe) folder, or the gMod.dll folder. -Each line in the modlist.txt is the full path to a mod you want to load (eg. D:\uMod\Mods\Borderless Cartography Made Easy 2015 1.3.tpf) -gMod will load all these files on startup diff --git a/cmake/dxtk.cmake b/cmake/dxtk.cmake index be77eb9..bd6e79d 100644 --- a/cmake/dxtk.cmake +++ b/cmake/dxtk.cmake @@ -12,13 +12,6 @@ endif() FetchContent_Populate(directxtex) -file(READ "${directxtex_SOURCE_DIR}/WICTextureLoader/WICTextureLoader9.cpp" FILE_CONTENT) -string(REPLACE - "hr = frame->GetPixelFormat(&pixelFormat);\n" - "hr = frame->GetPixelFormat(&pixelFormat); if (pixelFormat == GUID_WICPixelFormat32bppBGR) pixelFormat = GUID_WICPixelFormat32bppBGRA;\n" - FILE_CONTENT "${FILE_CONTENT}" ) -file(WRITE "${directxtex_SOURCE_DIR}/WICTextureLoader/WICTextureLoader9.cpp" "${FILE_CONTENT}") - add_library(directxtex) file(GLOB SOURCES "${directxtex_SOURCE_DIR}/DDSTextureLoader/DDSTextureLoader9.h" diff --git a/header/Defines.h b/header/Defines.h index fea4365..16fafa0 100644 --- a/header/Defines.h +++ b/header/Defines.h @@ -3,27 +3,36 @@ //#define HashType DWORD64 using HashType = DWORD32; -#ifdef LOG_MESSAGE -#include +struct TexEntry { + std::vector data{}; + HashType crc_hash = 0; // hash value + std::string ext{}; +}; +struct TextureFileStruct { + std::vector data{}; + HashType crc_hash = 0; // hash value +}; + +inline void Message(const char* format, ...) +{ #ifdef _DEBUG - -#if 1 -#define Message(...) { printf(__VA_ARGS__); } -#else -#define Message(...) +#if 0 + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); #endif -#define Warning(...) { fprintf(stderr, __VA_ARGS__); } - -#else - -#define Message(...) -#define Warning(...) - #endif +} +inline void Warning(const char* format, ...) +{ +#ifdef _DEBUG + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); #endif +} -#ifndef _countof -#define _countof(arr) sizeof(arr) / sizeof(*arr) -#endif diff --git a/header/FileLoader.h b/header/FileLoader.h deleted file mode 100644 index 3c2f444..0000000 --- a/header/FileLoader.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include -#include - -class FileLoader { - std::string file_name; - const std::string TPF_PASSWORD{ - 0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast(0xA6), static_cast(0xBD), - 0x7D, 0x65, 0x7E, 0x67, 0x61, 0x2A, 0x7F, 0x7F, - 0x74, 0x61, 0x67, 0x5B, 0x60, 0x70, 0x45, 0x74, - 0x5C, 0x22, 0x74, 0x5D, 0x6E, 0x6A, 0x73, 0x41, - 0x77, 0x6E, 0x46, 0x47, 0x77, 0x49, 0x0C, 0x4B, - 0x46, 0x6F - }; - -public: - FileLoader(const std::string& fileName); - - std::vector GetContents(); - -private: - - std::vector GetTpfContents(); - - std::vector GetFileContents(); - - void LoadEntries(libzippp::ZipArchive& archive, std::vector& entries); -}; diff --git a/header/Main.h b/header/Main.h index 96802a7..8fc85e1 100644 --- a/header/Main.h +++ b/header/Main.h @@ -5,7 +5,10 @@ #include #include #include +#include +#include #include +#include #include "Utils.h" #include @@ -13,8 +16,6 @@ #include "Defines.h" #include "Error.h" #include "Defines.h" -#include "dll_main.h" -#include "TextureFunction.h" #include "uMod_IDirect3D9.h" #include "uMod_IDirect3D9Ex.h" @@ -26,8 +27,6 @@ #include "uMod_IDirect3DTexture9.h" #include "uMod_IDirect3DVolumeTexture9.h" -#include "TextureClient.h" - #pragma warning(disable : 4477) extern unsigned int gl_ErrorState; diff --git a/header/TextureClient.h b/header/TextureClient.h deleted file mode 100644 index 9e4ccfd..0000000 --- a/header/TextureClient.h +++ /dev/null @@ -1,264 +0,0 @@ -#pragma once - -#include "FileLoader.h" -#include "uMod_IDirect3DTexture9.h" -#include -#include -#include - -extern unsigned int gl_ErrorState; - -struct TextureFileStruct { - std::vector data{}; - HashType crc_hash = 0; // hash value - bool is_wic_texture = false; -}; - -template -concept uModTexturePtr = requires(T a) -{ - std::same_as || - std::same_as || - std::same_as; -}; - -template -concept uModTexturePtrPtr = uModTexturePtr>; - -/* - * An object of this class is owned by each d3d9 device. - * All other functions are called from the render thread instance of the game itself. - */ -class TextureClient { -public: - TextureClient(IDirect3DDevice9* device); - ~TextureClient(); - - int AddTexture(uModTexturePtr auto pTexture); - int RemoveTexture(uModTexturePtr auto pTexture); //called from uMod_IDirect3DTexture9::Release() - int LookUpToMod(uModTexturePtr auto pTexture); - // called at the end AddTexture(...) and from Device->UpdateTexture(...) - - int MergeUpdate(); //called from uMod_IDirect3DDevice9::BeginScene() - void Initialize(); - - // Add TextureFileStruct data, return size of data added. 0 on failure. - unsigned long AddFile(TextureFileStruct& entry); - - std::vector OriginalTextures; - // stores the pointer to the uMod_IDirect3DTexture9 objects created by the game - std::vector OriginalVolumeTextures; - // stores the pointer to the uMod_IDirect3DVolumeTexture9 objects created by the game - std::vector OriginalCubeTextures; - // stores the pointer to the uMod_IDirect3DCubeTexture9 objects created by the game - - -private: - IDirect3DDevice9* D3D9Device; - // Cached info about whether this id a dx9ex device or not; used for proxy functions - bool isDirectXExDevice = false; - - // DX9 proxy functions - void SetLastCreatedTexture(uMod_IDirect3DTexture9*); - void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9*); - void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9*); - - bool should_update = false; - - int LockMutex(); - int UnlockMutex(); - HANDLE mutex; - - std::unordered_map modded_textures; - // array which stores the file in memory and the hash of each texture to be modded - - // called if a target texture is found - int LoadTexture(TextureFileStruct* file_in_memory, uModTexturePtrPtr auto ppTexture); - - void LoadModsFromFile(const char* source); -}; - -int TextureClient::AddTexture(uModTexturePtr auto pTexture) -{ - if constexpr (std::same_as) { - SetLastCreatedTexture(nullptr); - } - else if constexpr (std::same_as) { - SetLastCreatedVolumeTexture(nullptr); - } - else if constexpr (std::same_as) { - SetLastCreatedCubeTexture(nullptr); - } - - if (pTexture->FAKE) { - return RETURN_OK; // this is a fake texture - } - - if (gl_ErrorState & uMod_ERROR_FATAL) { - return RETURN_FATAL_ERROR; - } - - Message("TextureClient::AddTexture( Cube: %p): %p (thread: %u)\n", pTexture, this, GetCurrentThreadId()); - - pTexture->Hash = pTexture->GetHash(); - if (!pTexture->Hash) { - return RETURN_FATAL_ERROR; - } - - if constexpr (std::same_as) { - OriginalTextures.push_back(pTexture); - } - else if constexpr (std::same_as) { - OriginalVolumeTextures.push_back(pTexture); - } - else if constexpr (std::same_as) { - OriginalCubeTextures.push_back(pTexture); - } - - return LookUpToMod(pTexture); // check if this texture should be modded -} - -int TextureClient::RemoveTexture(uModTexturePtr auto pTexture) -{ - Message("TextureClient::RemoveTexture( %p, %#lX): %p\n", pTexture, pTexture->Hash, this); - - if (gl_ErrorState & uMod_ERROR_FATAL) { - return RETURN_FATAL_ERROR; - } - - if (!pTexture->FAKE) { - if constexpr (std::same_as) { - utils::erase_first(OriginalTextures, pTexture); - } - else if constexpr (std::same_as) { - utils::erase_first(OriginalVolumeTextures, pTexture); - } - else if constexpr (std::same_as) { - utils::erase_first(OriginalCubeTextures, pTexture); - } - } - if (!pTexture->Reference) - return RETURN_OK; // Should this ever happen? - return RETURN_OK; -} - -int TextureClient::LookUpToMod(uModTexturePtr auto pTexture) -{ - Message("TextureClient::LookUpToMod( %p): hash: %#lX, %p\n", pTexture, pTexture->Hash, this); - int ret = RETURN_OK; - - if (pTexture->CrossRef_D3Dtex != nullptr) - return ret; // bug, this texture is already switched - - const auto found = modded_textures.find(pTexture->Hash); - if (found == modded_textures.end()) - return ret; - - const auto textureFileStruct = found->second; - - decltype(pTexture) fake_Texture; - ret = LoadTexture(textureFileStruct, &fake_Texture); - if (ret != RETURN_OK) - return ret; - - ret = SwitchTextures(fake_Texture, pTexture); - if (ret != RETURN_OK) { - Message("TextureClient::LookUpToMod(): textures not switched %#lX\n", textureFileStruct->crc_hash); - fake_Texture->Release(); - return ret; - } - fake_Texture->Reference = textureFileStruct; - return ret; -} - -extern HINSTANCE gl_hThisInstance; -int TextureClient::LoadTexture(TextureFileStruct* file_in_memory, uModTexturePtrPtr auto ppTexture) -{ - Message("LoadTexture( %p, %p, %#lX): %p\n", file_in_memory, ppTexture, file_in_memory->crc_hash, this); - if (file_in_memory->is_wic_texture) { - Warning("(%#lX)\n", file_in_memory->crc_hash); - #if 0 - if (D3D_OK != D3DXCreateTextureFromFileInMemoryEx( - D3D9Device, file_in_memory->data.data(), - file_in_memory->data.size(), D3DX_DEFAULT, D3DX_DEFAULT, - D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, - D3DX_DEFAULT, D3DX_DEFAULT, 0, nullptr, nullptr, - reinterpret_cast(ppTexture))) { - *ppTexture = nullptr; - Warning("LoadWICTexture(%p, %#lX): FAILED\n", *ppTexture, file_in_memory->crc_hash); - return RETURN_TEXTURE_NOT_LOADED; - } - D3DXIMAGE_INFO info; - D3DXGetImageInfoFromFileInMemory(file_in_memory->data.data(), file_in_memory->data.size(), &info); - char dllpath[MAX_PATH]{}; - GetModuleFileName(gl_hThisInstance, dllpath, MAX_PATH); //ask for name and path of this dll - const auto dds_export_path = std::filesystem::path(dllpath).parent_path() / "d3dxout" / std::format("GW.EXE_{:X}.dds", file_in_memory->crc_hash); - if (!std::filesystem::exists(dds_export_path)) { - D3DXSaveTextureToFile(dds_export_path.string().c_str(), D3DXIFF_DDS, *ppTexture, nullptr); - } - #else - if (D3D_OK != DirectX::CreateWICTextureFromMemoryEx( - D3D9Device, - file_in_memory->data.data(), - file_in_memory->data.size(), - 0, 0, D3DPOOL_MANAGED, DirectX::WIC_LOADER_MIP_AUTOGEN, - reinterpret_cast(ppTexture))) { - *ppTexture = nullptr; - Warning("LoadWICTexture(%p, %#lX): FAILED\n", *ppTexture, file_in_memory->crc_hash); - return RETURN_TEXTURE_NOT_LOADED; - } - #endif - } - else if (D3D_OK != DirectX::CreateDDSTextureFromMemoryEx( - D3D9Device, - file_in_memory->data.data(), - file_in_memory->data.size(), - 0, D3DPOOL_MANAGED, false, - reinterpret_cast(ppTexture))) { - *ppTexture = nullptr; - Warning("LoadDDSTexture Normal(%p, %#lX): FAILED\n", *ppTexture, file_in_memory->crc_hash); - return RETURN_TEXTURE_NOT_LOADED; - } - if constexpr (std::same_as) { - - SetLastCreatedTexture(nullptr); - } - else if constexpr (std::same_as) { - SetLastCreatedVolumeTexture(nullptr); - } - else if constexpr (std::same_as) { - SetLastCreatedCubeTexture(nullptr); - } - (*ppTexture)->FAKE = true; - - Message("LoadTexture( %p, %#lX): DONE\n", *ppTexture, file_in_memory->crc_hash); - return RETURN_OK; -} - -template requires uModTexturePtr -void UnswitchTextures(T pTexture) -{ - decltype(pTexture) CrossRef = pTexture->CrossRef_D3Dtex; - if (CrossRef != nullptr) { - std::swap(pTexture->m_D3Dtex, CrossRef->m_D3Dtex); - - // cancel the link - CrossRef->CrossRef_D3Dtex = nullptr; - pTexture->CrossRef_D3Dtex = nullptr; - } -} - -template requires uModTexturePtr -int SwitchTextures(T pTexture1, T pTexture2) -{ - if (pTexture1->m_D3Ddev == pTexture2->m_D3Ddev && pTexture1->CrossRef_D3Dtex == nullptr && pTexture2->CrossRef_D3Dtex == nullptr) { - // make cross reference - pTexture1->CrossRef_D3Dtex = pTexture2; - pTexture2->CrossRef_D3Dtex = pTexture1; - - // switch textures - std::swap(pTexture1->m_D3Dtex, pTexture2->m_D3Dtex); - return RETURN_OK; - } - return RETURN_TEXTURE_NOT_SWITCHED; -} diff --git a/header/TextureFunction.h b/header/TextureFunction.h deleted file mode 100644 index bdc4974..0000000 --- a/header/TextureFunction.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once - -constexpr auto crc32_poly = 0xEDB88320u; -constexpr auto ul_crc_in = 0xffffffff; - -inline unsigned int GetCRC32(char* pcDatabuf, unsigned int ulDatalen) -{ - unsigned int crc = ul_crc_in; - for (unsigned int idx = 0u; idx < ulDatalen; idx++) { - unsigned int data = *pcDatabuf++; - for (unsigned int bit = 0u; bit < 8u; bit++, data >>= 1) { - crc = crc >> 1 ^ ((crc ^ data) & 1 ? crc32_poly : 0); - } - } - return crc; -} - -/* - case D3DFMT_MULTI2_ARGB8: - case D3DFMT_VERTEXDATA: - */ -inline int GetBitsFromFormat(D3DFORMAT format) -{ - switch (format) //switch trough the formats to calculate the size of the raw data - { - case D3DFMT_A1: // 1-bit monochrome. - { - return 1; - break; - } - - case D3DFMT_R3G3B2: // 8-bit RGB texture format using 3 bits for red, 3 bits for green, and 2 bits for blue. - case D3DFMT_A8: // 8-bit alpha only. - case D3DFMT_A8P8: // 8-bit color indexed with 8 bits of alpha. - case D3DFMT_P8: // 8-bit color indexed. - case D3DFMT_L8: // 8-bit luminance only. - case D3DFMT_A4L4: // 8-bit using 4 bits each for alpha and luminance. - case D3DFMT_FORCE_DWORD: - case D3DFMT_S8_LOCKABLE: // A lockable 8-bit stencil buffer. - { - return 8; - break; - } - - case D3DFMT_D16_LOCKABLE: //16-bit z-buffer bit depth. - case D3DFMT_D15S1: // 16-bit z-buffer bit depth where 15 bits are reserved for the depth channel and 1 bit is reserved for the stencil channel. - case D3DFMT_L6V5U5: // 16-bit bump-map format with luminance using 6 bits for luminance, and 5 bits each for v and u. - case D3DFMT_V8U8: // 16-bit bump-map format using 8 bits each for u and v data. - case D3DFMT_CxV8U8: // 16-bit normal compression format. The texture sampler computes the C channel from: C = sqrt(1 - U2 - V2). - case D3DFMT_R5G6B5: // 16-bit RGB pixel format with 5 bits for red, 6 bits for green, and 5 bits for blue. - case D3DFMT_X1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color. - case D3DFMT_A1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color and 1 bit is reserved for alpha. - case D3DFMT_A4R4G4B4: // 16-bit ARGB pixel format with 4 bits for each channel. - case D3DFMT_A8R3G3B2: // 16-bit ARGB texture format using 8 bits for alpha, 3 bits each for red and green, and 2 bits for blue. - case D3DFMT_X4R4G4B4: // 16-bit RGB pixel format using 4 bits for each color. - case D3DFMT_L16: // 16-bit luminance only. - case D3DFMT_R16F: // 16-bit float format using 16 bits for the red channel. - case D3DFMT_A8L8: // 16-bit using 8 bits each for alpha and luminance. - case D3DFMT_D16: // 16-bit z-buffer bit depth. - case D3DFMT_INDEX16: // 16-bit index buffer bit depth. - case D3DFMT_G8R8_G8B8: // ?? - case D3DFMT_R8G8_B8G8: // ?? - case D3DFMT_UYVY: // ?? - case D3DFMT_YUY2: // ?? - { - return 16; - break; - } - - - case D3DFMT_R8G8B8: //24-bit RGB pixel format with 8 bits per channel. - { - return 24; - break; - } - - case D3DFMT_R32F: // 32-bit float format using 32 bits for the red channel. - case D3DFMT_X8L8V8U8: // 32-bit bump-map format with luminance using 8 bits for each channel. - case D3DFMT_A2W10V10U10: // 32-bit bump-map format using 2 bits for alpha and 10 bits each for w, v, and u. - case D3DFMT_Q8W8V8U8: // 32-bit bump-map format using 8 bits for each channel. - case D3DFMT_V16U16: // 32-bit bump-map format using 16 bits for each channel. - case D3DFMT_A8R8G8B8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. - case D3DFMT_X8R8G8B8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. - case D3DFMT_A2B10G10R10: // 32-bit pixel format using 10 bits for each color and 2 bits for alpha. - case D3DFMT_A8B8G8R8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. - case D3DFMT_X8B8G8R8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. - case D3DFMT_G16R16: // 32-bit pixel format using 16 bits each for green and red. - case D3DFMT_G16R16F: // 32-bit float format using 16 bits for the red channel and 16 bits for the green channel. - case D3DFMT_A2R10G10B10: // 32-bit pixel format using 10 bits each for red, green, and blue, and 2 bits for alpha. - case D3DFMT_D32: // 32-bit z-buffer bit depth. - case D3DFMT_D24S8: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 8 bits for the stencil channel. - case D3DFMT_D24X8: //32-bit z-buffer bit depth using 24 bits for the depth channel. - case D3DFMT_D24X4S4: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 4 bits for the stencil channel. - case D3DFMT_D32F_LOCKABLE: // A lockable format where the depth value is represented as a standard IEEE floating-point number. - case D3DFMT_D24FS8: // A non-lockable format that contains 24 bits of depth (in a 24-bit floating point format - 20e4) and 8 bits of stencil. - case D3DFMT_D32_LOCKABLE: // A lockable 32-bit depth buffer. - case D3DFMT_INDEX32: // 32-bit index buffer bit depth. - //case : // - //case : // - //case : // - //case : // - { - return 32; - break; - } - - case D3DFMT_G32R32F: // 64-bit float format using 32 bits for the red channel and 32 bits for the green channel. - case D3DFMT_Q16W16V16U16: // 64-bit bump-map format using 16 bits for each component. - case D3DFMT_A16B16G16R16: // 64-bit pixel format using 16 bits for each component. - case D3DFMT_A16B16G16R16F: // 64-bit float format using 16 bits for the each channel (alpha, blue, green, red). - { - return 64; - break; - } - - case D3DFMT_A32B32G32R32F: // 128-bit float format using 32 bits for the each channel (alpha, blue, green, red). - { - return 128; - break; - } - case D3DFMT_DXT2: - case D3DFMT_DXT3: - case D3DFMT_DXT4: - case D3DFMT_DXT5: { - return 8; - break; - } - case D3DFMT_DXT1: { - return 4; - break; - } - default: //compressed formats - { - return 4; - break; - } - } -} diff --git a/header/dll_main.h b/header/dll_main.h deleted file mode 100644 index 2b0f00d..0000000 --- a/header/dll_main.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -void InitInstance(HINSTANCE hModule); -void ExitInstance(); -HMODULE LoadOriginalDll(); - diff --git a/header/uMod_IDirect3DDevice9.h b/header/uMod_IDirect3DDevice9.h index 05a37a6..634c1b9 100644 --- a/header/uMod_IDirect3DDevice9.h +++ b/header/uMod_IDirect3DDevice9.h @@ -4,8 +4,8 @@ #include "uMod_IDirect3DTexture9.h" #include "uMod_IDirect3DVolumeTexture9.h" #include "uMod_IDirect3DCubeTexture9.h" -#include "TextureClient.h" +class TextureClient; class uMod_IDirect3DDevice9 : public IDirect3DDevice9 { public: diff --git a/header/uMod_IDirect3DDevice9Ex.h b/header/uMod_IDirect3DDevice9Ex.h index 0dc576e..a678d06 100644 --- a/header/uMod_IDirect3DDevice9Ex.h +++ b/header/uMod_IDirect3DDevice9Ex.h @@ -1,11 +1,11 @@ #pragma once #include - #include "uMod_IDirect3DTexture9.h" #include "uMod_IDirect3DVolumeTexture9.h" #include "uMod_IDirect3DCubeTexture9.h" -#include "TextureClient.h" + +class TextureClient; class uMod_IDirect3DDevice9Ex : public IDirect3DDevice9Ex { public: diff --git a/source/FileLoader.cpp b/modules/ModfileLoader.ixx similarity index 57% rename from source/FileLoader.cpp rename to modules/ModfileLoader.ixx index d0384aa..ca7e729 100644 --- a/source/FileLoader.cpp +++ b/modules/ModfileLoader.ixx @@ -1,14 +1,50 @@ -#include <..\header\Main.h> -#include -#include "FileLoader.h" -#include "TpfReader.h" +module; -FileLoader::FileLoader(const std::string& fileName) +#include "Main.h" +#include "Defines.h" + +export module ModfileLoader; + +import ; +import ; +import ; +import ; +import ; +import ; +import ; +import ModfileLoader.TpfReader; + +export class ModfileLoader { + std::string file_name; + const std::string TPF_PASSWORD{ + 0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast(0xA6), static_cast(0xBD), + 0x7D, 0x65, 0x7E, 0x67, 0x61, 0x2A, 0x7F, 0x7F, + 0x74, 0x61, 0x67, 0x5B, 0x60, 0x70, 0x45, 0x74, + 0x5C, 0x22, 0x74, 0x5D, 0x6E, 0x6A, 0x73, 0x41, + 0x77, 0x6E, 0x46, 0x47, 0x77, 0x49, 0x0C, 0x4B, + 0x46, 0x6F + }; + +public: + ModfileLoader(const std::string& fileName); + + std::vector GetContents(); + +private: + + std::vector GetTpfContents(); + + std::vector GetFileContents(); + + void LoadEntries(libzippp::ZipArchive& archive, std::vector& entries); +}; + +ModfileLoader::ModfileLoader(const std::string& fileName) { file_name = std::filesystem::absolute(fileName).string(); } -std::vector FileLoader::GetContents() +std::vector ModfileLoader::GetContents() { try { return file_name.ends_with(".tpf") ? GetTpfContents() : GetFileContents(); @@ -19,9 +55,9 @@ std::vector FileLoader::GetContents() return {}; } -std::vector FileLoader::GetTpfContents() +std::vector ModfileLoader::GetTpfContents() { - std::vector entries; + std::vector entries; auto tpf_reader = TpfReader(file_name); const auto buffer = tpf_reader.ReadToEnd(); const auto zip_archive = libzippp::ZipArchive::fromBuffer(buffer.data(), buffer.size(), false, TPF_PASSWORD); @@ -41,9 +77,9 @@ std::vector FileLoader::GetTpfContents() return entries; } -std::vector FileLoader::GetFileContents() +std::vector ModfileLoader::GetFileContents() { - std::vector entries; + std::vector entries; libzippp::ZipArchive zip_archive(file_name); zip_archive.open(); @@ -53,35 +89,22 @@ std::vector FileLoader::GetFileContents() return entries; } -void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector& entries) +void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector& entries) { for (const auto& entry : archive.getEntries()) { if (entry.isFile()) { //TODO: #6 - Implement regex search auto name = entry.getName(); - // Remove the part before the last underscore (if any) - size_t firstIndex = name.find_last_of('_'); - while (firstIndex != std::string::npos) { - if (firstIndex >= entry.getName().length() - 1) { - name = entry.getName(); - } - else { - name = entry.getName().substr(firstIndex + 1); - } - - firstIndex = name.find_last_of('_'); - } - - // Remove the file extension (if any) - size_t lastIndex = name.find_last_of('.'); - if (lastIndex != std::string::npos) { - name = name.substr(0, lastIndex); + const static std::regex re(R"(0x[0-9a-f]{8})", std::regex::optimize | std::regex::icase); + std::smatch match; + if (!std::regex_search(name, match, re)) { + continue; } uint32_t crc_hash; - try { - crc_hash = std::stoul(name, nullptr, 16); + try { + crc_hash = std::stoul(match.str(), nullptr, 16); } catch (const std::invalid_argument& e) { Warning("Failed to parse %s as a hash", name.c_str()); @@ -96,63 +119,40 @@ void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector& lines, libzippp::ZipArchive& archive, std::vector& entries) +void ParseTexmodArchive(std::vector& lines, libzippp::ZipArchive& archive, std::vector& entries) { for (const auto& line : lines) { - std::istringstream iss(line); - std::string part; - std::vector splits; - - // Split the line by '|' - while (std::getline(iss, part, '|')) { - splits.push_back(part); - } - - if (splits.size() != 2) { + // 0xC57D73F7|GW.EXE_0xC57D73F7.tga\r\n + // match[1] | match[2] + const static auto address_file_regex = std::regex(R"(^[\\/.]*([^|]+)\|([^\r\n]+))", std::regex::optimize); + std::smatch match; + std::regex_search(line, match, address_file_regex); + if (match.size() != 3u) continue; - } + const auto address_string = match[1].str(); + const auto file_path = match[2].str(); - std::string addrstr = splits[0]; - std::string path = splits[1]; - - // Remove unwanted characters from the beginning of the path - while (!path.empty() && (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) || path[0] == '/' || path[0] == '\\') { - path.erase(0, 1); - } - - // Remove trailing newline and carriage return characters - if (const auto end_pos = path.find_last_not_of("\r\n"); end_pos != std::string::npos) { - path.erase(end_pos + 1); - } - else if (!path.empty()) { - path.clear(); - } - - const auto entry = archive.getEntry(path); - if (entry.isNull()) { - continue; - } - - if (!entry.isFile()) { + const auto entry = archive.getEntry(file_path); + if (entry.isNull() || !entry.isFile()) { continue; } uint32_t crc_hash{}; try { - crc_hash = std::stoul(addrstr, nullptr, 16); + crc_hash = std::stoul(address_string, nullptr, 16); } catch (const std::invalid_argument& e) { - Warning("Failed to parse %s as a hash", addrstr.c_str()); + Warning("Failed to parse %s as a hash", address_string.c_str()); continue; } catch (const std::out_of_range& e) { - Warning("Out of range while parsing %s as a hash", addrstr.c_str()); + Warning("Out of range while parsing %s as a hash", address_string.c_str()); continue; } @@ -160,12 +160,12 @@ void ParseTexmodArchive(std::vector& lines, libzippp::ZipArchive& a const auto size = static_cast(entry.getSize()); std::vector vec(data_ptr, data_ptr + size); const auto tex_name = std::filesystem::path(entry.getName()); - entries.emplace_back(std::move(vec), crc_hash, tex_name.extension() != ".dds"); + entries.emplace_back(std::move(vec), crc_hash, tex_name.extension().string()); delete[] data_ptr; } } -void FileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector& entries) +void ModfileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector& entries) { const auto def_file = archive.getEntry("texmod.def"); if (def_file.isNull() || !def_file.isFile()) { diff --git a/header/TpfReader.h b/modules/ModfileLoader_TpfReader.ixx similarity index 92% rename from header/TpfReader.h rename to modules/ModfileLoader_TpfReader.ixx index d391b09..f17ddf3 100644 --- a/header/TpfReader.h +++ b/modules/ModfileLoader_TpfReader.ixx @@ -1,9 +1,10 @@ -#pragma once +export module ModfileLoader.TpfReader; -#include -#include +import ; +import ; +import ; -class TpfReader { +export class TpfReader { public: TpfReader(const std::string& path) { diff --git a/modules/TextureClient.ixx b/modules/TextureClient.ixx new file mode 100644 index 0000000..688f0ff --- /dev/null +++ b/modules/TextureClient.ixx @@ -0,0 +1,380 @@ +module; + +#include "Main.h" +#include "Error.h" +#include "uMod_IDirect3DTexture9.h" +#include +#include + +export module TextureClient; +import TextureFunction; +import ModfileLoader; + +/* + * An object of this class is owned by each d3d9 device. + * All other functions are called from the render thread instance of the game itself. + */ +export class TextureClient { +public: + TextureClient(IDirect3DDevice9* device); + ~TextureClient(); + + int AddTexture(uModTexturePtr auto pTexture); + int RemoveTexture(uModTexturePtr auto pTexture); //called from uMod_IDirect3DTexture9::Release() + int LookUpToMod(uModTexturePtr auto pTexture); + // called at the end AddTexture(...) and from Device->UpdateTexture(...) + + int MergeUpdate(); //called from uMod_IDirect3DDevice9::BeginScene() + void Initialize(); + + // Add TextureFileStruct data, return size of data added. 0 on failure. + unsigned long AddFile(TexEntry& entry, bool compress = false); + + std::vector OriginalTextures; + // stores the pointer to the uMod_IDirect3DTexture9 objects created by the game + std::vector OriginalVolumeTextures; + // stores the pointer to the uMod_IDirect3DVolumeTexture9 objects created by the game + std::vector OriginalCubeTextures; + // stores the pointer to the uMod_IDirect3DCubeTexture9 objects created by the game + + +private: + IDirect3DDevice9* D3D9Device; + // Cached info about whether this id a dx9ex device or not; used for proxy functions + bool isDirectXExDevice = false; + + // DX9 proxy functions + void SetLastCreatedTexture(uMod_IDirect3DTexture9*); + void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9*); + void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9*); + + bool should_update = false; + + int LockMutex(); + int UnlockMutex(); + HANDLE hMutex; + std::mutex mutex; + + std::unordered_map modded_textures; + // array which stores the file in memory and the hash of each texture to be modded + + // called if a target texture is found + int LoadTexture(TextureFileStruct* file_in_memory, uModTexturePtrPtr auto ppTexture); + + void LoadModsFromFile(const char* source); + std::filesystem::path exe_path; // path to gw.exe + std::filesystem::path dll_path; // path to gmod dll +}; + +TextureClient::TextureClient(IDirect3DDevice9* device) +{ + Message("TextureClient::TextureClient(): %p\n", this); + D3D9Device = device; + + void* cpy; + isDirectXExDevice = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy) == 0x01000001L; + + hMutex = CreateMutex(nullptr, false, nullptr); +} + +TextureClient::~TextureClient() +{ + Message("TextureClient::~TextureClient(): %p\n", this); + if (hMutex != nullptr) { + CloseHandle(hMutex); + } + for (const auto& it : modded_textures) { + delete it.second; + } + modded_textures.clear(); +} + +int TextureClient::MergeUpdate() +{ + if (!should_update) return RETURN_OK; + should_update = false; + if (const int ret = LockMutex()) { + gl_ErrorState |= uMod_ERROR_TEXTURE; + return ret; + } + + Message("MergeUpdate(): %p\n", this); + + for (const auto pTexture : OriginalTextures) { + if (pTexture->CrossRef_D3Dtex == nullptr) { + LookUpToMod(pTexture); + } + } + for (const auto pTexture : OriginalVolumeTextures) { + if (pTexture->CrossRef_D3Dtex == nullptr) { + LookUpToMod(pTexture); + } + } + for (const auto pTexture : OriginalCubeTextures) { + if (pTexture->CrossRef_D3Dtex == nullptr) { + LookUpToMod(pTexture); + } + } + + return UnlockMutex(); +} + +void TextureClient::SetLastCreatedTexture(uMod_IDirect3DTexture9* texture) +{ + if (isDirectXExDevice) + return static_cast(D3D9Device)->SetLastCreatedTexture(texture); + return static_cast(D3D9Device)->SetLastCreatedTexture(texture); +} + +void TextureClient::SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* texture) +{ + if (isDirectXExDevice) + return static_cast(D3D9Device)->SetLastCreatedVolumeTexture(texture); + return static_cast(D3D9Device)->SetLastCreatedVolumeTexture(texture); +} + +void TextureClient::SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* texture) +{ + if (isDirectXExDevice) + return static_cast(D3D9Device)->SetLastCreatedCubeTexture(texture); + return static_cast(D3D9Device)->SetLastCreatedCubeTexture(texture); +} + +int TextureClient::LockMutex() +{ + if ((gl_ErrorState & (uMod_ERROR_FATAL | uMod_ERROR_MUTEX))) { + return RETURN_NO_MUTEX; + } + if (WAIT_OBJECT_0 != WaitForSingleObject(hMutex, 100)) { + return RETURN_MUTEX_LOCK; //waiting 100ms, to wait infinite pass INFINITE + } + return RETURN_OK; +} + +int TextureClient::UnlockMutex() +{ + if (ReleaseMutex(hMutex) == 0) { + return RETURN_MUTEX_UNLOCK; + } + return RETURN_OK; +} + +unsigned long TextureClient::AddFile(TexEntry& entry, const bool compress) +{ + if (modded_textures.contains(entry.crc_hash)) { + return 0; + } + auto texture_file_struct = new TextureFileStruct(); + texture_file_struct->crc_hash = entry.crc_hash; + should_update = true; + const auto dds_blob = TextureFunction::ConvertToCompressedDDS(entry, compress, dll_path); + texture_file_struct->data.assign(static_cast(dds_blob.GetBufferPointer()), static_cast(dds_blob.GetBufferPointer()) + dds_blob.GetBufferSize()); + std::lock_guard lock(mutex); + modded_textures.emplace(entry.crc_hash, texture_file_struct); + return texture_file_struct->data.size(); +} + +unsigned ProcessModfile(TextureClient& client, const std::string& modfile, const bool compress) +{ + const auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (FAILED(hr)) return 0; + Message("Initialize: loading file %s... ", modfile.c_str()); + auto file_loader = ModfileLoader(modfile); + auto entries = file_loader.GetContents(); + if (entries.empty()) { + Message("No entries found.\n"); + return 0; + } + Message("%zu textures... ", entries.size()); + unsigned long file_bytes_loaded = 0; + for (auto& tpf_entry : entries) { + file_bytes_loaded += client.AddFile(tpf_entry, compress); + } + entries.clear(); + Message("%d bytes loaded.\n", file_bytes_loaded); + CoUninitialize(); + return file_bytes_loaded; +} + +void TextureClient::LoadModsFromFile(const char* source) +{ + static std::vector loaded_modfiles{}; + static unsigned long loaded_size = 0; + Message("Initialize: searching in %s\n", source); + + std::ifstream file(source); + if (!file.is_open()) { + Warning("LoadModsFromFile: failed to open modlist.txt for reading; aborting!!!"); + return; + } + Message("Initialize: found modlist.txt. Reading\n"); + std::string line; + std::vector modfiles; + while (std::getline(file, line)) { + // Remove newline character + line.erase(std::ranges::remove(line, '\r').begin(), line.end()); + line.erase(std::ranges::remove(line, '\n').begin(), line.end()); + + if (!std::ranges::contains(loaded_modfiles, line)) { + modfiles.push_back(line); + loaded_modfiles.push_back(line); + } + } + auto files_size = 0u; + for (const auto modfile : modfiles) { + if (std::filesystem::exists(modfile)) { + files_size += std::filesystem::file_size(modfile); + } + } + std::vector> futures; + for (const auto modfile : modfiles) { + futures.emplace_back(std::async(std::launch::async, ProcessModfile, std::ref(*this), modfile, files_size > 400'000'000)); + } + // Join all threads + for (auto& future : futures) { + loaded_size += future.get(); + } + Message("Finished loading mods from %s: Loaded %u bytes (%u mb)", source, loaded_size, loaded_size / 1024 / 1024); +} + +void TextureClient::Initialize() +{ + Message("Initialize: begin\n"); + Message("Initialize: searching for modlist.txt\n"); + char gwpath[MAX_PATH]{}; + GetModuleFileName(GetModuleHandle(nullptr), gwpath, MAX_PATH); //ask for name and path of this executable + char dllpath[MAX_PATH]{}; + GetModuleFileName(gl_hThisInstance, dllpath, MAX_PATH); //ask for name and path of this dll + exe_path = std::filesystem::path(gwpath).parent_path(); + dll_path = std::filesystem::path(dllpath).parent_path(); + for (const auto& path : {exe_path, dll_path}) { + const auto modlist = path / "modlist.txt"; + if (std::filesystem::exists(modlist)) { + Message("Initialize: found %s\n", modlist.string().c_str()); + LoadModsFromFile(modlist.string().c_str()); + } + } + + Message("Initialize: end\n"); +} + +int TextureClient::AddTexture(uModTexturePtr auto pTexture) +{ + if constexpr (std::same_as) { + SetLastCreatedTexture(nullptr); + } + else if constexpr (std::same_as) { + SetLastCreatedVolumeTexture(nullptr); + } + else if constexpr (std::same_as) { + SetLastCreatedCubeTexture(nullptr); + } + + if (pTexture->FAKE) { + return RETURN_OK; // this is a fake texture + } + + if (gl_ErrorState & uMod_ERROR_FATAL) { + return RETURN_FATAL_ERROR; + } + + Message("TextureClient::AddTexture( Cube: %p): %p (thread: %u)\n", pTexture, this, GetCurrentThreadId()); + + pTexture->Hash = pTexture->GetHash(); + if (!pTexture->Hash) { + return RETURN_FATAL_ERROR; + } + + if constexpr (std::same_as) { + OriginalTextures.push_back(pTexture); + } + else if constexpr (std::same_as) { + OriginalVolumeTextures.push_back(pTexture); + } + else if constexpr (std::same_as) { + OriginalCubeTextures.push_back(pTexture); + } + + return LookUpToMod(pTexture); // check if this texture should be modded +} + +int TextureClient::RemoveTexture(uModTexturePtr auto pTexture) +{ + Message("TextureClient::RemoveTexture( %p, %#lX): %p\n", pTexture, pTexture->Hash, this); + + if (gl_ErrorState & uMod_ERROR_FATAL) { + return RETURN_FATAL_ERROR; + } + + if (!pTexture->FAKE) { + if constexpr (std::same_as) { + utils::erase_first(OriginalTextures, pTexture); + } + else if constexpr (std::same_as) { + utils::erase_first(OriginalVolumeTextures, pTexture); + } + else if constexpr (std::same_as) { + utils::erase_first(OriginalCubeTextures, pTexture); + } + } + if (!pTexture->Reference) + return RETURN_OK; // Should this ever happen? + return RETURN_OK; +} + +int TextureClient::LookUpToMod(uModTexturePtr auto pTexture) +{ + Message("TextureClient::LookUpToMod( %p): hash: %#lX, %p\n", pTexture, pTexture->Hash, this); + int ret = RETURN_OK; + + if (pTexture->CrossRef_D3Dtex != nullptr) + return ret; // bug, this texture is already switched + + const auto found = modded_textures.find(pTexture->Hash); + if (found == modded_textures.end()) + return ret; + + const auto textureFileStruct = found->second; + + decltype(pTexture) fake_Texture; + ret = LoadTexture(textureFileStruct, &fake_Texture); + if (ret != RETURN_OK) + return ret; + + ret = SwitchTextures(fake_Texture, pTexture); + if (ret != RETURN_OK) { + Message("TextureClient::LookUpToMod(): textures not switched %#lX\n", textureFileStruct->crc_hash); + fake_Texture->Release(); + return ret; + } + fake_Texture->Reference = textureFileStruct; + return ret; +} + +int TextureClient::LoadTexture(TextureFileStruct* file_in_memory, uModTexturePtrPtr auto ppTexture) +{ + Message("LoadTexture( %p, %p, %#lX): %p\n", file_in_memory, ppTexture, file_in_memory->crc_hash, this); + if (const auto ret = DirectX::CreateDDSTextureFromMemoryEx( + D3D9Device, + file_in_memory->data.data(), + file_in_memory->data.size(), + 0, D3DPOOL_MANAGED, false, + reinterpret_cast(ppTexture)); ret != D3D_OK) { + *ppTexture = nullptr; + Warning("LoadDDSTexture (%p, %#lX): FAILED ret: \n", file_in_memory->data.data(), file_in_memory->crc_hash, ret); + return RETURN_TEXTURE_NOT_LOADED; + } + if constexpr (std::same_as) { + SetLastCreatedTexture(nullptr); + } + else if constexpr (std::same_as) { + SetLastCreatedVolumeTexture(nullptr); + } + else if constexpr (std::same_as) { + SetLastCreatedCubeTexture(nullptr); + } + (*ppTexture)->FAKE = true; + + Message("LoadTexture (%p, %#lX): DONE\n", *ppTexture, file_in_memory->crc_hash); + return RETURN_OK; +} diff --git a/modules/TextureFunction.ixx b/modules/TextureFunction.ixx new file mode 100644 index 0000000..4a995c3 --- /dev/null +++ b/modules/TextureFunction.ixx @@ -0,0 +1,321 @@ +module; + +#include "Main.h" +#include +#include + +export module TextureFunction; + +export template +concept uModTexturePtr = requires(T a) +{ + std::same_as || + std::same_as || + std::same_as; +}; + +export template +concept uModTexturePtrPtr = uModTexturePtr>; + +export template requires uModTexturePtr +void UnswitchTextures(T pTexture) +{ + decltype(pTexture) CrossRef = pTexture->CrossRef_D3Dtex; + if (CrossRef != nullptr) { + std::swap(pTexture->m_D3Dtex, CrossRef->m_D3Dtex); + + // cancel the link + CrossRef->CrossRef_D3Dtex = nullptr; + pTexture->CrossRef_D3Dtex = nullptr; + } +} + +export template requires uModTexturePtr +int SwitchTextures(T pTexture1, T pTexture2) +{ + if (pTexture1->m_D3Ddev == pTexture2->m_D3Ddev && pTexture1->CrossRef_D3Dtex == nullptr && pTexture2->CrossRef_D3Dtex == nullptr) { + // make cross reference + pTexture1->CrossRef_D3Dtex = pTexture2; + pTexture2->CrossRef_D3Dtex = pTexture1; + + // switch textures + std::swap(pTexture1->m_D3Dtex, pTexture2->m_D3Dtex); + return RETURN_OK; + } + return RETURN_TEXTURE_NOT_SWITCHED; +} + +export namespace TextureFunction { + + unsigned int GetCRC32(char* pcDatabuf, unsigned int ulDatalen) + { + constexpr static auto crc32_poly = 0xEDB88320u; + constexpr static auto ul_crc_in = 0xffffffff; + unsigned int crc = ul_crc_in; + for (unsigned int idx = 0u; idx < ulDatalen; idx++) { + unsigned int data = *pcDatabuf++; + for (unsigned int bit = 0u; bit < 8u; bit++, data >>= 1) { + crc = crc >> 1 ^ ((crc ^ data) & 1 ? crc32_poly : 0); + } + } + return crc; + } + + int GetBitsFromFormat(D3DFORMAT format) + { + switch (format) //switch trough the formats to calculate the size of the raw data + { + case D3DFMT_A1: // 1-bit monochrome. + { + return 1; + } + + case D3DFMT_R3G3B2: // 8-bit RGB texture format using 3 bits for red, 3 bits for green, and 2 bits for blue. + case D3DFMT_A8: // 8-bit alpha only. + case D3DFMT_A8P8: // 8-bit color indexed with 8 bits of alpha. + case D3DFMT_P8: // 8-bit color indexed. + case D3DFMT_L8: // 8-bit luminance only. + case D3DFMT_A4L4: // 8-bit using 4 bits each for alpha and luminance. + case D3DFMT_FORCE_DWORD: + case D3DFMT_S8_LOCKABLE: // A lockable 8-bit stencil buffer. + { + return 8; + } + + case D3DFMT_D16_LOCKABLE: //16-bit z-buffer bit depth. + case D3DFMT_D15S1: // 16-bit z-buffer bit depth where 15 bits are reserved for the depth channel and 1 bit is reserved for the stencil channel. + case D3DFMT_L6V5U5: // 16-bit bump-map format with luminance using 6 bits for luminance, and 5 bits each for v and u. + case D3DFMT_V8U8: // 16-bit bump-map format using 8 bits each for u and v data. + case D3DFMT_CxV8U8: // 16-bit normal compression format. The texture sampler computes the C channel from: C = sqrt(1 - U2 - V2). + case D3DFMT_R5G6B5: // 16-bit RGB pixel format with 5 bits for red, 6 bits for green, and 5 bits for blue. + case D3DFMT_X1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color. + case D3DFMT_A1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color and 1 bit is reserved for alpha. + case D3DFMT_A4R4G4B4: // 16-bit ARGB pixel format with 4 bits for each channel. + case D3DFMT_A8R3G3B2: // 16-bit ARGB texture format using 8 bits for alpha, 3 bits each for red and green, and 2 bits for blue. + case D3DFMT_X4R4G4B4: // 16-bit RGB pixel format using 4 bits for each color. + case D3DFMT_L16: // 16-bit luminance only. + case D3DFMT_R16F: // 16-bit float format using 16 bits for the red channel. + case D3DFMT_A8L8: // 16-bit using 8 bits each for alpha and luminance. + case D3DFMT_D16: // 16-bit z-buffer bit depth. + case D3DFMT_INDEX16: // 16-bit index buffer bit depth. + case D3DFMT_G8R8_G8B8: // ?? + case D3DFMT_R8G8_B8G8: // ?? + case D3DFMT_UYVY: // ?? + case D3DFMT_YUY2: // ?? + { + return 16; + } + + + case D3DFMT_R8G8B8: //24-bit RGB pixel format with 8 bits per channel. + { + return 24; + } + + case D3DFMT_R32F: // 32-bit float format using 32 bits for the red channel. + case D3DFMT_X8L8V8U8: // 32-bit bump-map format with luminance using 8 bits for each channel. + case D3DFMT_A2W10V10U10: // 32-bit bump-map format using 2 bits for alpha and 10 bits each for w, v, and u. + case D3DFMT_Q8W8V8U8: // 32-bit bump-map format using 8 bits for each channel. + case D3DFMT_V16U16: // 32-bit bump-map format using 16 bits for each channel. + case D3DFMT_A8R8G8B8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. + case D3DFMT_X8R8G8B8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. + case D3DFMT_A2B10G10R10: // 32-bit pixel format using 10 bits for each color and 2 bits for alpha. + case D3DFMT_A8B8G8R8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. + case D3DFMT_X8B8G8R8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. + case D3DFMT_G16R16: // 32-bit pixel format using 16 bits each for green and red. + case D3DFMT_G16R16F: // 32-bit float format using 16 bits for the red channel and 16 bits for the green channel. + case D3DFMT_A2R10G10B10: // 32-bit pixel format using 10 bits each for red, green, and blue, and 2 bits for alpha. + case D3DFMT_D32: // 32-bit z-buffer bit depth. + case D3DFMT_D24S8: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 8 bits for the stencil channel. + case D3DFMT_D24X8: //32-bit z-buffer bit depth using 24 bits for the depth channel. + case D3DFMT_D24X4S4: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 4 bits for the stencil channel. + case D3DFMT_D32F_LOCKABLE: // A lockable format where the depth value is represented as a standard IEEE floating-point number. + case D3DFMT_D24FS8: // A non-lockable format that contains 24 bits of depth (in a 24-bit floating point format - 20e4) and 8 bits of stencil. + case D3DFMT_D32_LOCKABLE: // A lockable 32-bit depth buffer. + case D3DFMT_INDEX32: // 32-bit index buffer bit depth. + { + return 32; + } + + case D3DFMT_G32R32F: // 64-bit float format using 32 bits for the red channel and 32 bits for the green channel. + case D3DFMT_Q16W16V16U16: // 64-bit bump-map format using 16 bits for each component. + case D3DFMT_A16B16G16R16: // 64-bit pixel format using 16 bits for each component. + case D3DFMT_A16B16G16R16F: // 64-bit float format using 16 bits for the each channel (alpha, blue, green, red). + { + return 64; + } + + case D3DFMT_A32B32G32R32F: // 128-bit float format using 32 bits for the each channel (alpha, blue, green, red). + { + return 128; + } + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: { + return 8; + } + case D3DFMT_DXT1: { + return 4; + } + default: //compressed formats + { + return 4; + } + } + } + + DirectX::ScratchImage ImageConvertToBGRA(DirectX::ScratchImage& image, const TexEntry& entry) + { + if (image.GetMetadata().format == DXGI_FORMAT_B8G8R8A8_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC1_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC2_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC3_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC4_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC5_UNORM) { + return std::move(image); + } + DirectX::ScratchImage bgra_image; + const HRESULT hr = DirectX::Convert( + image.GetImages(), + image.GetImageCount(), + image.GetMetadata(), + DXGI_FORMAT_B8G8R8A8_UNORM, + DirectX::TEX_FILTER_DEFAULT, + DirectX::TEX_THRESHOLD_DEFAULT, + bgra_image); + if (FAILED(hr)) { + Warning("ImageConvertToBGRA (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str()); + bgra_image = std::move(image); + } + image.Release(); + return bgra_image; + } + + DirectX::ScratchImage ImageGenerateMipMaps(DirectX::ScratchImage& image, const TexEntry& entry) + { + if (entry.ext == ".dds") { + return std::move(image); + } + DirectX::ScratchImage mipmapped_image; + const auto hr = DirectX::GenerateMipMaps( + image.GetImages(), + image.GetImageCount(), + image.GetMetadata(), + DirectX::TEX_FILTER_DEFAULT, + 0, + mipmapped_image); + if (FAILED(hr)) { + Warning("GenerateMipMaps (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str()); + mipmapped_image = std::move(image); + } + image.Release(); + return mipmapped_image; + } + + DirectX::ScratchImage ImageCompress(DirectX::ScratchImage& image, const TexEntry& entry) + { + if (image.GetMetadata().format == DXGI_FORMAT_BC1_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC2_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC3_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC4_UNORM || + image.GetMetadata().format == DXGI_FORMAT_BC5_UNORM) { + return std::move(image); + } + DirectX::ScratchImage compressed_image; + const auto hr = DirectX::Compress( + image.GetImages(), + image.GetImageCount(), + image.GetMetadata(), + DXGI_FORMAT_BC3_UNORM, + DirectX::TEX_COMPRESS_DEFAULT, + DirectX::TEX_THRESHOLD_DEFAULT, + compressed_image); + if (FAILED(hr)) { + Warning("ImageCompress (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str()); + compressed_image = std::move(image); + } + image.Release(); + return compressed_image; + } + + void ImageSave(const DirectX::ScratchImage& image, const TexEntry& entry, const std::filesystem::path& dll_path) + { + const auto file_name = std::format("0x{:x}.dds", entry.crc_hash); + const auto file_out = dll_path / "textures" / file_name; + try { + if (std::filesystem::exists(file_out)) { + return; + } + if (!std::filesystem::exists(file_out.parent_path())) { + std::filesystem::create_directory(file_out.parent_path()); + } + const auto hr = DirectX::SaveToDDSFile( + image.GetImages(), + image.GetImageCount(), + image.GetMetadata(), + DirectX::DDS_FLAGS_NONE, + file_out.c_str()); + if (FAILED(hr)) { + Warning("SaveDDSImageToDisk (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str()); + } + } + catch (const std::exception& e) { + Warning("SaveDDSImageToDisk (%#lX%s): %s\n", entry.crc_hash, entry.ext.c_str(), e.what()); + return; + } + } + + DirectX::Blob ConvertToCompressedDDS(TexEntry& entry, const bool compress, const std::filesystem::path& dll_path) + { + DirectX::ScratchImage image; + HRESULT hr = 0; + + if (entry.ext == ".dds") { + hr = DirectX::LoadFromDDSMemory(entry.data.data(), entry.data.size(), DirectX::DDS_FLAGS_NONE, nullptr, image); + } + else if (entry.ext == ".tga") { + hr = DirectX::LoadFromTGAMemory(entry.data.data(), entry.data.size(), DirectX::TGA_FLAGS_BGR, nullptr, image); + } + else if (entry.ext == ".hdr") { + hr = DirectX::LoadFromHDRMemory(entry.data.data(), entry.data.size(), nullptr, image); + } + else { + hr = DirectX::LoadFromWICMemory(entry.data.data(), entry.data.size(), DirectX::WIC_FLAGS_NONE, nullptr, image); + if (image.GetMetadata().format == DXGI_FORMAT_B8G8R8X8_UNORM) { + // todo: this is undefined behaviour, but we must force them to be interpreted as BGRA instead of BGRX + const_cast(image.GetMetadata().format) = DXGI_FORMAT_B8G8R8A8_UNORM; + const auto images = image.GetImages(); + for (int i = 0; i < image.GetImageCount(); ++i) { + const_cast(images[i].format) = DXGI_FORMAT_B8G8R8A8_UNORM; + } + } + } + entry.data.clear(); + if (FAILED(hr)) { + Warning("LoadImageFromMemory (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str()); + return {}; + } + + auto bgra_image = ImageConvertToBGRA(image, entry); + auto mipmapped_image = ImageGenerateMipMaps(bgra_image, entry); + const auto compressed_image = compress ? ImageCompress(mipmapped_image, entry) : std::move(mipmapped_image); + + DirectX::Blob dds_blob; + hr = DirectX::SaveToDDSMemory( + compressed_image.GetImages(), + compressed_image.GetImageCount(), + compressed_image.GetMetadata(), + DirectX::DDS_FLAGS_NONE, + dds_blob); + if (FAILED(hr)) { + Warning("SaveDDSImageToMemory (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str()); + return {}; + } + + #ifdef _DEBUG + ImageSave(compressed_image, entry, dll_path); + #endif + return dds_blob; + } +} diff --git a/source/TextureClient.cpp b/source/TextureClient.cpp deleted file mode 100644 index 22f95b0..0000000 --- a/source/TextureClient.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include - -#include "Main.h" - -TextureClient::TextureClient(IDirect3DDevice9* device) -{ - Message("TextureClient::TextureClient(): %p\n", this); - D3D9Device = device; - - void* cpy; - isDirectXExDevice = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy) == 0x01000001L; - - mutex = CreateMutex(nullptr, false, nullptr); -} - -TextureClient::~TextureClient() -{ - Message("TextureClient::~TextureClient(): %p\n", this); - if (mutex != nullptr) { - CloseHandle(mutex); - } - for (const auto& it : modded_textures) { - delete it.second; - } - modded_textures.clear(); -} - -int TextureClient::MergeUpdate() -{ - if (!should_update) return RETURN_OK; - should_update = false; - if (const int ret = LockMutex()) { - gl_ErrorState |= uMod_ERROR_TEXTURE; - return ret; - } - - Message("MergeUpdate(): %p\n", this); - - for (const auto pTexture : OriginalTextures) { - if (pTexture->CrossRef_D3Dtex == nullptr) { - LookUpToMod(pTexture); - } - } - for (const auto pTexture : OriginalVolumeTextures) { - if (pTexture->CrossRef_D3Dtex == nullptr) { - LookUpToMod(pTexture); - } - } - for (const auto pTexture : OriginalCubeTextures) { - if (pTexture->CrossRef_D3Dtex == nullptr) { - LookUpToMod(pTexture); - } - } - - return UnlockMutex(); -} - -void TextureClient::SetLastCreatedTexture(uMod_IDirect3DTexture9* texture) -{ - if (isDirectXExDevice) - return static_cast(D3D9Device)->SetLastCreatedTexture(texture); - return static_cast(D3D9Device)->SetLastCreatedTexture(texture); -} - -void TextureClient::SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* texture) -{ - if (isDirectXExDevice) - return static_cast(D3D9Device)->SetLastCreatedVolumeTexture(texture); - return static_cast(D3D9Device)->SetLastCreatedVolumeTexture(texture); -} - -void TextureClient::SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* texture) -{ - if (isDirectXExDevice) - return static_cast(D3D9Device)->SetLastCreatedCubeTexture(texture); - return static_cast(D3D9Device)->SetLastCreatedCubeTexture(texture); -} - -int TextureClient::LockMutex() -{ - if ((gl_ErrorState & (uMod_ERROR_FATAL | uMod_ERROR_MUTEX))) { - return RETURN_NO_MUTEX; - } - if (WAIT_OBJECT_0 != WaitForSingleObject(mutex, 100)) { - return RETURN_MUTEX_LOCK; //waiting 100ms, to wait infinite pass INFINITE - } - return RETURN_OK; -} - -int TextureClient::UnlockMutex() -{ - if (ReleaseMutex(mutex) == 0) { - return RETURN_MUTEX_UNLOCK; - } - return RETURN_OK; -} - -unsigned long TextureClient::AddFile(TextureFileStruct& entry) -{ - if (modded_textures.contains(entry.crc_hash)) { - return 0; - } - TextureFileStruct* texture_file_struct = new TextureFileStruct(); - texture_file_struct->data = std::move(entry.data); - texture_file_struct->crc_hash = entry.crc_hash; - texture_file_struct->is_wic_texture = entry.is_wic_texture; - modded_textures.emplace(entry.crc_hash, texture_file_struct); - should_update = true; - return texture_file_struct->data.size(); -} - -void TextureClient::LoadModsFromFile(const char* source) -{ - static unsigned long loaded_size = 0; - Message("Initialize: searching in %s\n", source); - - std::ifstream file(source); - if (!file.is_open()) { - Warning("LoadModsFromFile: failed to open modlist.txt for reading; aborting!!!"); - return; - } - Message("Initialize: found modlist.txt. Reading\n"); - std::string line; - while (std::getline(file, line)) { - Message("Initialize: loading file %s... ", line.c_str()); - - // Remove newline character - line.erase(std::ranges::remove(line, '\n').begin(), line.end()); - - auto file_loader = FileLoader(line); - auto entries = file_loader.GetContents(); - if (loaded_size > 1'500'000'000) { - Message("LoadModsFromFile: Loaded %d bytes, aborting!!!\n", loaded_size); - return; - } - if (entries.empty()) { - Message("No entries found.\n"); - continue; - } - Message("%zu textures... ", entries.size()); - unsigned long file_bytes_loaded = 0; - for (auto& tpf_entry : entries) { - file_bytes_loaded += AddFile(tpf_entry); - } - entries.clear(); - Message("%d bytes loaded.\n", file_bytes_loaded); - loaded_size += file_bytes_loaded; - } - Message("Finished loading mods from %s: Loaded %u bytes (%u mb)", source, loaded_size, loaded_size / 1024 / 1024); -} - -void TextureClient::Initialize() -{ - Message("Initialize: begin\n"); - Message("Initialize: searching for modlist.txt\n"); - char gwpath[MAX_PATH]{}; - GetModuleFileName(GetModuleHandle(nullptr), gwpath, MAX_PATH); //ask for name and path of this executable - char dllpath[MAX_PATH]{}; - GetModuleFileName(gl_hThisInstance, dllpath, MAX_PATH); //ask for name and path of this dll - const auto exe = std::filesystem::path(gwpath).parent_path(); - const auto dll = std::filesystem::path(dllpath).parent_path(); - for (const auto& path : {exe, dll}) { - const auto modlist = path / "modlist.txt"; - if (std::filesystem::exists(modlist)) { - Message("Initialize: found %s\n", modlist.string().c_str()); - LoadModsFromFile(modlist.string().c_str()); - } - } - - Message("Initialize: end\n"); -} diff --git a/source/dll_main.cpp b/source/dll_main.cpp index 5d0ac10..920a8c4 100644 --- a/source/dll_main.cpp +++ b/source/dll_main.cpp @@ -1,15 +1,13 @@ -#include "dll_main.h" - -#include #include "Main.h" #include - #include "MinHook.h" -#include + +void ExitInstance(); +void InitInstance(HINSTANCE hModule); namespace { -#define DISABLE_HOOK(var) if(var) { MH_DisableHook(var);} + #define DISABLE_HOOK(var) if(var) { MH_DisableHook(var);} using Direct3DCreate9_type = IDirect3D9* (APIENTRY*)(UINT); using Direct3DCreate9Ex_type = HRESULT(APIENTRY*)(UINT SDKVersion, IDirect3D9Ex** ppD3D); @@ -29,9 +27,8 @@ namespace { HMODULE gMod_Loaded_d3d9_Module_Handle = nullptr; - - - HMODULE FindLoadedModuleByName(const char* name, bool include_this_module = false) { + HMODULE FindLoadedModuleByName(const char* name, bool include_this_module = false) + { HMODULE hModules[1024]; HANDLE hProcess; DWORD cbNeeded; @@ -66,8 +63,6 @@ namespace { const auto exe_path = std::filesystem::path(executable_path); const auto gmod_path = std::filesystem::path(dll_path); - bool successful_load = false; - if (exe_path.parent_path() != gmod_path.parent_path() || gmod_path.filename() != "d3d9.dll") { // Call basic LoadLibrary function; we're not in the same directory as the exe. @@ -75,7 +70,7 @@ namespace { } if (!gMod_Loaded_d3d9_Module_Handle) { // Tried resolving d3d9.dll locally, didn't work. Try system directory - char buffer[MAX_PATH] ; + char buffer[MAX_PATH]; ASSERT(GetSystemDirectory(buffer, _countof(buffer)) > 0); //get the system directory, we need to open the original d3d9.dll // Append dll name @@ -91,30 +86,32 @@ namespace { DISABLE_HOOK(GetProcAddress_fn); // GetProcAddress, hooked via OnGetProcAddress - Direct3DCreate9_ret = (Direct3DCreate9_type)GetProcAddress(found, "Direct3DCreate9"); - Direct3DCreate9Ex_ret = (Direct3DCreate9Ex_type)GetProcAddress(found, "Direct3DCreate9Ex"); + Direct3DCreate9_ret = reinterpret_cast(GetProcAddress(found, "Direct3DCreate9")); + Direct3DCreate9Ex_ret = reinterpret_cast(GetProcAddress(found, "Direct3DCreate9Ex")); return found; } - FARPROC APIENTRY OnGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { + FARPROC APIENTRY OnGetProcAddress(HMODULE hModule, LPCSTR lpProcName) + { ASSERT(GetProcAddress_ret); if ((int)lpProcName < 0xffff) return GetProcAddress_ret(hModule, lpProcName); // lpProcName is ordinal offset, not string - if (strcmp(lpProcName, "Direct3DCreate9") == 0) { - Direct3DCreate9_ret = (Direct3DCreate9_type)GetProcAddress_ret(hModule, lpProcName); - return (FARPROC)Direct3DCreate9; - } - if (strcmp(lpProcName, "Direct3DCreate9Ex") == 0) { - Direct3DCreate9Ex_ret = (Direct3DCreate9Ex_type)GetProcAddress_ret(hModule, lpProcName); - return (FARPROC)Direct3DCreate9Ex; - } - return GetProcAddress_ret(hModule, lpProcName); + if (strcmp(lpProcName, "Direct3DCreate9") == 0) { + Direct3DCreate9_ret = reinterpret_cast(GetProcAddress_ret(hModule, lpProcName)); + return reinterpret_cast(Direct3DCreate9); } + if (strcmp(lpProcName, "Direct3DCreate9Ex") == 0) { + Direct3DCreate9Ex_ret = reinterpret_cast(GetProcAddress_ret(hModule, lpProcName)); + return reinterpret_cast(Direct3DCreate9Ex); + } + return GetProcAddress_ret(hModule, lpProcName); + } // If the original d3d9 function is nullptr or points to gMod, load the actual d3d9 dll and redirect the addresses - void CheckLoadD3d9Dll() { + void CheckLoadD3d9Dll() + { if (!(Direct3DCreate9_ret && Direct3DCreate9_ret != Direct3DCreate9)) { ASSERT(LoadD3d9Dll()); ASSERT(Direct3DCreate9_ret && Direct3DCreate9_ret != Direct3DCreate9); @@ -132,7 +129,7 @@ namespace { unsigned int gl_ErrorState = 0; HINSTANCE gl_hThisInstance = nullptr; -extern "C" IDirect3D9* APIENTRY Direct3DCreate9(UINT SDKVersion) +IDirect3D9* APIENTRY Direct3DCreate9(UINT SDKVersion) { Message("uMod_Direct3DCreate9: uMod %p\n", Direct3DCreate9); @@ -150,7 +147,7 @@ extern "C" IDirect3D9* APIENTRY Direct3DCreate9(UINT SDKVersion) return new uMod_IDirect3D9(pIDirect3D9_orig); //return our object instead of the "real one" } -extern "C" HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D) +HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D) { Message("uMod_Direct3DCreate9Ex: uMod %p\n", Direct3DCreate9Ex); @@ -247,4 +244,3 @@ void ExitInstance() __except (EXCEPTION_CONTINUE_EXECUTION) { } #endif } - diff --git a/source/uMod_IDirect3DCubeTexture9.cpp b/source/uMod_IDirect3DCubeTexture9.cpp index 69f4e45..bfb50c7 100644 --- a/source/uMod_IDirect3DCubeTexture9.cpp +++ b/source/uMod_IDirect3DCubeTexture9.cpp @@ -1,5 +1,8 @@ #include "Main.h" +import TextureFunction; +import TextureClient; + //this function yields for the non switched texture object HRESULT APIENTRY uMod_IDirect3DCubeTexture9::QueryInterface(REFIID riid, void** ppvObj) { @@ -260,8 +263,8 @@ HashType uMod_IDirect3DCubeTexture9::GetHash() const } } - const int size = (GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8; - const auto hash = GetCRC32(static_cast(d3dlr.pBits), size); //calculate the crc32 of the texture + const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8; + const auto hash = TextureFunction::GetCRC32(static_cast(d3dlr.pBits), size); //calculate the crc32 of the texture // Only release surfaces after we're finished with d3dlr if (pResolvedSurface != nullptr) { diff --git a/source/uMod_IDirect3DDevice9.cpp b/source/uMod_IDirect3DDevice9.cpp index b86f1be..9af66aa 100644 --- a/source/uMod_IDirect3DDevice9.cpp +++ b/source/uMod_IDirect3DDevice9.cpp @@ -1,4 +1,5 @@ #include "Main.h" +import TextureClient; #ifndef RETURN_QueryInterface #define RETURN_QueryInterface 0x01000000L diff --git a/source/uMod_IDirect3DTexture9.cpp b/source/uMod_IDirect3DTexture9.cpp index c38267a..8a9f7b3 100644 --- a/source/uMod_IDirect3DTexture9.cpp +++ b/source/uMod_IDirect3DTexture9.cpp @@ -1,5 +1,8 @@ #include "Main.h" +import TextureFunction; +import TextureClient; + //this function yields for the non switched texture object HRESULT APIENTRY uMod_IDirect3DTexture9::QueryInterface(REFIID riid, void** ppvObj) { @@ -318,8 +321,8 @@ HashType uMod_IDirect3DTexture9::GetHash() const } } - const int size = (GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8; - const auto hash = GetCRC32(static_cast(d3dlr.pBits), size); //calculate the crc32 of the texture + const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8; + const auto hash = TextureFunction::GetCRC32(static_cast(d3dlr.pBits), size); //calculate the crc32 of the texture // Only release surfaces after we're finished with d3dlr if (pOffscreenSurface != nullptr) { diff --git a/source/uMod_IDirect3DVolumeTexture9.cpp b/source/uMod_IDirect3DVolumeTexture9.cpp index 8f85f86..51ad395 100644 --- a/source/uMod_IDirect3DVolumeTexture9.cpp +++ b/source/uMod_IDirect3DVolumeTexture9.cpp @@ -1,4 +1,6 @@ #include "Main.h" +import TextureFunction; +import TextureClient; HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::QueryInterface(REFIID riid, void** ppvObj) { @@ -257,8 +259,8 @@ HashType uMod_IDirect3DVolumeTexture9::GetHash() const } } - const int size = (GetBitsFromFormat(desc.Format) * desc.Width * desc.Height * desc.Depth) / 8; - const auto hash = GetCRC32(static_cast(d3dlr.pBits), size); //calculate the crc32 of the texture + const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height * desc.Depth) / 8; + const auto hash = TextureFunction::GetCRC32(static_cast(d3dlr.pBits), size); //calculate the crc32 of the texture // Only release surfaces after we're finished with d3dlr if (pResolvedSurface != nullptr) {