Compare commits

...

18 Commits

Author SHA1 Message Date
DubbleClick 93032262c3 1.7.0
semicolon instead of comma
2024-09-28 12:21:42 +02:00
DubbleClick fd9d1af477 support 64 bit hashes (#27)
* use image.OverrideFormat()

* 1.6.4

* import std

* uninitialised member variable

* debug statement for 64 bit hash testing

* nopetynope

* uint32_t

* support for 64 bit hashes, but rip compute time :/

* refactor weird comments and constructors

* 1.7.0.0 because of 64 bit hashes

* only check crc64 if at least one mod with crc64 is loaded

* do some dumb shit to deal with incorrect bmps somehow (needs work)

* remove image interpretation for bmps

* create TpfConvert.exe to convert tpf files easily

* attempt

* set up vcpkg and install d3dx though that

* missing env variable?

* Win32 architecture

* update ci to tag TpfConvert.exe and d3dx9.dll as well (required to run TpfConvert)

* documentation
2024-09-28 12:15:04 +02:00
Jon 866455567d Support for 64 bit hashes (truncate should work) 2024-09-25 11:22:05 +01:00
DubbleClick 26b4f4ce4a reshade disclaimer 2024-06-19 18:53:04 +02:00
DubbleClick 5b1bcf6638 Update README.md 2024-06-19 18:49:35 +02:00
DubbleClick 766e6439aa Update README.md 2024-06-19 18:49:00 +02:00
DubbleClick bca0786cff tweak version 1 (#25) 2024-01-24 10:02:55 +01:00
DubbleClick a1f32b5963 Remove d3d9 not loaded assertion (#24)
* Sack off d3d9 check

---------

Co-authored-by: Jon <jon.r+gh@live.com>
2024-01-24 09:22:03 +07:00
DubbleClick 21c20c80e5 fix unicode characters like Umlaute üäÜÖßéè 2023-12-20 16:50:49 +01:00
DubbleClick 1692a5526c 1.6.2 (#22)
* minimum 4 chars max 8 chars after 0x for hash in filename
2023-12-10 19:38:36 +01:00
DubbleClick f9d69fc91e remove d3dx sdk from readme 2023-12-09 15:27:07 +01:00
DubbleClick 7dbbdc480e fix potentially wrong texture loading order (#20)
* add gsl library to track memory allocations

* rework creation to respect mod order
slight slowdown but just to be safe

* 1.6.1

* print info on timing

* specify largeaddressaware (shouldn't matter since gw is linked with it, but can't hurt)
2023-12-05 16:11:44 +01:00
DubbleClick 9e593e83ee 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
2023-12-04 19:50:56 +01:00
DubbleClick b49428bafd bump version to 1.5.8 2023-11-30 16:58:49 +01:00
DubbleClick ae2c93fc32 1.5.8 (#17)
* remove d3dx9.dll dependency (still requires dx legacy sdk for development, but not for end users)

* fix

* Fix to allow gMod to be loaded as "d3d9.dll"
Don't check for d3d9 functions when checking dll's, its not that deep.
Fix to allow gMod to load "d3d9.dll" using the default method rather than defaulting to system directory

* use d3dx sdk for wic texture loading until we figure out how to load volume/cube textures without it

* fix jons commit

* 1.5.7

* create warning message

* pass correct pointer type, shouldn't matter but lets see

* use Warning instead of Message for failed actions

* need to use d3dpool_managed...

* use specialised methods

* actually do something in the Direct3DCreate9Ex method?

* spaces

* test loading WIC textures with modified WICTextureLoader9.cpp

* include

* Hook into GetProcAddress instead of d3d9 dll

* extern "C" the Direct3DCreate9/Ex functions

* turn on debug messages

* add back in creating of our replacement textures, woopsies

* add messages back in, not loading yet, debug later

* remove SingleTexture stuff

* dont rely on d3dx anymore :)

* Tidied up assertion error box
Added logic to use gmod as d3d9.dll or gmod.dll
Added check to avoid recursive calls to create d3d9

* Remove unused func
2023-11-30 16:57:09 +01:00
DubbleClick a1cadde802 1.5.7 (#16)
allow loading reshade either before gmod dll, or loading reshade as d3d9.dll in the game folder
2023-11-24 22:05:40 +01:00
DubbleClick 69b06d94a2 work with reshade (#15)
* use directxtex for dds textures

* use d3dx sdk for wic texture loading until we figure out how to load volume/cube textures without it

* update d3d9 loading
2023-11-24 01:56:16 +01:00
DubbleClick 514aefa371 Update README.txt (#14) 2023-11-23 10:46:18 +01:00
39 changed files with 1969 additions and 1452 deletions
+14 -54
View File
@@ -26,66 +26,26 @@ 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
- name: Install vcpkg
run: |
git clone https://github.com/microsoft/vcpkg.git
.\vcpkg\bootstrap-vcpkg.bat
- name: Set VCPKG_ROOT
run: |
echo "VCPKG_ROOT=$(Get-Location)\vcpkg" >> $env:GITHUB_ENV
shell: powershell
- name: Build CMake Files with vcpkg toolchain
run: cmake --preset=vcpkg
env:
DXSDK_DIR: ${{ env.DXSDK_DIR }}
VCPKG_ROOT: ${{ env.VCPKG_ROOT }}
- name: Build binaries
run: cmake --build build --config Release
env:
DXSDK_DIR: ${{ env.DXSDK_DIR }}
- name: Retrieve version
id: set_version
@@ -106,7 +66,7 @@ jobs:
mode: update
tag_name: v${{ steps.set_version.outputs.version }}
release_name: gMod v${{ steps.set_version.outputs.version }}
assets: .\bin\Release\gMod.dll
assets: .\bin\Release\gMod.dll;.\bin\Release\TpfConvert.exe;.\bin\Release\d3dx9_43.dll
github_token: ${{ env.GITHUB_TOKEN }}
replace_assets: true
body_mrkdwn: ${{ env.Changelog }}
+15 -57
View File
@@ -1,4 +1,4 @@
name: gMod CI Pipeline
name: gMod CI Pipeline
on:
pull_request:
@@ -8,9 +8,8 @@ on:
branches:
- dev
workflow_dispatch:
jobs:
jobs:
build:
strategy:
@@ -29,64 +28,23 @@ 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
- name: Install vcpkg
run: |
git clone https://github.com/microsoft/vcpkg.git
.\vcpkg\bootstrap-vcpkg.bat
- name: Set VCPKG_ROOT
run: |
echo "VCPKG_ROOT=$(Get-Location)\vcpkg" >> $env:GITHUB_ENV
shell: powershell
- name: Build CMake Files with vcpkg toolchain
run: cmake --preset=vcpkg
env:
DXSDK_DIR: ${{ env.DXSDK_DIR }}
VCPKG_ROOT: ${{ env.VCPKG_ROOT }}
- name: Build binaries
run: cmake --build build --config Release
env:
DXSDK_DIR: ${{ env.DXSDK_DIR }}
+2
View File
@@ -23,6 +23,8 @@ bin/
*/Release
*/bin
*/obj
vcpkg
vcpkg_installed
# Bloated Windows Databases
*.sdf
+14 -25
View File
@@ -16,8 +16,8 @@ if(${CLEAN} MATCHES "ON")
endif()
set(VERSION_MAJOR 1)
set(VERSION_MINOR 5)
set(VERSION_PATCH 6)
set(VERSION_MINOR 7)
set(VERSION_PATCH 0)
set(VERSION_TWEAK 0)
set(VERSION_RC "${CMAKE_CURRENT_BINARY_DIR}/version.rc")
@@ -31,36 +31,22 @@ 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)
include(dxtk)
include(msgsl)
add_library(gMod SHARED)
file(GLOB SOURCES
"header/*.h"
"source/*.cpp"
"modules/*.ixx"
${VERSION_RC}
)
target_include_directories(gMod PRIVATE $ENV{DXSDK_DIR}/Include)
target_include_directories(gMod PUBLIC
target_include_directories(gMod PRIVATE
"header"
${CMAKE_INSTALL_PREFIX}/include
)
@@ -68,15 +54,16 @@ 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
psapi
minhook
directxtex
Microsoft.GSL::GSL
)
target_link_options(gMod PRIVATE
"$<$<CONFIG:DEBUG>:/NODEFAULTLIB:LIBCMT>"
"/LARGEADDRESSAWARE"
)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES})
target_sources(gMod PRIVATE ${SOURCES})
@@ -88,3 +75,5 @@ target_compile_definitions(gMod PRIVATE
DIRECT_INJECTION
LOG_MESSAGE
)
add_subdirectory(TpfConvert)
+14
View File
@@ -0,0 +1,14 @@
{
"version": 2,
"configurePresets": [
{
"name": "vcpkg",
"generator": "Visual Studio 17 2022",
"architecture": "Win32",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
]
}
+45
View File
@@ -0,0 +1,45 @@
***gMod***
Continuation of the uMod project to improve performance and stability. Integrated with [Guild Wars Launcher](https://github.com/gwdevhub/gwlauncher) and [Daybreak](https://github.com/gwdevhub/Daybreak).
*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
**Disclaimer about [Reshade](https://github.com/crosire/reshade)**
Reshade in versions > 5.0.1 is known to cause glitches with TexMod, uMod and also gMod.
If you would like to use Reshade in combination with gMod, we recommend running version [5.0.1](https://github.com/crosire/reshade/releases/tag/v5.0.1) or [4.9.1](https://github.com/crosire/reshade/releases/tag/v4.9.1).
**Build from source**
Requirements:
- Visual Studio 2022
- CMake 3.16+, integrated into the Developer Powershell for VS 2022
- vcpkg, integrated into the Developer Powershell for VS 2022
Compile:
- cmake --preset=vcpkg
- cmake --open build
- compile
**TpfConvert**
Small utility to convert old .tpf files with invalid images into .zip files with working images.
Usage:
- put TpfConvert.exe and d3dx9.dll anywhere
- create a folder "plugins" in that folder and put your .tpf/.zip files with invalid images there
- run TpfConvert.exe, My_Texmod.tpf is fixed and copied into My_Texmod_.zip
- copy My_Texmod_.zip into your GW Launcher plugins folder, delete My_Texmod.tpf from it, if it still exists
-9
View File
@@ -1,9 +0,0 @@
Requirements:
- The DirectX SDK (I use June 2010)
- Visual Studio (2010+)
(- Maybe CMake if you don't want to use Visual Studio)
Usage:
Create a file in the root GuildWars folder (where gw.exe is located) called modlist.txt
Each line in the modlist.txt is the full path to a mod you want to load (eg. D:Games\uMod\Mods\Borderless Cartography Made Easy 2015 1.3.tpf)
uMod will load all these files on startup
+39
View File
@@ -0,0 +1,39 @@
add_executable(TpfConvert)
# Find all .ixx files in the TpfConvert folder
file(GLOB TPF_SOURCES "src/*.ixx")
# Add the .ixx files to the TpfConvert target
target_sources(TpfConvert PRIVATE ${TPF_SOURCES})
set_target_properties(TpfConvert PROPERTIES
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON
)
target_compile_definitions(TpfConvert PRIVATE
"NOMINMAX"
"_WIN32_WINNT=_WIN32_WINNT_WIN7"
"WIN32_LEAN_AND_MEAN"
"VC_EXTRALEAN"
)
if(DEFINED ENV{VCPKG_ROOT})
message(STATUS "VCPKG_ROOT: $ENV{VCPKG_ROOT}")
else()
message(STATUS "VCPKG_ROOT is not set")
endif()
if(DEFINED CMAKE_TOOLCHAIN_FILE)
message(STATUS "CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}")
else()
message(STATUS "CMAKE_TOOLCHAIN_FILE is not set")
endif()
find_package(dxsdk-d3dx CONFIG REQUIRED)
target_link_libraries(TpfConvert PRIVATE
libzippp
Microsoft::D3DX9
d3d9
)
+179
View File
@@ -0,0 +1,179 @@
export module ModfileLoader;
import std;
import <libzippp.h>;
import ModfileLoader.TpfReader;
export using HashType = uint64_t;
export struct TexEntry {
std::vector<uint8_t> data{};
HashType crc_hash = 0; // hash value
std::string ext{};
};
namespace {
HashType GetCrcFromFilename(const std::string& filename) {
const static std::regex re(R"(0x[0-9a-f]{4,16})", std::regex::optimize | std::regex::icase);
std::smatch match;
if (!std::regex_search(filename, match, re)) {
return 0;
}
uint64_t crc64_hash = 0;
const auto number_str = match.str();
try {
crc64_hash = std::stoull(number_str, nullptr, 16);
}
catch (const std::invalid_argument&) {
std::print(stderr, "Failed to parse {} as a hash\n", filename);
return 0;
}
catch (const std::out_of_range&) {
std::print(stderr, "Out of range while parsing {} as a hash\n", filename);
return 0;
}
return crc64_hash;
}
}
export class ModfileLoader {
std::filesystem::path 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::filesystem::path& fileName);
std::vector<TexEntry> GetContents() const;
private:
std::vector<TexEntry> GetTpfContents() const;
std::vector<TexEntry> GetFileContents() const;
static void LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries);
};
ModfileLoader::ModfileLoader(const std::filesystem::path& fileName)
{
file_name = std::filesystem::absolute(fileName);
}
std::vector<TexEntry> ModfileLoader::GetContents() const
{
try {
return file_name.wstring().ends_with(L".tpf") ? GetTpfContents() : GetFileContents();
}
catch (const std::exception&) {
std::print(stderr, "Failed to open mod file: {}\n", file_name.string().c_str());
}
return {};
}
std::vector<TexEntry> ModfileLoader::GetTpfContents() const
{
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);
if (!zip_archive) {
std::print(stderr, "Failed to open tpf file: {} - {} uint8_ts!\n", file_name.string(), buffer.size());
return {};
}
zip_archive->setErrorHandlerCallback(
[](const std::string& message, const std::string& strerror, int zip_error_code, int system_error_code) -> void {
std::print(stderr, "GetTpfContents: {} {} {} {}\n", message, strerror, zip_error_code, system_error_code);
});
zip_archive->open();
LoadEntries(*zip_archive, entries);
zip_archive->close();
libzippp::ZipArchive::free(zip_archive);
return entries;
}
std::vector<TexEntry> ModfileLoader::GetFileContents() const
{
std::vector<TexEntry> entries;
libzippp::ZipArchive zip_archive(file_name.string());
zip_archive.open();
LoadEntries(zip_archive, entries);
zip_archive.close();
return entries;
}
void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
{
for (const auto& entry : archive.getEntries()) {
if (!entry.isFile())
continue;
const auto crc_hash = GetCrcFromFilename(entry.getName());
if (!crc_hash)
continue;
const auto data_ptr = static_cast<uint8_t*>(entry.readAsBinary());
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().string());
delete[] data_ptr;
}
}
void ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
{
for (const auto& line : lines) {
// 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;
if (!std::regex_search(line, match, address_file_regex))
continue;
const auto address_string = match[1].str();
const auto file_path = match[2].str();
const auto crc_hash = GetCrcFromFilename(address_string);
if (!crc_hash)
continue;
const auto entry = archive.getEntry(file_path);
if (entry.isNull() || !entry.isFile())
continue;
const auto data_ptr = static_cast<uint8_t*>(entry.readAsBinary());
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().string());
delete[] data_ptr;
}
}
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()) {
ParseSimpleArchive(archive, entries);
}
else {
const auto def = def_file.readAsText();
std::istringstream iss(def);
std::vector<std::string> lines;
std::string line;
while (std::getline(iss, line)) {
lines.push_back(line);
}
ParseTexmodArchive(lines, archive, entries);
}
}
@@ -1,11 +1,10 @@
#pragma once
export module ModfileLoader.TpfReader;
#include <fstream>
#include <vector>
import std;
class TpfReader {
export class TpfReader {
public:
TpfReader(const std::string& path)
TpfReader(const std::filesystem::path& path)
{
file_stream = std::ifstream(path, std::ios::binary);
if (!file_stream.seekg(0, std::ios::end).good() || !file_stream.seekg(0, std::ios::beg).good()) {
@@ -43,7 +42,7 @@ public:
private:
std::ifstream file_stream;
long line_length;
long line_length = 0;
[[nodiscard]] char XOR(const char b, const long position) const
{
+144
View File
@@ -0,0 +1,144 @@
#include <corecrt_wstdio.h>
#include <Windows.h>
#include <d3dx9.h>
#include <d3d9.h>
import std;
import ModfileLoader;
import <libzippp.h>;
struct TexEntry;
namespace {
IDirect3D9* pD3D = nullptr;
IDirect3DDevice9* pDevice = nullptr;
bool InitializeDirect3D()
{
pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (pD3D == nullptr) {
std::print(stderr, "Failed to create Direct3D9 object\n");
return false;
}
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = GetDesktopWindow();
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow(),
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice))) {
std::print(stderr, "Failed to create Direct3D9 device\n");
pD3D->Release();
return false;
}
return true;
}
void CleanupDirect3D()
{
if (pDevice) pDevice->Release();
if (pD3D) pD3D->Release();
}
std::pair<std::string, std::vector<uint8_t>> SaveAsDDS(const TexEntry& entry)
{
IDirect3DTexture9* pTexture = nullptr;
ID3DXBuffer* pBuffer = nullptr;
HRESULT hr = D3DXCreateTextureFromFileInMemoryEx(pDevice,
entry.data.data(), entry.data.size(),
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0,
D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_NONE,
D3DX_FILTER_NONE, 0, NULL, NULL, &pTexture);
if (FAILED(hr)) {
std::print(stderr, "Failed to create texture from memory\n");
return {};
}
hr = D3DXSaveTextureToFileInMemory(&pBuffer, D3DXIFF_DDS, pTexture, NULL);
if (FAILED(hr)) {
std::print(stderr, "Failed to save texture to DDS memory buffer\n");
pTexture->Release();
return {};
}
std::string dds_filename = std::format("0x{:x}.dds", entry.crc_hash);
std::vector<uint8_t> dds_data(pBuffer->GetBufferSize());
std::memcpy(dds_data.data(), pBuffer->GetBufferPointer(), pBuffer->GetBufferSize());
pTexture->Release();
pBuffer->Release();
return {dds_filename, dds_data};
}
std::filesystem::path GetExecutablePath()
{
char buffer[MAX_PATH];
GetModuleFileNameA(NULL, buffer, MAX_PATH);
return std::filesystem::path(buffer).parent_path();
}
}
int main(int argc, char* argv[])
{
const std::filesystem::path path = argc > 1 ? argv[1] : GetExecutablePath() / "plugins";
if (!InitializeDirect3D()) {
return -1;
}
if (!std::filesystem::exists(path)) {
return 1;
}
for (const auto& modfile : std::filesystem::directory_iterator(path)) {
if (modfile.is_regular_file() && (modfile.path().extension() == ".tpf" || modfile.path().extension() == ".zip")) {
const auto mod_path = modfile.path();
if (mod_path.extension() == ".zip" && mod_path.stem().string().ends_with("_")) {
std::print("Skipping previous TpfConvert output: {}\n", mod_path.filename().string());
continue;
}
else {
std::print("Processing: {}\n", mod_path.filename().string());
}
const auto zip_filename = mod_path.parent_path() / (mod_path.stem().string() + "_.zip");
if (std::filesystem::exists(zip_filename)) {
std::print("{} was already processed\n", mod_path.filename().string());
continue;
}
libzippp::ZipArchive zip_archive(zip_filename.string());
ModfileLoader loader(mod_path);
std::vector<std::pair<std::string, std::vector<uint8_t>>> data_entries;
const auto entries = loader.GetContents();
zip_archive.open(libzippp::ZipArchive::Write);
for (const auto& entry : entries) {
auto [dds_filename, dds_data] = SaveAsDDS(entry);
if (!dds_filename.empty()) {
data_entries.emplace_back(dds_filename, std::move(dds_data));
}
}
for (const auto& [filename, data] : data_entries) {
const auto success = zip_archive.addData(filename, data.data(), data.size());
if (!success) {
std::print(stderr, "Failed to add data to ZIP: {}\n", filename);
}
}
zip_archive.close();
std::print("Saved to ZIP: {}\n", zip_filename.string());
}
}
CleanupDirect3D();
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
include_guard()
include(FetchContent)
FetchContent_Declare(
DirectXTex
GIT_REPOSITORY https://github.com/microsoft/DirectXTex
GIT_TAG oct2023)
FetchContent_GetProperties(directxtex)
if (directxtex_POPULATED)
return()
endif()
FetchContent_Populate(directxtex)
add_library(directxtex)
file(GLOB SOURCES
"${directxtex_SOURCE_DIR}/DDSTextureLoader/DDSTextureLoader9.h"
"${directxtex_SOURCE_DIR}/DDSTextureLoader/DDSTextureLoader9.cpp"
"${directxtex_SOURCE_DIR}/WICTextureLoader/WICTextureLoader9.h"
"${directxtex_SOURCE_DIR}/WICTextureLoader/WICTextureLoader9.cpp"
"${directxtex_SOURCE_DIR}/DirectXTex/*.h"
"${directxtex_SOURCE_DIR}/DirectXTex/*.cpp"
)
list(REMOVE_ITEM SOURCES
"${directxtex_SOURCE_DIR}/DirectXTex/BCDirectCompute.cpp"
)
source_group(TREE ${directxtex_SOURCE_DIR} FILES ${SOURCES})
target_sources(directxtex PRIVATE ${SOURCES})
target_include_directories(directxtex PUBLIC "${directxtex_SOURCE_DIR}")
set_target_properties(directxtex PROPERTIES FOLDER "Dependencies/")
+11
View File
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.14)
include(FetchContent)
FetchContent_Declare(GSL
GIT_REPOSITORY "https://github.com/microsoft/GSL"
GIT_TAG "v4.0.0"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(GSL)
+63 -7
View File
@@ -1,15 +1,71 @@
#pragma once
//#define HashType DWORD64
using HashType = DWORD32;
//using HashType = DWORD32;
using HashType = DWORD64;
#ifdef LOG_MESSAGE
#include <iostream>
struct HashTuple {
HashType crc32;
HashType crc64;
bool operator==(const HashTuple& other) const noexcept
{
return (other.crc32 == crc32) || (other.crc64 == crc64);
}
explicit operator bool() const noexcept
{
return crc32 != 0 || crc64 != 0;
}
explicit operator HashType() const noexcept
{
return crc32 ? crc32 : crc64;
}
};
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
#define Message(...) { printf(__VA_ARGS__); }
#else
#define Message(...)
#if 0
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
#endif
#endif
}
inline void Info(const char* format, ...)
{
#ifdef _DEBUG
const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
[[maybe_unused]] const auto success = SetConsoleTextAttribute(hConsole, 0); // white
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
#endif
}
inline void Warning(const char* format, ...)
{
#ifdef _DEBUG
const HANDLE hConsole = GetStdHandle(STD_ERROR_HANDLE);
[[maybe_unused]] const auto success = SetConsoleTextAttribute(hConsole, 6); // yellow
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
#endif
}
-38
View File
@@ -1,38 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <ranges>
#include <libzippp.h>
struct TpfEntry {
std::string name;
std::string entry;
uint32_t crc_hash;
std::vector<char> data;
};
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<TpfEntry> GetContents();
private:
std::vector<TpfEntry> GetTpfContents();
std::vector<TpfEntry> GetFileContents();
void LoadEntries(libzippp::ZipArchive& archive, std::vector<TpfEntry>& entries);
};
+6 -5
View File
@@ -4,16 +4,19 @@
#include <cstdlib>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <future>
#include <map>
#include <ranges>
#include "Utils.h"
#include <d3d9.h>
#include <d3dx9.h>
#include <gsl/gsl>
#include "Defines.h"
#include "Error.h"
#include "Defines.h"
#include "dll_main.h"
#include "TextureFunction.h"
#include "uMod_IDirect3D9.h"
#include "uMod_IDirect3D9Ex.h"
@@ -25,8 +28,6 @@
#include "uMod_IDirect3DTexture9.h"
#include "uMod_IDirect3DVolumeTexture9.h"
#include "TextureClient.h"
#pragma warning(disable : 4477)
extern unsigned int gl_ErrorState;
-251
View File
@@ -1,251 +0,0 @@
#pragma once
#include <map>
#include "FileLoader.h"
#include "uMod_IDirect3DTexture9.h"
extern unsigned int gl_ErrorState;
struct TextureFileStruct {
std::vector<char> data{};
HashType crc_hash = 0; // hash value
};
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.
* functions called by the Server are called from the server thread instance.
* 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()
// Add TpfEntry data, return size of data added. 0 on failure.
unsigned long AddFile(TpfEntry& 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
D3DCOLOR FontColour;
D3DCOLOR TextureColour;
void Initialize();
private:
IDirect3DDevice9* D3D9Device;
// Cached info about whether this id a dx9ex device or not; used for proxy functions
bool isDirectXExDevice = false;
// DX9 proxy functions
uMod_IDirect3DTexture9* GetSingleTexture();
uMod_IDirect3DVolumeTexture9* GetSingleVolumeTexture();
uMod_IDirect3DCubeTexture9* GetSingleCubeTexture();
int SetLastCreatedTexture(uMod_IDirect3DTexture9*);
int SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9*);
int 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;
}
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 constexpr (std::same_as<decltype(ppTexture), uMod_IDirect3DTexture9**>) {
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,
(IDirect3DTexture9**)ppTexture)) {
*ppTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
SetLastCreatedTexture(nullptr);
}
else if constexpr (std::same_as<decltype(ppTexture), uMod_IDirect3DVolumeTexture9**>) {
if (D3D_OK != D3DXCreateVolumeTextureFromFileInMemoryEx(
D3D9Device, file_in_memory->data.data(),
file_in_memory->data.size(), D3DX_DEFAULT, D3DX_DEFAULT,
D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0,
nullptr,
nullptr,
(IDirect3DVolumeTexture9**)ppTexture)) {
*ppTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
SetLastCreatedVolumeTexture(nullptr);
}
else if constexpr (std::same_as<decltype(ppTexture), uMod_IDirect3DCubeTexture9**>) {
if (D3D_OK != D3DXCreateCubeTextureFromFileInMemoryEx(
D3D9Device, file_in_memory->data.data(), file_in_memory->data.size(), D3DX_DEFAULT, D3DX_DEFAULT, 0,
D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
D3DX_DEFAULT, D3DX_DEFAULT, 0, nullptr, nullptr,
(IDirect3DCubeTexture9**)ppTexture)) {
*ppTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
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>
inline 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;
}
-138
View File
@@ -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;
}
}
}
+13
View File
@@ -12,4 +12,17 @@ namespace utils
vec.erase(found);
}
}
inline std::wstring utf8_to_wstring(const std::string& utf8str) {
if (utf8str.empty()) return {};
// Calculate the number of wide characters needed for the conversion
const int count = MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), -1, nullptr, 0);
if (count == 0) throw std::runtime_error("Failed to convert UTF-8 to UTF-16");
std::wstring wstr(count, 0);
MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), -1, wstr.data(), count);
return wstr;
}
}
-10
View File
@@ -1,10 +0,0 @@
#pragma once
#include <d3d9.h>
void InitInstance(HINSTANCE hModule);
void ExitInstance();
HMODULE LoadOriginalDll();
IDirect3D9* APIENTRY uMod_Direct3DCreate9(UINT SDKVersion);
HRESULT APIENTRY uMod_Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D);
+8 -11
View File
@@ -2,23 +2,20 @@
#include <d3d9.h>
interface uMod_IDirect3DCubeTexture9 : IDirect3DCubeTexture9 {
interface uMod_IDirect3DCubeTexture9 : IDirect3DCubeTexture9 {
uMod_IDirect3DCubeTexture9(IDirect3DCubeTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
{
m_D3Dtex = *ppTex; //Texture which will be displayed and will be passed to the game
m_D3Ddev = pIDirect3DDevice9; //device pointer
CrossRef_D3Dtex = nullptr; //cross reference
// fake texture: store the pointer to the original uMod_IDirect3DCubeTexture9 object, needed if a fake texture is unselected
// original texture: stores the pointer to the fake texture object, is needed if original texture is deleted,
// thus the fake texture can also be deleted
}
: m_D3Dtex(*ppTex),
m_D3Ddev(pIDirect3DDevice9)
{}
virtual ~uMod_IDirect3DCubeTexture9() = default;
// callback interface
IDirect3DCubeTexture9* m_D3Dtex = nullptr;
uMod_IDirect3DCubeTexture9* CrossRef_D3Dtex = nullptr;
IDirect3DDevice9* m_D3Ddev = nullptr;
TextureFileStruct* Reference = nullptr;
HashType Hash = 0u;
HashTuple Hash = {};
bool FAKE = false;
// original interface
@@ -47,5 +44,5 @@ interface uMod_IDirect3DCubeTexture9 : IDirect3DCubeTexture9 {
STDMETHOD(UnlockRect)(D3DCUBEMAP_FACES FaceType, UINT Level) override;
[[nodiscard]] HashType GetHash() const;
[[nodiscard]] HashTuple GetHash() const;
};
+6 -26
View File
@@ -1,12 +1,11 @@
#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include "uMod_IDirect3DTexture9.h"
#include "uMod_IDirect3DVolumeTexture9.h"
#include "uMod_IDirect3DCubeTexture9.h"
#include "TextureClient.h"
class TextureClient;
class uMod_IDirect3DDevice9 : public IDirect3DDevice9 {
public:
@@ -140,50 +139,31 @@ public:
uMod_IDirect3DTexture9* GetLastCreatedTexture() { return LastCreatedTexture; }
int SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
void SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
{
LastCreatedTexture = pTexture;
return RETURN_OK;
}
uMod_IDirect3DVolumeTexture9* GetLastCreatedVolumeTexture() { return LastCreatedVolumeTexture; }
int SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
{
LastCreatedVolumeTexture = pTexture;
return RETURN_OK;
}
uMod_IDirect3DCubeTexture9* GetLastCreatedCubeTexture() { return LastCreatedCubeTexture; }
int SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
{
LastCreatedCubeTexture = pTexture;
return RETURN_OK;
}
uMod_IDirect3DTexture9* GetSingleTexture() { return SingleTexture; }
uMod_IDirect3DVolumeTexture9* GetSingleVolumeTexture() { return SingleVolumeTexture; }
uMod_IDirect3DCubeTexture9* GetSingleCubeTexture() { return SingleCubeTexture; }
private:
int CreateSingleTexture();
IDirect3DDevice9* m_pIDirect3DDevice9 = nullptr;
int CounterSaveSingleTexture;
uMod_IDirect3DTexture9* SingleTexture = nullptr;
uMod_IDirect3DVolumeTexture9* SingleVolumeTexture = nullptr;
uMod_IDirect3DCubeTexture9* SingleCubeTexture = nullptr;
char SingleTextureMod;
D3DCOLOR TextureColour;
ID3DXFont* OSD_Font;
//D3DCOLOR FontColour;
int BackBufferCount;
bool NormalRendering;
int uMod_Reference;
bool NormalRendering = true;
int uMod_Reference = 1;
uMod_IDirect3DTexture9* LastCreatedTexture = nullptr;
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture = nullptr;
+10 -29
View File
@@ -1,12 +1,11 @@
#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include "uMod_IDirect3DTexture9.h"
#include "uMod_IDirect3DVolumeTexture9.h"
#include "uMod_IDirect3DCubeTexture9.h"
#include "TextureClient.h"
class TextureClient;
class uMod_IDirect3DDevice9Ex : public IDirect3DDevice9Ex {
public:
@@ -162,54 +161,36 @@ public:
uMod_IDirect3DTexture9* GetLastCreatedTexture() { return LastCreatedTexture; }
int SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
void SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
{
LastCreatedTexture = pTexture;
return RETURN_OK;
}
uMod_IDirect3DVolumeTexture9* GetLastCreatedVolumeTexture() { return LastCreatedVolumeTexture; }
int SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
{
LastCreatedVolumeTexture = pTexture;
return RETURN_OK;
}
uMod_IDirect3DCubeTexture9* GetLastCreatedCubeTexture() { return LastCreatedCubeTexture; }
int SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
{
LastCreatedCubeTexture = pTexture;
return RETURN_OK;
}
uMod_IDirect3DTexture9* GetSingleTexture() { return SingleTexture; }
uMod_IDirect3DVolumeTexture9* GetSingleVolumeTexture() { return SingleVolumeTexture; }
uMod_IDirect3DCubeTexture9* GetSingleCubeTexture() { return SingleCubeTexture; }
private:
int CreateSingleTexture();
IDirect3DDevice9Ex* m_pIDirect3DDevice9Ex;
int CounterSaveSingleTexture;
uMod_IDirect3DTexture9* SingleTexture;
uMod_IDirect3DVolumeTexture9* SingleVolumeTexture;
uMod_IDirect3DCubeTexture9* SingleCubeTexture;
char SingleTextureMod;
D3DCOLOR TextureColour;
ID3DXFont* OSD_Font;
//D3DCOLOR FontColour;
int BackBufferCount;
bool NormalRendering;
bool NormalRendering = true;
int uMod_Reference;
int uMod_Reference = 1;
uMod_IDirect3DTexture9* LastCreatedTexture;
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture;
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture;
uMod_IDirect3DTexture9* LastCreatedTexture = nullptr;
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture = nullptr;
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture = nullptr;
TextureClient* uMod_Client;
TextureClient* uMod_Client = nullptr;
};
+10 -11
View File
@@ -1,24 +1,23 @@
#pragma once
#include <d3d9.h>
#include "Defines.h"
struct TextureFileStruct;
interface uMod_IDirect3DTexture9 : public IDirect3DTexture9 {
interface uMod_IDirect3DTexture9 : IDirect3DTexture9 {
uMod_IDirect3DTexture9(IDirect3DTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
{
m_D3Dtex = *ppTex; //Texture which will be displayed and will be passed to the game
m_D3Ddev = pIDirect3DDevice9; //device pointer
CrossRef_D3Dtex = nullptr; //cross reference
// fake texture: store the pointer to the original uMod_IDirect3DTexture9 object, needed if a fake texture is unselected
// original texture: stores the pointer to the fake texture object, is needed if original texture is deleted,
// thus the fake texture can also be deleted
}
: m_D3Dtex(*ppTex),
m_D3Ddev(pIDirect3DDevice9)
{}
virtual ~uMod_IDirect3DTexture9() = default;
// callback interface
IDirect3DTexture9* m_D3Dtex = nullptr;
uMod_IDirect3DTexture9* CrossRef_D3Dtex = nullptr;
IDirect3DDevice9* m_D3Ddev = nullptr;
TextureFileStruct* Reference = nullptr;
HashType Hash = 0u;
HashTuple Hash = {};
bool FAKE = false;
// original interface
@@ -45,5 +44,5 @@ interface uMod_IDirect3DTexture9 : public IDirect3DTexture9 {
STDMETHOD(UnlockRect)(UINT Level) override;
STDMETHOD(AddDirtyRect)(CONST RECT* pDirtyRect) override;
[[nodiscard]] HashType GetHash() const;
[[nodiscard]] HashTuple GetHash() const;
};
+7 -10
View File
@@ -4,21 +4,18 @@
interface uMod_IDirect3DVolumeTexture9 : IDirect3DVolumeTexture9 {
uMod_IDirect3DVolumeTexture9(IDirect3DVolumeTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
{
m_D3Dtex = *ppTex; //Texture which will be displayed and will be passed to the game
m_D3Ddev = pIDirect3DDevice9; //device pointer
CrossRef_D3Dtex = nullptr; //cross reference
// fake texture: store the pointer to the original uMod_IDirect3DVolumeTexture9 object, needed if a fake texture is unselected
// original texture: stores the pointer to the fake texture object, is needed if original texture is deleted,
// thus the fake texture can also be deleted
}
: m_D3Dtex(*ppTex),
m_D3Ddev(pIDirect3DDevice9)
{}
virtual ~uMod_IDirect3DVolumeTexture9() = default;
// callback interface
IDirect3DVolumeTexture9* m_D3Dtex = nullptr;
uMod_IDirect3DVolumeTexture9* CrossRef_D3Dtex = nullptr;
IDirect3DDevice9* m_D3Ddev = nullptr;
TextureFileStruct* Reference = nullptr;
HashType Hash = 0u;
HashTuple Hash = {};
bool FAKE = false;
// original interface
@@ -46,5 +43,5 @@ interface uMod_IDirect3DVolumeTexture9 : IDirect3DVolumeTexture9 {
STDMETHOD(UnlockBox)(UINT Level) override;
[[nodiscard]] HashType GetHash() const;
[[nodiscard]] HashTuple GetHash() const;
};
+186
View File
@@ -0,0 +1,186 @@
module;
#include "Main.h"
#include "Defines.h"
export module ModfileLoader;
import std;
import <libzippp.h>;
import ModfileLoader.TpfReader;
import TextureFunction;
namespace {
bool use_64_bit_crc = false;
HashType GetCrcFromFilename(const std::string& filename) {
const static std::regex re(R"(0x[0-9a-f]{4,16})", std::regex::optimize | std::regex::icase);
std::smatch match;
if (!std::regex_search(filename, match, re)) {
return 0;
}
uint64_t crc64_hash = 0;
const auto number_str = match.str();
try {
crc64_hash = std::stoull(number_str, nullptr, 16);
}
catch (const std::invalid_argument&) {
Warning("Failed to parse %s as a hash\n", filename.c_str());
return 0;
}
catch (const std::out_of_range&) {
Warning("Out of range while parsing %s as a hash\n", filename.c_str());
return 0;
}
use_64_bit_crc = use_64_bit_crc || crc64_hash > 0xFFFFFFFF;
return crc64_hash;
}
}
namespace HashCheck {
export bool Use64BitCrc() {
return use_64_bit_crc;
}
}
export class ModfileLoader {
std::filesystem::path 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::filesystem::path& fileName);
std::vector<TexEntry> GetContents() const;
private:
std::vector<TexEntry> GetTpfContents() const;
std::vector<TexEntry> GetFileContents() const;
static void LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries);
};
ModfileLoader::ModfileLoader(const std::filesystem::path& fileName)
{
file_name = std::filesystem::absolute(fileName);
}
std::vector<TexEntry> ModfileLoader::GetContents() const
{
try {
return file_name.wstring().ends_with(L".tpf") ? GetTpfContents() : GetFileContents();
}
catch (const std::exception&) {
Warning("Failed to open mod file: %s\n", file_name.c_str());
}
return {};
}
std::vector<TexEntry> ModfileLoader::GetTpfContents() const
{
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);
if (!zip_archive) {
Warning("Failed to open tpf file: %s - %u bytes!", file_name.c_str(), buffer.size());
return {};
}
zip_archive->setErrorHandlerCallback(
[](const std::string& message, const std::string& strerror, int zip_error_code, int system_error_code) -> void {
Message("GetTpfContents: %s %s %d %d\n", message.c_str(), strerror.c_str(), zip_error_code, system_error_code);
});
zip_archive->open();
LoadEntries(*zip_archive, entries);
zip_archive->close();
libzippp::ZipArchive::free(zip_archive);
return entries;
}
std::vector<TexEntry> ModfileLoader::GetFileContents() const
{
std::vector<TexEntry> entries;
libzippp::ZipArchive zip_archive(file_name.string());
zip_archive.open();
LoadEntries(zip_archive, entries);
zip_archive.close();
return entries;
}
void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
{
for (const auto& entry : archive.getEntries()) {
if (!entry.isFile())
continue;
const auto crc_hash = GetCrcFromFilename(entry.getName());
if (!crc_hash)
continue;
const auto data_ptr = static_cast<BYTE*>(entry.readAsBinary());
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().string());
delete[] data_ptr;
}
}
void ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
{
for (const auto& line : lines) {
// 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;
if (!std::regex_search(line, match, address_file_regex))
continue;
const auto address_string = match[1].str();
const auto file_path = match[2].str();
const auto crc_hash = GetCrcFromFilename(address_string);
if (!crc_hash)
continue;
const auto entry = archive.getEntry(file_path);
if (entry.isNull() || !entry.isFile())
continue;
const auto data_ptr = static_cast<BYTE*>(entry.readAsBinary());
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().string());
delete[] data_ptr;
}
}
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()) {
ParseSimpleArchive(archive, entries);
}
else {
const auto def = def_file.readAsText();
std::istringstream iss(def);
std::vector<std::string> lines;
std::string line;
while (std::getline(iss, line)) {
lines.push_back(line);
}
ParseTexmodArchive(lines, archive, entries);
}
}
+58
View File
@@ -0,0 +1,58 @@
export module ModfileLoader.TpfReader;
import std;
export class TpfReader {
public:
TpfReader(const std::filesystem::path& path)
{
file_stream = std::ifstream(path, std::ios::binary);
if (!file_stream.seekg(0, std::ios::end).good() || !file_stream.seekg(0, std::ios::beg).good()) {
throw std::invalid_argument("Provided stream needs to have SEEK set to True");
}
}
~TpfReader()
{
file_stream.close();
}
std::vector<char> ReadToEnd()
{
file_stream.seekg(0, std::ios::end);
line_length = file_stream.tellg();
file_stream.seekg(0, std::ios::beg); // Go to the beginning of the stream
std::vector<char> data(line_length);
file_stream.read(data.data(), line_length);
for (auto i = 0; i < data.size(); i++) {
data[i] = XOR(data[i], i);
}
for (int i = data.size() - 1; i > 0 && data[i] != 0; i--) {
data[i] = 0;
}
// in the other zip libraries, these had to be cut off, with libzip we need to zero them out
// cutting them off makes the archive invalid
//data.resize(last_zero);
return data;
}
private:
std::ifstream file_stream;
long line_length = 0;
[[nodiscard]] char XOR(const char b, const long position) const
{
if (position > line_length - 4) {
return b ^ TPF_XOREven;
}
return position % 2 == 0 ? b ^ TPF_XOREven : b ^ TPF_XOROdd;
}
static constexpr char TPF_XOROdd = 0x3F;
static constexpr char TPF_XOREven = static_cast<char>(0xA4);
};
+390
View File
@@ -0,0 +1,390 @@
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();
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::unordered_map<HashType, gsl::owner<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 texture_file_struct : modded_textures | std::views::values) {
delete texture_file_struct;
}
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;
}
gsl::owner<TextureFileStruct*> AddFile(TexEntry& entry, const bool compress, const std::filesystem::path& dll_path)
{
const auto texture_file_struct = new TextureFileStruct();
texture_file_struct->crc_hash = entry.crc_hash;
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());
return texture_file_struct;
}
std::vector<gsl::owner<TextureFileStruct*>> ProcessModfile(const std::filesystem::path& modfile, const std::filesystem::path& dll_path, const bool compress)
{
const auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) return {};
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 {};
}
Message("%zu textures... ", entries.size());
std::vector<gsl::owner<TextureFileStruct*>> texture_file_structs;
texture_file_structs.reserve(entries.size());
unsigned file_bytes_loaded = 0;
for (auto& tpf_entry : entries) {
const auto tex_file_struct = AddFile(tpf_entry, compress, dll_path);
texture_file_structs.push_back(tex_file_struct);
file_bytes_loaded += texture_file_structs.back()->data.size();
}
entries.clear();
Message("%d bytes loaded.\n", file_bytes_loaded);
CoUninitialize();
return texture_file_structs;
}
void TextureClient::LoadModsFromFile(const char* source)
{
static std::vector<std::filesystem::path> loaded_modfiles{};
Message("Initialize: searching in %s\n", source);
std::locale::global(std::locale(""));
std::ifstream file(source, std::ios::binary);
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::filesystem::path> 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());
const auto wline = utils::utf8_to_wstring(line);
const auto fsline = std::filesystem::path(wline);
if (!std::ranges::contains(loaded_modfiles, fsline)) {
modfiles.push_back(fsline);
loaded_modfiles.push_back(fsline);
}
}
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<std::vector<gsl::owner<TextureFileStruct*>>>> futures;
for (const auto modfile : modfiles) {
futures.emplace_back(std::async(std::launch::async, ProcessModfile, modfile, dll_path, files_size > 400'000'000));
}
auto loaded_size = 0u;
for (auto& future : futures) {
const auto texture_file_structs = future.get();
for (const auto texture_file_struct : texture_file_structs) {
if (!texture_file_struct->crc_hash) continue;
if (!modded_textures.contains(texture_file_struct->crc_hash)) {
modded_textures.emplace(texture_file_struct->crc_hash, texture_file_struct);
loaded_size += texture_file_struct->data.size();
}
else {
delete texture_file_struct;
}
}
should_update = true;
}
Message("Finished loading mods from %s: Loaded %u bytes (%u mb)", source, loaded_size, loaded_size / 1024 / 1024);
}
void TextureClient::Initialize()
{
const auto t1 = std::chrono::high_resolution_clock::now();
Info("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());
}
}
const auto t2 = std::chrono::high_resolution_clock::now();
const auto ms = duration_cast<std::chrono::milliseconds>(t2 - t1);
Info("Initialize: end, took %d ms\n", ms);
}
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
auto found = modded_textures.find(pTexture->Hash.crc32);
if (found == modded_textures.end())
if (found = modded_textures.find(pTexture->Hash.crc64), !pTexture->Hash.crc64 || 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;
}
+415
View File
@@ -0,0 +1,415 @@
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;
}
constexpr auto crctab64 = std::to_array({
0x0000000000000000ULL, 0x7ad870c830358979ULL, 0xf5b0e190606b12f2ULL,
0x8f689158505e9b8bULL, 0xc038e5739841b68fULL, 0xbae095bba8743ff6ULL,
0x358804e3f82aa47dULL, 0x4f50742bc81f2d04ULL, 0xab28ecb46814fe75ULL,
0xd1f09c7c5821770cULL, 0x5e980d24087fec87ULL, 0x24407dec384a65feULL,
0x6b1009c7f05548faULL, 0x11c8790fc060c183ULL, 0x9ea0e857903e5a08ULL,
0xe478989fa00bd371ULL, 0x7d08ff3b88be6f81ULL, 0x07d08ff3b88be6f8ULL,
0x88b81eabe8d57d73ULL, 0xf2606e63d8e0f40aULL, 0xbd301a4810ffd90eULL,
0xc7e86a8020ca5077ULL, 0x4880fbd87094cbfcULL, 0x32588b1040a14285ULL,
0xd620138fe0aa91f4ULL, 0xacf86347d09f188dULL, 0x2390f21f80c18306ULL,
0x594882d7b0f40a7fULL, 0x1618f6fc78eb277bULL, 0x6cc0863448deae02ULL,
0xe3a8176c18803589ULL, 0x997067a428b5bcf0ULL, 0xfa11fe77117cdf02ULL,
0x80c98ebf2149567bULL, 0x0fa11fe77117cdf0ULL, 0x75796f2f41224489ULL,
0x3a291b04893d698dULL, 0x40f16bccb908e0f4ULL, 0xcf99fa94e9567b7fULL,
0xb5418a5cd963f206ULL, 0x513912c379682177ULL, 0x2be1620b495da80eULL,
0xa489f35319033385ULL, 0xde51839b2936bafcULL, 0x9101f7b0e12997f8ULL,
0xebd98778d11c1e81ULL, 0x64b116208142850aULL, 0x1e6966e8b1770c73ULL,
0x8719014c99c2b083ULL, 0xfdc17184a9f739faULL, 0x72a9e0dcf9a9a271ULL,
0x08719014c99c2b08ULL, 0x4721e43f0183060cULL, 0x3df994f731b68f75ULL,
0xb29105af61e814feULL, 0xc849756751dd9d87ULL, 0x2c31edf8f1d64ef6ULL,
0x56e99d30c1e3c78fULL, 0xd9810c6891bd5c04ULL, 0xa3597ca0a188d57dULL,
0xec09088b6997f879ULL, 0x96d1784359a27100ULL, 0x19b9e91b09fcea8bULL,
0x636199d339c963f2ULL, 0xdf7adabd7a6e2d6fULL, 0xa5a2aa754a5ba416ULL,
0x2aca3b2d1a053f9dULL, 0x50124be52a30b6e4ULL, 0x1f423fcee22f9be0ULL,
0x659a4f06d21a1299ULL, 0xeaf2de5e82448912ULL, 0x902aae96b271006bULL,
0x74523609127ad31aULL, 0x0e8a46c1224f5a63ULL, 0x81e2d7997211c1e8ULL,
0xfb3aa75142244891ULL, 0xb46ad37a8a3b6595ULL, 0xceb2a3b2ba0eececULL,
0x41da32eaea507767ULL, 0x3b024222da65fe1eULL, 0xa2722586f2d042eeULL,
0xd8aa554ec2e5cb97ULL, 0x57c2c41692bb501cULL, 0x2d1ab4dea28ed965ULL,
0x624ac0f56a91f461ULL, 0x1892b03d5aa47d18ULL, 0x97fa21650afae693ULL,
0xed2251ad3acf6feaULL, 0x095ac9329ac4bc9bULL, 0x7382b9faaaf135e2ULL,
0xfcea28a2faafae69ULL, 0x8632586aca9a2710ULL, 0xc9622c4102850a14ULL,
0xb3ba5c8932b0836dULL, 0x3cd2cdd162ee18e6ULL, 0x460abd1952db919fULL,
0x256b24ca6b12f26dULL, 0x5fb354025b277b14ULL, 0xd0dbc55a0b79e09fULL,
0xaa03b5923b4c69e6ULL, 0xe553c1b9f35344e2ULL, 0x9f8bb171c366cd9bULL,
0x10e3202993385610ULL, 0x6a3b50e1a30ddf69ULL, 0x8e43c87e03060c18ULL,
0xf49bb8b633338561ULL, 0x7bf329ee636d1eeaULL, 0x012b592653589793ULL,
0x4e7b2d0d9b47ba97ULL, 0x34a35dc5ab7233eeULL, 0xbbcbcc9dfb2ca865ULL,
0xc113bc55cb19211cULL, 0x5863dbf1e3ac9decULL, 0x22bbab39d3991495ULL,
0xadd33a6183c78f1eULL, 0xd70b4aa9b3f20667ULL, 0x985b3e827bed2b63ULL,
0xe2834e4a4bd8a21aULL, 0x6debdf121b863991ULL, 0x1733afda2bb3b0e8ULL,
0xf34b37458bb86399ULL, 0x8993478dbb8deae0ULL, 0x06fbd6d5ebd3716bULL,
0x7c23a61ddbe6f812ULL, 0x3373d23613f9d516ULL, 0x49aba2fe23cc5c6fULL,
0xc6c333a67392c7e4ULL, 0xbc1b436e43a74e9dULL, 0x95ac9329ac4bc9b5ULL,
0xef74e3e19c7e40ccULL, 0x601c72b9cc20db47ULL, 0x1ac40271fc15523eULL,
0x5594765a340a7f3aULL, 0x2f4c0692043ff643ULL, 0xa02497ca54616dc8ULL,
0xdafce7026454e4b1ULL, 0x3e847f9dc45f37c0ULL, 0x445c0f55f46abeb9ULL,
0xcb349e0da4342532ULL, 0xb1eceec59401ac4bULL, 0xfebc9aee5c1e814fULL,
0x8464ea266c2b0836ULL, 0x0b0c7b7e3c7593bdULL, 0x71d40bb60c401ac4ULL,
0xe8a46c1224f5a634ULL, 0x927c1cda14c02f4dULL, 0x1d148d82449eb4c6ULL,
0x67ccfd4a74ab3dbfULL, 0x289c8961bcb410bbULL, 0x5244f9a98c8199c2ULL,
0xdd2c68f1dcdf0249ULL, 0xa7f41839ecea8b30ULL, 0x438c80a64ce15841ULL,
0x3954f06e7cd4d138ULL, 0xb63c61362c8a4ab3ULL, 0xcce411fe1cbfc3caULL,
0x83b465d5d4a0eeceULL, 0xf96c151de49567b7ULL, 0x76048445b4cbfc3cULL,
0x0cdcf48d84fe7545ULL, 0x6fbd6d5ebd3716b7ULL, 0x15651d968d029fceULL,
0x9a0d8ccedd5c0445ULL, 0xe0d5fc06ed698d3cULL, 0xaf85882d2576a038ULL,
0xd55df8e515432941ULL, 0x5a3569bd451db2caULL, 0x20ed197575283bb3ULL,
0xc49581ead523e8c2ULL, 0xbe4df122e51661bbULL, 0x3125607ab548fa30ULL,
0x4bfd10b2857d7349ULL, 0x04ad64994d625e4dULL, 0x7e7514517d57d734ULL,
0xf11d85092d094cbfULL, 0x8bc5f5c11d3cc5c6ULL, 0x12b5926535897936ULL,
0x686de2ad05bcf04fULL, 0xe70573f555e26bc4ULL, 0x9ddd033d65d7e2bdULL,
0xd28d7716adc8cfb9ULL, 0xa85507de9dfd46c0ULL, 0x273d9686cda3dd4bULL,
0x5de5e64efd965432ULL, 0xb99d7ed15d9d8743ULL, 0xc3450e196da80e3aULL,
0x4c2d9f413df695b1ULL, 0x36f5ef890dc31cc8ULL, 0x79a59ba2c5dc31ccULL,
0x037deb6af5e9b8b5ULL, 0x8c157a32a5b7233eULL, 0xf6cd0afa9582aa47ULL,
0x4ad64994d625e4daULL, 0x300e395ce6106da3ULL, 0xbf66a804b64ef628ULL,
0xc5bed8cc867b7f51ULL, 0x8aeeace74e645255ULL, 0xf036dc2f7e51db2cULL,
0x7f5e4d772e0f40a7ULL, 0x05863dbf1e3ac9deULL, 0xe1fea520be311aafULL,
0x9b26d5e88e0493d6ULL, 0x144e44b0de5a085dULL, 0x6e963478ee6f8124ULL,
0x21c640532670ac20ULL, 0x5b1e309b16452559ULL, 0xd476a1c3461bbed2ULL,
0xaeaed10b762e37abULL, 0x37deb6af5e9b8b5bULL, 0x4d06c6676eae0222ULL,
0xc26e573f3ef099a9ULL, 0xb8b627f70ec510d0ULL, 0xf7e653dcc6da3dd4ULL,
0x8d3e2314f6efb4adULL, 0x0256b24ca6b12f26ULL, 0x788ec2849684a65fULL,
0x9cf65a1b368f752eULL, 0xe62e2ad306bafc57ULL, 0x6946bb8b56e467dcULL,
0x139ecb4366d1eea5ULL, 0x5ccebf68aecec3a1ULL, 0x2616cfa09efb4ad8ULL,
0xa97e5ef8cea5d153ULL, 0xd3a62e30fe90582aULL, 0xb0c7b7e3c7593bd8ULL,
0xca1fc72bf76cb2a1ULL, 0x45775673a732292aULL, 0x3faf26bb9707a053ULL,
0x70ff52905f188d57ULL, 0x0a2722586f2d042eULL, 0x854fb3003f739fa5ULL,
0xff97c3c80f4616dcULL, 0x1bef5b57af4dc5adULL, 0x61372b9f9f784cd4ULL,
0xee5fbac7cf26d75fULL, 0x9487ca0fff135e26ULL, 0xdbd7be24370c7322ULL,
0xa10fceec0739fa5bULL, 0x2e675fb4576761d0ULL, 0x54bf2f7c6752e8a9ULL,
0xcdcf48d84fe75459ULL, 0xb71738107fd2dd20ULL, 0x387fa9482f8c46abULL,
0x42a7d9801fb9cfd2ULL, 0x0df7adabd7a6e2d6ULL, 0x772fdd63e7936bafULL,
0xf8474c3bb7cdf024ULL, 0x829f3cf387f8795dULL, 0x66e7a46c27f3aa2cULL,
0x1c3fd4a417c62355ULL, 0x935745fc4798b8deULL, 0xe98f353477ad31a7ULL,
0xa6df411fbfb21ca3ULL, 0xdc0731d78f8795daULL, 0x536fa08fdfd90e51ULL,
0x29b7d047efec8728ULL
});
export namespace TextureFunction {
uint64_t get_crc64(const char* data, unsigned int length) {
uint64_t crc = 0xFFFFFFFFFFFFFFFFULL;
while (length--) {
crc = crctab64[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
}
return crc;
}
uint32_t get_crc32(const char* data_ptr, const int length)
{
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 < length; idx++) {
unsigned int data = *data_ptr++;
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) {
image.OverrideFormat(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;
}
}
+14 -6
View File
@@ -1,8 +1,9 @@
#include "Error.h"
#include <Windows.h>
#include <stdio.h>
#include <cstdio>
#include <process.h>
#include <Main.h>
__declspec(noreturn) void FatalAssert(
const char *expr,
@@ -10,13 +11,20 @@ const char *file,
unsigned int line,
const char *function)
{
const char* fmt = "%s\n%s\n%s line %d";
int len = snprintf(NULL, 0, fmt, expr, file, function, line);
char module_path[MAX_PATH]{};
if (gl_hThisInstance) {
GetModuleFileName(gl_hThisInstance, module_path, _countof(module_path));
}
if (!*module_path) {
strcpy(module_path, "Unknown");
}
const char* fmt = "Module: %s\n\nExpr: %s\n\nFile: %s\n\nFunction: %s, line %d";
int len = snprintf(NULL, 0, fmt, module_path, expr, file, function, line);
char* buf = new char[len + 1];
snprintf(buf,len + 1, fmt, expr, file, function, line);
snprintf(buf,len + 1, fmt, module_path, expr, file, function, line);
MessageBox(0, "uMod Assertion", buf, MB_OK | MB_ICONERROR);
MessageBox(0, buf, "uMod Assertion Failure", MB_OK | MB_ICONERROR);
delete[] buf;
abort();
-185
View File
@@ -1,185 +0,0 @@
#include <..\header\Main.h>
#include <filesystem>
#include "FileLoader.h"
#include "TpfReader.h"
FileLoader::FileLoader(const std::string& fileName)
{
file_name = std::filesystem::absolute(fileName).string();
}
std::vector<TpfEntry> FileLoader::GetContents()
{
try {
return file_name.ends_with(".tpf") ? GetTpfContents() : GetFileContents();
}
catch (const std::exception&) {
Message("Failed to open mod file: %s\n", file_name.c_str());
}
return {};
}
std::vector<TpfEntry> FileLoader::GetTpfContents()
{
std::vector<TpfEntry> 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);
if (!zip_archive) {
Message("Failed to open tpf file: %s - %u bytes!", file_name.c_str(), buffer.size());
return {};
}
zip_archive->setErrorHandlerCallback(
[](const std::string& message, const std::string& strerror, int zip_error_code, int system_error_code) -> void {
Message("GetTpfContents: %s %s %d %d\n", message.c_str(), strerror.c_str(), zip_error_code, system_error_code);
});
zip_archive->open();
LoadEntries(*zip_archive, entries);
zip_archive->close();
libzippp::ZipArchive::free(zip_archive);
return entries;
}
std::vector<TpfEntry> FileLoader::GetFileContents()
{
std::vector<TpfEntry> entries;
libzippp::ZipArchive zip_archive(file_name);
zip_archive.open();
LoadEntries(zip_archive, entries);
zip_archive.close();
return entries;
}
void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TpfEntry>& 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);
}
uint32_t crc_hash;
try {
crc_hash = std::stoul(name, nullptr, 16);
}
catch (const std::invalid_argument& e) {
Message("Failed to parse %s as a hash", name.c_str());
continue;
}
catch (const std::out_of_range& e) {
Message("Out of range while parsing %s as a hash", name.c_str());
continue;
}
const auto data_ptr = static_cast<char*>(entry.readAsBinary());
const auto size = entry.getSize();
std::vector<char> vec;
vec.assign(data_ptr, data_ptr + size);
entries.emplace_back(name, entry.getName(), crc_hash, std::move(vec));
}
}
}
void ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& archive, std::vector<TpfEntry>& 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) {
continue;
}
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()) {
continue;
}
uint32_t crc_hash{};
try {
crc_hash = std::stoul(addrstr, nullptr, 16);
}
catch (const std::invalid_argument& e) {
Message("Failed to parse %s as a hash", addrstr.c_str());
continue;
}
catch (const std::out_of_range& e) {
Message("Out of range while parsing %s as a hash", addrstr.c_str());
continue;
}
const auto data_ptr = static_cast<char*>(entry.readAsBinary());
const auto size = static_cast<size_t>(entry.getSize());
std::vector vec(data_ptr, data_ptr + size);
entries.emplace_back(addrstr, entry.getName(), crc_hash, std::move(vec));
delete[] data_ptr;
}
}
void FileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector<TpfEntry>& entries)
{
// Iterate over the files in the zip archive
const auto def_file = archive.getEntry("texmod.def");
if (def_file.isNull() || !def_file.isFile()) {
ParseSimpleArchive(archive, entries);
}
else {
const auto def = def_file.readAsText();
std::istringstream iss(def);
std::vector<std::string> lines;
std::string line;
while (std::getline(iss, line)) {
lines.push_back(line);
}
ParseTexmodArchive(lines, archive, entries);
}
}
-208
View File
@@ -1,208 +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);
FontColour = D3DCOLOR_ARGB(255, 255, 0, 0);
TextureColour = D3DCOLOR_ARGB(255, 0, 255, 0);
}
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);
const auto single_texture = GetSingleTexture();
for (const auto pTexture : OriginalTextures) {
if (pTexture->CrossRef_D3Dtex == nullptr || pTexture->CrossRef_D3Dtex == single_texture) {
UnswitchTextures(pTexture); //this we can do always, so we unswitch the single texture
LookUpToMod(pTexture);
}
}
const auto single_volume_texture = GetSingleVolumeTexture();
for (const auto pTexture : OriginalVolumeTextures) {
if (pTexture->CrossRef_D3Dtex == nullptr || pTexture->CrossRef_D3Dtex == single_volume_texture) {
UnswitchTextures(pTexture); //this we can do always, so we unswitch the single texture
LookUpToMod(pTexture);
}
}
const auto single_cube_texture = GetSingleCubeTexture();
for (const auto pTexture : OriginalCubeTextures) {
if (pTexture->CrossRef_D3Dtex == nullptr || pTexture->CrossRef_D3Dtex == single_cube_texture) {
UnswitchTextures(pTexture); //this we can do always, so we unswitch the single texture
LookUpToMod(pTexture);
}
}
return UnlockMutex();
}
uMod_IDirect3DTexture9* TextureClient::GetSingleTexture()
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->GetSingleTexture();
//this texture must no be added twice
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->GetSingleTexture();
}
uMod_IDirect3DVolumeTexture9* TextureClient::GetSingleVolumeTexture()
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->GetSingleVolumeTexture();
//this texture must no be added twice
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->GetSingleVolumeTexture();
}
uMod_IDirect3DCubeTexture9* TextureClient::GetSingleCubeTexture()
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->GetSingleCubeTexture();
//this texture must no be added twice
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->GetSingleCubeTexture();
}
int TextureClient::SetLastCreatedTexture(uMod_IDirect3DTexture9* texture)
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedTexture(texture);
//this texture must no be added twice
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedTexture(texture);
}
int TextureClient::SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* texture)
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
//this texture must no be added twice
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
}
int TextureClient::SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* texture)
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedCubeTexture(texture);
//this texture must no be added twice
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(TpfEntry& 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;
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()) {
Message("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");
}
+161 -118
View File
@@ -1,52 +1,33 @@
#include "dll_main.h"
#include <array>
#include <Windows.h>
#include "Main.h"
#include <Psapi.h>
#include "MinHook.h"
void ExitInstance();
void InitInstance(HINSTANCE hModule);
namespace {
#define DISABLE_HOOK(var) if(var) { MH_DisableHook(var);}
using Direct3DCreate9_type = IDirect3D9* (APIENTRY*)(UINT);
using Direct3DCreate9Ex_type = HRESULT(APIENTRY*)(UINT SDKVersion, IDirect3D9Ex** ppD3D);
using GetProcAddress_type = FARPROC(APIENTRY*)(HMODULE, LPCSTR);
// Pointer to original address of Direct3DCreate9
Direct3DCreate9_type Direct3DCreate9_fn = nullptr;
Direct3DCreate9_type Direct3DCreate9_ret = nullptr;
// Pointer to original address of Direct3DCreate9
Direct3DCreate9Ex_type Direct3DCreate9Ex_fn = nullptr;
Direct3DCreate9Ex_type Direct3DCreate9Ex_ret = nullptr;
static FILE* stdout_proxy;
static FILE* stderr_proxy;
GetProcAddress_type GetProcAddress_fn = nullptr;
GetProcAddress_type GetProcAddress_ret = nullptr;
/*
* global variable which are linked external
*/
unsigned int gl_ErrorState = 0u;
FILE* stdout_proxy;
FILE* stderr_proxy;
// If not nullptr, we're responsible for freeing this library on termination
HMODULE gl_hOriginalDll = nullptr;
HMODULE gMod_Loaded_d3d9_Module_Handle = nullptr;
// If this hModule called d3d9.dll?
bool IsD3d9Module(HMODULE hModule, HANDLE hProcess)
{
TCHAR szModuleName[MAX_PATH];
GetModuleBaseName(hProcess, hModule, szModuleName, sizeof(szModuleName) / sizeof(TCHAR));
return strcmp(szModuleName, TEXT("d3d9.dll")) == 0;
}
// Does this module contain exported function calls for creating a d3d9 device?
bool HasD3d9Methods(HMODULE hModule, HANDLE hProcess)
{
return GetProcAddress(hModule, "Direct3DCreate9")
&& GetProcAddress(hModule, "Direct3DCreate9Ex");
}
HMODULE FindLoadedDll()
HMODULE FindLoadedModuleByName(const char* name, bool include_this_module = false)
{
HMODULE hModules[1024];
HANDLE hProcess;
@@ -58,18 +39,140 @@ namespace {
if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded))
return nullptr;
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
if (IsD3d9Module(hModules[i], hProcess)
|| HasD3d9Methods(hModules[i], hProcess)) {
if (hModules[i] == gl_hThisInstance && !include_this_module)
continue;
TCHAR szModuleName[MAX_PATH];
ASSERT(GetModuleFileName(hModules[i], szModuleName, _countof(szModuleName)) > 0);
const auto basename = strrchr(szModuleName, '\\');
if (basename && stricmp(basename + 1, name) == 0)
return hModules[i];
}
}
return nullptr;
}
HMODULE LoadD3d9Dll()
{
HMODULE found = FindLoadedModuleByName("d3d9.dll");
if (!found) {
char executable_path[MAX_PATH]{};
ASSERT(GetModuleFileName(GetModuleHandle(nullptr), executable_path, _countof(executable_path)) > 0);
char dll_path[MAX_PATH]{};
ASSERT(GetModuleFileName(gl_hThisInstance, dll_path, _countof(dll_path)) > 0);
const auto exe_path = std::filesystem::path(executable_path);
const auto gmod_path = std::filesystem::path(dll_path);
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.
gMod_Loaded_d3d9_Module_Handle = LoadLibrary("d3d9.dll");
}
if (!gMod_Loaded_d3d9_Module_Handle) {
// Tried resolving d3d9.dll locally, didn't work. Try system directory
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
strcat_s(buffer, _countof(buffer), "\\d3d9.dll");
gMod_Loaded_d3d9_Module_Handle = LoadLibrary(buffer);
}
ASSERT(gMod_Loaded_d3d9_Module_Handle);
found = FindLoadedModuleByName("d3d9.dll");
ASSERT(found && found == gMod_Loaded_d3d9_Module_Handle);
}
DISABLE_HOOK(GetProcAddress_fn);
// GetProcAddress, hooked via OnGetProcAddress
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)
{
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 = 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()
{
if (!(Direct3DCreate9_ret && Direct3DCreate9_ret != Direct3DCreate9)) {
ASSERT(LoadD3d9Dll());
ASSERT(Direct3DCreate9_ret && Direct3DCreate9_ret != Direct3DCreate9);
}
if (!(Direct3DCreate9Ex_ret && Direct3DCreate9Ex_ret != Direct3DCreate9Ex)) {
ASSERT(LoadD3d9Dll());
ASSERT(Direct3DCreate9Ex_ret && Direct3DCreate9Ex_ret != Direct3DCreate9Ex);
}
}
// There may be a sitation where more than 1 gmod is loaded; avoid recursions!
bool creating_d3d9 = false;
}
unsigned int gl_ErrorState = 0;
HINSTANCE gl_hThisInstance = nullptr;
IDirect3D9* APIENTRY Direct3DCreate9(UINT SDKVersion)
{
Message("uMod_Direct3DCreate9: uMod %p\n", Direct3DCreate9);
ASSERT(!creating_d3d9);
creating_d3d9 = true;
DISABLE_HOOK(GetProcAddress_fn);
CheckLoadD3d9Dll();
IDirect3D9* pIDirect3D9_orig = Direct3DCreate9_ret(SDKVersion); //creating the original IDirect3D9 object
ASSERT(pIDirect3D9_orig);
creating_d3d9 = false;
return new uMod_IDirect3D9(pIDirect3D9_orig); //return our object instead of the "real one"
}
HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D)
{
Message("uMod_Direct3DCreate9Ex: uMod %p\n", Direct3DCreate9Ex);
ASSERT(!creating_d3d9);
creating_d3d9 = true;
DISABLE_HOOK(GetProcAddress_fn);
CheckLoadD3d9Dll();
IDirect3D9Ex* pIDirect3D9Ex_orig = nullptr;
HRESULT ret = Direct3DCreate9Ex_ret(SDKVersion, &pIDirect3D9Ex_orig); //creating the original IDirect3D9 object
creating_d3d9 = false;
if (ret != S_OK)
return ret;
// @Cleanup: should be we freeing pIDirect3D9Ex at the end of our own lifecycle?
const auto pIDirect3D9Ex = new uMod_IDirect3D9Ex(pIDirect3D9Ex_orig);
// original umod does not do this for some reason
*ppD3D = static_cast<IDirect3D9Ex*>(pIDirect3D9Ex);
return ret;
}
/*
* dll entry routine, here we initialize or clean up
*/
@@ -80,10 +183,10 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
#ifdef _DEBUG
AllocConsole();
SetConsoleTitleA("gMod Console");
freopen_s(&stdout_proxy, "CONOUT$", "w", stdout);
freopen_s(&stderr_proxy, "CONOUT$", "w", stderr);
AllocConsole();
SetConsoleTitleA("gMod Console");
freopen_s(&stdout_proxy, "CONOUT$", "w", stdout);
freopen_s(&stderr_proxy, "CONOUT$", "w", stderr);
#endif
InitInstance(hModule);
break;
@@ -100,104 +203,44 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
void InitInstance(HINSTANCE hModule)
{
DisableThreadLibraryCalls(hModule); //reduce overhead
gl_hThisInstance = hModule;
Message("InitInstance: %p\n", hModule);
DisableThreadLibraryCalls(hModule); //reduce overhead
const auto d3d9_dll = LoadOriginalDll();
ASSERT(d3d9_dll);
// Store the handle to this module
gl_hThisInstance = hModule;
Direct3DCreate9_fn = reinterpret_cast<Direct3DCreate9_type>(GetProcAddress(d3d9_dll, "Direct3DCreate9"));
ASSERT(Direct3DCreate9_fn);
Direct3DCreate9Ex_fn = reinterpret_cast<Direct3DCreate9Ex_type>(GetProcAddress(d3d9_dll, "Direct3DCreate9Ex"));
ASSERT(Direct3DCreate9Ex_fn);
// d3d9.dll shouldn't be loaded at this point.
const auto d3d9_loaded = FindLoadedModuleByName("d3d9.dll");
//ASSERT(!d3d9_loaded);
MH_Initialize();
if (Direct3DCreate9_fn) {
MH_CreateHook(Direct3DCreate9_fn, uMod_Direct3DCreate9, (void**)&Direct3DCreate9_ret);
MH_EnableHook(Direct3DCreate9_fn);
// Hook into LoadLibraryA - we'll do our hooks on the flip side
GetProcAddress_fn = reinterpret_cast<GetProcAddress_type>(GetProcAddress);
ASSERT(GetProcAddress_fn);
if (GetProcAddress_fn) {
MH_CreateHook(GetProcAddress_fn, OnGetProcAddress, (void**)&GetProcAddress_ret);
MH_EnableHook(GetProcAddress_fn);
}
if (Direct3DCreate9Ex_fn) {
MH_CreateHook(Direct3DCreate9Ex_fn, uMod_Direct3DCreate9Ex, (void**)&Direct3DCreate9Ex_ret);
MH_EnableHook(Direct3DCreate9Ex_fn);
}
}
void ExitInstance()
{
if(Direct3DCreate9_fn)
MH_DisableHook(Direct3DCreate9_fn);
if(Direct3DCreate9Ex_fn)
MH_DisableHook(Direct3DCreate9Ex_fn);
DISABLE_HOOK(GetProcAddress_fn);
MH_Uninitialize();
// Release the system's d3d9.dll
if (gl_hOriginalDll != nullptr) {
FreeLibrary(gl_hOriginalDll);
gl_hOriginalDll = nullptr;
}
if (gMod_Loaded_d3d9_Module_Handle)
FreeLibrary(gMod_Loaded_d3d9_Module_Handle);
#ifdef _DEBUG
if (stdout_proxy)
fclose(stdout_proxy);
if (stderr_proxy)
fclose(stderr_proxy);
FreeConsole();
__try {
FreeConsole();
}
__except (EXCEPTION_CONTINUE_EXECUTION) { }
#endif
}
HMODULE LoadOriginalDll()
{
HMODULE found = FindLoadedDll();
if (found)
return found;
char buffer[MAX_PATH];
GetSystemDirectory(buffer, MAX_PATH); //get the system directory, we need to open the original d3d9.dll
// Append dll name
strcat_s(buffer, MAX_PATH, "\\d3d9.dll");
gl_hOriginalDll = LoadLibrary(buffer);
found = FindLoadedDll();
ASSERT(found && found == gl_hOriginalDll);
return found;
}
/*
* We inject the dll into the game, thus we retour the original Direct3DCreate9 function to our MyDirect3DCreate9 function
*/
IDirect3D9* APIENTRY uMod_Direct3DCreate9(UINT SDKVersion)
{
Message("uMod_Direct3DCreate9: original %p, uMod %p\n", Direct3DCreate9_fn, uMod_Direct3DCreate9);
ASSERT(Direct3DCreate9_ret);
IDirect3D9* pIDirect3D9_orig = Direct3DCreate9_ret(SDKVersion); //creating the original IDirect3D9 object
ASSERT(pIDirect3D9_orig);
return new uMod_IDirect3D9(pIDirect3D9_orig); //return our object instead of the "real one"
}
HRESULT APIENTRY uMod_Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D)
{
Message("uMod_Direct3DCreate9Ex: original %p, uMod %p\n", Direct3DCreate9Ex_fn, uMod_Direct3DCreate9Ex);
ASSERT(Direct3DCreate9Ex_ret);
IDirect3D9Ex* pIDirect3D9Ex_orig = nullptr;
HRESULT ret = Direct3DCreate9Ex_ret(SDKVersion, &pIDirect3D9Ex_orig); //creating the original IDirect3D9 object
if (ret != S_OK)
return ret;
// @Cleanup: should be we freeing pIDirect3D9Ex at the end of our own lifecycle?
uMod_IDirect3D9Ex* pIDirect3D9Ex = new uMod_IDirect3D9Ex(pIDirect3D9Ex_orig);
ppD3D = (IDirect3D9Ex**)&pIDirect3D9Ex;
return ret;
}
+20 -25
View File
@@ -1,5 +1,9 @@
#include "Main.h"
import ModfileLoader;
import TextureClient;
import TextureFunction;
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::QueryInterface(REFIID riid, void** ppvObj)
{
@@ -62,16 +66,7 @@ ULONG APIENTRY uMod_IDirect3DCubeTexture9::Release()
if (count == 0) //if texture is released we switch the textures back
{
UnswitchTextures(this);
if (ret == 0x01000000L) {
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetSingleCubeTexture() != fake_texture) {
fake_texture->Release(); // we release the fake texture
}
}
else {
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetSingleCubeTexture() != fake_texture) {
fake_texture->Release(); // we release the fake texture
}
}
fake_texture->Release(); // we release the fake texture
}
}
else {
@@ -233,12 +228,10 @@ HRESULT APIENTRY uMod_IDirect3DCubeTexture9::UnlockRect(D3DCUBEMAP_FACES FaceTyp
return m_D3Dtex->UnlockRect(FaceType, Level);
}
HashType uMod_IDirect3DCubeTexture9::GetHash() const
HashTuple uMod_IDirect3DCubeTexture9::GetHash() const
{
if (FAKE) {
return 0;
return {};
}
IDirect3DCubeTexture9* pTexture = m_D3Dtex;
if (CrossRef_D3Dtex != nullptr) {
@@ -251,28 +244,29 @@ HashType uMod_IDirect3DCubeTexture9::GetHash() const
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) //get the format and the size of the texture
{
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetLevelDesc \n");
return 0;
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetLevelDesc \n");
return {};
}
Message("uMod_IDirect3DCubeTexture9::GetHash() (%d %d) %d\n", desc.Width, desc.Height, desc.Format);
if (pTexture->LockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK)
{
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 1\n");
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 1\n");
if (pTexture->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_X, 0, &pResolvedSurface) != D3D_OK) {
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetSurfaceLevel\n");
return 0;
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetSurfaceLevel\n");
return {};
}
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 2\n");
return 0;
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 2\n");
return {};
}
}
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 crc32 = TextureFunction::get_crc32(static_cast<char*>(d3dlr.pBits), size);
const auto crc64 = HashCheck::Use64BitCrc() ? TextureFunction::get_crc64(static_cast<char*>(d3dlr.pBits), size) : 0;
// Only release surfaces after we're finished with d3dlr
if (pResolvedSurface != nullptr) {
@@ -283,6 +277,7 @@ HashType uMod_IDirect3DCubeTexture9::GetHash() const
pTexture->UnlockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0); //unlock the raw data
}
Message("uMod_IDirect3DCubeTexture9::GetHash() %#lX (%d %d) %d = %d\n", hash, desc.Width, desc.Height, desc.Format, size);
return hash;
Message("uMod_IDirect3DCubeTexture9::GetHash() %#lX (%d %d) %d = %d\n", crc32, desc.Width, desc.Height, desc.Format, size);
Message("uMod_IDirect3DCubeTexture9::GetHash() %#llX (%d %d) %d = %d\n", crc64, desc.Width, desc.Height, desc.Format, size);
return {crc32, crc64};
}
+17 -160
View File
@@ -1,4 +1,5 @@
#include "Main.h"
import TextureClient;
#ifndef RETURN_QueryInterface
#define RETURN_QueryInterface 0x01000000L
@@ -8,128 +9,15 @@
#define PRE_MESSAGE "uMod_IDirect3DDevice9"
#endif
int uMod_IDirect3DDevice9::CreateSingleTexture()
{
if (SingleTexture != nullptr && SingleVolumeTexture != nullptr && SingleCubeTexture != nullptr && TextureColour == uMod_Client->TextureColour) {
return RETURN_OK;
}
TextureColour = uMod_Client->TextureColour;
if (SingleTexture == nullptr) //create texture
{
if (D3D_OK != CreateTexture(8, 8, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, (IDirect3DTexture9**)&SingleTexture, nullptr)) {
Message(PRE_MESSAGE "::CreateSingleTexture(): CreateTexture Failed\n");
SingleTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
LastCreatedTexture = nullptr; // set LastCreatedTexture to NULL, cause LastCreatedTexture is equal SingleTexture
SingleTexture->FAKE = true; //this is no texture created from by game
}
{
D3DLOCKED_RECT d3dlr;
IDirect3DTexture9* pD3Dtex = SingleTexture->m_D3Dtex;
if (D3D_OK != pD3Dtex->LockRect(0, &d3dlr, nullptr, 0)) {
Message(PRE_MESSAGE "::CreateSingleTexture(): LockRect Failed\n");
SingleTexture->Release();
SingleTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
const auto pDst = static_cast<DWORD*>(d3dlr.pBits);
for (int i = 0; i < 8 * 8; i++) {
pDst[i] = TextureColour;
}
pD3Dtex->UnlockRect(0);
}
if (SingleVolumeTexture == nullptr) //create texture
{
if (D3D_OK != CreateVolumeTexture(8, 8, 8, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, (IDirect3DVolumeTexture9**)&SingleVolumeTexture, nullptr)) {
Message(PRE_MESSAGE "::CreateSingleTexture(): CreateVolumeTexture Failed\n");
SingleVolumeTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
LastCreatedVolumeTexture = nullptr; // set LastCreatedTexture to NULL, cause LastCreatedTexture is equal SingleTexture
SingleVolumeTexture->FAKE = true; //this is no texture created from by game
}
{
D3DLOCKED_BOX d3dlr;
IDirect3DVolumeTexture9* pD3Dtex = SingleVolumeTexture->m_D3Dtex;
//LockBox)(UINT Level, D3DLOCKED_BOX *pLockedVolume, CONST D3DBOX *pBox,
if (D3D_OK != pD3Dtex->LockBox(0, &d3dlr, nullptr, 0)) {
Message(PRE_MESSAGE "::CreateSingleTexture(): LockBox Failed\n");
SingleVolumeTexture->Release();
SingleVolumeTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
const auto pDst = static_cast<DWORD*>(d3dlr.pBits);
for (int i = 0; i < 8 * 8 * 8; i++) {
pDst[i] = TextureColour;
}
pD3Dtex->UnlockBox(0);
}
if (SingleCubeTexture == nullptr) //create texture
{
if (D3D_OK != CreateCubeTexture(8, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, (IDirect3DCubeTexture9**)&SingleCubeTexture, nullptr)) {
Message(PRE_MESSAGE "::CreateSingleTexture(): CreateCubeTexture Failed\n");
SingleCubeTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
LastCreatedCubeTexture = nullptr; // set LastCreatedTexture to NULL, cause LastCreatedTexture is equal SingleTexture
SingleCubeTexture->FAKE = true; //this is no texture created from by game
}
{
D3DLOCKED_RECT d3dlr;
IDirect3DCubeTexture9* pD3Dtex = SingleCubeTexture->m_D3Dtex;
for (int c = 0; c < 6; c++) {
if (D3D_OK != pD3Dtex->LockRect(static_cast<D3DCUBEMAP_FACES>(c), 0, &d3dlr, nullptr, 0)) {
Message(PRE_MESSAGE "::CreateSingleTexture(): LockRect (Cube) Failed\n");
SingleCubeTexture->Release();
SingleCubeTexture = nullptr;
return RETURN_TEXTURE_NOT_LOADED;
}
const auto pDst = static_cast<DWORD*>(d3dlr.pBits);
for (int i = 0; i < 8 * 8; i++) {
pDst[i] = TextureColour;
}
pD3Dtex->UnlockRect(static_cast<D3DCUBEMAP_FACES>(c), 0);
}
}
return RETURN_OK;
}
uMod_IDirect3DDevice9::uMod_IDirect3DDevice9(IDirect3DDevice9* pOriginal, int back_buffer_count)
{
Message(PRE_MESSAGE "::" PRE_MESSAGE " (%p): %p\n", pOriginal, this);
BackBufferCount = back_buffer_count;
NormalRendering = true;
uMod_Client = new TextureClient(this); //get a new texture client for this device
uMod_Client->Initialize();
LastCreatedTexture = nullptr;
LastCreatedVolumeTexture = nullptr;
LastCreatedCubeTexture = nullptr;
m_pIDirect3DDevice9 = pOriginal; // store the pointer to original object
TextureColour = D3DCOLOR_ARGB(255, 0, 255, 0);
CounterSaveSingleTexture = -20;
SingleTextureMod = 0;
SingleTexture = nullptr;
SingleVolumeTexture = nullptr;
SingleCubeTexture = nullptr;
OSD_Font = nullptr;
uMod_Reference = 1;
}
uMod_IDirect3DDevice9::~uMod_IDirect3DDevice9()
@@ -172,23 +60,8 @@ ULONG uMod_IDirect3DDevice9::Release()
// we must not release the fake textures, cause they are released if the target textures are released
// and the target textures are released by the game.
if (SingleTexture != nullptr) {
SingleTexture->Release(); //this is the only texture we must release by ourself
}
if (SingleVolumeTexture != nullptr) {
SingleVolumeTexture->Release(); //this is the only texture we must release by ourself
}
if (SingleCubeTexture != nullptr) {
SingleCubeTexture->Release(); //this is the only texture we must release by ourself
}
if (OSD_Font != nullptr) {
OSD_Font->Release();
}
delete uMod_Client; //must be deleted at the end, because other releases might call a function of this object
uMod_Client = nullptr;
SingleTexture = nullptr;
OSD_Font = nullptr;
}
const ULONG count = m_pIDirect3DDevice9->Release();
@@ -271,10 +144,6 @@ UINT uMod_IDirect3DDevice9::GetNumberOfSwapChains()
HRESULT uMod_IDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters)
{
if (OSD_Font != nullptr) {
OSD_Font->Release();
OSD_Font = nullptr;
} //the game will crashes if the font is not released before the game is minimized!
return m_pIDirect3DDevice9->Reset(pPresentationParameters);
}
@@ -311,23 +180,18 @@ void uMod_IDirect3DDevice9::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp)
HRESULT uMod_IDirect3DDevice9::CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle)
{
//create real texture
//Message("uMod_IDirect3DDevice9::CreateTexture()\n");
Message("uMod_IDirect3DDevice9::CreateTexture()\n");
const HRESULT ret = m_pIDirect3DDevice9->CreateTexture(Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
if (ret != D3D_OK) {
return ret;
}
//create fake texture
const auto texture = new uMod_IDirect3DTexture9(ppTexture, this);
if (texture) {
*ppTexture = texture;
}
*ppTexture = texture;
if (LastCreatedTexture != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
if (LastCreatedTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
{
if (uMod_Client != nullptr) {
uMod_Client->AddTexture(LastCreatedTexture);
}
uMod_Client->AddTexture(LastCreatedTexture);
}
LastCreatedTexture = texture;
return ret;
@@ -336,7 +200,7 @@ HRESULT uMod_IDirect3DDevice9::CreateTexture(UINT Width, UINT Height, UINT Level
HRESULT uMod_IDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle)
{
//create real texture
//Message("uMod_IDirect3DDevice9::CreateVolumeTexture()\n");
Message("uMod_IDirect3DDevice9::CreateVolumeTexture()\n");
const HRESULT ret = m_pIDirect3DDevice9->CreateVolumeTexture(Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
if (ret != D3D_OK) {
return ret;
@@ -344,15 +208,11 @@ HRESULT uMod_IDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT
//create fake texture
const auto texture = new uMod_IDirect3DVolumeTexture9(ppVolumeTexture, this);
if (texture) {
*ppVolumeTexture = texture;
}
*ppVolumeTexture = texture;
if (LastCreatedVolumeTexture != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
if (LastCreatedVolumeTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
{
if (uMod_Client != nullptr) {
uMod_Client->AddTexture(LastCreatedVolumeTexture);
}
uMod_Client->AddTexture(LastCreatedVolumeTexture);
}
LastCreatedVolumeTexture = texture;
return ret;
@@ -361,7 +221,7 @@ HRESULT uMod_IDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT
HRESULT uMod_IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle)
{
//create real texture
//Message("uMod_IDirect3DDevice9::CreateCubeTexture()\n");
Message("uMod_IDirect3DDevice9::CreateCubeTexture()\n");
const HRESULT ret = m_pIDirect3DDevice9->CreateCubeTexture(EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
if (ret != D3D_OK) {
return ret;
@@ -369,15 +229,11 @@ HRESULT uMod_IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength, UINT Levels, D
//create fake texture
const auto texture = new uMod_IDirect3DCubeTexture9(ppCubeTexture, this);
if (texture) {
*ppCubeTexture = texture;
}
*ppCubeTexture = texture;
if (LastCreatedCubeTexture != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
if (LastCreatedCubeTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
{
if (uMod_Client != nullptr) {
uMod_Client->AddTexture(LastCreatedCubeTexture);
}
uMod_Client->AddTexture(LastCreatedCubeTexture);
}
LastCreatedCubeTexture = texture;
return ret;
@@ -419,10 +275,11 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
uMod_IDirect3DCubeTexture9* pSourceCube = nullptr;
IDirect3DBaseTexture9* cpy;
if (pSourceTexture != nullptr) {
const auto hash = pSource->GetHash();
switch (pSourceTexture->QueryInterface(IID_IDirect3D9, (void**)&cpy)) {
case 0x01000000L: {
pSource = static_cast<uMod_IDirect3DTexture9*>(pSourceTexture);
if (const auto hash = pSource->GetHash()) {
if (hash) {
if (hash != pSource->Hash) // this hash has changed !!
{
pSource->Hash = hash;
@@ -447,7 +304,7 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
}
case 0x01000001L: {
pSourceVolume = static_cast<uMod_IDirect3DVolumeTexture9*>(pSourceTexture);
if (const auto hash = pSource->GetHash()) {
if (hash) {
if (hash != pSourceVolume->Hash) // this hash has changed !!
{
pSourceVolume->Hash = hash;
@@ -472,7 +329,7 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
}
case 0x01000002L: {
pSourceCube = static_cast<uMod_IDirect3DCubeTexture9*>(pSourceTexture);
if (const auto hash = pSourceCube->GetHash()) {
if (hash) {
if (hash != pSourceCube->Hash) // this hash has changed !!
{
pSourceCube->Hash = hash;
+33 -35
View File
@@ -1,5 +1,9 @@
#include "Main.h"
import ModfileLoader;
import TextureClient;
import TextureFunction;
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::QueryInterface(REFIID riid, void** ppvObj)
{
@@ -62,16 +66,7 @@ ULONG APIENTRY uMod_IDirect3DTexture9::Release()
if (count == 0) //if texture is released we switch the textures back
{
UnswitchTextures(this);
if (ret == 0x01000000L) {
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetSingleTexture() != fake_texture) {
fake_texture->Release(); // we release the fake texture
}
}
else {
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetSingleTexture() != fake_texture) {
fake_texture->Release(); // we release the fake texture
}
}
fake_texture->Release(); // we release the fake texture
}
}
else {
@@ -209,7 +204,7 @@ HRESULT APIENTRY uMod_IDirect3DTexture9::GetSurfaceLevel(UINT Level, IDirect3DSu
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect, DWORD Flags)
HRESULT APIENTRY uMod_IDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->LockRect(Level, pLockedRect, pRect, Flags);
@@ -236,7 +231,7 @@ HRESULT APIENTRY uMod_IDirect3DTexture9::AddDirtyRect(CONST RECT* pDirtyRect)
}
HashType uMod_IDirect3DTexture9::GetHash() const
HashTuple uMod_IDirect3DTexture9::GetHash() const
{
ASSERT(!FAKE);
IDirect3DTexture9* pTexture = m_D3Dtex;
@@ -252,8 +247,8 @@ HashType uMod_IDirect3DTexture9::GetHash() const
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) //get the format and the size of the texture
{
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetLevelDesc \n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetLevelDesc \n");
return {};
}
Message("uMod_IDirect3DTexture9::GetHash() (%d %d) %d\n", desc.Width, desc.Height, desc.Format);
@@ -265,21 +260,21 @@ HashType uMod_IDirect3DTexture9::GetHash() const
IDirect3DSurface9* pSurfaceLevel_orig = nullptr;
if (pTexture->GetSurfaceLevel(0, &pSurfaceLevel_orig) != D3D_OK) {
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel 1 (D3DPOOL_DEFAULT)\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel 1 (D3DPOOL_DEFAULT)\n");
return {};
}
if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) {
//Message("uMod_IDirect3DTexture9::GetHash() MultiSampleType\n");
if (D3D_OK != m_D3Ddev->CreateRenderTarget(desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pResolvedSurface, nullptr)) {
pSurfaceLevel_orig->Release();
Message("uMod_IDirect3DTexture9::GetHash() Failed: CreateRenderTarget (D3DPOOL_DEFAULT)\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: CreateRenderTarget (D3DPOOL_DEFAULT)\n");
return {};
}
if (D3D_OK != m_D3Ddev->StretchRect(pSurfaceLevel_orig, nullptr, pResolvedSurface, nullptr, D3DTEXF_NONE)) {
pSurfaceLevel_orig->Release();
Message("uMod_IDirect3DTexture9::GetHash() Failed: StretchRect (D3DPOOL_DEFAULT)\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: StretchRect (D3DPOOL_DEFAULT)\n");
return {};
}
pSurfaceLevel_orig = pResolvedSurface;
@@ -290,8 +285,8 @@ HashType uMod_IDirect3DTexture9::GetHash() const
if (pResolvedSurface != nullptr) {
pResolvedSurface->Release();
}
Message("uMod_IDirect3DTexture9::GetHash() Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
return {};
}
if (D3D_OK != m_D3Ddev->GetRenderTargetData(pSurfaceLevel_orig, pOffscreenSurface)) {
@@ -300,8 +295,8 @@ HashType uMod_IDirect3DTexture9::GetHash() const
pResolvedSurface->Release();
}
pOffscreenSurface->Release();
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
return {};
}
pSurfaceLevel_orig->Release();
@@ -310,25 +305,26 @@ HashType uMod_IDirect3DTexture9::GetHash() const
pResolvedSurface->Release();
}
pOffscreenSurface->Release();
Message("uMod_IDirect3DTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
return {};
}
}
else if (pTexture->LockRect(0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
Message("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 1\n");
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 1\n");
if (pTexture->GetSurfaceLevel(0, &pResolvedSurface) != D3D_OK) {
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel\n");
return {};
}
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Message("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 2\n");
return 0;
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 2\n");
return {};
}
}
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 crc32 = TextureFunction::get_crc32(static_cast<char*>(d3dlr.pBits), size);
const auto crc64 = HashCheck::Use64BitCrc() ? TextureFunction::get_crc64(static_cast<char*>(d3dlr.pBits), size) : 0;
// Only release surfaces after we're finished with d3dlr
if (pOffscreenSurface != nullptr) {
@@ -345,6 +341,8 @@ HashType uMod_IDirect3DTexture9::GetHash() const
else {
pTexture->UnlockRect(0);
}
Message("uMod_IDirect3DTexture9::GetHash() %#lX (%d %d) %d = %d\n", hash, desc.Width, desc.Height, desc.Format, size);
return hash;
Message("uMod_IDirect3DTexture9::GetHash() crc32 %#lX (%d %d) %d = %d\n", crc32, desc.Width, desc.Height, desc.Format, size);
Message("uMod_IDirect3DTexture9::GetHash() crc64 %#llX (%d %d) %d = %d\n", crc64, desc.Width, desc.Height, desc.Format, size);
return {crc32, crc64};
}
+20 -28
View File
@@ -1,5 +1,9 @@
#include "Main.h"
import ModfileLoader;
import TextureClient;
import TextureFunction;
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::QueryInterface(REFIID riid, void** ppvObj)
{
if (riid == IID_IDirect3D9) {
@@ -61,16 +65,7 @@ ULONG APIENTRY uMod_IDirect3DVolumeTexture9::Release()
if (count == 0) //if texture is released we switch the textures back
{
UnswitchTextures(this);
if (ret == 0x01000000L) {
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetSingleVolumeTexture() != fake_texture) {
fake_texture->Release(); // we release the fake texture
}
}
else {
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetSingleVolumeTexture() != fake_texture) {
fake_texture->Release(); // we release the fake texture
}
}
fake_texture->Release(); // we release the fake texture
}
}
else {
@@ -187,8 +182,6 @@ void APIENTRY uMod_IDirect3DVolumeTexture9::GenerateMipSubLevels()
m_D3Dtex->GenerateMipSubLevels();
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::AddDirtyBox(CONST D3DBOX* pDirtyBox)
{
@@ -234,11 +227,10 @@ HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::UnlockBox(UINT Level)
return m_D3Dtex->UnlockBox(Level);
}
HashType uMod_IDirect3DVolumeTexture9::GetHash() const
HashTuple uMod_IDirect3DVolumeTexture9::GetHash() const
{
if (FAKE) {
return 0;
return {};
}
IDirect3DVolumeTexture9* pTexture = m_D3Dtex;
if (CrossRef_D3Dtex != nullptr) {
@@ -251,28 +243,27 @@ HashType uMod_IDirect3DVolumeTexture9::GetHash() const
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) //get the format and the size of the texture
{
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetLevelDesc \n");
return 0;
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetLevelDesc \n");
return {};
}
Message("uMod_IDirect3DVolumeTexture9::GetHash() (%d %d %d) %d\n", desc.Width, desc.Height, desc.Depth, desc.Format);
if (pTexture->LockBox(0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 1\n");
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 1\n");
if (pTexture->GetVolumeLevel(0, &pResolvedSurface) != D3D_OK) {
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetSurfaceLevel\n");
return 0;
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetSurfaceLevel\n");
return {};
}
if (pResolvedSurface->LockBox(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 2\n");
return 0;
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 2\n");
return {};
}
}
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 crc32 = TextureFunction::get_crc32(static_cast<char*>(d3dlr.pBits), size);
const auto crc64 = HashCheck::Use64BitCrc() ? TextureFunction::get_crc64(static_cast<char*>(d3dlr.pBits), size) : 0;
// Only release surfaces after we're finished with d3dlr
if (pResolvedSurface != nullptr) {
@@ -283,6 +274,7 @@ HashType uMod_IDirect3DVolumeTexture9::GetHash() const
pTexture->UnlockBox(0);
}
Message("uMod_IDirect3DVolumeTexture9::GetHash() %#lX (%d %d) %d = %d\n", hash, desc.Width, desc.Height, desc.Format, size);
return hash;
Message("uMod_IDirect3DVolumeTexture9::GetHash() crc32 %#lX (%d %d) %d = %d\n", crc32, desc.Width, desc.Height, desc.Format, size);
Message("uMod_IDirect3DVolumeTexture9::GetHash() crc64 %#llX (%d %d) %d = %d\n", crc64, desc.Width, desc.Height, desc.Format, size);
return {crc32, crc64};
}
+14
View File
@@ -0,0 +1,14 @@
{
"default-registry": {
"kind": "git",
"baseline": "7f9f0e44db287e8e67c0e888141bfa200ab45121",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
{
"kind": "artifact",
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
"name": "microsoft"
}
]
}
+5
View File
@@ -0,0 +1,5 @@
{
"dependencies": [
"dxsdk-d3dx"
]
}