mirror of
https://github.com/gwdevhub/gMod.git
synced 2026-07-15 15:09:30 +00:00
remove d3dx dependency, severely improve memory usage if necessary (#19)
* basic tga/hdr image loading * bgr tga tex * convert to dds during loading doesn't work yet, fails to create textures from dds memory * remove ext member from TextureFileStruct * do not convert images, leads to weird loading problems... * use regex matching for tpf loading * convert non-RGBA images to RGBA * remove d3dx (mostly) * fix moving wrong image * move TextureFunction to module * move FileLoader to ModfileLoader module * move TextureClient to module * spaces * ifdef debug * 1.6.0 * compress images to dxt5 (bc3_unorm) to use less memory * remove unnecessary directxtex source code patch * don't move unnecessarily * only compress if mods in filesystem use up more than 400mb * use std::future to prepare to multithread image loading fails when using std::launch::async though, maybe something in the directxtex library is not thread safe * remove d3dx sdk from workflows * remove extern "C" * catch exception when saving texture * make loading async (call CoInitializeEx) * support DXGI_FORMAT_BC1_UNORM (DXT1) compressed textures without warning * don't warn for BC2 BC4 or BC5 either * update README.md
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
+7
-25
@@ -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
|
||||
"$<$<CONFIG:DEBUG>:/NODEFAULTLIB:LIBCMT>"
|
||||
|
||||
@@ -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
|
||||
-14
@@ -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
|
||||
@@ -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"
|
||||
|
||||
+26
-17
@@ -3,27 +3,36 @@
|
||||
//#define HashType DWORD64
|
||||
using HashType = DWORD32;
|
||||
|
||||
#ifdef LOG_MESSAGE
|
||||
#include <iostream>
|
||||
struct TexEntry {
|
||||
std::vector<BYTE> data{};
|
||||
HashType crc_hash = 0; // hash value
|
||||
std::string ext{};
|
||||
};
|
||||
|
||||
struct TextureFileStruct {
|
||||
std::vector<BYTE> 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
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <libzippp.h>
|
||||
|
||||
class FileLoader {
|
||||
std::string file_name;
|
||||
const std::string TPF_PASSWORD{
|
||||
0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast<char>(0xA6), static_cast<char>(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<TextureFileStruct> GetContents();
|
||||
|
||||
private:
|
||||
|
||||
std::vector<TextureFileStruct> GetTpfContents();
|
||||
|
||||
std::vector<TextureFileStruct> GetFileContents();
|
||||
|
||||
void LoadEntries(libzippp::ZipArchive& archive, std::vector<TextureFileStruct>& entries);
|
||||
};
|
||||
+3
-4
@@ -5,7 +5,10 @@
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include "Utils.h"
|
||||
|
||||
#include <d3d9.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "FileLoader.h"
|
||||
#include "uMod_IDirect3DTexture9.h"
|
||||
#include <DDSTextureLoader/DDSTextureLoader9.h>
|
||||
#include <WICTextureLoader/WICTextureLoader9.h>
|
||||
#include <d3dx9.h>
|
||||
|
||||
extern unsigned int gl_ErrorState;
|
||||
|
||||
struct TextureFileStruct {
|
||||
std::vector<BYTE> data{};
|
||||
HashType crc_hash = 0; // hash value
|
||||
bool is_wic_texture = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept uModTexturePtr = requires(T a)
|
||||
{
|
||||
std::same_as<uMod_IDirect3DTexture9*, T> ||
|
||||
std::same_as<uMod_IDirect3DVolumeTexture9*, T> ||
|
||||
std::same_as<uMod_IDirect3DCubeTexture9*, T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept uModTexturePtrPtr = uModTexturePtr<std::remove_pointer_t<T>>;
|
||||
|
||||
/*
|
||||
* 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<uMod_IDirect3DTexture9*> OriginalTextures;
|
||||
// stores the pointer to the uMod_IDirect3DTexture9 objects created by the game
|
||||
std::vector<uMod_IDirect3DVolumeTexture9*> OriginalVolumeTextures;
|
||||
// stores the pointer to the uMod_IDirect3DVolumeTexture9 objects created by the game
|
||||
std::vector<uMod_IDirect3DCubeTexture9*> 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<HashType, TextureFileStruct*> 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<decltype(pTexture), uMod_IDirect3DTexture9*>) {
|
||||
SetLastCreatedTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DVolumeTexture9*>) {
|
||||
SetLastCreatedVolumeTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DCubeTexture9*>) {
|
||||
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<decltype(pTexture), uMod_IDirect3DTexture9*>) {
|
||||
OriginalTextures.push_back(pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DVolumeTexture9*>) {
|
||||
OriginalVolumeTextures.push_back(pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DCubeTexture9*>) {
|
||||
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<decltype(pTexture), uMod_IDirect3DTexture9*>) {
|
||||
utils::erase_first(OriginalTextures, pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DVolumeTexture9*>) {
|
||||
utils::erase_first(OriginalVolumeTextures, pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DCubeTexture9*>) {
|
||||
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<IDirect3DTexture9**>(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<IDirect3DTexture9**>(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<LPDIRECT3DTEXTURE9*>(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<decltype(ppTexture), uMod_IDirect3DTexture9**>) {
|
||||
|
||||
SetLastCreatedTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(ppTexture), uMod_IDirect3DVolumeTexture9**>) {
|
||||
SetLastCreatedVolumeTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(ppTexture), uMod_IDirect3DCubeTexture9**>) {
|
||||
SetLastCreatedCubeTexture(nullptr);
|
||||
}
|
||||
(*ppTexture)->FAKE = true;
|
||||
|
||||
Message("LoadTexture( %p, %#lX): DONE\n", *ppTexture, file_in_memory->crc_hash);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
template <typename T> requires uModTexturePtr<T>
|
||||
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 <typename T> requires uModTexturePtr<T>
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
|
||||
void InitInstance(HINSTANCE hModule);
|
||||
void ExitInstance();
|
||||
HMODULE LoadOriginalDll();
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
|
||||
#include "uMod_IDirect3DTexture9.h"
|
||||
#include "uMod_IDirect3DVolumeTexture9.h"
|
||||
#include "uMod_IDirect3DCubeTexture9.h"
|
||||
#include "TextureClient.h"
|
||||
|
||||
class TextureClient;
|
||||
|
||||
class uMod_IDirect3DDevice9Ex : public IDirect3DDevice9Ex {
|
||||
public:
|
||||
|
||||
@@ -1,14 +1,50 @@
|
||||
#include <..\header\Main.h>
|
||||
#include <filesystem>
|
||||
#include "FileLoader.h"
|
||||
#include "TpfReader.h"
|
||||
module;
|
||||
|
||||
FileLoader::FileLoader(const std::string& fileName)
|
||||
#include "Main.h"
|
||||
#include "Defines.h"
|
||||
|
||||
export module ModfileLoader;
|
||||
|
||||
import <intsafe.h>;
|
||||
import <vector>;
|
||||
import <string>;
|
||||
import <libzippp.h>;
|
||||
import <regex>;
|
||||
import <algorithm>;
|
||||
import <filesystem>;
|
||||
import ModfileLoader.TpfReader;
|
||||
|
||||
export class ModfileLoader {
|
||||
std::string file_name;
|
||||
const std::string TPF_PASSWORD{
|
||||
0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast<char>(0xA6), static_cast<char>(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<TexEntry> GetContents();
|
||||
|
||||
private:
|
||||
|
||||
std::vector<TexEntry> GetTpfContents();
|
||||
|
||||
std::vector<TexEntry> GetFileContents();
|
||||
|
||||
void LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries);
|
||||
};
|
||||
|
||||
ModfileLoader::ModfileLoader(const std::string& fileName)
|
||||
{
|
||||
file_name = std::filesystem::absolute(fileName).string();
|
||||
}
|
||||
|
||||
std::vector<TextureFileStruct> FileLoader::GetContents()
|
||||
std::vector<TexEntry> ModfileLoader::GetContents()
|
||||
{
|
||||
try {
|
||||
return file_name.ends_with(".tpf") ? GetTpfContents() : GetFileContents();
|
||||
@@ -19,9 +55,9 @@ std::vector<TextureFileStruct> FileLoader::GetContents()
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<TextureFileStruct> FileLoader::GetTpfContents()
|
||||
std::vector<TexEntry> ModfileLoader::GetTpfContents()
|
||||
{
|
||||
std::vector<TextureFileStruct> entries;
|
||||
std::vector<TexEntry> 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<TextureFileStruct> FileLoader::GetTpfContents()
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::vector<TextureFileStruct> FileLoader::GetFileContents()
|
||||
std::vector<TexEntry> ModfileLoader::GetFileContents()
|
||||
{
|
||||
std::vector<TextureFileStruct> entries;
|
||||
std::vector<TexEntry> entries;
|
||||
|
||||
libzippp::ZipArchive zip_archive(file_name);
|
||||
zip_archive.open();
|
||||
@@ -53,35 +89,22 @@ std::vector<TextureFileStruct> FileLoader::GetFileContents()
|
||||
return entries;
|
||||
}
|
||||
|
||||
void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TextureFileStruct>& entries)
|
||||
void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TexEntry>& 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<Texture
|
||||
const auto size = entry.getSize();
|
||||
std::vector vec(data_ptr, data_ptr + size);
|
||||
std::filesystem::path tex_name(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 ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& archive, std::vector<TextureFileStruct>& entries)
|
||||
void ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
for (const auto& line : lines) {
|
||||
std::istringstream iss(line);
|
||||
std::string part;
|
||||
std::vector<std::string> 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<std::string>& lines, libzippp::ZipArchive& a
|
||||
const auto size = static_cast<size_t>(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<TextureFileStruct>& entries)
|
||||
void ModfileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
const auto def_file = archive.getEntry("texmod.def");
|
||||
if (def_file.isNull() || !def_file.isFile()) {
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
export module ModfileLoader.TpfReader;
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
import <string>;
|
||||
import <fstream>;
|
||||
import <vector>;
|
||||
|
||||
class TpfReader {
|
||||
export class TpfReader {
|
||||
public:
|
||||
TpfReader(const std::string& path)
|
||||
{
|
||||
@@ -0,0 +1,380 @@
|
||||
module;
|
||||
|
||||
#include "Main.h"
|
||||
#include "Error.h"
|
||||
#include "uMod_IDirect3DTexture9.h"
|
||||
#include <DDSTextureLoader/DDSTextureLoader9.h>
|
||||
#include <DirectXTex/DirectXTex.h>
|
||||
|
||||
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<uMod_IDirect3DTexture9*> OriginalTextures;
|
||||
// stores the pointer to the uMod_IDirect3DTexture9 objects created by the game
|
||||
std::vector<uMod_IDirect3DVolumeTexture9*> OriginalVolumeTextures;
|
||||
// stores the pointer to the uMod_IDirect3DVolumeTexture9 objects created by the game
|
||||
std::vector<uMod_IDirect3DCubeTexture9*> 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<HashType, TextureFileStruct*> 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<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedTexture(texture);
|
||||
}
|
||||
|
||||
void TextureClient::SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* texture)
|
||||
{
|
||||
if (isDirectXExDevice)
|
||||
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
|
||||
}
|
||||
|
||||
void TextureClient::SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* texture)
|
||||
{
|
||||
if (isDirectXExDevice)
|
||||
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedCubeTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(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<BYTE*>(dds_blob.GetBufferPointer()), static_cast<BYTE*>(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<std::string> 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<std::string> 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<std::future<unsigned>> 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<decltype(pTexture), uMod_IDirect3DTexture9*>) {
|
||||
SetLastCreatedTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DVolumeTexture9*>) {
|
||||
SetLastCreatedVolumeTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DCubeTexture9*>) {
|
||||
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<decltype(pTexture), uMod_IDirect3DTexture9*>) {
|
||||
OriginalTextures.push_back(pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DVolumeTexture9*>) {
|
||||
OriginalVolumeTextures.push_back(pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DCubeTexture9*>) {
|
||||
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<decltype(pTexture), uMod_IDirect3DTexture9*>) {
|
||||
utils::erase_first(OriginalTextures, pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DVolumeTexture9*>) {
|
||||
utils::erase_first(OriginalVolumeTextures, pTexture);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(pTexture), uMod_IDirect3DCubeTexture9*>) {
|
||||
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<LPDIRECT3DTEXTURE9*>(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<decltype(ppTexture), uMod_IDirect3DTexture9**>) {
|
||||
SetLastCreatedTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(ppTexture), uMod_IDirect3DVolumeTexture9**>) {
|
||||
SetLastCreatedVolumeTexture(nullptr);
|
||||
}
|
||||
else if constexpr (std::same_as<decltype(ppTexture), uMod_IDirect3DCubeTexture9**>) {
|
||||
SetLastCreatedCubeTexture(nullptr);
|
||||
}
|
||||
(*ppTexture)->FAKE = true;
|
||||
|
||||
Message("LoadTexture (%p, %#lX): DONE\n", *ppTexture, file_in_memory->crc_hash);
|
||||
return RETURN_OK;
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
module;
|
||||
|
||||
#include "Main.h"
|
||||
#include <d3d9types.h>
|
||||
#include <DirectXTex/DirectXTex.h>
|
||||
|
||||
export module TextureFunction;
|
||||
|
||||
export template <typename T>
|
||||
concept uModTexturePtr = requires(T a)
|
||||
{
|
||||
std::same_as<uMod_IDirect3DTexture9*, T> ||
|
||||
std::same_as<uMod_IDirect3DVolumeTexture9*, T> ||
|
||||
std::same_as<uMod_IDirect3DCubeTexture9*, T>;
|
||||
};
|
||||
|
||||
export template <typename T>
|
||||
concept uModTexturePtrPtr = uModTexturePtr<std::remove_pointer_t<T>>;
|
||||
|
||||
export template <typename T> requires uModTexturePtr<T>
|
||||
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 <typename T> requires uModTexturePtr<T>
|
||||
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<DXGI_FORMAT&>(image.GetMetadata().format) = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
const auto images = image.GetImages();
|
||||
for (int i = 0; i < image.GetImageCount(); ++i) {
|
||||
const_cast<DXGI_FORMAT&>(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;
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#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<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedTexture(texture);
|
||||
}
|
||||
|
||||
void TextureClient::SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* texture)
|
||||
{
|
||||
if (isDirectXExDevice)
|
||||
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
|
||||
}
|
||||
|
||||
void TextureClient::SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* texture)
|
||||
{
|
||||
if (isDirectXExDevice)
|
||||
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedCubeTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(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");
|
||||
}
|
||||
+24
-28
@@ -1,15 +1,13 @@
|
||||
#include "dll_main.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include "Main.h"
|
||||
#include <Psapi.h>
|
||||
|
||||
#include "MinHook.h"
|
||||
#include <filesystem>
|
||||
|
||||
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<Direct3DCreate9_type>(GetProcAddress(found, "Direct3DCreate9"));
|
||||
Direct3DCreate9Ex_ret = reinterpret_cast<Direct3DCreate9Ex_type>(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<Direct3DCreate9_type>(GetProcAddress_ret(hModule, lpProcName));
|
||||
return reinterpret_cast<FARPROC>(Direct3DCreate9);
|
||||
}
|
||||
if (strcmp(lpProcName, "Direct3DCreate9Ex") == 0) {
|
||||
Direct3DCreate9Ex_ret = reinterpret_cast<Direct3DCreate9Ex_type>(GetProcAddress_ret(hModule, lpProcName));
|
||||
return reinterpret_cast<FARPROC>(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
|
||||
}
|
||||
|
||||
|
||||
@@ -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<char*>(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<char*>(d3dlr.pBits), size); //calculate the crc32 of the texture
|
||||
|
||||
// Only release surfaces after we're finished with d3dlr
|
||||
if (pResolvedSurface != nullptr) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Main.h"
|
||||
import TextureClient;
|
||||
|
||||
#ifndef RETURN_QueryInterface
|
||||
#define RETURN_QueryInterface 0x01000000L
|
||||
|
||||
@@ -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<char*>(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<char*>(d3dlr.pBits), size); //calculate the crc32 of the texture
|
||||
|
||||
// Only release surfaces after we're finished with d3dlr
|
||||
if (pOffscreenSurface != nullptr) {
|
||||
|
||||
@@ -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<char*>(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<char*>(d3dlr.pBits), size); //calculate the crc32 of the texture
|
||||
|
||||
// Only release surfaces after we're finished with d3dlr
|
||||
if (pResolvedSurface != nullptr) {
|
||||
|
||||
Reference in New Issue
Block a user