Compare commits

...

29 Commits

Author SHA1 Message Date
Marc 66663fa9f9 v1.10.0 - signed binaries (#39)
* Sign release binaries with Certum and bump to v2.0.0.0

Add Certum SimplySign cloud code signing to the CD pipeline so gMod.dll
and TpfConvert.exe are signed before being published as release assets.
The signing scripts are ported from gwlauncher (commit 5ae825a).

Signing is gated on the CERTUM_OTP_URI secret, so forks/unconfigured
repos still build, just unsigned. Requires repo secrets CERTUM_OTP_URI,
CERTUM_USERID and CERTUM_CERT_SHA1.

Bump the major version to 2.0.0.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* 1.10

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:46:55 +07:00
Marc 34dd80388f Merge dev: emulation re-JIT flush, unhook fallthrough, teardown safety (v1.9.0.3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 18:06:00 +00:00
Marc f420bbd50a Bump version to 1.9.0.3
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 18:05:51 +00:00
Marc e762e1b716 Flush instruction cache after (un)hooking so the ARM64 emulator re-JITs
MinHook flushes only the 5 patched bytes; under the x86-on-ARM64
emulator (xtajit) that can leave a stale JIT translation of the
modified prologue and trap with a non-continuable breakpoint. Flush the
whole prologue and the trampoline on install, and the restored prologue
on teardown, so the emulator re-translates them. No-op on native x86.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 18:03:36 +00:00
Marc 13abd4e546 Bump version to 1.9.0.2
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:35:14 +00:00
Marc 92c6b115f3 Make D3D9 detours fall through after unhook to avoid teardown crash
Keep the o_* trampoline pointers valid on RemoveAllD3D9Hooks and add a
g_unhooked flag each detour checks after calling the original, so a
surviving vtable patch invoked during/after teardown just returns the
real result instead of touching freed TextureClient state. Tear down
off the loader lock via a new Shutdown export and skip teardown on
process exit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 15:13:00 +00:00
Marc 2b87e0e53a Fix surface ref leak and double-release in HashTexture2D multisample path
The D3DPOOL_DEFAULT multisample branch aliased pSurfaceLevel_orig onto
pResolvedSurface, leaking the GetSurfaceLevel reference and releasing the
resolved surface twice (use-after-free). Track the read source in a separate
non-owning pointer so each surface is released exactly once on every path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 17:14:17 +00:00
Marc b04b4583f4 Bump version to 1.9.0.1
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 17:00:10 +00:00
Marc 18d650a422 Expand CLAUDE.md with build constraints, hooking model, and conventions
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 16:24:05 +00:00
Jon 55e36db265 Merge branch 'master' into dev 2026-06-08 17:15:11 +01:00
Jon 379878bd6d Claude stuff 2026-06-08 17:14:56 +01:00
Jon ac39241ff9 Release replacement textures when a client is torn down (#38)
* 1.9

* Release replacement textures when a client is torn down

TextureClient::~TextureClient deleted the per-texture side-state but never
released the replacement IDirect3DTexture9 objects gMod created. That's
fine when the client dies because the device hit refcount 0 (a texture
refs its device, so by then every fake is already released and the maps
are empty). But when gMod is unloaded via FreeLibrary while the game's
device is still alive (late-injected/SetDevice integrations), the maps
are full of textures gMod still owns and they all leak - and ExitInstance
never deleted the clients, so the destructor didn't even run.

- ~TextureClient now releases each replacement it still owns (a fake is
  still owned while it has a partner; an orphaned fake was already
  released and is left alone). No-op in the device-release path.
- Add DestroyAllTextureClients() to delete the per-device clients.
- ExitInstance calls it, gated on a genuine FreeLibrary
  (lpReserved == nullptr) so it's skipped during process termination
  where the device/d3d9 may already be gone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Jon <>
Co-authored-by: Marc <m@pyc.ac>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 17:14:10 +01:00
Jon 5044df11b8 1.9 2026-06-08 14:09:55 +01:00
DubbleClick b34da98139 unsloppify comments 2026-06-08 17:44:00 +07:00
henderkes 17c7d5bdfc Replace D3D9 proxy wrappers with vtable hooks 2026-06-08 17:15:02 +07:00
Jon 63110be15a Merge branch 'master' of https://github.com/gwdevhub/gMod 2026-06-03 07:08:19 +01:00
DubbleClick ce23dab0cd comment for GetFiles return 2026-05-01 16:43:38 +07:00
DubbleClick dfb95484ea const and use size_t 2026-05-01 16:37:08 +07:00
DubbleClick 5be00dd712 make umod able to load and unload per dll export call 2026-05-01 16:31:40 +07:00
DubbleClick 23a2c38935 update to vs 2026 2026-05-01 14:35:46 +07:00
DubbleClick edd937f4c7 release 1.8.0.2 2026-04-15 22:29:18 +07:00
DubbleClick e1900cd342 fix edge case in tpf unscrambling logic 2026-04-15 22:22:32 +07:00
Marc 313c7390ca Increment version tweak to 1.8.0.1 2026-01-09 14:00:26 +01:00
Marc ab1a3a19e1 might have 0X instead of 0x (#36) 2026-01-09 13:53:52 +01:00
Marc 4fa1d8e2c5 1.8.0 (#35)
* change tpfconvert functionality to backup into backup folder

* use vcpkg for more packages

* update readme, bump to 1.7.0.2

* rework dll path

* https://github.com/gwdevhub/gMod/issues/33

* v1.7.0.3

* debug mode enabled

* fix... something... somehow??? @STL can you explain this???

* safety

* 1.8.0.0
2026-01-09 00:43:28 +01:00
Marc b060e25ee2 v1.7.0.3 (#34)
* change tpfconvert functionality to backup into backup folder

* use vcpkg for more packages

* update readme, bump to 1.7.0.2

* rework dll path

* https://github.com/gwdevhub/gMod/issues/33

* v1.7.0.3
2025-07-20 22:08:50 +07:00
DubbleClick 326b7086c9 1.7.0.2 (#32)
* change tpfconvert functionality to backup into backup folder

* use vcpkg for more packages

* update readme, bump to 1.7.0.2
2024-11-11 23:35:43 +07:00
DubbleClick 485ecd1341 fix release build (#31) 2024-11-10 23:09:22 +07:00
DubbleClick 175002a9e4 1.7.0.1 (#30)
* read modlist.txt files immediately on launch, textures still loaded on d3d creation
2024-11-10 23:06:49 +07:00
52 changed files with 2139 additions and 3334 deletions
+48
View File
@@ -0,0 +1,48 @@
---
Language: Cpp
Standard: Latest
# Long, hand-wrapped declarations (vtable typedefs, D3D signatures) are kept as
# written rather than reflowed to a column.
ColumnLimit: 0
IndentWidth: 4
TabWidth: 4
UseTab: Never
AccessModifierOffset: -4
NamespaceIndentation: All
IndentCaseLabels: true
PointerAlignment: Left
MaxEmptyLinesToKeep: 2
Cpp11BracedListStyle: true
SpaceBeforeParens: ControlStatements
AllowShortCaseLabelsOnASingleLine: true
AllowShortEnumsOnASingleLine: true
FixNamespaceComments: false
# Include order is load-bearing in the Windows headers; never reorder.
SortIncludes: Never
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortBlocksOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
AfterControlStatement: Never
AfterCaseLabel: false
AfterClass: false
AfterStruct: false
AfterEnum: false
AfterUnion: false
AfterNamespace: false
AfterExternBlock: false
BeforeElse: true
BeforeCatch: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
+38
View File
@@ -0,0 +1,38 @@
# Build output and artifacts
build/
bin/
Debug/
Release/
MinSizeRel/
RelWithDebInfo/
win32/
install/
# CMake generated directories
*.dir/
CMakeFiles/
_deps/
# vcpkg vendored dependencies
vcpkg_installed/
# Visual Studio files
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
*.sln
*.slnx
*.sdf
*.suo
*.user
*.aps
# CMake cache/generated
CMakeCache.txt
cmake_install.cmake
ALL_BUILD*
ZERO_CHECK*
INSTALL*
# Version resource (generated)
version.rc
+2
View File
@@ -0,0 +1,2 @@
# Shell scripts must stay LF or bash on the CI runner chokes on \r.
*.sh text eol=lf
+28
View File
@@ -0,0 +1,28 @@
# Pre-configure SimplySign Desktop for unattended use:
# - auto-show the login dialog on launch (so the TOTP keystrokes have a target)
# - cache the smart-card PIN in the CSP, so signtool signs without a per-call
# PIN prompt, and forget it again when the session disconnects.
# Mirrors the settings used by the blinkdisk / docuscope CI signing setups.
$ErrorActionPreference = "Stop"
$RegistryPath = "HKCU:\Software\Certum\SimplySign"
$settings = [ordered]@{
ShowLoginDialogOnStart = 1
ShowLoginDialogOnAppRequest = 1
RememberLastUserName = 0
Autostart = 0
UnregisterCertificatesOnDisconnect = 0
RememberPINinCSP = 1
ForgetPINinCSPonDisconnect = 1
LangID = 9
}
Write-Host "=== Configuring SimplySign Desktop registry ==="
New-Item -Path $RegistryPath -Force | Out-Null
foreach ($name in $settings.Keys) {
Set-ItemProperty -Path $RegistryPath -Name $name -Value $settings[$name] -Type DWord
Write-Host " $name = $($settings[$name])"
}
Write-Host "Done."
+245
View File
@@ -0,0 +1,245 @@
# Authenticate SimplySign Desktop non-interactively.
#
# Certum's SimplySign cloud has no headless login: the certificate only reaches
# the Windows store after the GUI client authenticates. So we generate the
# current TOTP from the otpauth:// secret (CERTUM_OTP_URI) and paste the
# credentials into the login dialog. This needs an interactive desktop session,
# which GitHub-hosted Windows runners provide.
#
# Based on https://www.devas.life/how-to-automate-signing-your-windows-app-with-certum/
# and the refinements in blinkdisk's connect-simplysign.ps1.
param(
[string]$OtpUri = $env:CERTUM_OTP_URI,
[string]$UserId = $env:CERTUM_USERID,
[string]$ExePath = $env:CERTUM_EXE_PATH
)
if (-not $OtpUri) { Write-Host "ERROR: CERTUM_OTP_URI not provided"; exit 1 }
if (-not $UserId) { Write-Host "ERROR: CERTUM_USERID not provided"; exit 1 }
if (-not $ExePath) {
$ExePath = "C:\Program Files\Certum\SimplySign Desktop\SimplySignDesktop.exe"
}
Write-Host "=== SimplySign Desktop TOTP authentication ==="
if (-not (Test-Path $ExePath)) {
Write-Host "ERROR: SimplySign Desktop not found at $ExePath"
exit 1
}
# --- Parse the otpauth:// URI (works on PowerShell 5.1 and 7+) ---------------
$uri = [Uri]$OtpUri
try {
$q = [System.Web.HttpUtility]::ParseQueryString($uri.Query)
} catch {
$q = @{}
foreach ($part in $uri.Query.TrimStart('?') -split '&') {
$kv = $part -split '=', 2
if ($kv.Count -eq 2) { $q[$kv[0]] = [Uri]::UnescapeDataString($kv[1]) }
}
}
$Base32 = $q['secret']
$Digits = if ($q['digits']) { [int]$q['digits'] } else { 6 }
$Period = if ($q['period']) { [int]$q['period'] } else { 30 }
$Algorithm = if ($q['algorithm']) { $q['algorithm'].ToUpper() } else { 'SHA256' }
if (-not $Base32) { Write-Host "ERROR: otpauth URI has no 'secret'"; exit 1 }
if ($Algorithm -notin @('SHA1', 'SHA256', 'SHA512')) {
Write-Host "ERROR: unsupported TOTP algorithm: $Algorithm"
exit 1
}
# --- TOTP generator (RFC 6238), inline C# so there are no dependencies --------
Add-Type -Language CSharp @"
using System;
using System.Security.Cryptography;
public static class Totp
{
private const string B32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
private static byte[] Base32Decode(string s)
{
s = s.TrimEnd('=').ToUpperInvariant();
byte[] bytes = new byte[s.Length * 5 / 8];
int bitBuffer = 0, bitsLeft = 0, idx = 0;
foreach (char c in s)
{
int val = B32.IndexOf(c);
if (val < 0) throw new ArgumentException("Invalid Base32 char: " + c);
bitBuffer = (bitBuffer << 5) | val;
bitsLeft += 5;
if (bitsLeft >= 8) { bytes[idx++] = (byte)(bitBuffer >> (bitsLeft - 8)); bitsLeft -= 8; }
}
return bytes;
}
private static HMAC Hmac(string algorithm, byte[] key)
{
switch (algorithm.ToUpper())
{
case "SHA1": return new HMACSHA1(key);
case "SHA256": return new HMACSHA256(key);
case "SHA512": return new HMACSHA512(key);
default: throw new ArgumentException("Unsupported algorithm: " + algorithm);
}
}
public static string Now(string secret, int digits, int period, string algorithm)
{
byte[] key = Base32Decode(secret);
long counter = DateTimeOffset.UtcNow.ToUnixTimeSeconds() / period;
byte[] cnt = BitConverter.GetBytes(counter);
if (BitConverter.IsLittleEndian) Array.Reverse(cnt);
byte[] hash;
using (var h = Hmac(algorithm, key)) { hash = h.ComputeHash(cnt); }
int offset = hash[hash.Length - 1] & 0x0F;
int binary =
((hash[offset] & 0x7F) << 24) |
((hash[offset + 1] & 0xFF) << 16) |
((hash[offset + 2] & 0xFF) << 8) |
(hash[offset + 3] & 0xFF);
int otp = binary % (int)Math.Pow(10, digits);
return otp.ToString(new string('0', digits));
}
}
"@
function Find-UiByName($el, $walker, $name) {
$c = $walker.GetFirstChild($el)
while ($c) {
if ($c.Current.Name -eq $name) { return $c }
$r = Find-UiByName $c $walker $name
if ($r) { return $r }
$c = $walker.GetNextSibling($c)
}
return $null
}
# An outdated SimplySign build pops a modal "New version found - download?" box
# over the login form, which swallows the credential keystrokes. Decline it by
# clicking "No" (Invoke / legacy default action / click the element's point).
function Dismiss-UpdatePrompt {
try { Add-Type -AssemblyName UIAutomationClient, UIAutomationTypes -ErrorAction Stop } catch { return $false }
if (-not ('Win32Mouse' -as [type])) {
Add-Type @"
using System;
using System.Runtime.InteropServices;
public static class Win32Mouse {
[DllImport("user32.dll")] static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")] static extern void mouse_event(uint f, uint x, uint y, uint d, int e);
public static void Click(int x, int y){ SetCursorPos(x,y); mouse_event(0x02,0,0,0,0); mouse_event(0x04,0,0,0,0); }
}
"@
}
$procIds = @((Get-Process -Name '*SimplySign*' -ErrorAction SilentlyContinue).Id)
$walker = [System.Windows.Automation.TreeWalker]::ControlViewWalker
$top = $walker.GetFirstChild([System.Windows.Automation.AutomationElement]::RootElement)
while ($top) {
if ($procIds -contains $top.Current.ProcessId) {
$no = Find-UiByName $top $walker "No"
if ($no) {
Write-Host "Update prompt detected; declining (clicking 'No')."
try { ($no.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern)).Invoke(); return $true } catch {}
try { ($no.GetCurrentPattern([System.Windows.Automation.LegacyIAccessiblePattern]::Pattern)).DoDefaultAction(); return $true } catch {}
try { $pt = $no.GetClickablePoint(); [Win32Mouse]::Click([int]$pt.X, [int]$pt.Y); return $true } catch { Write-Host "Click 'No' failed: $($_.Exception.Message)" }
}
}
$top = $walker.GetNextSibling($top)
}
return $false
}
# Start from a clean slate so a stale window/session can't swallow the keystrokes.
if ($existing = Get-Process -Name "SimplySignDesktop" -ErrorAction Ignore) {
Write-Host "Killing existing SimplySignDesktop process..."
$existing | Stop-Process -Force
Start-Sleep -Seconds 1
}
Write-Host "Launching SimplySign Desktop..."
$proc = Start-Process -FilePath $ExePath -PassThru
Start-Sleep -Seconds 3
$wshell = New-Object -ComObject WScript.Shell
Write-Host "Focusing the login window..."
$focused = $wshell.AppActivate($proc.Id)
if (-not $focused) { $focused = $wshell.AppActivate('SimplySign Desktop') }
for ($i = 0; (-not $focused) -and ($i -lt 10); $i++) {
Start-Sleep -Milliseconds 500
$focused = $wshell.AppActivate($proc.Id) -or $wshell.AppActivate('SimplySign Desktop')
}
if (-not $focused) {
Write-Host "ERROR: could not bring SimplySign Desktop to the foreground"
exit 1
}
# Decline the "new version available" modal if it's covering the login form.
if (Dismiss-UpdatePrompt) { Start-Sleep -Milliseconds 800 }
# Re-assert focus: dismissing the dialog can move the foreground window, and
# keystrokes sent to the wrong window are silently dropped.
$wshell.AppActivate($proc.Id) | Out-Null
$wshell.AppActivate('SimplySign Desktop') | Out-Null
Start-Sleep -Milliseconds 400
# Paste rather than type: SendKeys mangles characters like + ^ % ( ) and can
# drop characters; pasting delivers the exact string. Falls back to typing if
# the clipboard is unavailable.
function Set-Field([string]$text) {
try {
Set-Clipboard -Value $text -ErrorAction Stop
Start-Sleep -Milliseconds 150
$wshell.SendKeys("^v")
} catch {
Write-Host "Clipboard unavailable ($($_.Exception.Message)); typing instead."
$wshell.SendKeys($text)
}
Start-Sleep -Milliseconds 250
}
Write-Host "Injecting credentials..."
Set-Field $UserId
$wshell.SendKeys("{TAB}")
Start-Sleep -Milliseconds 200
# Generate the code right before sending it so it can't expire while we focus.
$otp = [Totp]::Now($Base32, $Digits, $Period, $Algorithm)
Set-Field $otp
Start-Sleep -Milliseconds 200
$wshell.SendKeys("{ENTER}")
# Don't leave the OTP / username sitting on the clipboard afterwards.
try { Set-Clipboard -Value " " -ErrorAction Stop } catch {}
Write-Host "Waiting for authentication to settle..."
Start-Sleep -Seconds 5
if (-not (Get-Process -Id $proc.Id -ErrorAction SilentlyContinue)) {
Write-Host "ERROR: SimplySign Desktop exited - authentication failed."
exit 1
}
# Confirm the login actually mounted the signing certificate into the store.
$thumb = if ($env:CERTUM_CERT_SHA1) { ($env:CERTUM_CERT_SHA1 -replace '\s', '').ToUpperInvariant() } else { $null }
Write-Host "Verifying the signing certificate reached the store..."
$deadline = (Get-Date).AddSeconds(60)
$found = $false
do {
$certs = Get-ChildItem Cert:\CurrentUser\My, Cert:\LocalMachine\My -ErrorAction SilentlyContinue
if ($thumb) { $found = [bool]($certs | Where-Object { $_.Thumbprint -eq $thumb }) }
else { $found = [bool]($certs | Where-Object { $_.Subject -like '*Certum*' -or $_.Issuer -like '*Certum*' }) }
if ($found) { break }
Start-Sleep -Seconds 3
} while ((Get-Date) -lt $deadline)
if ($found) {
Write-Host "=== Authentication complete: signing certificate is available. ==="
} else {
Write-Host "ERROR: signing certificate did not appear after authentication."
exit 1
}
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
# Install Certum SimplySign Desktop on the (ephemeral) Windows runner.
# SimplySign Desktop is what mounts the cloud signing certificate as a virtual
# smart card into the Windows certificate store; signtool then selects it by
# thumbprint. The version + checksum are pinned for reproducibility.
set -euo pipefail
VERSION="9.3.4.72"
URL="https://files.certum.eu/software/SimplySignDesktop/Windows/${VERSION}/SimplySignDesktop-${VERSION}-64-bit-en.msi"
EXPECTED_SHA256="bd51ebbaaac20fc7d59ab7103b5ed532b7800586df4e31f6999d03a394f9c515"
INSTALLER="SimplySignDesktop.msi"
INSTALL_DIR="/c/Program Files/Certum/SimplySign Desktop"
echo "=== Installing Certum SimplySign Desktop ${VERSION} ==="
# Idempotent: a cached/pre-provisioned image may already have it.
if [ -d "$INSTALL_DIR" ]; then
echo "Already installed at: $INSTALL_DIR"
exit 0
fi
echo "Downloading installer..."
curl -L "$URL" -o "$INSTALLER" --fail --max-time 600
ACTUAL_SHA256=$(sha256sum "$INSTALLER" | awk '{print $1}')
if [ "$EXPECTED_SHA256" != "$ACTUAL_SHA256" ]; then
echo "ERROR: checksum mismatch"
echo " expected: $EXPECTED_SHA256"
echo " actual: $ACTUAL_SHA256"
exit 1
fi
echo "Checksum verified."
echo "Running msiexec (silent)..."
# Start-Process inherits this CWD, so the relative installer path resolves here.
powershell -Command "Start-Process msiexec.exe -ArgumentList '/i','${INSTALLER}','/quiet','/norestart','/l*v','install.log','ALLUSERS=1','REBOOT=ReallySuppress' -Wait -NoNewWindow"
if [ ! -d "$INSTALL_DIR" ]; then
echo "ERROR: installation directory not found after install"
echo "Last 20 lines of install.log:"
tail -20 install.log 2>/dev/null || echo "(no install.log)"
exit 1
fi
echo "SimplySign Desktop installed."
+66
View File
@@ -0,0 +1,66 @@
# Sign the given files with the Certum cloud certificate (selected by SHA1
# thumbprint from the store) and verify each signature. Assumes SimplySign
# Desktop has already authenticated (connect-simplysign.ps1).
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string[]]$Files,
[string]$CertSha1 = $env:CERTUM_CERT_SHA1,
[string]$TimestampUrl = "http://time.certum.pl"
)
$ErrorActionPreference = "Stop"
if (-not $CertSha1) { throw "CERTUM_CERT_SHA1 not provided." }
$thumb = ($CertSha1 -replace '\s', '').ToUpperInvariant()
# Resolve the newest signtool.exe from the installed Windows SDK(s).
$kitsBin = "C:\Program Files (x86)\Windows Kits\10\bin"
$signtool = Get-ChildItem -Path $kitsBin -Recurse -Filter signtool.exe -File -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -like '*\x64\*' } |
Sort-Object { [version]$_.Directory.Parent.Name } |
Select-Object -Last 1 -ExpandProperty FullName
if (-not $signtool) { throw "signtool.exe not found under $kitsBin" }
Write-Host "Using signtool: $signtool"
# The SimplySign virtual smart card registers in the store a moment after the
# desktop client authenticates; poll for our certificate before signing.
Write-Host "Waiting for certificate $thumb to appear in the store..."
$deadline = (Get-Date).AddSeconds(120)
$cert = $null
$elapsed = 0
do {
$cert = Get-ChildItem Cert:\CurrentUser\My, Cert:\LocalMachine\My -ErrorAction SilentlyContinue |
Where-Object { $_.Thumbprint -eq $thumb } | Select-Object -First 1
if ($cert) { break }
Start-Sleep -Seconds 3
$elapsed += 3
Write-Host " ...still waiting (${elapsed}s)"
} while ((Get-Date) -lt $deadline)
if (-not $cert) {
Write-Host "Certificate not found. CurrentUser\My + LocalMachine\My contents:"
Get-ChildItem Cert:\CurrentUser\My, Cert:\LocalMachine\My -ErrorAction SilentlyContinue |
Select-Object Thumbprint, Subject, HasPrivateKey | Format-Table -AutoSize | Out-String | Write-Host
Write-Host "SimplySign processes:"
Get-Process -Name '*SimplySign*' -ErrorAction SilentlyContinue |
Select-Object Name, Id, Responding, MainWindowTitle | Format-Table -AutoSize | Out-String | Write-Host
throw "Certificate $thumb not found in the store - SimplySign authentication likely failed (see dump above)."
}
Write-Host "Found signing certificate: $($cert.Subject)"
$failed = @()
foreach ($file in $Files) {
if (-not (Test-Path $file)) { throw "File to sign not found: $file" }
Write-Host "=== Signing $file ==="
& $signtool sign /sha1 $thumb /fd sha256 /td sha256 /tr $TimestampUrl /v $file
if ($LASTEXITCODE -ne 0) { $failed += $file; continue }
& $signtool verify /pa /v $file
if ($LASTEXITCODE -ne 0) { $failed += $file }
}
if ($failed.Count -gt 0) {
throw "Signing/verification failed for: $($failed -join ', ')"
}
Write-Host "All binaries signed and verified."
+29 -2
View File
@@ -14,11 +14,17 @@ jobs:
matrix:
targetplatform: [x86]
runs-on: windows-latest
runs-on: windows-2025-vs2026
permissions:
contents: write
env:
Configuration: Release
Actions_Allow_Unsecure_Commands: true
CERTUM_OTP_URI: ${{ secrets.CERTUM_OTP_URI }}
CERTUM_USERID: ${{ secrets.CERTUM_USERID }}
CERTUM_CERT_SHA1: ${{ secrets.CERTUM_CERT_SHA1 }}
steps:
- name: Checkout
@@ -46,7 +52,28 @@ jobs:
- name: Build binaries
run: cmake --build build --config Release
# Signing only runs when the Certum secrets are present (i.e. on the real
# repo, not forks); without them the build still produces unsigned binaries.
- name: Set up Certum SimplySign
if: env.CERTUM_OTP_URI != ''
shell: bash
run: |
chmod +x ./.github/scripts/install-simplysign.sh
./.github/scripts/install-simplysign.sh
powershell -ExecutionPolicy Bypass -File "./.github/scripts/configure-simplysign.ps1"
- name: Authenticate Certum SimplySign
if: env.CERTUM_OTP_URI != ''
shell: bash
run: powershell -ExecutionPolicy Bypass -File "./.github/scripts/connect-simplysign.ps1"
- name: Sign release binaries
if: env.CERTUM_OTP_URI != ''
shell: pwsh
run: |
./.github/scripts/sign-certum.ps1 -Files @(".\bin\Release\gMod.dll", ".\bin\Release\TpfConvert.exe")
- name: Retrieve version
id: set_version
run: |
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
matrix:
targetplatform: [x86]
runs-on: windows-latest
runs-on: windows-2025-vs2026
env:
Configuration: Release
+40
View File
@@ -0,0 +1,40 @@
name: gMod Lint
on:
pull_request:
branches:
- master
push:
branches:
- dev
workflow_dispatch:
permissions:
contents: write
jobs:
clang-format:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
# Pinned to the version the tree was formatted with so CI and local agree.
- name: Install clang-format
run: pipx install clang-format==22.1.5
- name: Apply clang-format
run: clang-format -i header/*.h source/*.cpp modules/*.ixx TpfConvert/src/*.ixx
# Push / same-repo PRs: commit the fixes back. Fork PRs can't be pushed to,
# so fail the check instead and let the contributor format.
- name: Commit fixes
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "ci: apply clang-format"
- name: Verify formatting (fork PRs)
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
run: git diff --exit-code
+96
View File
@@ -0,0 +1,96 @@
# gMod
A 32-bit Windows DLL that hooks Direct3D 9 to load texture mods for Guild Wars. Continuation of uMod. Integrated with [GW Launcher](https://github.com/gwdevhub/gwlauncher) and [Daybreak](https://github.com/gwdevhub/Daybreak).
## Project structure
- `header/` — header files (D3D9Hooks, D3D9State, Defines, Error, Main, Utils)
- `source/` — implementation files (D3D9Hooks.cpp, dll_main.cpp, Error.cpp)
- `modules/` — C++23 module files (ModfileLoader, ModfileLoader_TpfReader, TextureClient, TextureFunction)
- `TpfConvert/` — standalone utility to fix broken .tpf files
- `cmake/` — CMake helper scripts
- `build/` — CMake build tree (generated, ignored)
- `bin/` — compiled output (generated, ignored)
## Build
Requires Visual Studio 2022, CMake 3.29+, and vcpkg — all via the VS 2022 Developer PowerShell.
```
cmake --preset=vcpkg
cmake --open build
# then compile inside Visual Studio, or:
cmake --build build --config Release
```
- Target: 32-bit only (`-A Win32` / `CMAKE_GENERATOR_PLATFORM=win32`)
- Standard: C++23
- Output: `bin/` (gMod.dll, TpfConvert.exe)
- Version: set in `CMakeLists.txt` (`VERSION_MAJOR/MINOR/PATCH/TWEAK`)
> **Cannot be built or run in this agent environment** (Linux, no MSVC, no 32-bit
> D3D9, no Guild Wars to inject into). Don't burn turns attempting `cmake`/builds
> here — validate changes by reading and matching existing patterns, and lean on
> Windows CI (`ci.yaml`) for the real build. When an actual compile/test is needed,
> ask the user to do it in Visual Studio rather than trying locally.
## Key dependencies (via vcpkg)
- `minhook` — D3D9 function hooking
- `libzippp` / `libzip` / `zlib` — reading .tpf/.zip mod files
- `directxtex` — texture format conversion
- `Microsoft.GSL` — Guidelines Support Library
## How it works
1. `dll_main.cpp` — DLL entry point, hooks d3d9.dll via MinHook
2. `D3D9Hooks.cpp` — intercepts `Direct3DCreate9` and IDirect3DDevice9 methods
3. `ModfileLoader` — reads `modlist.txt`, loads .tpf/.zip mod archives
4. `TextureClient` / `TextureFunction` — matches and replaces textures by hash at runtime
### Hooking model (read before touching D3D9 code)
gMod uses **MinHook vtable hooks**, not proxy/subclass wrappers (the old uMod model
was replaced — see `git log` "Replace D3D9 proxy wrappers with vtable hooks"). The
game keeps the **real** `IDirect3D9` / `IDirect3DDevice9` / texture objects byte-for-byte
untouched; gMod patches only the individual vtable slots it cares about (CreateDevice,
CreateTexture/Volume/Cube, UpdateTexture, BeginScene, Set/GetTexture, Release).
- Per-texture side-state lives **out of band** in `header/D3D9State.h` (`TexState`,
keyed by the real texture pointer), so reverting the hooks fully detaches gMod.
- `RemoveAllD3D9Hooks()` must leave the host process pristine — preserve that invariant.
- A vtable is shared by all instances of a class, so each slot is hooked once; texture
Release slots are hooked lazily on first instance. Don't double-hook.
## Conventions
- **Formatting is CI-enforced** by clang-format `22.1.5` (`.clang-format`, applied by
`lint.yaml` on push to `dev`). Don't hand-reformat or "tidy" whole files — it just
churns the diff. Notable rules: `ColumnLimit: 0` (never reflow long D3D signatures /
vtable typedefs), `SortIncludes: Never` (include order is load-bearing in Windows
headers — never reorder), 4-space indent, braces on their own line after functions.
- **C++23 named modules** (`modules/*.ixx`). Editing a module *interface* triggers wide
rebuilds; prefer changing implementation over interface when possible.
- **Public exported API is a fixed surface** — four `extern "C" __declspec(dllexport)`
functions in `dll_main.cpp`: `SetDevice`, `AddFile`, `RemoveFile`, `GetFiles`. These
are consumed by GW Launcher and Daybreak; do **not** change their names, signatures,
or calling convention (`__cdecl`) without coordinating downstream.
- **Commits**: short imperative summaries, lowercase, no trailing period
(e.g. "Keep loaded_files in load order so GetFiles returns priority order").
- **Branching**: `dev` is the integration branch; PRs target `master`. CI builds on
push to `dev` and on PRs to `master`.
### Where things live (by size / how often they change)
- `modules/TextureClient.ixx` (~670 lines) — texture match/replace bookkeeping, hot
- `source/D3D9Hooks.cpp` (~580) — the vtable detours and install/remove
- `modules/TextureFunction.ixx` (~380) — texture creation/conversion helpers
- `source/dll_main.cpp` (~345) — entry point + exported C API
- `modules/ModfileLoader*.ixx` — .tpf/.zip parsing
- `header/Defines.h` — shared structs/constants (`TextureFileStruct`, `HashTuple`, etc.)
## Notes
- Must be injected before d3d9.dll loads, or renamed to d3d9.dll in the GW folder
- Reshade > 5.0.1 causes glitches; recommend 5.0.1 or 4.9.1
- `modlist.txt` contains full paths to .tpf/.zip mod files, one per line
+8 -14
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.29)
set(CMAKE_GENERATOR_PLATFORM win32)
@@ -9,14 +9,8 @@ if(NOT(CMAKE_SIZEOF_VOID_P EQUAL 4))
message(FATAL_ERROR "You are configuring a non 32-bit build, this is not supported. Run cmake with `-A Win32`")
endif()
option(CLEAN "Cleans third party libraries and recompiles them" OFF)
if(${CLEAN} MATCHES "ON")
message("Removing directory: ${PROJECT_SOURCE_DIR}/bin/install")
file(REMOVE_RECURSE ${PROJECT_SOURCE_DIR}/bin/install)
endif()
set(VERSION_MAJOR 1)
set(VERSION_MINOR 7)
set(VERSION_MINOR 10)
set(VERSION_PATCH 0)
set(VERSION_TWEAK 0)
@@ -27,15 +21,14 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin")
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/bin/install)
add_compile_options(/MP /permissive-)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(libzippp)
include(minhook)
find_package(libzippp CONFIG REQUIRED)
find_package(minhook CONFIG REQUIRED)
find_package(Microsoft.GSL CONFIG REQUIRED)
include(dxtk)
include(msgsl)
add_library(gMod SHARED)
@@ -52,12 +45,13 @@ target_include_directories(gMod PRIVATE
)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES})
target_sources(gMod PRIVATE ${SOURCES})
target_compile_options(gMod PRIVATE /W4 /WX)
target_link_libraries(gMod PRIVATE
dxguid
libzippp
libzippp::libzippp
psapi
minhook
minhook::minhook
directxtex
Microsoft.GSL::GSL
)
+3 -1
View File
@@ -3,10 +3,12 @@
"configurePresets": [
{
"name": "vcpkg",
"generator": "Visual Studio 17 2022",
"generator": "Visual Studio 18 2026",
"architecture": "Win32",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"VCPKG_OVERLAY_TRIPLETS": "${sourceDir}/triplets",
"VCPKG_TARGET_TRIPLET": "x86-windows-mixed",
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
+4 -5
View File
@@ -28,7 +28,7 @@ If you would like to use Reshade in combination with gMod, we recommend running
Requirements:
- Visual Studio 2022
- CMake 3.16+, integrated into the Developer Powershell for VS 2022
- CMake 3.29+, integrated into the Developer Powershell for VS 2022
- vcpkg, integrated into the Developer Powershell for VS 2022
Compile:
@@ -39,7 +39,6 @@ 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
- Put TpfConvert.exe and d3dx9.dll in the folder where you have your old, broken texmods with invalid images.
- Run TpfConvert.exe, all *.tpf and *.zip files are processed. The originals are saved into a newly created backup folder.
- Done.
+1 -1
View File
@@ -33,7 +33,7 @@ endif()
find_package(dxsdk-d3dx CONFIG REQUIRED)
target_link_libraries(TpfConvert PRIVATE
libzippp
libzippp::libzippp
Microsoft::D3DX9
d3d9
)
+8 -8
View File
@@ -13,8 +13,9 @@ export struct TexEntry {
};
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);
HashType GetCrcFromFilename(const std::string& filename)
{
const static std::regex re(R"(0[xX][0-9a-fA-F]{4,16})", std::regex::optimize);
std::smatch match;
if (!std::regex_search(filename, match, re)) {
return 0;
@@ -45,8 +46,7 @@ export class ModfileLoader {
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
};
0x46, 0x6F};
public:
ModfileLoader(const std::filesystem::path& fileName);
@@ -54,7 +54,6 @@ public:
std::vector<TexEntry> GetContents() const;
private:
std::vector<TexEntry> GetTpfContents() const;
std::vector<TexEntry> GetFileContents() const;
@@ -85,7 +84,7 @@ std::vector<TexEntry> ModfileLoader::GetTpfContents() const
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());
std::print(stderr, "Failed to open tpf file: {} - {} uint8_ts!\n", file_name.string(), buffer.size());
return {};
}
zip_archive->setErrorHandlerCallback(
@@ -117,13 +116,14 @@ void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TexEntr
for (const auto& entry : archive.getEntries()) {
if (!entry.isFile())
continue;
const auto crc_hash = GetCrcFromFilename(entry.getName());
const auto entry_name = entry.getName();
const auto crc_hash = GetCrcFromFilename(entry_name);
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());
std::filesystem::path tex_name(entry_name);
entries.emplace_back(std::move(vec), crc_hash, tex_name.extension().string());
delete[] data_ptr;
}
+2 -2
View File
@@ -35,7 +35,7 @@ public:
// 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);
// data.resize(last_zero);
return data;
}
@@ -46,7 +46,7 @@ private:
[[nodiscard]] char XOR(const char b, const long position) const
{
if (position > line_length - 4) {
if (position >= (line_length / 4) * 4) {
return b ^ TPF_XOREven;
}
+16 -8
View File
@@ -27,7 +27,7 @@ namespace {
d3dpp.hDeviceWindow = GetDesktopWindow();
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow(),
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice))) {
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice))) {
std::print(stderr, "Failed to create Direct3D9 device\n");
pD3D->Release();
return false;
@@ -85,7 +85,8 @@ namespace {
int main(int argc, char* argv[])
{
const std::filesystem::path path = argc > 1 ? argv[1] : GetExecutablePath() / "plugins";
const std::filesystem::path path = argc > 1 ? argv[1] : GetExecutablePath();
const auto backup_path = path / "backup";
if (!InitializeDirect3D()) {
return -1;
@@ -95,28 +96,35 @@ int main(int argc, char* argv[])
return 1;
}
if (!std::filesystem::exists(backup_path)) {
std::filesystem::create_directory(backup_path);
}
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("_")) {
const auto backup_file = backup_path / mod_path.filename();
if (std::filesystem::exists(backup_file)) {
std::print("Skipping previous TpfConvert output: {}\n", mod_path.filename().string());
continue;
}
else {
std::print("Processing: {}\n", mod_path.filename().string());
std::error_code ec;
std::filesystem::rename(mod_path, backup_file, ec);
}
const auto zip_filename = mod_path.parent_path() / (mod_path.stem().string() + "_.zip");
const auto zip_filename = path / (mod_path.stem().string() + ".zip");
if (std::filesystem::exists(zip_filename)) {
std::print("{} was already processed\n", mod_path.filename().string());
continue;
std::filesystem::remove(zip_filename);
}
libzippp::ZipArchive zip_archive(zip_filename.string());
ModfileLoader loader(mod_path);
ModfileLoader loader(backup_file);
std::vector<std::pair<std::string, std::vector<uint8_t>>> data_entries;
const auto entries = loader.GetContents();
libzippp::ZipArchive zip_archive(zip_filename.string());
zip_archive.open(libzippp::ZipArchive::Write);
for (const auto& entry : entries) {
-65
View File
@@ -1,65 +0,0 @@
include_guard()
include(FetchContent)
include(zlib)
FetchContent_Declare(
libzip
GIT_REPOSITORY https://github.com/nih-at/libzip
GIT_TAG v1.10.1)
FetchContent_GetProperties(libzip)
if (libzip_POPULATED)
message(STATUS "Skipping libzip download")
return()
endif()
FetchContent_Populate(libzip)
if(EXISTS ${CMAKE_INSTALL_PREFIX}/lib/zip.lib)
message(STATUS "Skipping libzip build")
return()
endif()
set(OPTIONS
"-A" "Win32"
"-DZLIB_LIBRARY:PATH=${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib"
"-DZLIB_INCLUDE_DIR:PATH=${CMAKE_INSTALL_PREFIX}/include"
"-DENABLE_COMMONCRYPTO=OFF"
"-DENABLE_GNUTLS=OFF"
"-DENABLE_MBEDTLS=OFF"
"-DENABLE_OPENSSL=OFF"
"-DENABLE_WINDOWS_CRYPTO=ON"
"-DENABLE_FDOPEN=OFF"
"-DENABLE_BZIP2=OFF"
"-DENABLE_LZMA=OFF"
"-DENABLE_ZSTD=OFF"
"-DBUILD_TOOLS=OFF"
"-DBUILD_REGRESS=OFF"
"-DBUILD_EXAMPLES=OFF"
"-DBUILD_DOC=OFF"
"-DLIBZIP_DO_INSTALL=ON"
"-DBUILD_SHARED_LIBS=OFF"
"-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}"
"-DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}"
)
message("Building libzip with OPTIONS:\n${OPTIONS}")
# Patch CMakeLists.txt to require version 3.15 - otherwise cmake ignores MSVC_RUNTIME_LIBRARY
file(READ ${libzip_SOURCE_DIR}/CMakeLists.txt FILE_CONTENT)
string(REPLACE "VERSION 3.5.0" "VERSION 3.15.0" UPDATED_CONTENT "${FILE_CONTENT}")
file(WRITE ${libzip_SOURCE_DIR}/CMakeLists.txt "${UPDATED_CONTENT}")
execute_process(
COMMAND ${CMAKE_COMMAND} ${OPTIONS} .
WORKING_DIRECTORY ${libzip_SOURCE_DIR}
)
execute_process(
COMMAND ${CMAKE_COMMAND} --build . --config Release
WORKING_DIRECTORY ${libzip_SOURCE_DIR}
)
execute_process(
COMMAND ${CMAKE_COMMAND} --install . --config Release
WORKING_DIRECTORY ${libzip_SOURCE_DIR}
)
message(STATUS "Finished libzip build")
-42
View File
@@ -1,42 +0,0 @@
include_guard()
include(FetchContent)
include(libzip)
find_library(ZLIB_LIBRARY REQUIRED
NAMES zlibstatic
PATHS ${CMAKE_INSTALL_PREFIX}/lib
)
find_library(LIBZIP_LIBRARY REQUIRED
NAMES zip
PATHS ${CMAKE_INSTALL_PREFIX}/lib
)
FetchContent_Declare(
libzippp
GIT_REPOSITORY https://github.com/ctabin/libzippp
GIT_TAG libzippp-v7.0-1.10.1)
FetchContent_GetProperties(libzippp)
if (NOT libzippp_POPULATED)
FetchContent_Populate(libzippp)
endif()
add_library(libzippp STATIC)
set(SOURCES
"${libzippp_SOURCE_DIR}/src/libzippp.h"
"${libzippp_SOURCE_DIR}/src/libzippp.cpp"
)
source_group(TREE ${libzippp_SOURCE_DIR} FILES ${SOURCES})
target_sources(libzippp PRIVATE ${SOURCES})
target_include_directories(libzippp PUBLIC "${libzippp_SOURCE_DIR}/src")
target_include_directories(libzippp PRIVATE "${CMAKE_INSTALL_PREFIX}/include")
target_compile_definitions(libzippp PUBLIC
LIBZIPPP_WITH_ENCRYPTION
)
target_link_libraries(libzippp PRIVATE
${LIBZIP_LIBRARY}
${ZLIB_LIBRARY}
)
set_target_properties(libzippp PROPERTIES FOLDER "Dependencies/")
-16
View File
@@ -1,16 +0,0 @@
include_guard()
include(FetchContent)
FetchContent_Declare(
minhook
GIT_REPOSITORY https://github.com/TsudaKageyu/minhook
GIT_TAG master)
FetchContent_GetProperties(minhook)
if (NOT minhook_POPULATED)
FetchContent_Populate(minhook)
endif()
add_subdirectory(${minhook_SOURCE_DIR} EXCLUDE_FROM_ALL)
set_target_properties(minhook PROPERTIES FOLDER "Dependencies/")
-11
View File
@@ -1,11 +0,0 @@
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)
-47
View File
@@ -1,47 +0,0 @@
include_guard()
include(FetchContent)
# Fetch zlib using FetchContent
FetchContent_Declare(
zlib
GIT_REPOSITORY https://github.com/madler/zlib
GIT_TAG v1.3
)
FetchContent_GetProperties(zlib)
if(zlib_POPULATED)
message(STATUS "Skipping zlib download")
return()
endif()
FetchContent_Populate(zlib)
if(EXISTS ${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib)
message(STATUS "Skipping zlib build")
return()
endif()
set(OPTIONS
"-A" "Win32"
"-DBUILD_SHARED_LIBS=OFF"
"-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}"
"-DCMAKE_MSVC_RUNTIME_LIBRARY=${CMAKE_MSVC_RUNTIME_LIBRARY}"
)
message("Building zlib with OPTIONS:\n${OPTIONS}")
execute_process(
COMMAND ${CMAKE_COMMAND} ${OPTIONS} .
WORKING_DIRECTORY ${zlib_SOURCE_DIR}
)
execute_process(
COMMAND ${CMAKE_COMMAND} --build . --config Release
WORKING_DIRECTORY ${zlib_SOURCE_DIR}
)
execute_process(
COMMAND ${CMAKE_COMMAND} --install . --config Release
WORKING_DIRECTORY ${zlib_SOURCE_DIR}
)
message(STATUS "Finished zlib build")
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <d3d9.h>
void InstallD3D9Hooks(IDirect3D9* d3d9, bool is_ex);
void RemoveAllD3D9Hooks();
// Delete every per-device TextureClient, releasing its replacement textures. Only safe
// on a real FreeLibrary (device still alive), not during process termination.
void DestroyAllTextureClients();
bool RegisterExistingDevice(IDirect3DDevice9* device);
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <d3d9.h>
#include "Defines.h"
// Per-texture side-state, keyed by the real texture pointer (see D3D9Hooks.h).
// Held out-of-band so reverting the vtable hooks fully detaches gMod.
enum class TexType {
Tex2D,
Volume,
Cube,
};
// State for one texture: an "original" the game created, or a "fake" we loaded
// from a mod to stand in for one.
struct TexState {
IDirect3DBaseTexture9* real = nullptr;
// An original points at the fake bound in its place (or nullptr); a fake
// points back at the original it replaces.
TexState* partner = nullptr;
IDirect3DDevice9* device = nullptr;
TextureFileStruct* reference = nullptr; // the modfile backing a fake
HashTuple hash = {};
TexType type = TexType::Tex2D;
bool isFake = false;
};
// Content hash (CRC32 + optional CRC64) of an original texture. Defined in
// D3D9Hooks.cpp.
HashTuple GetTextureHash(const TexState* state);
+17 -17
View File
@@ -1,6 +1,6 @@
#pragma once
//using HashType = DWORD32;
// using HashType = DWORD32;
using HashType = DWORD64;
struct HashTuple {
@@ -34,23 +34,11 @@ struct TextureFileStruct {
HashType crc_hash = 0; // hash value
};
inline void Message(const char* format, ...)
inline void Message([[maybe_unused]] const char* format, ...)
{
#ifdef _DEBUG
#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
// 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);
@@ -58,7 +46,19 @@ inline void Info(const char* format, ...)
#endif
}
inline void Warning(const char* format, ...)
inline void Info([[maybe_unused]] 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([[maybe_unused]] const char* format, ...)
{
#ifdef _DEBUG
const HANDLE hConsole = GetStdHandle(STD_ERROR_HANDLE);
+8 -9
View File
@@ -33,14 +33,14 @@
// define error states
#define uMod_ERROR_FATAL 1u
#define uMod_ERROR_MUTEX 1u<<1
#define uMod_ERROR_PIPE 1u<<2
#define uMod_ERROR_MEMORY 1u<<3
#define uMod_ERROR_TEXTURE 1u<<4
#define uMod_ERROR_MULTIPLE_IDirect3D9 1u<<5
#define uMod_ERROR_MULTIPLE_IDirect3DDevice9 1u<<6
#define uMod_ERROR_UPDATE 1u<<7
#define uMod_ERROR_SERVER 1u<<8
#define uMod_ERROR_MUTEX 1u << 1
#define uMod_ERROR_PIPE 1u << 2
#define uMod_ERROR_MEMORY 1u << 3
#define uMod_ERROR_TEXTURE 1u << 4
#define uMod_ERROR_MULTIPLE_IDirect3D9 1u << 5
#define uMod_ERROR_MULTIPLE_IDirect3DDevice9 1u << 6
#define uMod_ERROR_UPDATE 1u << 7
#define uMod_ERROR_SERVER 1u << 8
__declspec(noreturn) void FatalAssert(
const char* expr,
@@ -49,4 +49,3 @@ __declspec(noreturn) void FatalAssert(
const char* function);
#define ASSERT(expr) ((void)(!!(expr) || (FatalAssert(#expr, __FILE__, (unsigned)__LINE__, __FUNCTION__), 0)))
+2 -10
View File
@@ -16,19 +16,11 @@
#include "Defines.h"
#include "Error.h"
#include "Defines.h"
#include "uMod_IDirect3D9.h"
#include "uMod_IDirect3D9Ex.h"
#include "uMod_IDirect3DDevice9.h"
#include "uMod_IDirect3DDevice9Ex.h"
#include "uMod_IDirect3DCubeTexture9.h"
#include "uMod_IDirect3DTexture9.h"
#include "uMod_IDirect3DVolumeTexture9.h"
#include "D3D9State.h"
#pragma warning(disable : 4477)
extern unsigned int gl_ErrorState;
extern HINSTANCE gl_hThisInstance;
inline std::filesystem::path gmod_dll_path;
+4 -4
View File
@@ -2,9 +2,8 @@
#include <vector>
namespace utils
{
template<typename T>
namespace utils {
template <typename T>
void erase_first(std::vector<T>& vec, const T& elem)
{
const auto found = std::ranges::find(vec, elem);
@@ -13,7 +12,8 @@ namespace utils
}
}
inline std::wstring utf8_to_wstring(const std::string& utf8str) {
inline std::wstring utf8_to_wstring(const std::string& utf8str)
{
if (utf8str.empty()) return {};
// Calculate the number of wide characters needed for the conversion
-31
View File
@@ -1,31 +0,0 @@
#pragma once
#include <d3d9.h>
class uMod_IDirect3D9 : public IDirect3D9 {
public:
uMod_IDirect3D9(IDirect3D9* pOriginal);
virtual ~uMod_IDirect3D9();
// The original DX9 function definitions
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
HRESULT __stdcall RegisterSoftwareDevice(void* pInitializeFunction) override;
UINT __stdcall GetAdapterCount() override;
HRESULT __stdcall GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier) override;
UINT __stdcall GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) override;
HRESULT __stdcall EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) override;
HRESULT __stdcall GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) override;
HRESULT __stdcall CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) override;
HRESULT __stdcall CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) override;
HRESULT __stdcall CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) override;
HRESULT __stdcall CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) override;
HRESULT __stdcall CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) override;
HRESULT __stdcall GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps) override;
HMONITOR __stdcall GetAdapterMonitor(UINT Adapter) override;
HRESULT __stdcall CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) override;
private:
IDirect3D9* m_pIDirect3D9;
};
-39
View File
@@ -1,39 +0,0 @@
#pragma once
#include <d3d9.h>
class uMod_IDirect3D9Ex : public IDirect3D9Ex {
public:
uMod_IDirect3D9Ex(IDirect3D9Ex* pOriginal);
virtual ~uMod_IDirect3D9Ex();
// The original DX9 function definitions
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
HRESULT __stdcall RegisterSoftwareDevice(void* pInitializeFunction) override;
UINT __stdcall GetAdapterCount() override;
HRESULT __stdcall GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier) override;
UINT __stdcall GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) override;
HRESULT __stdcall EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode) override;
HRESULT __stdcall GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) override;
HRESULT __stdcall CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) override;
HRESULT __stdcall CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) override;
HRESULT __stdcall CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) override;
HRESULT __stdcall CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) override;
HRESULT __stdcall CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) override;
HRESULT __stdcall GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps) override;
HMONITOR __stdcall GetAdapterMonitor(UINT Adapter) override;
HRESULT __stdcall CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface) override;
HRESULT __stdcall CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode,
IDirect3DDevice9Ex** ppReturnedDeviceInterface) override;
HRESULT __stdcall EnumAdapterModesEx(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter, UINT Mode, D3DDISPLAYMODEEX* pMode) override;
HRESULT __stdcall GetAdapterDisplayModeEx(UINT Adapter, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation) override;
HRESULT __stdcall GetAdapterLUID(UINT Adapter, LUID* pLUID) override;
UINT __stdcall GetAdapterModeCountEx(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter) override;
private:
IDirect3D9Ex* m_pIDirect3D9Ex;
};
-48
View File
@@ -1,48 +0,0 @@
#pragma once
#include <d3d9.h>
interface uMod_IDirect3DCubeTexture9 : IDirect3DCubeTexture9 {
uMod_IDirect3DCubeTexture9(IDirect3DCubeTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
: 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;
HashTuple Hash = {};
bool FAKE = false;
// original interface
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override;
STDMETHOD_(ULONG, AddRef)() override;
STDMETHOD_(ULONG, Release)() override;
STDMETHOD(GetDevice)(IDirect3DDevice9** ppDevice) override;
STDMETHOD(SetPrivateData)(REFGUID refguid,CONST void* pData, DWORD SizeOfData, DWORD Flags) override;
STDMETHOD(GetPrivateData)(REFGUID refguid, void* pData, DWORD* pSizeOfData) override;
STDMETHOD(FreePrivateData)(REFGUID refguid) override;
STDMETHOD_(DWORD, SetPriority)(DWORD PriorityNew) override;
STDMETHOD_(DWORD, GetPriority)() override;
STDMETHOD_(void, PreLoad)() override;
STDMETHOD_(D3DRESOURCETYPE, GetType)() override;
STDMETHOD_(DWORD, SetLOD)(DWORD LODNew) override;
STDMETHOD_(DWORD, GetLOD)() override;
STDMETHOD_(DWORD, GetLevelCount)() override;
STDMETHOD(SetAutoGenFilterType)(D3DTEXTUREFILTERTYPE FilterType) override;
STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)() override;
STDMETHOD_(void, GenerateMipSubLevels)() override;
STDMETHOD(AddDirtyRect)(D3DCUBEMAP_FACES FaceType, CONST RECT* pDirtyRect) override;
STDMETHOD(GetLevelDesc)(UINT Level, D3DSURFACE_DESC* pDesc) override;
STDMETHOD(GetCubeMapSurface)(D3DCUBEMAP_FACES FaceType, UINT Level, IDirect3DSurface9** ppCubeMapSurface) override;
STDMETHOD(LockRect)(D3DCUBEMAP_FACES FaceType, UINT Level, D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect, DWORD Flags) override;
STDMETHOD(UnlockRect)(D3DCUBEMAP_FACES FaceType, UINT Level) override;
[[nodiscard]] HashTuple GetHash() const;
};
-173
View File
@@ -1,173 +0,0 @@
#pragma once
#include <d3d9.h>
#include "uMod_IDirect3DTexture9.h"
#include "uMod_IDirect3DVolumeTexture9.h"
#include "uMod_IDirect3DCubeTexture9.h"
class TextureClient;
class uMod_IDirect3DDevice9 : public IDirect3DDevice9 {
public:
uMod_IDirect3DDevice9(IDirect3DDevice9* pOriginal, int back_buffer_count);
virtual ~uMod_IDirect3DDevice9();
// START: The original DX9 function definitions
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
HRESULT __stdcall TestCooperativeLevel() override;
UINT __stdcall GetAvailableTextureMem() override;
HRESULT __stdcall EvictManagedResources() override;
HRESULT __stdcall GetDirect3D(IDirect3D9** ppD3D9) override;
HRESULT __stdcall GetDeviceCaps(D3DCAPS9* pCaps) override;
HRESULT __stdcall GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode) override;
HRESULT __stdcall GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS* pParameters) override;
HRESULT __stdcall SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap) override;
void __stdcall SetCursorPosition(int X, int Y, DWORD Flags) override;
BOOL __stdcall ShowCursor(BOOL bShow) override;
HRESULT __stdcall CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain) override;
HRESULT __stdcall GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain) override;
UINT __stdcall GetNumberOfSwapChains() override;
HRESULT __stdcall Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) override;
HRESULT __stdcall Present(CONST RECT* pSourceRect,CONST RECT* pDestRect, HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion) override;
HRESULT __stdcall GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer) override;
HRESULT __stdcall GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) override;
HRESULT __stdcall SetDialogBoxMode(BOOL bEnableDialogs) override;
void __stdcall SetGammaRamp(UINT iSwapChain, DWORD Flags,CONST D3DGAMMARAMP* pRamp) override;
void __stdcall GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp) override;
HRESULT __stdcall CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override;
HRESULT __stdcall UpdateSurface(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface,CONST POINT* pDestPoint) override;
HRESULT __stdcall UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture) override;
HRESULT __stdcall GetRenderTargetData(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface) override;
HRESULT __stdcall GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface) override;
HRESULT __stdcall StretchRect(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect, IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter) override;
HRESULT __stdcall ColorFill(IDirect3DSurface9* pSurface,CONST RECT* pRect, D3DCOLOR color) override;
HRESULT __stdcall CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override;
HRESULT __stdcall SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget) override;
HRESULT __stdcall GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget) override;
HRESULT __stdcall SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil) override;
HRESULT __stdcall GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface) override;
HRESULT __stdcall BeginScene() override;
HRESULT __stdcall EndScene() override;
HRESULT __stdcall Clear(DWORD Count,CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) override;
HRESULT __stdcall SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix) override;
HRESULT __stdcall GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) override;
HRESULT __stdcall MultiplyTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix) override;
HRESULT __stdcall SetViewport(CONST D3DVIEWPORT9* pViewport) override;
HRESULT __stdcall GetViewport(D3DVIEWPORT9* pViewport) override;
HRESULT __stdcall SetMaterial(CONST D3DMATERIAL9* pMaterial) override;
HRESULT __stdcall GetMaterial(D3DMATERIAL9* pMaterial) override;
HRESULT __stdcall SetLight(DWORD Index,CONST D3DLIGHT9* pLight) override;
HRESULT __stdcall GetLight(DWORD Index, D3DLIGHT9* pLight) override;
HRESULT __stdcall LightEnable(DWORD Index, BOOL Enable) override;
HRESULT __stdcall GetLightEnable(DWORD Index, BOOL* pEnable) override;
HRESULT __stdcall SetClipPlane(DWORD Index,CONST float* pPlane) override;
HRESULT __stdcall GetClipPlane(DWORD Index, float* pPlane) override;
HRESULT __stdcall SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) override;
HRESULT __stdcall GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue) override;
HRESULT __stdcall CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB) override;
HRESULT __stdcall BeginStateBlock() override;
HRESULT __stdcall EndStateBlock(IDirect3DStateBlock9** ppSB) override;
HRESULT __stdcall SetClipStatus(CONST D3DCLIPSTATUS9* pClipStatus) override;
HRESULT __stdcall GetClipStatus(D3DCLIPSTATUS9* pClipStatus) override;
HRESULT __stdcall GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture) override;
HRESULT __stdcall SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture) override;
HRESULT __stdcall GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) override;
HRESULT __stdcall SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) override;
HRESULT __stdcall GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue) override;
HRESULT __stdcall SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) override;
HRESULT __stdcall ValidateDevice(DWORD* pNumPasses) override;
HRESULT __stdcall SetPaletteEntries(UINT PaletteNumber,CONST PALETTEENTRY* pEntries) override;
HRESULT __stdcall GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries) override;
HRESULT __stdcall SetCurrentTexturePalette(UINT PaletteNumber) override;
HRESULT __stdcall GetCurrentTexturePalette(UINT* PaletteNumber) override;
HRESULT __stdcall SetScissorRect(CONST RECT* pRect) override;
HRESULT __stdcall GetScissorRect(RECT* pRect) override;
HRESULT __stdcall SetSoftwareVertexProcessing(BOOL bSoftware) override;
BOOL __stdcall GetSoftwareVertexProcessing() override;
HRESULT __stdcall SetNPatchMode(float nSegments) override;
float __stdcall GetNPatchMode() override;
HRESULT __stdcall DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) override;
HRESULT __stdcall DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) override;
HRESULT __stdcall DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
HRESULT __stdcall DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount,CONST void* pIndexData, D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
UINT VertexStreamZeroStride) override;
HRESULT __stdcall ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags) override;
HRESULT __stdcall CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl) override;
HRESULT __stdcall SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) override;
HRESULT __stdcall GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl) override;
HRESULT __stdcall SetFVF(DWORD FVF) override;
HRESULT __stdcall GetFVF(DWORD* pFVF) override;
HRESULT __stdcall CreateVertexShader(CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader) override;
HRESULT __stdcall SetVertexShader(IDirect3DVertexShader9* pShader) override;
HRESULT __stdcall GetVertexShader(IDirect3DVertexShader9** ppShader) override;
HRESULT __stdcall SetVertexShaderConstantF(UINT StartRegister,CONST float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall GetVertexShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall GetVertexShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall GetVertexShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride) override;
HRESULT __stdcall GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* OffsetInBytes, UINT* pStride) override;
HRESULT __stdcall SetStreamSourceFreq(UINT StreamNumber, UINT Divider) override;
HRESULT __stdcall GetStreamSourceFreq(UINT StreamNumber, UINT* Divider) override;
HRESULT __stdcall SetIndices(IDirect3DIndexBuffer9* pIndexData) override;
HRESULT __stdcall GetIndices(IDirect3DIndexBuffer9** ppIndexData) override;
HRESULT __stdcall CreatePixelShader(CONST DWORD* pFunction, IDirect3DPixelShader9** ppShader) override;
HRESULT __stdcall SetPixelShader(IDirect3DPixelShader9* pShader) override;
HRESULT __stdcall GetPixelShader(IDirect3DPixelShader9** ppShader) override;
HRESULT __stdcall SetPixelShaderConstantF(UINT StartRegister,CONST float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall GetPixelShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall SetPixelShaderConstantI(UINT StartRegister,CONST int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall GetPixelShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall SetPixelShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall GetPixelShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall DrawRectPatch(UINT Handle,CONST float* pNumSegs,CONST D3DRECTPATCH_INFO* pRectPatchInfo) override;
HRESULT __stdcall DrawTriPatch(UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo) override;
HRESULT __stdcall DeletePatch(UINT Handle) override;
HRESULT __stdcall CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) override;
// END: The original DX9 function definitions
TextureClient* GetuMod_Client() { return uMod_Client; }
uMod_IDirect3DTexture9* GetLastCreatedTexture() { return LastCreatedTexture; }
void SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
{
LastCreatedTexture = pTexture;
}
uMod_IDirect3DVolumeTexture9* GetLastCreatedVolumeTexture() { return LastCreatedVolumeTexture; }
void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
{
LastCreatedVolumeTexture = pTexture;
}
uMod_IDirect3DCubeTexture9* GetLastCreatedCubeTexture() { return LastCreatedCubeTexture; }
void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
{
LastCreatedCubeTexture = pTexture;
}
private:
IDirect3DDevice9* m_pIDirect3DDevice9 = nullptr;
int BackBufferCount;
bool NormalRendering = true;
int uMod_Reference = 1;
uMod_IDirect3DTexture9* LastCreatedTexture = nullptr;
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture = nullptr;
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture = nullptr;
TextureClient* uMod_Client;
};
-196
View File
@@ -1,196 +0,0 @@
#pragma once
#include <d3d9.h>
#include "uMod_IDirect3DTexture9.h"
#include "uMod_IDirect3DVolumeTexture9.h"
#include "uMod_IDirect3DCubeTexture9.h"
class TextureClient;
class uMod_IDirect3DDevice9Ex : public IDirect3DDevice9Ex {
public:
uMod_IDirect3DDevice9Ex(IDirect3DDevice9Ex* pOriginal, int back_buffer_count);
virtual ~uMod_IDirect3DDevice9Ex();
// START: The original DX9 function definitions
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
HRESULT __stdcall TestCooperativeLevel() override;
UINT __stdcall GetAvailableTextureMem() override;
HRESULT __stdcall EvictManagedResources() override;
HRESULT __stdcall GetDirect3D(IDirect3D9** ppD3D9) override;
HRESULT __stdcall GetDeviceCaps(D3DCAPS9* pCaps) override;
HRESULT __stdcall GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode) override;
HRESULT __stdcall GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS* pParameters) override;
HRESULT __stdcall SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap) override;
void __stdcall SetCursorPosition(int X, int Y, DWORD Flags) override;
BOOL __stdcall ShowCursor(BOOL bShow) override;
HRESULT __stdcall CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain) override;
HRESULT __stdcall GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain) override;
UINT __stdcall GetNumberOfSwapChains() override;
HRESULT __stdcall Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) override;
HRESULT __stdcall Present(CONST RECT* pSourceRect,CONST RECT* pDestRect, HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion) override;
HRESULT __stdcall GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer) override;
HRESULT __stdcall GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus) override;
HRESULT __stdcall SetDialogBoxMode(BOOL bEnableDialogs) override;
void __stdcall SetGammaRamp(UINT iSwapChain, DWORD Flags,CONST D3DGAMMARAMP* pRamp) override;
void __stdcall GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp) override;
HRESULT __stdcall CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override;
HRESULT __stdcall CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override;
HRESULT __stdcall UpdateSurface(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface,CONST POINT* pDestPoint) override;
HRESULT __stdcall UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture) override;
HRESULT __stdcall GetRenderTargetData(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface) override;
HRESULT __stdcall GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface) override;
HRESULT __stdcall StretchRect(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect, IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter) override;
HRESULT __stdcall ColorFill(IDirect3DSurface9* pSurface,CONST RECT* pRect, D3DCOLOR color) override;
HRESULT __stdcall CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle) override;
HRESULT __stdcall SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget) override;
HRESULT __stdcall GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget) override;
HRESULT __stdcall SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil) override;
HRESULT __stdcall GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface) override;
HRESULT __stdcall BeginScene() override;
HRESULT __stdcall EndScene() override;
HRESULT __stdcall Clear(DWORD Count,CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) override;
HRESULT __stdcall SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix) override;
HRESULT __stdcall GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix) override;
HRESULT __stdcall MultiplyTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix) override;
HRESULT __stdcall SetViewport(CONST D3DVIEWPORT9* pViewport) override;
HRESULT __stdcall GetViewport(D3DVIEWPORT9* pViewport) override;
HRESULT __stdcall SetMaterial(CONST D3DMATERIAL9* pMaterial) override;
HRESULT __stdcall GetMaterial(D3DMATERIAL9* pMaterial) override;
HRESULT __stdcall SetLight(DWORD Index,CONST D3DLIGHT9* pLight) override;
HRESULT __stdcall GetLight(DWORD Index, D3DLIGHT9* pLight) override;
HRESULT __stdcall LightEnable(DWORD Index, BOOL Enable) override;
HRESULT __stdcall GetLightEnable(DWORD Index, BOOL* pEnable) override;
HRESULT __stdcall SetClipPlane(DWORD Index,CONST float* pPlane) override;
HRESULT __stdcall GetClipPlane(DWORD Index, float* pPlane) override;
HRESULT __stdcall SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) override;
HRESULT __stdcall GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue) override;
HRESULT __stdcall CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB) override;
HRESULT __stdcall BeginStateBlock() override;
HRESULT __stdcall EndStateBlock(IDirect3DStateBlock9** ppSB) override;
HRESULT __stdcall SetClipStatus(CONST D3DCLIPSTATUS9* pClipStatus) override;
HRESULT __stdcall GetClipStatus(D3DCLIPSTATUS9* pClipStatus) override;
HRESULT __stdcall GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture) override;
HRESULT __stdcall SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture) override;
HRESULT __stdcall GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) override;
HRESULT __stdcall SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) override;
HRESULT __stdcall GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue) override;
HRESULT __stdcall SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) override;
HRESULT __stdcall ValidateDevice(DWORD* pNumPasses) override;
HRESULT __stdcall SetPaletteEntries(UINT PaletteNumber,CONST PALETTEENTRY* pEntries) override;
HRESULT __stdcall GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries) override;
HRESULT __stdcall SetCurrentTexturePalette(UINT PaletteNumber) override;
HRESULT __stdcall GetCurrentTexturePalette(UINT* PaletteNumber) override;
HRESULT __stdcall SetScissorRect(CONST RECT* pRect) override;
HRESULT __stdcall GetScissorRect(RECT* pRect) override;
HRESULT __stdcall SetSoftwareVertexProcessing(BOOL bSoftware) override;
BOOL __stdcall GetSoftwareVertexProcessing() override;
HRESULT __stdcall SetNPatchMode(float nSegments) override;
float __stdcall GetNPatchMode() override;
HRESULT __stdcall DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) override;
HRESULT __stdcall DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) override;
HRESULT __stdcall DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
HRESULT __stdcall DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount,CONST void* pIndexData, D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
UINT VertexStreamZeroStride) override;
HRESULT __stdcall ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags) override;
HRESULT __stdcall CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl) override;
HRESULT __stdcall SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) override;
HRESULT __stdcall GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl) override;
HRESULT __stdcall SetFVF(DWORD FVF) override;
HRESULT __stdcall GetFVF(DWORD* pFVF) override;
HRESULT __stdcall CreateVertexShader(CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader) override;
HRESULT __stdcall SetVertexShader(IDirect3DVertexShader9* pShader) override;
HRESULT __stdcall GetVertexShader(IDirect3DVertexShader9** ppShader) override;
HRESULT __stdcall SetVertexShaderConstantF(UINT StartRegister,CONST float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall GetVertexShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall GetVertexShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall GetVertexShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride) override;
HRESULT __stdcall GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* OffsetInBytes, UINT* pStride) override;
HRESULT __stdcall SetStreamSourceFreq(UINT StreamNumber, UINT Divider) override;
HRESULT __stdcall GetStreamSourceFreq(UINT StreamNumber, UINT* Divider) override;
HRESULT __stdcall SetIndices(IDirect3DIndexBuffer9* pIndexData) override;
HRESULT __stdcall GetIndices(IDirect3DIndexBuffer9** ppIndexData) override;
HRESULT __stdcall CreatePixelShader(CONST DWORD* pFunction, IDirect3DPixelShader9** ppShader) override;
HRESULT __stdcall SetPixelShader(IDirect3DPixelShader9* pShader) override;
HRESULT __stdcall GetPixelShader(IDirect3DPixelShader9** ppShader) override;
HRESULT __stdcall SetPixelShaderConstantF(UINT StartRegister,CONST float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall GetPixelShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount) override;
HRESULT __stdcall SetPixelShaderConstantI(UINT StartRegister,CONST int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall GetPixelShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount) override;
HRESULT __stdcall SetPixelShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall GetPixelShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount) override;
HRESULT __stdcall DrawRectPatch(UINT Handle,CONST float* pNumSegs,CONST D3DRECTPATCH_INFO* pRectPatchInfo) override;
HRESULT __stdcall DrawTriPatch(UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo) override;
HRESULT __stdcall DeletePatch(UINT Handle) override;
HRESULT __stdcall CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) override;
HRESULT __stdcall CheckDeviceState(HWND hWindow) override;
HRESULT __stdcall CheckResourceResidency(IDirect3DResource9** pResourceArray, UINT32 NumResources) override;
HRESULT __stdcall ComposeRects(IDirect3DSurface9* pSource, IDirect3DSurface9* pDestination, IDirect3DVertexBuffer9* pSrcRectDescriptors, UINT NumRects, IDirect3DVertexBuffer9* pDstRectDescriptors, D3DCOMPOSERECTSOP Operation, INT XOffset,
INT YOffset) override;
HRESULT __stdcall CreateDepthStencilSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) override;
HRESULT __stdcall CreateOffscreenPlainSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) override;
HRESULT __stdcall CreateRenderTargetEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage) override;
HRESULT __stdcall GetDisplayModeEx(UINT iSwapChain, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation) override;
HRESULT __stdcall GetGPUThreadPriority(INT* pPriority) override;
HRESULT __stdcall GetMaximumFrameLatency(UINT* pMaxLatency) override;
HRESULT __stdcall PresentEx(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion, DWORD dwFlags) override;
HRESULT __stdcall ResetEx(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) override;
HRESULT __stdcall SetConvolutionMonoKernel(UINT Width, UINT Height, float* RowWeights, float* ColumnWeights) override;
HRESULT __stdcall SetGPUThreadPriority(INT pPriority) override;
HRESULT __stdcall SetMaximumFrameLatency(UINT pMaxLatency) override;
//HRESULT __stdcall TestCooperativeLevel();
HRESULT __stdcall WaitForVBlank(UINT SwapChainIndex) override;
// END: The original DX9 function definitions
TextureClient* GetuMod_Client() { return uMod_Client; }
uMod_IDirect3DTexture9* GetLastCreatedTexture() { return LastCreatedTexture; }
void SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
{
LastCreatedTexture = pTexture;
}
uMod_IDirect3DVolumeTexture9* GetLastCreatedVolumeTexture() { return LastCreatedVolumeTexture; }
void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
{
LastCreatedVolumeTexture = pTexture;
}
uMod_IDirect3DCubeTexture9* GetLastCreatedCubeTexture() { return LastCreatedCubeTexture; }
void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
{
LastCreatedCubeTexture = pTexture;
}
private:
IDirect3DDevice9Ex* m_pIDirect3DDevice9Ex;
int BackBufferCount;
bool NormalRendering = true;
int uMod_Reference = 1;
uMod_IDirect3DTexture9* LastCreatedTexture = nullptr;
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture = nullptr;
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture = nullptr;
TextureClient* uMod_Client = nullptr;
};
-48
View File
@@ -1,48 +0,0 @@
#pragma once
#include <d3d9.h>
#include "Defines.h"
struct TextureFileStruct;
interface uMod_IDirect3DTexture9 : IDirect3DTexture9 {
uMod_IDirect3DTexture9(IDirect3DTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
: 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;
HashTuple Hash = {};
bool FAKE = false;
// original interface
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override;
STDMETHOD_(ULONG, AddRef)() override;
STDMETHOD_(ULONG, Release)() override;
STDMETHOD(GetDevice)(IDirect3DDevice9** ppDevice) override;
STDMETHOD(SetPrivateData)(REFGUID refguid,CONST void* pData, DWORD SizeOfData, DWORD Flags) override;
STDMETHOD(GetPrivateData)(REFGUID refguid, void* pData, DWORD* pSizeOfData) override;
STDMETHOD(FreePrivateData)(REFGUID refguid) override;
STDMETHOD_(DWORD, SetPriority)(DWORD PriorityNew) override;
STDMETHOD_(DWORD, GetPriority)() override;
STDMETHOD_(void, PreLoad)() override;
STDMETHOD_(D3DRESOURCETYPE, GetType)() override;
STDMETHOD_(DWORD, SetLOD)(DWORD LODNew) override;
STDMETHOD_(DWORD, GetLOD)() override;
STDMETHOD_(DWORD, GetLevelCount)() override;
STDMETHOD(SetAutoGenFilterType)(D3DTEXTUREFILTERTYPE FilterType) override;
STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)() override;
STDMETHOD_(void, GenerateMipSubLevels)() override;
STDMETHOD(GetLevelDesc)(UINT Level, D3DSURFACE_DESC* pDesc) override;
STDMETHOD(GetSurfaceLevel)(UINT Level, IDirect3DSurface9** ppSurfaceLevel) override;
STDMETHOD(LockRect)(UINT Level, D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect, DWORD Flags) override;
STDMETHOD(UnlockRect)(UINT Level) override;
STDMETHOD(AddDirtyRect)(CONST RECT* pDirtyRect) override;
[[nodiscard]] HashTuple GetHash() const;
};
-47
View File
@@ -1,47 +0,0 @@
#pragma once
#include <d3d9.h>
interface uMod_IDirect3DVolumeTexture9 : IDirect3DVolumeTexture9 {
uMod_IDirect3DVolumeTexture9(IDirect3DVolumeTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
: 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;
HashTuple Hash = {};
bool FAKE = false;
// original interface
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj) override;
STDMETHOD_(ULONG, AddRef)() override;
STDMETHOD_(ULONG, Release)() override;
STDMETHOD(GetDevice)(IDirect3DDevice9** ppDevice) override;
STDMETHOD(SetPrivateData)(REFGUID refguid,CONST void* pData, DWORD SizeOfData, DWORD Flags) override;
STDMETHOD(GetPrivateData)(REFGUID refguid, void* pData, DWORD* pSizeOfData) override;
STDMETHOD(FreePrivateData)(REFGUID refguid) override;
STDMETHOD_(DWORD, SetPriority)(DWORD PriorityNew) override;
STDMETHOD_(DWORD, GetPriority)() override;
STDMETHOD_(void, PreLoad)() override;
STDMETHOD_(D3DRESOURCETYPE, GetType)() override;
STDMETHOD_(DWORD, SetLOD)(DWORD LODNew) override;
STDMETHOD_(DWORD, GetLOD)() override;
STDMETHOD_(DWORD, GetLevelCount)() override;
STDMETHOD(SetAutoGenFilterType)(D3DTEXTUREFILTERTYPE FilterType) override;
STDMETHOD_(D3DTEXTUREFILTERTYPE, GetAutoGenFilterType)() override;
STDMETHOD_(void, GenerateMipSubLevels)() override;
STDMETHOD(AddDirtyBox)(CONST D3DBOX* pDirtyBox) override;
STDMETHOD(GetLevelDesc)(UINT Level, D3DVOLUME_DESC* pDesc) override;
STDMETHOD(GetVolumeLevel)(UINT Level, IDirect3DVolume9** ppVolumeLevel) override;
STDMETHOD(LockBox)(UINT Level, D3DLOCKED_BOX* pLockedVolume, CONST D3DBOX* pBox, DWORD Flags) override;
STDMETHOD(UnlockBox)(UINT Level) override;
[[nodiscard]] HashTuple GetHash() const;
};
+13 -8
View File
@@ -13,8 +13,9 @@ 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);
HashType GetCrcFromFilename(const std::string& filename)
{
const static std::regex re(R"(0[xX][0-9a-fA-F]{4,16})", std::regex::optimize);
std::smatch match;
if (!std::regex_search(filename, match, re)) {
return 0;
@@ -39,7 +40,8 @@ namespace {
}
namespace HashCheck {
export bool Use64BitCrc() {
export bool Use64BitCrc()
{
return use_64_bit_crc;
}
}
@@ -52,8 +54,7 @@ export class ModfileLoader {
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
};
0x46, 0x6F};
public:
ModfileLoader(const std::filesystem::path& fileName);
@@ -61,7 +62,6 @@ public:
std::vector<TexEntry> GetContents() const;
private:
std::vector<TexEntry> GetTpfContents() const;
std::vector<TexEntry> GetFileContents() const;
@@ -124,9 +124,12 @@ void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TexEntr
for (const auto& entry : archive.getEntries()) {
if (!entry.isFile())
continue;
const auto entry_name = entry.getName();
const auto crc_hash = GetCrcFromFilename(entry.getName());
if (!crc_hash)
if (!crc_hash) {
Warning("Entry with name %s could not be parsed", entry_name.c_str());
continue;
}
const auto data_ptr = static_cast<BYTE*>(entry.readAsBinary());
const auto size = entry.getSize();
std::vector vec(data_ptr, data_ptr + size);
@@ -143,8 +146,10 @@ void ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& a
// 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))
if (!std::regex_search(line, match, address_file_regex)) {
Warning("Failed to parse texmod.def archive line: %s - %s", line.c_str(), line.c_str());
continue;
}
const auto address_string = match[1].str();
const auto file_path = match[2].str();
+6 -6
View File
@@ -23,30 +23,30 @@ public:
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);
std::vector<char> data(static_cast<long>(line_length));
file_stream.read(data.data(), line_length);
for (auto i = 0; i < data.size(); i++) {
for (auto i = 0u; i < data.size(); i++) {
data[i] = XOR(data[i], i);
}
for (int i = data.size() - 1; i > 0 && data[i] != 0; i--) {
for (auto 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);
// data.resize(last_zero);
return data;
}
private:
std::ifstream file_stream;
long line_length = 0;
std::streamoff line_length = 0;
[[nodiscard]] char XOR(const char b, const long position) const
{
if (position > line_length - 4) {
if (position >= (line_length / 4) * 4) {
return b ^ TPF_XOREven;
}
+523 -242
View File
@@ -2,79 +2,180 @@ module;
#include "Main.h"
#include "Error.h"
#include "uMod_IDirect3DTexture9.h"
#include "D3D9State.h"
#include <DDSTextureLoader/DDSTextureLoader9.h>
#include <DirectXTex/DirectXTex.h>
#include <mutex>
#include <unordered_map>
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 std::vector<std::pair<std::string, std::string>> modlists_contents;
struct PendingOp {
enum class Kind {
Add,
Remove
};
Kind kind;
HashType hash;
std::vector<BYTE> data;
};
// Couples a value with the mutex guarding it; the value is only reachable while
// the lock is held.
template <class T>
class Guarded {
std::mutex mutex;
T value;
public:
template <class Fn>
auto with(Fn&& fn)
{
std::lock_guard lock(mutex);
return fn(value);
}
};
// Owned by each d3d9 device (see D3D9Hooks.cpp). Holds per-texture side-state
// and does the modding; the On*() methods are the vtable-hook entry points.
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(...)
// Called from the hooked vtable slots:
TexState* OnCreateTexture(IDirect3DBaseTexture9* texture, TexType type);
void OnBeginScene();
// The fake replacement when `texture` is a modded original, else `texture`.
IDirect3DBaseTexture9* ResolveBinding(IDirect3DBaseTexture9* texture);
// For GetTexture: the original behind one of our fakes, or nullptr.
IDirect3DBaseTexture9* ResolveOriginalFromFake(IDirect3DBaseTexture9* texture);
void OnUpdateTexture(IDirect3DBaseTexture9* source, IDirect3DBaseTexture9* destination);
void OnReleaseTexture(IDirect3DBaseTexture9* texture); // called once the real refcount hit zero
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
void EnqueueAdd(HashType hash, std::vector<BYTE> data);
void EnqueueRemove(HashType hash);
static int AddFile(const std::filesystem::path& path);
static int RemoveFile(const std::filesystem::path& path);
static std::vector<std::filesystem::path> GetFiles();
// The texture Release hook has only a texture pointer, so it finds its client here.
static TextureClient* CurrentClient();
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*);
// Side-state keyed by real texture pointer: the game's textures vs. our fakes.
std::recursive_mutex registry_mutex;
std::unordered_map<IDirect3DBaseTexture9*, TexState*> originals;
std::unordered_map<IDirect3DBaseTexture9*, TexState*> fakes;
// Hashed one creation later, once the game has filled it with data.
IDirect3DBaseTexture9* last_created[3] = {};
bool loading_fake = false; // set while LoadTexture() drives CreateTexture internally
bool shutting_down = false; // set in ~TextureClient so the Release hook stops touching us
bool should_update = false;
int AddTexture(IDirect3DBaseTexture9* texture); // hash a freshly filled original + look up its mod
int LookUpToMod(TexState* state); // switch in a fake if a mod matches the hash
int LoadTexture(TextureFileStruct* file_in_memory, IDirect3DBaseTexture9** ppTexture, TexState** ppState);
static void Switch(TexState* original, TexState* fake);
static void Unswitch(TexState* original);
void UnswitchAndRelease(TexState* original); // unswitch + release our fake
int MergeUpdate();
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
Guarded<std::vector<PendingOp>> pending_ops;
void ProcessPendingOps();
void RemoveModdedTexture(HashType hash);
// called if a target texture is found
int LoadTexture(TextureFileStruct* file_in_memory, uModTexturePtrPtr auto ppTexture);
std::unordered_map<HashType, gsl::owner<TextureFileStruct*>> modded_textures; // hash -> mod file in memory
void LoadModsFromFile(const char* source);
std::filesystem::path exe_path; // path to gw.exe
std::filesystem::path dll_path; // path to gmod dll
static void LoadStartupModlists();
// Enqueue an Add per distinct non-zero hash, free the structs, return the hashes
// in load order; accumulates moved bytes into loaded_bytes when given.
static std::vector<HashType> IngestModfile(std::vector<gsl::owner<TextureFileStruct*>>& texture_file_structs, uint64_t* loaded_bytes = nullptr);
// Kept in load order, which is priority order: on a hash collision the
// earlier file wins (see ProcessPendingOps).
struct LoadedFile {
std::filesystem::path path;
std::vector<HashType> hashes;
};
static inline std::mutex global_mutex;
static inline TextureClient* current_client = nullptr;
// A vector, not a map: tens of mods at most, and their order is meaningful.
static inline std::vector<LoadedFile> loaded_files;
// Caller holds global_mutex; path must already be absolute.
static std::vector<LoadedFile>::iterator FindLoadedFile(const std::filesystem::path& absolute_path)
{
return std::ranges::find(loaded_files, absolute_path, &LoadedFile::path);
}
};
TextureClient* TextureClient::CurrentClient()
{
std::lock_guard lk(global_mutex);
return current_client;
}
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);
std::lock_guard lk(global_mutex);
ASSERT(current_client == nullptr); // gMod assumes a single d3d9 device per process
current_client = this;
}
TextureClient::~TextureClient()
{
Message("TextureClient::~TextureClient(): %p\n", this);
{
std::lock_guard lk(global_mutex);
if (current_client == this) current_client = nullptr;
}
{
std::lock_guard lk(registry_mutex);
shutting_down = true; // the texture Release hook now no-ops for our textures
// Release replacements we still own (still partnered) so they aren't leaked when
// torn down with the device alive (FreeLibrary). Orphaned fakes were already
// released; a device-release teardown leaves the maps empty, so this is a no-op.
for (const auto fake : fakes | std::views::values) {
if (fake->partner != nullptr) {
fake->partner->partner = nullptr; // detach the original's back-pointer
if (fake->real) fake->real->Release();
}
delete fake;
}
fakes.clear();
for (const auto state : originals | std::views::values) {
delete state;
}
originals.clear();
}
if (hMutex != nullptr) {
CloseHandle(hMutex);
}
@@ -84,10 +185,217 @@ TextureClient::~TextureClient()
modded_textures.clear();
}
void TextureClient::Switch(TexState* original, TexState* fake)
{
original->partner = fake;
fake->partner = original;
}
void TextureClient::Unswitch(TexState* original)
{
if (original->partner != nullptr) {
original->partner->partner = nullptr;
original->partner = nullptr;
}
}
void TextureClient::UnswitchAndRelease(TexState* original)
{
TexState* fake = original->partner;
if (fake == nullptr) return;
Unswitch(original); // detach before releasing so the fake's Release hook won't touch `original`
if (fake->real) fake->real->Release(); // re-enters OnReleaseTexture(fake), which frees its state
}
TexState* TextureClient::OnCreateTexture(IDirect3DBaseTexture9* texture, TexType type)
{
std::lock_guard lk(registry_mutex);
const auto state = new TexState();
state->real = texture;
state->device = D3D9Device;
state->type = type;
if (loading_fake) {
// A replacement we're creating: track as a fake, skip the originals bookkeeping.
state->isFake = true;
fakes.emplace(texture, state);
return state;
}
originals.emplace(texture, state);
// The previous texture of this type is now filled, so hash it.
if (const auto last = last_created[static_cast<int>(type)]) {
AddTexture(last);
}
last_created[static_cast<int>(type)] = texture;
return state;
}
int TextureClient::AddTexture(IDirect3DBaseTexture9* texture)
{
const auto it = originals.find(texture);
if (it == originals.end()) return RETURN_OK;
const auto state = it->second;
// No longer pending.
if (last_created[static_cast<int>(state->type)] == texture) {
last_created[static_cast<int>(state->type)] = nullptr;
}
if (gl_ErrorState & uMod_ERROR_FATAL) {
return RETURN_FATAL_ERROR;
}
state->hash = GetTextureHash(state);
if (!state->hash) {
return RETURN_FATAL_ERROR;
}
return LookUpToMod(state); // check if this texture should be modded
}
int TextureClient::LookUpToMod(TexState* state)
{
Message("TextureClient::LookUpToMod( %p): hash: %#lX\n", state->real, state->hash);
if (state->partner != nullptr)
return RETURN_OK; // already switched
auto found = modded_textures.find(state->hash.crc32);
if (found == modded_textures.end())
if (found = modded_textures.find(state->hash.crc64), !state->hash.crc64 || found == modded_textures.end())
return RETURN_OK;
const auto textureFileStruct = found->second;
IDirect3DBaseTexture9* fake_texture = nullptr;
TexState* fake_state = nullptr;
if (const int ret = LoadTexture(textureFileStruct, &fake_texture, &fake_state); ret != RETURN_OK)
return ret;
Switch(state, fake_state);
fake_state->reference = textureFileStruct;
return RETURN_OK;
}
int TextureClient::LoadTexture(TextureFileStruct* file_in_memory, IDirect3DBaseTexture9** ppTexture, TexState** ppState)
{
Message("LoadTexture( %p, %#lX): %p\n", file_in_memory, file_in_memory->crc_hash, this);
*ppTexture = nullptr;
*ppState = nullptr;
// CreateDDSTextureFromMemoryEx calls the hooked CreateTexture; loading_fake
// makes that hook register the result as a fake, not a game original.
IDirect3DTexture9* texture = nullptr;
loading_fake = true;
const auto ret = DirectX::CreateDDSTextureFromMemoryEx(
D3D9Device,
file_in_memory->data.data(),
file_in_memory->data.size(),
0, D3DPOOL_MANAGED, false,
&texture);
loading_fake = false;
if (ret != D3D_OK || texture == nullptr) {
Warning("LoadDDSTexture (%p, %#lX): FAILED ret: \n", file_in_memory->data.data(), file_in_memory->crc_hash, ret);
return RETURN_TEXTURE_NOT_LOADED;
}
const auto fake = static_cast<IDirect3DBaseTexture9*>(texture);
const auto state_it = fakes.find(fake);
ASSERT(state_it != fakes.end()); // must have been registered by the CreateTexture hook
*ppTexture = fake;
*ppState = state_it->second;
Message("LoadTexture (%p, %#lX): DONE\n", fake, file_in_memory->crc_hash);
return RETURN_OK;
}
IDirect3DBaseTexture9* TextureClient::ResolveBinding(IDirect3DBaseTexture9* texture)
{
if (texture == nullptr) return nullptr;
std::lock_guard lk(registry_mutex);
const auto it = originals.find(texture);
if (it != originals.end() && it->second->partner != nullptr) {
return it->second->partner->real; // bind the fake in place of the original
}
return texture;
}
IDirect3DBaseTexture9* TextureClient::ResolveOriginalFromFake(IDirect3DBaseTexture9* texture)
{
if (texture == nullptr) return nullptr;
std::lock_guard lk(registry_mutex);
const auto it = fakes.find(texture);
if (it != fakes.end() && it->second->partner != nullptr) {
return it->second->partner->real;
}
return nullptr;
}
void TextureClient::OnBeginScene()
{
{
std::lock_guard lk(registry_mutex);
for (int type = 0; type < 3; ++type) {
if (last_created[type] != nullptr) {
AddTexture(last_created[type]); // hashes + clears the slot
}
}
}
MergeUpdate();
}
void TextureClient::OnUpdateTexture(IDirect3DBaseTexture9* source, IDirect3DBaseTexture9* destination)
{
// The copy already happened; re-hash both textures and re-run the mod lookup.
std::lock_guard lk(registry_mutex);
auto refresh = [this](IDirect3DBaseTexture9* texture) {
const auto it = originals.find(texture);
if (it == originals.end()) return;
const auto state = it->second;
const auto hash = GetTextureHash(state);
if (hash == state->hash) return; // unchanged
state->hash = hash;
if (state->partner != nullptr) UnswitchAndRelease(state);
if (hash) LookUpToMod(state);
};
refresh(source);
refresh(destination);
}
void TextureClient::OnReleaseTexture(IDirect3DBaseTexture9* texture)
{
std::lock_guard lk(registry_mutex);
if (shutting_down) return; // ~TextureClient is tearing everything down itself
// A fake of ours being released (either by us during cleanup, or transitively).
if (const auto fit = fakes.find(texture); fit != fakes.end()) {
const auto state = fit->second;
if (state->partner != nullptr) state->partner->partner = nullptr;
fakes.erase(fit);
delete state;
return;
}
// A game texture (original) reaching zero references.
if (const auto oit = originals.find(texture); oit != originals.end()) {
const auto state = oit->second;
if (last_created[static_cast<int>(state->type)] == texture) {
last_created[static_cast<int>(state->type)] = nullptr;
}
originals.erase(oit);
UnswitchAndRelease(state); // release the fake we held for it, if any
delete state;
}
}
int TextureClient::MergeUpdate()
{
if (!should_update) return RETURN_OK;
should_update = false;
const bool has_pending = pending_ops.with([](auto& ops) { return !ops.empty(); });
if (!should_update && !has_pending) return RETURN_OK;
if (const int ret = LockMutex()) {
gl_ErrorState |= uMod_ERROR_TEXTURE;
return ret;
@@ -95,44 +403,70 @@ int TextureClient::MergeUpdate()
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);
ProcessPendingOps();
{
std::lock_guard lk(registry_mutex);
for (const auto state : originals | std::views::values) {
if (state->partner == nullptr && state->hash) {
LookUpToMod(state);
}
}
}
should_update = false;
return UnlockMutex();
}
void TextureClient::SetLastCreatedTexture(uMod_IDirect3DTexture9* texture)
void TextureClient::EnqueueAdd(HashType hash, std::vector<BYTE> data)
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedTexture(texture);
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedTexture(texture);
if (!hash) return;
pending_ops.with([&](auto& ops) { ops.push_back(PendingOp{PendingOp::Kind::Add, hash, std::move(data)}); });
}
void TextureClient::SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* texture)
void TextureClient::EnqueueRemove(HashType hash)
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
if (!hash) return;
pending_ops.with([&](auto& ops) { ops.push_back(PendingOp{PendingOp::Kind::Remove, hash, {}}); });
}
void TextureClient::SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* texture)
void TextureClient::ProcessPendingOps()
{
if (isDirectXExDevice)
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedCubeTexture(texture);
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedCubeTexture(texture);
std::vector<PendingOp> ops;
pending_ops.with([&](auto& pending) { ops.swap(pending); });
for (auto& op : ops) {
if (op.kind == PendingOp::Kind::Add) {
if (modded_textures.contains(op.hash)) continue;
const auto texture_file_struct = new TextureFileStruct();
texture_file_struct->crc_hash = op.hash;
texture_file_struct->data = std::move(op.data);
modded_textures.emplace(op.hash, texture_file_struct);
should_update = true;
}
else {
RemoveModdedTexture(op.hash);
}
}
}
void TextureClient::RemoveModdedTexture(HashType hash)
{
const auto it = modded_textures.find(hash);
if (it == modded_textures.end()) return;
const auto texture_file_struct = it->second;
{
std::lock_guard lk(registry_mutex);
for (const auto original : originals | std::views::values) {
const auto fake = original->partner;
if (fake != nullptr && fake->reference == texture_file_struct) {
UnswitchAndRelease(original);
}
}
}
modded_textures.erase(it);
delete texture_file_struct;
}
int TextureClient::LockMutex()
@@ -141,7 +475,7 @@ int TextureClient::LockMutex()
return RETURN_NO_MUTEX;
}
if (WAIT_OBJECT_0 != WaitForSingleObject(hMutex, 100)) {
return RETURN_MUTEX_LOCK; //waiting 100ms, to wait infinite pass INFINITE
return RETURN_MUTEX_LOCK; // waiting 100ms, to wait infinite pass INFINITE
}
return RETURN_OK;
}
@@ -154,24 +488,26 @@ int TextureClient::UnlockMutex()
return RETURN_OK;
}
gsl::owner<TextureFileStruct*> AddFile(TexEntry& entry, const bool compress, const std::filesystem::path& dll_path)
gsl::owner<TextureFileStruct*> MakeTextureFileStruct(TexEntry& entry, const bool compress)
{
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);
const auto dds_blob = TextureFunction::ConvertToCompressedDDS(entry, compress);
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)
std::vector<gsl::owner<TextureFileStruct*>> ProcessModfile(const std::filesystem::path& modfile, const bool compress)
{
const auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) return {};
Message("Initialize: loading file %s... ", modfile.c_str());
const auto modfile_str = modfile.string();
Message("Initialize: loading file %s... ", modfile_str.c_str());
auto file_loader = ModfileLoader(modfile);
auto entries = file_loader.GetContents();
if (entries.empty()) {
Message("No entries found.\n");
CoUninitialize();
return {};
}
Message("%zu textures... ", entries.size());
@@ -179,9 +515,9 @@ std::vector<gsl::owner<TextureFileStruct*>> ProcessModfile(const std::filesystem
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();
const auto texture_file_struct = MakeTextureFileStruct(tpf_entry, compress);
texture_file_structs.push_back(texture_file_struct);
file_bytes_loaded += static_cast<unsigned>(texture_file_structs.back()->data.size());
}
entries.clear();
Message("%d bytes loaded.\n", file_bytes_loaded);
@@ -189,202 +525,147 @@ std::vector<gsl::owner<TextureFileStruct*>> ProcessModfile(const std::filesystem
return texture_file_structs;
}
void TextureClient::LoadModsFromFile(const char* source)
std::vector<HashType> TextureClient::IngestModfile(std::vector<gsl::owner<TextureFileStruct*>>& texture_file_structs, uint64_t* loaded_bytes)
{
static std::vector<std::filesystem::path> loaded_modfiles{};
Message("Initialize: searching in %s\n", source);
std::vector<HashType> hashes;
for (auto* texture_file_struct : texture_file_structs) {
const auto hash = texture_file_struct->crc_hash;
if (hash && std::ranges::find(hashes, hash) == hashes.end()) {
hashes.push_back(hash);
if (loaded_bytes) *loaded_bytes += texture_file_struct->data.size();
if (current_client) {
current_client->EnqueueAdd(hash, std::move(texture_file_struct->data));
}
}
delete texture_file_struct;
}
texture_file_structs.clear();
return hashes;
}
std::vector<std::filesystem::path> TextureClient::GetFiles()
{
std::lock_guard lk(global_mutex);
std::vector<std::filesystem::path> result;
result.reserve(loaded_files.size());
for (const auto& loaded_file : loaded_files) {
result.push_back(loaded_file.path);
}
return result;
}
int TextureClient::RemoveFile(const std::filesystem::path& path)
{
const auto absolute_path = std::filesystem::absolute(path);
std::lock_guard lk(global_mutex);
const auto it = FindLoadedFile(absolute_path);
if (it == loaded_files.end()) return RETURN_FILE_NOT_LOADED;
if (current_client) {
for (const auto hash : it->hashes) {
current_client->EnqueueRemove(hash);
}
}
loaded_files.erase(it);
return RETURN_OK;
}
int TextureClient::AddFile(const std::filesystem::path& path)
{
const auto absolute_path = std::filesystem::absolute(path);
{
std::lock_guard lk(global_mutex);
if (FindLoadedFile(absolute_path) != loaded_files.end()) return RETURN_EXISTS;
}
if (!std::filesystem::exists(absolute_path)) return RETURN_FILE_NOT_LOADED;
const auto file_size = std::filesystem::file_size(absolute_path);
auto texture_file_structs = ProcessModfile(absolute_path, file_size > 400'000'000);
if (texture_file_structs.empty()) return RETURN_FILE_NOT_LOADED;
std::lock_guard lk(global_mutex);
// Re-check under lock; another thread may have loaded the same path concurrently.
if (FindLoadedFile(absolute_path) != loaded_files.end()) {
for (auto* texture_file_struct : texture_file_structs)
delete texture_file_struct;
return RETURN_EXISTS;
}
auto hashes = IngestModfile(texture_file_structs);
if (hashes.empty()) return RETURN_TEXTURE_NOT_LOADED;
loaded_files.push_back({absolute_path, std::move(hashes)});
return RETURN_OK;
}
void TextureClient::LoadStartupModlists()
{
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());
for (const auto& content : modlists_contents | std::views::values) {
std::istringstream iss(content);
std::string line;
while (std::getline(iss, line)) {
if (line.starts_with("//") || line.starts_with("#") || line.empty()) {
continue;
}
// Remove newline character
line.erase(std::ranges::remove(line, '\r').begin(), line.end());
line.erase(std::ranges::remove(line, '\n').begin(), line.end());
if (line.empty()) continue;
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 modfile = std::filesystem::absolute(std::filesystem::path(utils::utf8_to_wstring(line)));
if (!std::ranges::contains(modfiles, modfile)) {
modfiles.push_back(std::move(modfile));
}
}
}
auto files_size = 0u;
for (const auto modfile : modfiles) {
if (std::filesystem::exists(modfile)) {
files_size += std::filesystem::file_size(modfile);
}
auto total_size = 0ull;
for (const auto& modfile : modfiles) {
if (std::filesystem::exists(modfile)) total_size += std::filesystem::file_size(modfile);
}
const bool compress = total_size > 400'000'000;
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));
futures.reserve(modfiles.size());
for (const auto& modfile : modfiles) {
futures.emplace_back(std::async(std::launch::async, ProcessModfile, modfile, compress));
}
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 {
auto loaded_size = 0ull;
for (size_t i = 0; i < modfiles.size(); ++i) {
auto texture_file_structs = futures[i].get();
std::lock_guard lk(global_mutex);
if (FindLoadedFile(modfiles[i]) != loaded_files.end()) {
for (const auto* texture_file_struct : texture_file_structs)
delete texture_file_struct;
}
continue;
}
auto hashes = IngestModfile(texture_file_structs, &loaded_size);
if (!hashes.empty()) {
loaded_files.push_back({modfiles[i], std::move(hashes)});
}
should_update = true;
}
Message("Finished loading mods from %s: Loaded %u bytes (%u mb)", source, loaded_size, loaded_size / 1024 / 1024);
Info("LoadStartupModlists: %llu bytes (%llu MB)\n", 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());
}
// AddFile() before the device existed recorded files but couldn't enqueue them
// (no client yet); enqueue them now.
for (const auto& path : GetFiles()) {
if (!std::filesystem::exists(path)) continue;
const auto file_size = std::filesystem::file_size(path);
auto texture_file_structs = ProcessModfile(path, file_size > 400'000'000);
IngestModfile(texture_file_structs);
}
LoadStartupModlists();
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;
}
+62 -99
View File
@@ -6,45 +6,7 @@ module;
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;
}
// clang-format off
constexpr auto crctab64 = std::to_array({
0x0000000000000000ULL, 0x7ad870c830358979ULL, 0xf5b0e190606b12f2ULL,
0x8f689158505e9b8bULL, 0xc038e5739841b68fULL, 0xbae095bba8743ff6ULL,
@@ -133,10 +95,12 @@ constexpr auto crctab64 = std::to_array({
0xa6df411fbfb21ca3ULL, 0xdc0731d78f8795daULL, 0x536fa08fdfd90e51ULL,
0x29b7d047efec8728ULL
});
// clang-format on
export namespace TextureFunction {
uint64_t get_crc64(const char* data, unsigned int length) {
uint64_t get_crc64(const char* data, unsigned int length)
{
uint64_t crc = 0xFFFFFFFFFFFFFFFFULL;
while (length--) {
@@ -146,7 +110,7 @@ export namespace TextureFunction {
return crc;
}
uint32_t get_crc32(const char* data_ptr, const int length)
uint32_t get_crc32(const char* data_ptr, const unsigned int length)
{
constexpr static auto crc32_poly = 0xEDB88320u;
constexpr static auto ul_crc_in = 0xffffffff;
@@ -162,7 +126,7 @@ export namespace TextureFunction {
int GetBitsFromFormat(D3DFORMAT format)
{
switch (format) //switch trough the formats to calculate the size of the raw data
switch (format) // switch trough the formats to calculate the size of the raw data
{
case D3DFMT_A1: // 1-bit monochrome.
{
@@ -170,75 +134,75 @@ export namespace TextureFunction {
}
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_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: // ??
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.
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_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 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_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;
@@ -257,7 +221,7 @@ export namespace TextureFunction {
case D3DFMT_DXT1: {
return 4;
}
default: //compressed formats
default: // compressed formats
{
return 4;
}
@@ -338,10 +302,10 @@ export namespace TextureFunction {
return compressed_image;
}
void ImageSave(const DirectX::ScratchImage& image, const TexEntry& entry, const std::filesystem::path& dll_path)
void ImageSave(const DirectX::ScratchImage& image, const TexEntry& entry)
{
const auto file_name = std::format("0x{:x}.dds", entry.crc_hash);
const auto file_out = dll_path / "textures" / file_name;
const auto file_out = gmod_dll_path.parent_path() / "textures" / file_name;
try {
if (std::filesystem::exists(file_out)) {
return;
@@ -361,11 +325,10 @@ export namespace TextureFunction {
}
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::Blob ConvertToCompressedDDS(TexEntry& entry, const bool compress)
{
DirectX::ScratchImage image;
HRESULT hr = 0;
@@ -407,9 +370,9 @@ export namespace TextureFunction {
return {};
}
#ifdef _DEBUG
ImageSave(compressed_image, entry, dll_path);
#endif
#ifdef _DEBUG
ImageSave(compressed_image, entry);
#endif
return dds_blob;
}
}
+611
View File
@@ -0,0 +1,611 @@
#include "Main.h"
#include "D3D9Hooks.h"
#include "MinHook.h"
#include <atomic>
#include <mutex>
#include <unordered_map>
#include <vector>
import TextureClient;
import TextureFunction;
import ModfileLoader; // HashCheck::Use64BitCrc
// Hooked vtable slot indices (frozen D3D9 ABI). Device9Ex shares Device9's prefix.
namespace {
// --- IDirect3D9 / IDirect3D9Ex --------------------------------------
constexpr int kIDirect3D9_CreateDevice = 16;
constexpr int kIDirect3D9Ex_CreateDeviceEx = 20;
// --- IDirect3DDevice9 -----------------------------------------------
constexpr int kDevice_Release = 2;
constexpr int kDevice_CreateTexture = 23;
constexpr int kDevice_CreateVolumeTexture = 24;
constexpr int kDevice_CreateCubeTexture = 25;
constexpr int kDevice_UpdateTexture = 31;
constexpr int kDevice_BeginScene = 41;
constexpr int kDevice_GetTexture = 64;
constexpr int kDevice_SetTexture = 65;
// --- IDirect3D*Texture9 (IUnknown layout) ---------------------------
constexpr int kResource_Release = 2;
// Bytes to flush from a hook target / trampoline so the x86-on-ARM64 emulator re-JITs
// it. Covers MinHook's max prologue patch and its 64-byte trampoline slot.
constexpr SIZE_T kFlushSpan = 64;
void** GetVTable(void* com_object)
{
return *static_cast<void***>(com_object);
}
// ---- trampolines to the real implementations -----------------------
using CreateDevice_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3D9*, UINT, D3DDEVTYPE, HWND, DWORD, D3DPRESENT_PARAMETERS*, IDirect3DDevice9**);
using CreateDeviceEx_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3D9Ex*, UINT, D3DDEVTYPE, HWND, DWORD, D3DPRESENT_PARAMETERS*, D3DDISPLAYMODEEX*, IDirect3DDevice9Ex**);
using DeviceRelease_t = ULONG(STDMETHODCALLTYPE*)(IDirect3DDevice9*);
using CreateTexture_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3DDevice9*, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DTexture9**, HANDLE*);
using CreateVolumeTexture_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3DDevice9*, UINT, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DVolumeTexture9**, HANDLE*);
using CreateCubeTexture_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3DDevice9*, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DCubeTexture9**, HANDLE*);
using UpdateTexture_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3DDevice9*, IDirect3DBaseTexture9*, IDirect3DBaseTexture9*);
using BeginScene_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3DDevice9*);
using SetTexture_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3DDevice9*, DWORD, IDirect3DBaseTexture9*);
using GetTexture_t = HRESULT(STDMETHODCALLTYPE*)(IDirect3DDevice9*, DWORD, IDirect3DBaseTexture9**);
using ResourceRelease_t = ULONG(STDMETHODCALLTYPE*)(IUnknown*);
CreateDevice_t o_CreateDevice = nullptr;
CreateDeviceEx_t o_CreateDeviceEx = nullptr;
DeviceRelease_t o_DeviceRelease = nullptr;
CreateTexture_t o_CreateTexture = nullptr;
CreateVolumeTexture_t o_CreateVolumeTexture = nullptr;
CreateCubeTexture_t o_CreateCubeTexture = nullptr;
UpdateTexture_t o_UpdateTexture = nullptr;
BeginScene_t o_BeginScene = nullptr;
SetTexture_t o_SetTexture = nullptr;
GetTexture_t o_GetTexture = nullptr;
ResourceRelease_t o_Tex2DRelease = nullptr;
ResourceRelease_t o_VolumeRelease = nullptr;
ResourceRelease_t o_CubeRelease = nullptr;
// A vtable is shared by every instance of its class, so each is hooked once.
bool g_d3d9_hooks_installed = false;
bool g_device_hooks_installed = false;
bool g_tex2d_release_installed = false;
bool g_volume_release_installed = false;
bool g_cube_release_installed = false;
std::vector<void*> g_hooked_targets;
// Set when teardown begins; a detour still reached after this just calls the original.
std::atomic<bool> g_unhooked{false};
// device -> owning TextureClient
std::mutex g_devices_mutex;
std::unordered_map<IDirect3DDevice9*, TextureClient*> g_devices;
TextureClient* ClientFor(IDirect3DDevice9* device)
{
std::lock_guard lk(g_devices_mutex);
const auto it = g_devices.find(device);
return it != g_devices.end() ? it->second : nullptr;
}
bool HookRaw(void* target, void* detour, void** original)
{
if (target == nullptr) return false;
if (MH_CreateHook(target, detour, original) != MH_OK) {
Warning("D3D9Hooks: MH_CreateHook failed for %p\n", target);
return false;
}
if (MH_EnableHook(target) != MH_OK) {
Warning("D3D9Hooks: MH_EnableHook failed for %p\n", target);
return false;
}
// Under the x86-on-ARM64 emulator, patched code is only re-translated when its
// instruction cache is flushed. MinHook flushes just the 5 patched bytes, which can
// leave a stale/guarded JIT block and trap; flush the whole prologue and the freshly
// built trampoline so the emulator re-JITs both. No-op on native x86.
const HANDLE proc = GetCurrentProcess();
FlushInstructionCache(proc, target, kFlushSpan);
if (original && *original) FlushInstructionCache(proc, *original, kFlushSpan);
g_hooked_targets.push_back(target);
return true;
}
// Funnels the fn-ptr <-> void* casts through one spot so call sites stay /WX-clean.
template <typename TDetour, typename TOrig>
bool Hook(void* target, TDetour detour, TOrig* original)
{
return HookRaw(target, reinterpret_cast<void*>(detour), reinterpret_cast<void**>(original));
}
HRESULT STDMETHODCALLTYPE h_CreateDevice(IDirect3D9*, UINT, D3DDEVTYPE, HWND, DWORD, D3DPRESENT_PARAMETERS*, IDirect3DDevice9**);
HRESULT STDMETHODCALLTYPE h_CreateDeviceEx(IDirect3D9Ex*, UINT, D3DDEVTYPE, HWND, DWORD, D3DPRESENT_PARAMETERS*, D3DDISPLAYMODEEX*, IDirect3DDevice9Ex**);
ULONG STDMETHODCALLTYPE h_DeviceRelease(IDirect3DDevice9*);
HRESULT STDMETHODCALLTYPE h_CreateTexture(IDirect3DDevice9*, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DTexture9**, HANDLE*);
HRESULT STDMETHODCALLTYPE h_CreateVolumeTexture(IDirect3DDevice9*, UINT, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DVolumeTexture9**, HANDLE*);
HRESULT STDMETHODCALLTYPE h_CreateCubeTexture(IDirect3DDevice9*, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, IDirect3DCubeTexture9**, HANDLE*);
HRESULT STDMETHODCALLTYPE h_UpdateTexture(IDirect3DDevice9*, IDirect3DBaseTexture9*, IDirect3DBaseTexture9*);
HRESULT STDMETHODCALLTYPE h_BeginScene(IDirect3DDevice9*);
HRESULT STDMETHODCALLTYPE h_SetTexture(IDirect3DDevice9*, DWORD, IDirect3DBaseTexture9*);
HRESULT STDMETHODCALLTYPE h_GetTexture(IDirect3DDevice9*, DWORD, IDirect3DBaseTexture9**);
ULONG STDMETHODCALLTYPE h_Tex2DRelease(IUnknown*);
ULONG STDMETHODCALLTYPE h_VolumeRelease(IUnknown*);
ULONG STDMETHODCALLTYPE h_CubeRelease(IUnknown*);
void InstallDeviceHooks(IDirect3DDevice9* device)
{
if (g_device_hooks_installed) return;
void** vt = GetVTable(device);
Hook(vt[kDevice_Release], &h_DeviceRelease, reinterpret_cast<void**>(&o_DeviceRelease));
Hook(vt[kDevice_CreateTexture], &h_CreateTexture, reinterpret_cast<void**>(&o_CreateTexture));
Hook(vt[kDevice_CreateVolumeTexture], &h_CreateVolumeTexture, reinterpret_cast<void**>(&o_CreateVolumeTexture));
Hook(vt[kDevice_CreateCubeTexture], &h_CreateCubeTexture, reinterpret_cast<void**>(&o_CreateCubeTexture));
Hook(vt[kDevice_UpdateTexture], &h_UpdateTexture, reinterpret_cast<void**>(&o_UpdateTexture));
Hook(vt[kDevice_BeginScene], &h_BeginScene, reinterpret_cast<void**>(&o_BeginScene));
Hook(vt[kDevice_GetTexture], &h_GetTexture, reinterpret_cast<void**>(&o_GetTexture));
Hook(vt[kDevice_SetTexture], &h_SetTexture, reinterpret_cast<void**>(&o_SetTexture));
g_device_hooks_installed = true;
}
// A texture vtable is reachable only via an instance, so hook Release lazily per kind.
void InstallTextureReleaseHook(void* sample_texture, TexType type)
{
void** vt = GetVTable(sample_texture);
switch (type) {
case TexType::Tex2D:
if (!g_tex2d_release_installed && Hook(vt[kResource_Release], &h_Tex2DRelease, reinterpret_cast<void**>(&o_Tex2DRelease)))
g_tex2d_release_installed = true;
break;
case TexType::Volume:
if (!g_volume_release_installed && Hook(vt[kResource_Release], &h_VolumeRelease, reinterpret_cast<void**>(&o_VolumeRelease)))
g_volume_release_installed = true;
break;
case TexType::Cube:
if (!g_cube_release_installed && Hook(vt[kResource_Release], &h_CubeRelease, reinterpret_cast<void**>(&o_CubeRelease)))
g_cube_release_installed = true;
break;
}
}
void OnDeviceCreated(IDirect3DDevice9* device)
{
if (device == nullptr) return;
TextureClient* client = nullptr;
{
// Lock spans check+install+create so racing callers can't double-register.
std::lock_guard lk(g_devices_mutex);
if (g_devices.contains(device)) return;
InstallDeviceHooks(device);
client = new TextureClient(device);
g_devices.emplace(device, client);
}
client->Initialize();
}
HRESULT STDMETHODCALLTYPE h_CreateDevice(IDirect3D9* self, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface)
{
const HRESULT hr = o_CreateDevice(self, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
if (g_unhooked) return hr;
if (SUCCEEDED(hr) && ppReturnedDeviceInterface && *ppReturnedDeviceInterface) {
OnDeviceCreated(*ppReturnedDeviceInterface);
}
return hr;
}
HRESULT STDMETHODCALLTYPE h_CreateDeviceEx(IDirect3D9Ex* self, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode, IDirect3DDevice9Ex** ppReturnedDeviceInterface)
{
const HRESULT hr = o_CreateDeviceEx(self, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode, ppReturnedDeviceInterface);
if (g_unhooked) return hr;
if (SUCCEEDED(hr) && ppReturnedDeviceInterface && *ppReturnedDeviceInterface) {
OnDeviceCreated(*ppReturnedDeviceInterface);
}
return hr;
}
ULONG STDMETHODCALLTYPE h_DeviceRelease(IDirect3DDevice9* self)
{
const ULONG count = o_DeviceRelease(self);
if (g_unhooked) return count;
if (count == 0) {
TextureClient* client = nullptr;
{
std::lock_guard lk(g_devices_mutex);
const auto it = g_devices.find(self);
if (it != g_devices.end()) {
client = it->second;
g_devices.erase(it);
}
}
delete client; // ~TextureClient drops all side-state
}
return count;
}
HRESULT STDMETHODCALLTYPE h_CreateTexture(IDirect3DDevice9* self, UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle)
{
const HRESULT hr = o_CreateTexture(self, Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
if (g_unhooked) return hr;
if (SUCCEEDED(hr) && ppTexture && *ppTexture) {
InstallTextureReleaseHook(*ppTexture, TexType::Tex2D);
if (auto* client = ClientFor(self))
client->OnCreateTexture(static_cast<IDirect3DBaseTexture9*>(*ppTexture), TexType::Tex2D);
}
return hr;
}
HRESULT STDMETHODCALLTYPE h_CreateVolumeTexture(IDirect3DDevice9* self, UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle)
{
const HRESULT hr = o_CreateVolumeTexture(self, Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
if (g_unhooked) return hr;
if (SUCCEEDED(hr) && ppVolumeTexture && *ppVolumeTexture) {
InstallTextureReleaseHook(*ppVolumeTexture, TexType::Volume);
if (auto* client = ClientFor(self))
client->OnCreateTexture(static_cast<IDirect3DBaseTexture9*>(*ppVolumeTexture), TexType::Volume);
}
return hr;
}
HRESULT STDMETHODCALLTYPE h_CreateCubeTexture(IDirect3DDevice9* self, UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle)
{
const HRESULT hr = o_CreateCubeTexture(self, EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
if (g_unhooked) return hr;
if (SUCCEEDED(hr) && ppCubeTexture && *ppCubeTexture) {
InstallTextureReleaseHook(*ppCubeTexture, TexType::Cube);
if (auto* client = ClientFor(self))
client->OnCreateTexture(static_cast<IDirect3DBaseTexture9*>(*ppCubeTexture), TexType::Cube);
}
return hr;
}
HRESULT STDMETHODCALLTYPE h_UpdateTexture(IDirect3DDevice9* self, IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture)
{
// Pass the real textures through, then re-evaluate mods on the changed destination.
const HRESULT hr = o_UpdateTexture(self, pSourceTexture, pDestinationTexture);
if (g_unhooked) return hr;
if (SUCCEEDED(hr)) {
if (auto* client = ClientFor(self))
client->OnUpdateTexture(pSourceTexture, pDestinationTexture);
}
return hr;
}
HRESULT STDMETHODCALLTYPE h_BeginScene(IDirect3DDevice9* self)
{
if (g_unhooked) return o_BeginScene(self);
if (auto* client = ClientFor(self))
client->OnBeginScene();
return o_BeginScene(self);
}
HRESULT STDMETHODCALLTYPE h_SetTexture(IDirect3DDevice9* self, DWORD Stage, IDirect3DBaseTexture9* pTexture)
{
if (g_unhooked) return o_SetTexture(self, Stage, pTexture);
IDirect3DBaseTexture9* bind = pTexture;
if (auto* client = ClientFor(self))
bind = client->ResolveBinding(pTexture); // substitute the fake when modded
return o_SetTexture(self, Stage, bind);
}
HRESULT STDMETHODCALLTYPE h_GetTexture(IDirect3DDevice9* self, DWORD Stage, IDirect3DBaseTexture9** ppTexture)
{
const HRESULT hr = o_GetTexture(self, Stage, ppTexture);
if (g_unhooked) return hr;
if (SUCCEEDED(hr) && ppTexture && *ppTexture) {
if (auto* client = ClientFor(self)) {
if (auto* original = client->ResolveOriginalFromFake(*ppTexture)) {
(*ppTexture)->Release(); // drop the fake reference the runtime handed back
original->AddRef(); // return the original the game set, with a matching ref
*ppTexture = original;
}
}
}
return hr;
}
void ReleaseTextureCleanup(IUnknown* self, ULONG count)
{
if (count != 0) return;
if (auto* client = TextureClient::CurrentClient())
client->OnReleaseTexture(reinterpret_cast<IDirect3DBaseTexture9*>(self));
}
ULONG STDMETHODCALLTYPE h_Tex2DRelease(IUnknown* self)
{
const ULONG count = o_Tex2DRelease(self);
if (g_unhooked) return count;
ReleaseTextureCleanup(self, count);
return count;
}
ULONG STDMETHODCALLTYPE h_VolumeRelease(IUnknown* self)
{
const ULONG count = o_VolumeRelease(self);
if (g_unhooked) return count;
ReleaseTextureCleanup(self, count);
return count;
}
ULONG STDMETHODCALLTYPE h_CubeRelease(IUnknown* self)
{
const ULONG count = o_CubeRelease(self);
if (g_unhooked) return count;
ReleaseTextureCleanup(self, count);
return count;
}
}
void InstallD3D9Hooks(IDirect3D9* d3d9, const bool is_ex)
{
if (d3d9 == nullptr || g_d3d9_hooks_installed) return;
g_unhooked = false; // re-arm in case a prior teardown left the flag set
void** vt = GetVTable(d3d9);
Hook(vt[kIDirect3D9_CreateDevice], &h_CreateDevice, reinterpret_cast<void**>(&o_CreateDevice));
if (is_ex) {
Hook(vt[kIDirect3D9Ex_CreateDeviceEx], &h_CreateDeviceEx, reinterpret_cast<void**>(&o_CreateDeviceEx));
}
g_d3d9_hooks_installed = true;
}
bool RegisterExistingDevice(IDirect3DDevice9* device)
{
if (device == nullptr) return false;
{
std::lock_guard lk(g_devices_mutex);
if (g_devices.contains(device)) return false; // already known
if (!g_devices.empty()) return false; // gMod supports a single device at a time
}
g_unhooked = false; // re-arm in case a prior teardown left the flag set
OnDeviceCreated(device); // installs device hooks + TextureClient (idempotent)
return ClientFor(device) != nullptr;
}
void RemoveAllD3D9Hooks()
{
// Signal first: a detour reached after this (e.g. a surviving patch) falls through.
g_unhooked = true;
const HANDLE proc = GetCurrentProcess();
for (void* target : g_hooked_targets) {
MH_DisableHook(target);
MH_RemoveHook(target);
FlushInstructionCache(proc, target, kFlushSpan); // re-JIT the restored prologue under emulation
}
g_hooked_targets.clear();
g_d3d9_hooks_installed = false;
g_device_hooks_installed = false;
g_tex2d_release_installed = false;
g_volume_release_installed = false;
g_cube_release_installed = false;
// Leave the o_* trampoline pointers intact so a surviving detour can still call through.
}
void DestroyAllTextureClients()
{
// Collect under the lock, delete outside it (~TextureClient takes its own locks).
std::vector<TextureClient*> clients;
{
std::lock_guard lk(g_devices_mutex);
for (const auto& entry : g_devices) {
clients.push_back(entry.second);
}
g_devices.clear();
}
for (auto* client : clients) {
delete client;
}
}
// All three read state->real directly; gMod never swaps the underlying resource.
namespace {
HashTuple HashBits(const void* bits, const int size)
{
const auto data = static_cast<const char*>(bits);
const auto crc32 = TextureFunction::get_crc32(data, size);
const auto crc64 = HashCheck::Use64BitCrc() ? TextureFunction::get_crc64(data, size) : 0;
return {crc32, crc64};
}
HashTuple HashTexture2D(const TexState* state)
{
const auto pTexture = static_cast<IDirect3DTexture9*>(state->real);
IDirect3DDevice9* device = state->device;
IDirect3DSurface9* pOffscreenSurface = nullptr;
IDirect3DSurface9* pResolvedSurface = nullptr;
D3DLOCKED_RECT d3dlr;
D3DSURFACE_DESC desc;
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) {
Warning("GetTextureHash(2D) Failed: GetLevelDesc\n");
return {};
}
if (desc.Pool == D3DPOOL_DEFAULT) {
IDirect3DSurface9* pSurfaceLevel_orig = nullptr;
if (pTexture->GetSurfaceLevel(0, &pSurfaceLevel_orig) != D3D_OK) {
Warning("GetTextureHash(2D) Failed: GetSurfaceLevel 1 (D3DPOOL_DEFAULT)\n");
return {};
}
// The surface GetRenderTargetData reads from: either the level itself, or a
// non-multisampled resolve of it. Non-owning; pSurfaceLevel_orig and
// pResolvedSurface each own a ref and are released exactly once below.
IDirect3DSurface9* pCopySource = pSurfaceLevel_orig;
if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) {
if (D3D_OK != device->CreateRenderTarget(desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pResolvedSurface, nullptr)) {
pSurfaceLevel_orig->Release();
Warning("GetTextureHash(2D) Failed: CreateRenderTarget (D3DPOOL_DEFAULT)\n");
return {};
}
if (D3D_OK != device->StretchRect(pSurfaceLevel_orig, nullptr, pResolvedSurface, nullptr, D3DTEXF_NONE)) {
pResolvedSurface->Release();
pResolvedSurface = nullptr;
pSurfaceLevel_orig->Release();
Warning("GetTextureHash(2D) Failed: StretchRect (D3DPOOL_DEFAULT)\n");
return {};
}
pCopySource = pResolvedSurface;
}
if (D3D_OK != device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &pOffscreenSurface, nullptr)) {
if (pResolvedSurface != nullptr) pResolvedSurface->Release();
pSurfaceLevel_orig->Release();
Warning("GetTextureHash(2D) Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
return {};
}
if (D3D_OK != device->GetRenderTargetData(pCopySource, pOffscreenSurface)) {
pOffscreenSurface->Release();
if (pResolvedSurface != nullptr) pResolvedSurface->Release();
pSurfaceLevel_orig->Release();
Warning("GetTextureHash(2D) Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
return {};
}
// Copy is done; both source surfaces are finished with. Null pResolvedSurface
// so the shared cleanup below treats this as the pOffscreenSurface case.
if (pResolvedSurface != nullptr) {
pResolvedSurface->Release();
pResolvedSurface = nullptr;
}
pSurfaceLevel_orig->Release();
if (pOffscreenSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pOffscreenSurface->Release();
Warning("GetTextureHash(2D) Failed: LockRect (D3DPOOL_DEFAULT)\n");
return {};
}
}
else if (pTexture->LockRect(0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
Warning("GetTextureHash(2D) Failed: LockRect 1\n");
if (pTexture->GetSurfaceLevel(0, &pResolvedSurface) != D3D_OK) {
Warning("GetTextureHash(2D) Failed: GetSurfaceLevel\n");
return {};
}
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Warning("GetTextureHash(2D) Failed: LockRect 2\n");
return {};
}
}
const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8;
const auto hash = HashBits(d3dlr.pBits, size);
if (pOffscreenSurface != nullptr) {
pOffscreenSurface->UnlockRect();
pOffscreenSurface->Release();
}
else if (pResolvedSurface != nullptr) {
pResolvedSurface->UnlockRect();
pResolvedSurface->Release();
}
else {
pTexture->UnlockRect(0);
}
return hash;
}
HashTuple HashVolume(const TexState* state)
{
const auto pTexture = static_cast<IDirect3DVolumeTexture9*>(state->real);
IDirect3DVolume9* pResolvedSurface = nullptr;
D3DLOCKED_BOX d3dlr;
D3DVOLUME_DESC desc;
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) {
Warning("GetTextureHash(Volume) Failed: GetLevelDesc\n");
return {};
}
if (pTexture->LockBox(0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
if (pTexture->GetVolumeLevel(0, &pResolvedSurface) != D3D_OK) {
Warning("GetTextureHash(Volume) Failed: GetVolumeLevel\n");
return {};
}
if (pResolvedSurface->LockBox(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Warning("GetTextureHash(Volume) Failed: LockBox\n");
return {};
}
}
const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height * desc.Depth) / 8;
const auto hash = HashBits(d3dlr.pBits, size);
if (pResolvedSurface != nullptr) {
pResolvedSurface->UnlockBox();
pResolvedSurface->Release();
}
else {
pTexture->UnlockBox(0);
}
return hash;
}
HashTuple HashCube(const TexState* state)
{
const auto pTexture = static_cast<IDirect3DCubeTexture9*>(state->real);
IDirect3DSurface9* pResolvedSurface = nullptr;
D3DLOCKED_RECT d3dlr;
D3DSURFACE_DESC desc;
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) {
Warning("GetTextureHash(Cube) Failed: GetLevelDesc\n");
return {};
}
if (pTexture->LockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
if (pTexture->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_X, 0, &pResolvedSurface) != D3D_OK) {
Warning("GetTextureHash(Cube) Failed: GetCubeMapSurface\n");
return {};
}
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Warning("GetTextureHash(Cube) Failed: LockRect\n");
return {};
}
}
const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8;
const auto hash = HashBits(d3dlr.pBits, size);
if (pResolvedSurface != nullptr) {
pResolvedSurface->UnlockRect();
pResolvedSurface->Release();
}
else {
pTexture->UnlockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0);
}
return hash;
}
}
HashTuple GetTextureHash(const TexState* state)
{
if (state == nullptr || state->real == nullptr || state->isFake) return {};
switch (state->type) {
case TexType::Tex2D: return HashTexture2D(state);
case TexType::Volume: return HashVolume(state);
case TexType::Cube: return HashCube(state);
}
return {};
}
+6 -6
View File
@@ -6,22 +6,22 @@
#include <Main.h>
__declspec(noreturn) void FatalAssert(
const char *expr,
const char *file,
unsigned int line,
const char *function)
const char* expr,
const char* file,
unsigned int line,
const char* function)
{
char module_path[MAX_PATH]{};
if (gl_hThisInstance) {
GetModuleFileName(gl_hThisInstance, module_path, _countof(module_path));
}
if (!*module_path) {
strcpy(module_path, "Unknown");
strcpy_s(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, module_path, expr, file, function, line);
snprintf(buf, len + 1, fmt, module_path, expr, file, function, line);
MessageBox(0, buf, "uMod Assertion Failure", MB_OK | MB_ICONERROR);
+144 -25
View File
@@ -1,15 +1,20 @@
#include "Main.h"
#include <Psapi.h>
#include "MinHook.h"
#include "D3D9Hooks.h"
#include <atomic>
void ExitInstance();
import TextureClient;
void ExitInstance(bool is_unloading);
void InitInstance(HINSTANCE hModule);
namespace {
#define DISABLE_HOOK(var) if(var) { MH_DisableHook(var);}
#define DISABLE_HOOK(var) \
if (var) { MH_DisableHook(var); }
using Direct3DCreate9_type = IDirect3D9* (APIENTRY*)(UINT);
using Direct3DCreate9_type = IDirect3D9*(APIENTRY*)(UINT);
using Direct3DCreate9Ex_type = HRESULT(APIENTRY*)(UINT SDKVersion, IDirect3D9Ex** ppD3D);
using GetProcAddress_type = FARPROC(APIENTRY*)(HMODULE, LPCSTR);
@@ -44,7 +49,7 @@ namespace {
TCHAR szModuleName[MAX_PATH];
ASSERT(GetModuleFileName(hModules[i], szModuleName, _countof(szModuleName)) > 0);
const auto basename = strrchr(szModuleName, '\\');
if (basename && stricmp(basename + 1, name) == 0)
if (basename && _stricmp(basename + 1, name) == 0)
return hModules[i];
}
return nullptr;
@@ -63,15 +68,14 @@ namespace {
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") {
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
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");
@@ -139,12 +143,14 @@ IDirect3D9* APIENTRY Direct3DCreate9(UINT SDKVersion)
DISABLE_HOOK(GetProcAddress_fn);
CheckLoadD3d9Dll();
IDirect3D9* pIDirect3D9_orig = Direct3DCreate9_ret(SDKVersion); //creating the original IDirect3D9 object
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"
// Hook the vtable and hand the game back the real object untouched.
InstallD3D9Hooks(pIDirect3D9_orig, false);
return pIDirect3D9_orig;
}
HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D)
@@ -159,30 +165,27 @@ HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D)
CheckLoadD3d9Dll();
IDirect3D9Ex* pIDirect3D9Ex_orig = nullptr;
HRESULT ret = Direct3DCreate9Ex_ret(SDKVersion, &pIDirect3D9Ex_orig); //creating the original IDirect3D9 object
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);
// Hook the vtable (CreateDevice + CreateDeviceEx) and return the real object untouched.
InstallD3D9Hooks(pIDirect3D9Ex_orig, true);
*ppD3D = pIDirect3D9Ex_orig;
return ret;
}
/*
* dll entry routine, here we initialize or clean up
*/
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(lpReserved);
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
#ifdef _DEBUG
wchar_t dllFilePath[512 + 1]{};
GetModuleFileNameW(hModule, dllFilePath, 512);
gmod_dll_path = dllFilePath;
AllocConsole();
SetConsoleTitleA("gMod Console");
freopen_s(&stdout_proxy, "CONOUT$", "w", stdout);
@@ -192,7 +195,12 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
break;
}
case DLL_PROCESS_DETACH: {
ExitInstance();
// Process exit (lpReserved != nullptr): other threads are gone and the OS
// reclaims everything, so touching MinHook/the device here only risks a hang.
if (lpReserved != nullptr)
break;
// FreeLibrary unload: the device is still live, so tear down cleanly.
ExitInstance(true);
break;
}
default: break;
@@ -201,17 +209,40 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
return true;
}
void LoadModlists()
{
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_path = std::filesystem::path(gwpath).parent_path();
const auto 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());
std::ifstream t(modlist, std::ios::binary);
std::stringstream buffer;
buffer << t.rdbuf();
modlists_contents.emplace_back(modlist.string(), buffer.str());
}
}
}
void InitInstance(HINSTANCE hModule)
{
Message("InitInstance: %p\n", hModule);
DisableThreadLibraryCalls(hModule); //reduce overhead
// Store the handle to this module
gl_hThisInstance = hModule;
LoadModlists();
DisableThreadLibraryCalls(hModule); // reduce overhead
// d3d9.dll shouldn't be loaded at this point.
const auto d3d9_loaded = FindLoadedModuleByName("d3d9.dll");
//ASSERT(!d3d9_loaded);
[[maybe_unused]] const auto d3d9_loaded = FindLoadedModuleByName("d3d9.dll");
// ASSERT(!d3d9_loaded);
MH_Initialize();
@@ -221,13 +252,100 @@ void InitInstance(HINSTANCE hModule)
if (GetProcAddress_fn) {
MH_CreateHook(GetProcAddress_fn, OnGetProcAddress, (void**)&GetProcAddress_ret);
MH_EnableHook(GetProcAddress_fn);
// Re-JIT the patched prologue + trampoline under the x86-on-ARM64 emulator (no-op native).
const HANDLE proc = GetCurrentProcess();
FlushInstructionCache(proc, (void*)GetProcAddress_fn, 64);
if (GetProcAddress_ret) FlushInstructionCache(proc, (void*)GetProcAddress_ret, 64);
}
}
void ExitInstance()
// Exported entry for late injection: hand gMod an existing device so it hooks
// the vtable and mods textures from here on.
extern "C" __declspec(dllexport) int __cdecl SetDevice(IDirect3DDevice9* device)
{
if (!device) return RETURN_BAD_ARGUMENT;
try {
return RegisterExistingDevice(device) ? RETURN_OK : RETURN_EXISTS;
}
catch (...) {
return RETURN_FATAL_ERROR;
}
}
extern "C" __declspec(dllexport) int __cdecl AddFile(const wchar_t* path)
{
if (!path) return RETURN_BAD_ARGUMENT;
try {
return TextureClient::AddFile(std::filesystem::path(path));
}
catch (...) {
return RETURN_FATAL_ERROR;
}
}
extern "C" __declspec(dllexport) int __cdecl RemoveFile(const wchar_t* path)
{
if (!path) return RETURN_BAD_ARGUMENT;
try {
return TextureClient::RemoveFile(std::filesystem::path(path));
}
catch (...) {
return RETURN_FATAL_ERROR;
}
}
// nullptr first arg = return required size; paths come back in load (priority) order
// returns paths separated by null terminator, e.g. "C:\foo.tpf\0C:\bar.zip\0\0"
extern "C" __declspec(dllexport) int __cdecl GetFiles(wchar_t* buffer, const size_t buffer_size_chars)
{
try {
const auto files = TextureClient::GetFiles();
size_t required = 1;
for (const auto& path : files) {
required += path.native().size() + 1;
}
if (buffer && buffer_size_chars > 0 && buffer_size_chars >= required) {
wchar_t* out = buffer;
for (const auto& path : files) {
const auto& native = path.native();
std::ranges::copy(native, out);
out += native.size();
*out++ = L'\0';
}
*out = L'\0';
}
return static_cast<int>(required);
}
catch (...) {
return RETURN_FATAL_ERROR;
}
}
// Optional clean-shutdown entry: call this from the host (on a normal thread) BEFORE
// FreeLibrary so teardown runs off the loader lock, where MinHook can safely suspend
// the render thread. A later FreeLibrary then unloads with nothing left to undo.
extern "C" __declspec(dllexport) void __cdecl Shutdown()
{
ExitInstance(true);
}
void ExitInstance(bool is_unloading)
{
// Teardown must run exactly once, whether reached via Shutdown() or DllMain detach.
static std::atomic<bool> torn_down{false};
if (torn_down.exchange(true)) return;
DISABLE_HOOK(GetProcAddress_fn);
// Revert every D3D9 vtable hook so the original objects are left pristine.
RemoveAllD3D9Hooks();
// On a real unload the device is still alive; release our replacement textures.
if (is_unloading) {
DestroyAllTextureClients();
}
MH_Uninitialize();
if (gMod_Loaded_d3d9_Module_Handle)
@@ -241,6 +359,7 @@ void ExitInstance()
__try {
FreeConsole();
}
__except (EXCEPTION_CONTINUE_EXECUTION) { }
__except (EXCEPTION_CONTINUE_EXECUTION) {
}
#endif
}
-134
View File
@@ -1,134 +0,0 @@
#include "Main.h"
#ifndef PRE_MESSAGE
#define PRE_MESSAGE "uMod_IDirect3D9"
#endif
uMod_IDirect3D9::uMod_IDirect3D9(IDirect3D9* pOriginal)
{
Message(PRE_MESSAGE "::" PRE_MESSAGE " (%p): %p\n", pOriginal, this);
m_pIDirect3D9 = pOriginal;
}
uMod_IDirect3D9::~uMod_IDirect3D9()
{
Message(PRE_MESSAGE "::~" PRE_MESSAGE "(): %p\n", this);
}
HRESULT __stdcall uMod_IDirect3D9::QueryInterface(REFIID riid, void** ppvObj)
{
*ppvObj = nullptr;
// call this to increase AddRef at original object
// and to check if such an interface is there
const HRESULT hRes = m_pIDirect3D9->QueryInterface(riid, ppvObj);
if (hRes == NOERROR) // if OK, send our "fake" address
{
*ppvObj = this;
}
return hRes;
}
ULONG __stdcall uMod_IDirect3D9::AddRef()
{
return m_pIDirect3D9->AddRef();
}
ULONG __stdcall uMod_IDirect3D9::Release()
{
// call original routine
const ULONG count = m_pIDirect3D9->Release();
// in case no further Ref is there, the Original Object has deleted itself
if (count == 0) {
delete this;
}
return count;
}
HRESULT __stdcall uMod_IDirect3D9::RegisterSoftwareDevice(void* pInitializeFunction)
{
return m_pIDirect3D9->RegisterSoftwareDevice(pInitializeFunction);
}
UINT __stdcall uMod_IDirect3D9::GetAdapterCount()
{
return m_pIDirect3D9->GetAdapterCount();
}
HRESULT __stdcall uMod_IDirect3D9::GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier)
{
return m_pIDirect3D9->GetAdapterIdentifier(Adapter, Flags, pIdentifier);
}
UINT __stdcall uMod_IDirect3D9::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format)
{
return m_pIDirect3D9->GetAdapterModeCount(Adapter, Format);
}
HRESULT __stdcall uMod_IDirect3D9::EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode)
{
return m_pIDirect3D9->EnumAdapterModes(Adapter, Format, Mode, pMode);
}
HRESULT __stdcall uMod_IDirect3D9::GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode)
{
return m_pIDirect3D9->GetAdapterDisplayMode(Adapter, pMode);
}
HRESULT __stdcall uMod_IDirect3D9::CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed)
{
return m_pIDirect3D9->CheckDeviceType(iAdapter, DevType, DisplayFormat, BackBufferFormat, bWindowed);
}
HRESULT __stdcall uMod_IDirect3D9::CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat)
{
return m_pIDirect3D9->CheckDeviceFormat(Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat);
}
HRESULT __stdcall uMod_IDirect3D9::CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels)
{
return m_pIDirect3D9->CheckDeviceMultiSampleType(Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, pQualityLevels);
}
HRESULT __stdcall uMod_IDirect3D9::CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat)
{
return m_pIDirect3D9->CheckDepthStencilMatch(Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat);
}
HRESULT __stdcall uMod_IDirect3D9::CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat)
{
return m_pIDirect3D9->CheckDeviceFormatConversion(Adapter, DeviceType, SourceFormat, TargetFormat);
}
HRESULT __stdcall uMod_IDirect3D9::GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps)
{
return m_pIDirect3D9->GetDeviceCaps(Adapter, DeviceType, pCaps);
}
HMONITOR __stdcall uMod_IDirect3D9::GetAdapterMonitor(UINT Adapter)
{
return m_pIDirect3D9->GetAdapterMonitor(Adapter);
}
HRESULT __stdcall uMod_IDirect3D9::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface)
{
Message(PRE_MESSAGE "::CreateDevice(): %p\n", this);
// we intercept this call and provide our own "fake" Device Object
const HRESULT hres = m_pIDirect3D9->CreateDevice(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
int count = 1;
if (pPresentationParameters != nullptr) {
count = pPresentationParameters->BackBufferCount;
}
const auto pIDirect3DDevice9 = new uMod_IDirect3DDevice9(*ppReturnedDeviceInterface, count);
// store our pointer (the fake one) for returning it to the calling program
*ppReturnedDeviceInterface = pIDirect3DDevice9;
return hres;
}
-48
View File
@@ -1,48 +0,0 @@
#include "Main.h"
#define IDirect3D9 IDirect3D9Ex
#define uMod_IDirect3D9 uMod_IDirect3D9Ex
#define m_pIDirect3D9 m_pIDirect3D9Ex
#define PRE_MESSAGE "uMod_IDirect3D9Ex"
// ReSharper disable once CppUnusedIncludeDirective
#include "uMod_IDirect3D9.cpp"
HRESULT __stdcall uMod_IDirect3D9Ex::CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode,
IDirect3DDevice9Ex** ppReturnedDeviceInterface)
{
Message("uMod_IDirect3D9Ex::CreateDeviceEx: %p\n", this);
// we intercept this call and provide our own "fake" Device Object
const HRESULT hres = m_pIDirect3D9Ex->CreateDeviceEx(Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, pFullscreenDisplayMode, ppReturnedDeviceInterface);
int count = 1;
if (pPresentationParameters != nullptr) {
count = pPresentationParameters->BackBufferCount;
}
const auto pIDirect3DDevice9Ex = new uMod_IDirect3DDevice9Ex(*ppReturnedDeviceInterface, count);
// store our pointer (the fake one) for returning it to the calling program
*ppReturnedDeviceInterface = pIDirect3DDevice9Ex;
return hres;
}
HRESULT __stdcall uMod_IDirect3D9Ex::EnumAdapterModesEx(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter, UINT Mode, D3DDISPLAYMODEEX* pMode)
{
return m_pIDirect3D9Ex->EnumAdapterModesEx(Adapter, pFilter, Mode, pMode);
}
HRESULT __stdcall uMod_IDirect3D9Ex::GetAdapterDisplayModeEx(UINT Adapter, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation)
{
return m_pIDirect3D9Ex->GetAdapterDisplayModeEx(Adapter, pMode, pRotation);
}
HRESULT __stdcall uMod_IDirect3D9Ex::GetAdapterLUID(UINT Adapter, LUID* pLUID)
{
return m_pIDirect3D9Ex->GetAdapterLUID(Adapter, pLUID);
}
UINT __stdcall uMod_IDirect3D9Ex::GetAdapterModeCountEx(UINT Adapter, const D3DDISPLAYMODEFILTER* pFilter)
{
return m_pIDirect3D9Ex->GetAdapterModeCountEx(Adapter, pFilter);
}
-283
View File
@@ -1,283 +0,0 @@
#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)
{
if (riid == IID_IDirect3D9) {
// This function should never be called with IID_IDirect3D9 by the game
// thus this call comes from our own dll to ask for the texture type
// 0x01000000L == uMod_IDirect3DTexture9
// 0x01000001L == uMod_IDirect3DVolumeTexture9
// 0x01000002L == uMod_IDirect3DCubeTexture9
*ppvObj = this;
return 0x01000002L;
}
HRESULT hRes;
if (CrossRef_D3Dtex != nullptr) {
hRes = CrossRef_D3Dtex->m_D3Dtex->QueryInterface(riid, ppvObj);
if (*ppvObj == CrossRef_D3Dtex->m_D3Dtex) {
*ppvObj = this;
}
}
else {
hRes = m_D3Dtex->QueryInterface(riid, ppvObj);
if (*ppvObj == m_D3Dtex) {
*ppvObj = this;
}
}
return hRes;
}
//this function yields for the non switched texture object
ULONG APIENTRY uMod_IDirect3DCubeTexture9::AddRef()
{
if (FAKE) {
return 1; //bug, this case should never happen
}
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->AddRef();
}
return m_D3Dtex->AddRef();
}
//this function yields for the non switched texture object
ULONG APIENTRY uMod_IDirect3DCubeTexture9::Release()
{
Message("uMod_IDirect3DCubeTexture9::Release(): %p\n", this);
void* cpy;
const long ret = m_D3Ddev->QueryInterface(IID_IDirect3DTexture9, &cpy);
ULONG count;
if (FAKE) {
UnswitchTextures(this);
count = m_D3Dtex->Release(); //count must be zero, cause we don't call AddRef of fake_textures
}
else {
if (CrossRef_D3Dtex != nullptr) //if this texture is switched with a fake texture
{
uMod_IDirect3DCubeTexture9* fake_texture = CrossRef_D3Dtex;
count = fake_texture->m_D3Dtex->Release(); //release the original texture
if (count == 0) //if texture is released we switch the textures back
{
UnswitchTextures(this);
fake_texture->Release(); // we release the fake texture
}
}
else {
count = m_D3Dtex->Release();
}
}
if (count == 0) //if this texture is released, we clean up
{
// if this texture is the LastCreatedTexture, the next time LastCreatedTexture would be added,
// the hash of a non existing texture would be calculated
if (ret == 0x01000000L) {
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetLastCreatedCubeTexture() == this) {
static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->SetLastCreatedCubeTexture(nullptr);
}
else {
static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetuMod_Client()->RemoveTexture(this); // remove this texture from the texture client
}
}
else {
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetLastCreatedCubeTexture() == this) {
static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->SetLastCreatedCubeTexture(nullptr);
}
else {
static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetuMod_Client()->RemoveTexture(this); // remove this texture from the texture client
}
}
delete this;
}
return count;
}
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::GetDevice(IDirect3DDevice9** ppDevice)
{
*ppDevice = m_D3Ddev;
return D3D_OK;
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::SetPrivateData(REFGUID refguid,CONST void* pData, DWORD SizeOfData, DWORD Flags)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->SetPrivateData(refguid, pData, SizeOfData, Flags);
}
return m_D3Dtex->SetPrivateData(refguid, pData, SizeOfData, Flags);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::GetPrivateData(REFGUID refguid, void* pData, DWORD* pSizeOfData)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetPrivateData(refguid, pData, pSizeOfData);
}
return m_D3Dtex->GetPrivateData(refguid, pData, pSizeOfData);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::FreePrivateData(REFGUID refguid)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->FreePrivateData(refguid);
}
return m_D3Dtex->FreePrivateData(refguid);
}
DWORD APIENTRY uMod_IDirect3DCubeTexture9::SetPriority(DWORD PriorityNew)
{
return m_D3Dtex->SetPriority(PriorityNew);
}
DWORD APIENTRY uMod_IDirect3DCubeTexture9::GetPriority()
{
return m_D3Dtex->GetPriority();
}
void APIENTRY uMod_IDirect3DCubeTexture9::PreLoad()
{
m_D3Dtex->PreLoad();
}
D3DRESOURCETYPE APIENTRY uMod_IDirect3DCubeTexture9::GetType()
{
return m_D3Dtex->GetType();
}
DWORD APIENTRY uMod_IDirect3DCubeTexture9::SetLOD(DWORD LODNew)
{
return m_D3Dtex->SetLOD(LODNew);
}
DWORD APIENTRY uMod_IDirect3DCubeTexture9::GetLOD()
{
return m_D3Dtex->GetLOD();
}
DWORD APIENTRY uMod_IDirect3DCubeTexture9::GetLevelCount()
{
return m_D3Dtex->GetLevelCount();
}
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType)
{
return m_D3Dtex->SetAutoGenFilterType(FilterType);
}
D3DTEXTUREFILTERTYPE APIENTRY uMod_IDirect3DCubeTexture9::GetAutoGenFilterType()
{
return m_D3Dtex->GetAutoGenFilterType();
}
void APIENTRY uMod_IDirect3DCubeTexture9::GenerateMipSubLevels()
{
m_D3Dtex->GenerateMipSubLevels();
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::AddDirtyRect(D3DCUBEMAP_FACES FaceType, CONST RECT* pDirtyRect)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->AddDirtyRect(FaceType, pDirtyRect);
}
return m_D3Dtex->AddDirtyRect(FaceType, pDirtyRect);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetLevelDesc(Level, pDesc);
}
return m_D3Dtex->GetLevelDesc(Level, pDesc);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::GetCubeMapSurface(D3DCUBEMAP_FACES FaceType, UINT Level, IDirect3DSurface9** ppCubeMapSurface)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetCubeMapSurface(FaceType, Level, ppCubeMapSurface);
}
return m_D3Dtex->GetCubeMapSurface(FaceType, Level, ppCubeMapSurface);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::LockRect(D3DCUBEMAP_FACES FaceType, UINT Level, D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect, DWORD Flags)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->LockRect(FaceType, Level, pLockedRect, pRect, Flags);
}
return m_D3Dtex->LockRect(FaceType, Level, pLockedRect, pRect, Flags);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DCubeTexture9::UnlockRect(D3DCUBEMAP_FACES FaceType, UINT Level)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->UnlockRect(FaceType, Level);
}
return m_D3Dtex->UnlockRect(FaceType, Level);
}
HashTuple uMod_IDirect3DCubeTexture9::GetHash() const
{
if (FAKE) {
return {};
}
IDirect3DCubeTexture9* pTexture = m_D3Dtex;
if (CrossRef_D3Dtex != nullptr) {
pTexture = CrossRef_D3Dtex->m_D3Dtex;
}
IDirect3DSurface9* pResolvedSurface = nullptr;
D3DLOCKED_RECT d3dlr;
D3DSURFACE_DESC desc;
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) //get the format and the size of the texture
{
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)
{
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 1\n");
if (pTexture->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_X, 0, &pResolvedSurface) != D3D_OK) {
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetSurfaceLevel\n");
return {};
}
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 2\n");
return {};
}
}
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) {
pResolvedSurface->UnlockRect();
pResolvedSurface->Release();
}
else {
pTexture->UnlockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0); //unlock the raw data
}
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};
}
-914
View File
@@ -1,914 +0,0 @@
#include "Main.h"
import TextureClient;
#ifndef RETURN_QueryInterface
#define RETURN_QueryInterface 0x01000000L
#endif
#ifndef PRE_MESSAGE
#define PRE_MESSAGE "uMod_IDirect3DDevice9"
#endif
uMod_IDirect3DDevice9::uMod_IDirect3DDevice9(IDirect3DDevice9* pOriginal, int back_buffer_count)
{
Message(PRE_MESSAGE "::" PRE_MESSAGE " (%p): %p\n", pOriginal, this);
BackBufferCount = back_buffer_count;
uMod_Client = new TextureClient(this); //get a new texture client for this device
uMod_Client->Initialize();
m_pIDirect3DDevice9 = pOriginal; // store the pointer to original object
}
uMod_IDirect3DDevice9::~uMod_IDirect3DDevice9()
{
Message(PRE_MESSAGE "::~" PRE_MESSAGE "(): %p\n", this);
}
HRESULT uMod_IDirect3DDevice9::QueryInterface(REFIID riid, void** ppvObj)
{
// check if original dll can provide interface. then send *our* address
if (riid == IID_IDirect3DTexture9) {
// This function should never be called with IDirect3DTexture9 by the game
*ppvObj = this;
return RETURN_QueryInterface;
}
*ppvObj = nullptr;
Message(PRE_MESSAGE "::QueryInterface(): %p\n", this);
const HRESULT hRes = m_pIDirect3DDevice9->QueryInterface(riid, ppvObj);
if (*ppvObj == m_pIDirect3DDevice9) {
uMod_Reference++; //increasing our counter
*ppvObj = this;
}
return hRes;
}
ULONG uMod_IDirect3DDevice9::AddRef()
{
uMod_Reference++; //increasing our counter
Message("%p = " PRE_MESSAGE "::AddRef(): %p\n", uMod_Reference, this);
return m_pIDirect3DDevice9->AddRef();
}
ULONG uMod_IDirect3DDevice9::Release()
{
if (--uMod_Reference == 0) //if our counter drops to zero, the real device will be deleted, so we clean up before
{
// 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.
delete uMod_Client; //must be deleted at the end, because other releases might call a function of this object
uMod_Client = nullptr;
}
const ULONG count = m_pIDirect3DDevice9->Release();
Message("%p = " PRE_MESSAGE "::Release(): %p\n", count, this);
if (uMod_Reference != count) //bug
{
Message("Error in " PRE_MESSAGE "::Release(): %p!=%p\n", uMod_Reference, count);
}
if (count == 0u) {
delete this;
}
return count;
}
HRESULT uMod_IDirect3DDevice9::TestCooperativeLevel()
{
return m_pIDirect3DDevice9->TestCooperativeLevel();
}
UINT uMod_IDirect3DDevice9::GetAvailableTextureMem()
{
return m_pIDirect3DDevice9->GetAvailableTextureMem();
}
HRESULT uMod_IDirect3DDevice9::EvictManagedResources()
{
return m_pIDirect3DDevice9->EvictManagedResources();
}
HRESULT uMod_IDirect3DDevice9::GetDirect3D(IDirect3D9** ppD3D9)
{
return m_pIDirect3DDevice9->GetDirect3D(ppD3D9);
}
HRESULT uMod_IDirect3DDevice9::GetDeviceCaps(D3DCAPS9* pCaps)
{
return m_pIDirect3DDevice9->GetDeviceCaps(pCaps);
}
HRESULT uMod_IDirect3DDevice9::GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode)
{
return m_pIDirect3DDevice9->GetDisplayMode(iSwapChain, pMode);
}
HRESULT uMod_IDirect3DDevice9::GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS* pParameters)
{
return m_pIDirect3DDevice9->GetCreationParameters(pParameters);
}
HRESULT uMod_IDirect3DDevice9::SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap)
{
return m_pIDirect3DDevice9->SetCursorProperties(XHotSpot, YHotSpot, pCursorBitmap);
}
void uMod_IDirect3DDevice9::SetCursorPosition(int X, int Y, DWORD Flags)
{
m_pIDirect3DDevice9->SetCursorPosition(X, Y, Flags);
}
BOOL uMod_IDirect3DDevice9::ShowCursor(BOOL bShow)
{
return m_pIDirect3DDevice9->ShowCursor(bShow);
}
HRESULT uMod_IDirect3DDevice9::CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain)
{
return m_pIDirect3DDevice9->CreateAdditionalSwapChain(pPresentationParameters, pSwapChain);
}
HRESULT uMod_IDirect3DDevice9::GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain)
{
return m_pIDirect3DDevice9->GetSwapChain(iSwapChain, pSwapChain);
}
UINT uMod_IDirect3DDevice9::GetNumberOfSwapChains()
{
return m_pIDirect3DDevice9->GetNumberOfSwapChains();
}
HRESULT uMod_IDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters)
{
return m_pIDirect3DDevice9->Reset(pPresentationParameters);
}
HRESULT uMod_IDirect3DDevice9::Present(CONST RECT* pSourceRect,CONST RECT* pDestRect, HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion)
{
return m_pIDirect3DDevice9->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
HRESULT uMod_IDirect3DDevice9::GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer)
{
return m_pIDirect3DDevice9->GetBackBuffer(iSwapChain, iBackBuffer, Type, ppBackBuffer);
}
HRESULT uMod_IDirect3DDevice9::GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus)
{
return m_pIDirect3DDevice9->GetRasterStatus(iSwapChain, pRasterStatus);
}
HRESULT uMod_IDirect3DDevice9::SetDialogBoxMode(BOOL bEnableDialogs)
{
return m_pIDirect3DDevice9->SetDialogBoxMode(bEnableDialogs);
}
void uMod_IDirect3DDevice9::SetGammaRamp(UINT iSwapChain, DWORD Flags,CONST D3DGAMMARAMP* pRamp)
{
return m_pIDirect3DDevice9->SetGammaRamp(iSwapChain, Flags, pRamp);
}
void uMod_IDirect3DDevice9::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp)
{
return m_pIDirect3DDevice9->GetGammaRamp(iSwapChain, 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");
const HRESULT ret = m_pIDirect3DDevice9->CreateTexture(Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
if (ret != D3D_OK) {
return ret;
}
const auto texture = new uMod_IDirect3DTexture9(ppTexture, this);
*ppTexture = texture;
if (LastCreatedTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
{
uMod_Client->AddTexture(LastCreatedTexture);
}
LastCreatedTexture = texture;
return ret;
}
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");
const HRESULT ret = m_pIDirect3DDevice9->CreateVolumeTexture(Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
if (ret != D3D_OK) {
return ret;
}
//create fake texture
const auto texture = new uMod_IDirect3DVolumeTexture9(ppVolumeTexture, this);
*ppVolumeTexture = texture;
if (LastCreatedVolumeTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
{
uMod_Client->AddTexture(LastCreatedVolumeTexture);
}
LastCreatedVolumeTexture = texture;
return ret;
}
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");
const HRESULT ret = m_pIDirect3DDevice9->CreateCubeTexture(EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
if (ret != D3D_OK) {
return ret;
}
//create fake texture
const auto texture = new uMod_IDirect3DCubeTexture9(ppCubeTexture, this);
*ppCubeTexture = texture;
if (LastCreatedCubeTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
{
uMod_Client->AddTexture(LastCreatedCubeTexture);
}
LastCreatedCubeTexture = texture;
return ret;
}
HRESULT uMod_IDirect3DDevice9::CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle)
{
return m_pIDirect3DDevice9->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle);
}
HRESULT uMod_IDirect3DDevice9::CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle)
{
return m_pIDirect3DDevice9->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, pSharedHandle);
}
HRESULT uMod_IDirect3DDevice9::CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle)
{
return m_pIDirect3DDevice9->CreateRenderTarget(Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle);
}
HRESULT uMod_IDirect3DDevice9::CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle)
{
return m_pIDirect3DDevice9->CreateDepthStencilSurface(Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle);
}
HRESULT uMod_IDirect3DDevice9::UpdateSurface(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface,CONST POINT* pDestPoint)
{
return m_pIDirect3DDevice9->UpdateSurface(pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
}
HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture)
{
Message(PRE_MESSAGE "::UpdateTexture( %p, %p): %p\n", pSourceTexture, pDestinationTexture, this);
// we must pass the real texture objects
uMod_IDirect3DTexture9* pSource = nullptr;
uMod_IDirect3DVolumeTexture9* pSourceVolume = nullptr;
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 (hash) {
if (hash != pSource->Hash) // this hash has changed !!
{
pSource->Hash = hash;
if (pSource->CrossRef_D3Dtex != nullptr) {
UnswitchTextures(pSource);
}
uMod_Client->LookUpToMod(pSource);
}
}
else if (pSource->CrossRef_D3Dtex != nullptr) {
UnswitchTextures(pSource); // we better unswitch
}
// the source must be the original texture if not switched and the fake texture if it is switched
if (pSource->CrossRef_D3Dtex != nullptr) {
pSourceTexture = pSource->CrossRef_D3Dtex->m_D3Dtex;
}
else {
pSourceTexture = pSource->m_D3Dtex;
}
break;
}
case 0x01000001L: {
pSourceVolume = static_cast<uMod_IDirect3DVolumeTexture9*>(pSourceTexture);
if (hash) {
if (hash != pSourceVolume->Hash) // this hash has changed !!
{
pSourceVolume->Hash = hash;
if (pSourceVolume->CrossRef_D3Dtex != nullptr) {
UnswitchTextures(pSourceVolume);
}
uMod_Client->LookUpToMod(pSourceVolume);
}
}
else if (pSourceVolume->CrossRef_D3Dtex != nullptr) {
UnswitchTextures(pSourceVolume); // we better unswitch
}
// the source must be the original texture if not switched and the fake texture if it is switched
if (pSourceVolume->CrossRef_D3Dtex != nullptr) {
pSourceTexture = pSourceVolume->CrossRef_D3Dtex->m_D3Dtex;
}
else {
pSourceTexture = pSourceVolume->m_D3Dtex;
}
break;
}
case 0x01000002L: {
pSourceCube = static_cast<uMod_IDirect3DCubeTexture9*>(pSourceTexture);
if (hash) {
if (hash != pSourceCube->Hash) // this hash has changed !!
{
pSourceCube->Hash = hash;
if (pSourceCube->CrossRef_D3Dtex != nullptr) {
UnswitchTextures(pSourceCube);
}
uMod_Client->LookUpToMod(pSourceCube);
}
}
else if (pSourceCube->CrossRef_D3Dtex != nullptr) {
UnswitchTextures(pSourceCube); // we better unswitch
}
// the source must be the original texture if not switched and the fake texture if it is switched
if (pSourceCube->CrossRef_D3Dtex != nullptr) {
pSourceTexture = pSourceCube->CrossRef_D3Dtex->m_D3Dtex;
}
else {
pSourceTexture = pSourceCube->m_D3Dtex;
}
break;
}
default:
break; // this is no fake texture and QueryInterface failed, because IDirect3DBaseTexture9 object cannot be a IDirect3D9 object ;)
}
}
if (pDestinationTexture != nullptr) {
switch (pSourceTexture->QueryInterface(IID_IDirect3D9, (void**)&cpy)) {
case 0x01000000L: {
const auto pDest = static_cast<uMod_IDirect3DTexture9*>(pDestinationTexture);
if (pSource != nullptr && pDest->Hash != pSource->Hash) {
pDest->Hash = pSource->Hash; // take over the hash
UnswitchTextures(pDest);
if (pSource->CrossRef_D3Dtex != nullptr) {
uMod_IDirect3DTexture9* cpy = pSource->CrossRef_D3Dtex;
UnswitchTextures(pSource);
SwitchTextures(cpy, pDest);
}
}
if (pDest->CrossRef_D3Dtex != nullptr) {
pDestinationTexture = pDest->CrossRef_D3Dtex->m_D3Dtex; // make sure to copy into the original texture
}
else {
pDestinationTexture = pDest->m_D3Dtex;
}
break;
}
case 0x01000001L: {
const auto pDest = static_cast<uMod_IDirect3DVolumeTexture9*>(pDestinationTexture);
if (pSourceVolume != nullptr && pDest->Hash != pSourceVolume->Hash) {
pDest->Hash = pSourceVolume->Hash; // take over the hash
UnswitchTextures(pDest);
if (pSourceVolume->CrossRef_D3Dtex != nullptr) {
uMod_IDirect3DVolumeTexture9* cpy = pSourceVolume->CrossRef_D3Dtex;
UnswitchTextures(pSourceVolume);
SwitchTextures(cpy, pDest);
}
}
if (pDest->CrossRef_D3Dtex != nullptr) {
pDestinationTexture = pDest->CrossRef_D3Dtex->m_D3Dtex; // make sure to copy into the original texture
}
else {
pDestinationTexture = pDest->m_D3Dtex;
}
break;
}
case 0x01000002L: {
auto pDest = static_cast<uMod_IDirect3DCubeTexture9*>(pDestinationTexture);
if (pSourceCube != nullptr && pDest->Hash != pSourceCube->Hash) {
pDest->Hash = pSourceCube->Hash; // take over the hash
UnswitchTextures(pDest);
if (pSourceCube->CrossRef_D3Dtex != nullptr) {
uMod_IDirect3DCubeTexture9* cpy = pSourceCube->CrossRef_D3Dtex;
UnswitchTextures(pSourceCube);
SwitchTextures(cpy, pDest);
}
}
if (pDest->CrossRef_D3Dtex != nullptr) {
pDestinationTexture = pDest->CrossRef_D3Dtex->m_D3Dtex; // make sure to copy into the original texture
}
else {
pDestinationTexture = pDest->m_D3Dtex;
}
break;
}
}
}
return m_pIDirect3DDevice9->UpdateTexture(pSourceTexture, pDestinationTexture);
}
HRESULT uMod_IDirect3DDevice9::GetRenderTargetData(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface)
{
return m_pIDirect3DDevice9->GetRenderTargetData(pRenderTarget, pDestSurface);
}
HRESULT uMod_IDirect3DDevice9::GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface)
{
return m_pIDirect3DDevice9->GetFrontBufferData(iSwapChain, pDestSurface);
}
HRESULT uMod_IDirect3DDevice9::StretchRect(IDirect3DSurface9* pSourceSurface,CONST RECT* pSourceRect, IDirect3DSurface9* pDestSurface,CONST RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter)
{
return m_pIDirect3DDevice9->StretchRect(pSourceSurface, pSourceRect, pDestSurface, pDestRect, Filter);
}
HRESULT uMod_IDirect3DDevice9::ColorFill(IDirect3DSurface9* pSurface,CONST RECT* pRect, D3DCOLOR color)
{
return m_pIDirect3DDevice9->ColorFill(pSurface, pRect, color);
}
HRESULT uMod_IDirect3DDevice9::CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle)
{
return m_pIDirect3DDevice9->CreateOffscreenPlainSurface(Width, Height, Format, Pool, ppSurface, pSharedHandle);
}
HRESULT uMod_IDirect3DDevice9::SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget)
{
{
IDirect3DSurface9* back_buffer;
NormalRendering = false;
for (int i = 0; !NormalRendering && i < BackBufferCount; i++) {
m_pIDirect3DDevice9->GetBackBuffer(0, i, D3DBACKBUFFER_TYPE_MONO, &back_buffer);
if (back_buffer == pRenderTarget) {
NormalRendering = true;
}
back_buffer->Release();
}
}
return m_pIDirect3DDevice9->SetRenderTarget(RenderTargetIndex, pRenderTarget);
}
HRESULT uMod_IDirect3DDevice9::GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget)
{
return m_pIDirect3DDevice9->GetRenderTarget(RenderTargetIndex, ppRenderTarget);
}
HRESULT uMod_IDirect3DDevice9::SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil)
{
return m_pIDirect3DDevice9->SetDepthStencilSurface(pNewZStencil);
}
HRESULT uMod_IDirect3DDevice9::GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface)
{
return m_pIDirect3DDevice9->GetDepthStencilSurface(ppZStencilSurface);
}
HRESULT uMod_IDirect3DDevice9::BeginScene()
{
if (LastCreatedTexture != nullptr) // add the last created texture
{
uMod_Client->AddTexture(LastCreatedTexture);
}
if (LastCreatedVolumeTexture != nullptr) // add the last created texture
{
uMod_Client->AddTexture(LastCreatedVolumeTexture);
}
if (LastCreatedCubeTexture != nullptr) // add the last created texture
{
uMod_Client->AddTexture(LastCreatedCubeTexture);
}
uMod_Client->MergeUpdate(); // merge an update, if present
return m_pIDirect3DDevice9->BeginScene();
}
HRESULT uMod_IDirect3DDevice9::EndScene()
{
return m_pIDirect3DDevice9->EndScene();
}
HRESULT uMod_IDirect3DDevice9::Clear(DWORD Count,CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil)
{
return m_pIDirect3DDevice9->Clear(Count, pRects, Flags, Color, Z, Stencil);
}
HRESULT uMod_IDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix)
{
return m_pIDirect3DDevice9->SetTransform(State, pMatrix);
}
HRESULT uMod_IDirect3DDevice9::GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix)
{
return m_pIDirect3DDevice9->GetTransform(State, pMatrix);
}
HRESULT uMod_IDirect3DDevice9::MultiplyTransform(D3DTRANSFORMSTATETYPE State,CONST D3DMATRIX* pMatrix)
{
return m_pIDirect3DDevice9->MultiplyTransform(State, pMatrix);
}
HRESULT uMod_IDirect3DDevice9::SetViewport(CONST D3DVIEWPORT9* pViewport)
{
return m_pIDirect3DDevice9->SetViewport(pViewport);
}
HRESULT uMod_IDirect3DDevice9::GetViewport(D3DVIEWPORT9* pViewport)
{
return m_pIDirect3DDevice9->GetViewport(pViewport);
}
HRESULT uMod_IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9* pMaterial)
{
return m_pIDirect3DDevice9->SetMaterial(pMaterial);
}
HRESULT uMod_IDirect3DDevice9::GetMaterial(D3DMATERIAL9* pMaterial)
{
return m_pIDirect3DDevice9->GetMaterial(pMaterial);
}
HRESULT uMod_IDirect3DDevice9::SetLight(DWORD Index,CONST D3DLIGHT9* pLight)
{
return m_pIDirect3DDevice9->SetLight(Index, pLight);
}
HRESULT uMod_IDirect3DDevice9::GetLight(DWORD Index, D3DLIGHT9* pLight)
{
return m_pIDirect3DDevice9->GetLight(Index, pLight);
}
HRESULT uMod_IDirect3DDevice9::LightEnable(DWORD Index, BOOL Enable)
{
return m_pIDirect3DDevice9->LightEnable(Index, Enable);
}
HRESULT uMod_IDirect3DDevice9::GetLightEnable(DWORD Index, BOOL* pEnable)
{
return m_pIDirect3DDevice9->GetLightEnable(Index, pEnable);
}
HRESULT uMod_IDirect3DDevice9::SetClipPlane(DWORD Index,CONST float* pPlane)
{
return m_pIDirect3DDevice9->SetClipPlane(Index, pPlane);
}
HRESULT uMod_IDirect3DDevice9::GetClipPlane(DWORD Index, float* pPlane)
{
return m_pIDirect3DDevice9->GetClipPlane(Index, pPlane);
}
HRESULT uMod_IDirect3DDevice9::SetRenderState(D3DRENDERSTATETYPE State, DWORD Value)
{
return m_pIDirect3DDevice9->SetRenderState(State, Value);
}
HRESULT uMod_IDirect3DDevice9::GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue)
{
return m_pIDirect3DDevice9->GetRenderState(State, pValue);
}
HRESULT uMod_IDirect3DDevice9::CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB)
{
return m_pIDirect3DDevice9->CreateStateBlock(Type, ppSB);
}
HRESULT uMod_IDirect3DDevice9::BeginStateBlock()
{
return m_pIDirect3DDevice9->BeginStateBlock();
}
HRESULT uMod_IDirect3DDevice9::EndStateBlock(IDirect3DStateBlock9** ppSB)
{
return m_pIDirect3DDevice9->EndStateBlock(ppSB);
}
HRESULT uMod_IDirect3DDevice9::SetClipStatus(CONST D3DCLIPSTATUS9* pClipStatus)
{
return m_pIDirect3DDevice9->SetClipStatus(pClipStatus);
}
HRESULT uMod_IDirect3DDevice9::GetClipStatus(D3DCLIPSTATUS9* pClipStatus)
{
return m_pIDirect3DDevice9->GetClipStatus(pClipStatus);
}
HRESULT uMod_IDirect3DDevice9::GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture)
{
return m_pIDirect3DDevice9->GetTexture(Stage, ppTexture);
}
HRESULT uMod_IDirect3DDevice9::SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture)
{
// we must pass the real texture objects
// if (dev != this) this texture was not initialized through our device and is thus no fake texture object
//IDirect3DDevice9 *dev = NULL;
IDirect3DBaseTexture9* cpy;
if (pTexture != nullptr) {
long int ret = pTexture->QueryInterface(IID_IDirect3D9, (void**)&cpy);
switch (ret) {
case 0x01000000L:
pTexture = static_cast<uMod_IDirect3DTexture9*>(pTexture)->m_D3Dtex;
break;
case 0x01000001L:
pTexture = static_cast<uMod_IDirect3DVolumeTexture9*>(pTexture)->m_D3Dtex;
break;
case 0x01000002L:
pTexture = static_cast<uMod_IDirect3DCubeTexture9*>(pTexture)->m_D3Dtex;
break;
default:
break; // this is no fake texture and QueryInterface failed, because IDirect3DBaseTexture9 object cannot be a IDirect3D9 object ;)
}
}
/*
if (pTexture != NULL && ((uMod_IDirect3DTexture9*)(pTexture))->GetDevice(&dev) == D3D_OK)
{
if(dev == this) pTexture = ((uMod_IDirect3DTexture9*)(pTexture))->m_D3Dtex;
}
*/
return m_pIDirect3DDevice9->SetTexture(Stage, pTexture);
}
HRESULT uMod_IDirect3DDevice9::GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue)
{
return m_pIDirect3DDevice9->GetTextureStageState(Stage, Type, pValue);
}
HRESULT uMod_IDirect3DDevice9::SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value)
{
return m_pIDirect3DDevice9->SetTextureStageState(Stage, Type, Value);
}
HRESULT uMod_IDirect3DDevice9::GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue)
{
return m_pIDirect3DDevice9->GetSamplerState(Sampler, Type, pValue);
}
HRESULT uMod_IDirect3DDevice9::SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value)
{
return m_pIDirect3DDevice9->SetSamplerState(Sampler, Type, Value);
}
HRESULT uMod_IDirect3DDevice9::ValidateDevice(DWORD* pNumPasses)
{
return m_pIDirect3DDevice9->ValidateDevice(pNumPasses);
}
HRESULT uMod_IDirect3DDevice9::SetPaletteEntries(UINT PaletteNumber,CONST PALETTEENTRY* pEntries)
{
return m_pIDirect3DDevice9->SetPaletteEntries(PaletteNumber, pEntries);
}
HRESULT uMod_IDirect3DDevice9::GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries)
{
return m_pIDirect3DDevice9->GetPaletteEntries(PaletteNumber, pEntries);
}
HRESULT uMod_IDirect3DDevice9::SetCurrentTexturePalette(UINT PaletteNumber)
{
return m_pIDirect3DDevice9->SetCurrentTexturePalette(PaletteNumber);
}
HRESULT uMod_IDirect3DDevice9::GetCurrentTexturePalette(UINT* PaletteNumber)
{
return m_pIDirect3DDevice9->GetCurrentTexturePalette(PaletteNumber);
}
HRESULT uMod_IDirect3DDevice9::SetScissorRect(CONST RECT* pRect)
{
return m_pIDirect3DDevice9->SetScissorRect(pRect);
}
HRESULT uMod_IDirect3DDevice9::GetScissorRect(RECT* pRect)
{
return m_pIDirect3DDevice9->GetScissorRect(pRect);
}
HRESULT uMod_IDirect3DDevice9::SetSoftwareVertexProcessing(BOOL bSoftware)
{
return m_pIDirect3DDevice9->SetSoftwareVertexProcessing(bSoftware);
}
BOOL uMod_IDirect3DDevice9::GetSoftwareVertexProcessing()
{
return m_pIDirect3DDevice9->GetSoftwareVertexProcessing();
}
HRESULT uMod_IDirect3DDevice9::SetNPatchMode(float nSegments)
{
return m_pIDirect3DDevice9->SetNPatchMode(nSegments);
}
float uMod_IDirect3DDevice9::GetNPatchMode()
{
return m_pIDirect3DDevice9->GetNPatchMode();
}
HRESULT uMod_IDirect3DDevice9::DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount)
{
return m_pIDirect3DDevice9->DrawPrimitive(PrimitiveType, StartVertex, PrimitiveCount);
}
HRESULT uMod_IDirect3DDevice9::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount)
{
return m_pIDirect3DDevice9->DrawIndexedPrimitive(PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
}
HRESULT uMod_IDirect3DDevice9::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride)
{
return m_pIDirect3DDevice9->DrawPrimitiveUP(PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
}
HRESULT uMod_IDirect3DDevice9::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount,CONST void* pIndexData, D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
UINT VertexStreamZeroStride)
{
return m_pIDirect3DDevice9->DrawIndexedPrimitiveUP(PrimitiveType, MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
}
HRESULT uMod_IDirect3DDevice9::ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags)
{
return m_pIDirect3DDevice9->ProcessVertices(SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
}
HRESULT uMod_IDirect3DDevice9::CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl)
{
return m_pIDirect3DDevice9->CreateVertexDeclaration(pVertexElements, ppDecl);
}
HRESULT uMod_IDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl)
{
return m_pIDirect3DDevice9->SetVertexDeclaration(pDecl);
}
HRESULT uMod_IDirect3DDevice9::GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl)
{
return m_pIDirect3DDevice9->GetVertexDeclaration(ppDecl);
}
HRESULT uMod_IDirect3DDevice9::SetFVF(DWORD FVF)
{
return m_pIDirect3DDevice9->SetFVF(FVF);
}
HRESULT uMod_IDirect3DDevice9::GetFVF(DWORD* pFVF)
{
return m_pIDirect3DDevice9->GetFVF(pFVF);
}
HRESULT uMod_IDirect3DDevice9::CreateVertexShader(CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader)
{
return m_pIDirect3DDevice9->CreateVertexShader(pFunction, ppShader);
}
HRESULT uMod_IDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9* pShader)
{
return m_pIDirect3DDevice9->SetVertexShader(pShader);
}
HRESULT uMod_IDirect3DDevice9::GetVertexShader(IDirect3DVertexShader9** ppShader)
{
return m_pIDirect3DDevice9->GetVertexShader(ppShader);
}
HRESULT uMod_IDirect3DDevice9::SetVertexShaderConstantF(UINT StartRegister,CONST float* pConstantData, UINT Vector4fCount)
{
return m_pIDirect3DDevice9->SetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}
HRESULT uMod_IDirect3DDevice9::GetVertexShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount)
{
return m_pIDirect3DDevice9->GetVertexShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}
HRESULT uMod_IDirect3DDevice9::SetVertexShaderConstantI(UINT StartRegister,CONST int* pConstantData, UINT Vector4iCount)
{
return m_pIDirect3DDevice9->SetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}
HRESULT uMod_IDirect3DDevice9::GetVertexShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount)
{
return m_pIDirect3DDevice9->GetVertexShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}
HRESULT uMod_IDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData, UINT BoolCount)
{
return m_pIDirect3DDevice9->SetVertexShaderConstantB(StartRegister, pConstantData, BoolCount);
}
HRESULT uMod_IDirect3DDevice9::GetVertexShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount)
{
return m_pIDirect3DDevice9->GetVertexShaderConstantB(StartRegister, pConstantData, BoolCount);
}
HRESULT uMod_IDirect3DDevice9::SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride)
{
return m_pIDirect3DDevice9->SetStreamSource(StreamNumber, pStreamData, OffsetInBytes, Stride);
}
HRESULT uMod_IDirect3DDevice9::GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* OffsetInBytes, UINT* pStride)
{
return m_pIDirect3DDevice9->GetStreamSource(StreamNumber, ppStreamData, OffsetInBytes, pStride);
}
HRESULT uMod_IDirect3DDevice9::SetStreamSourceFreq(UINT StreamNumber, UINT Divider)
{
return m_pIDirect3DDevice9->SetStreamSourceFreq(StreamNumber, Divider);
}
HRESULT uMod_IDirect3DDevice9::GetStreamSourceFreq(UINT StreamNumber, UINT* Divider)
{
return m_pIDirect3DDevice9->GetStreamSourceFreq(StreamNumber, Divider);
}
HRESULT uMod_IDirect3DDevice9::SetIndices(IDirect3DIndexBuffer9* pIndexData)
{
return m_pIDirect3DDevice9->SetIndices(pIndexData);
}
HRESULT uMod_IDirect3DDevice9::GetIndices(IDirect3DIndexBuffer9** ppIndexData)
{
return m_pIDirect3DDevice9->GetIndices(ppIndexData);
}
HRESULT uMod_IDirect3DDevice9::CreatePixelShader(CONST DWORD* pFunction, IDirect3DPixelShader9** ppShader)
{
return m_pIDirect3DDevice9->CreatePixelShader(pFunction, ppShader);
}
HRESULT uMod_IDirect3DDevice9::SetPixelShader(IDirect3DPixelShader9* pShader)
{
return m_pIDirect3DDevice9->SetPixelShader(pShader);
}
HRESULT uMod_IDirect3DDevice9::GetPixelShader(IDirect3DPixelShader9** ppShader)
{
return m_pIDirect3DDevice9->GetPixelShader(ppShader);
}
HRESULT uMod_IDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister,CONST float* pConstantData, UINT Vector4fCount)
{
return m_pIDirect3DDevice9->SetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}
HRESULT uMod_IDirect3DDevice9::GetPixelShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount)
{
return m_pIDirect3DDevice9->GetPixelShaderConstantF(StartRegister, pConstantData, Vector4fCount);
}
HRESULT uMod_IDirect3DDevice9::SetPixelShaderConstantI(UINT StartRegister,CONST int* pConstantData, UINT Vector4iCount)
{
return m_pIDirect3DDevice9->SetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}
HRESULT uMod_IDirect3DDevice9::GetPixelShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount)
{
return m_pIDirect3DDevice9->GetPixelShaderConstantI(StartRegister, pConstantData, Vector4iCount);
}
HRESULT uMod_IDirect3DDevice9::SetPixelShaderConstantB(UINT StartRegister,CONST BOOL* pConstantData, UINT BoolCount)
{
return m_pIDirect3DDevice9->SetPixelShaderConstantB(StartRegister, pConstantData, BoolCount);
}
HRESULT uMod_IDirect3DDevice9::GetPixelShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount)
{
return m_pIDirect3DDevice9->GetPixelShaderConstantB(StartRegister, pConstantData, BoolCount);
}
HRESULT uMod_IDirect3DDevice9::DrawRectPatch(UINT Handle,CONST float* pNumSegs,CONST D3DRECTPATCH_INFO* pRectPatchInfo)
{
return m_pIDirect3DDevice9->DrawRectPatch(Handle, pNumSegs, pRectPatchInfo);
}
HRESULT uMod_IDirect3DDevice9::DrawTriPatch(UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo)
{
return m_pIDirect3DDevice9->DrawTriPatch(Handle, pNumSegs, pTriPatchInfo);
}
HRESULT uMod_IDirect3DDevice9::DeletePatch(UINT Handle)
{
return m_pIDirect3DDevice9->DeletePatch(Handle);
}
HRESULT uMod_IDirect3DDevice9::CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery)
{
return m_pIDirect3DDevice9->CreateQuery(Type, ppQuery);
}
-95
View File
@@ -1,95 +0,0 @@
#include "Main.h"
#define uMod_IDirect3DDevice9 uMod_IDirect3DDevice9Ex
#define IDirect3DDevice9 IDirect3DDevice9Ex
#define m_pIDirect3DDevice9 m_pIDirect3DDevice9Ex
#define RETURN_QueryInterface 0x01000001L
#define PRE_MESSAGE "uMod_IDirect3DDevice9Ex"
// ReSharper disable once CppUnusedIncludeDirective
#include "uMod_IDirect3DDevice9.cpp"
HRESULT __stdcall uMod_IDirect3DDevice9Ex::CheckDeviceState(HWND hWindow)
{
return m_pIDirect3DDevice9Ex->CheckDeviceState(hWindow);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::CheckResourceResidency(IDirect3DResource9** ppResourceArray, UINT32 NumResources)
{
return m_pIDirect3DDevice9Ex->CheckResourceResidency(ppResourceArray, NumResources);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::ComposeRects(IDirect3DSurface9* pSource, IDirect3DSurface9* pDestination, IDirect3DVertexBuffer9* pSrcRectDescriptors, UINT NumRects, IDirect3DVertexBuffer9* pDstRectDescriptors, D3DCOMPOSERECTSOP Operation,
INT XOffset, INT YOffset)
{
return m_pIDirect3DDevice9Ex->ComposeRects(pSource, pDestination, pSrcRectDescriptors, NumRects, pDstRectDescriptors, Operation, XOffset, YOffset);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::CreateDepthStencilSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage)
{
return m_pIDirect3DDevice9Ex->CreateDepthStencilSurfaceEx(Width, Height, Format, MultiSample, MultisampleQuality, Discard, ppSurface, pSharedHandle, Usage);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::CreateOffscreenPlainSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage)
{
return m_pIDirect3DDevice9Ex->CreateOffscreenPlainSurfaceEx(Width, Height, Format, Pool, ppSurface, pSharedHandle, Usage);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::CreateRenderTargetEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle, DWORD Usage)
{
return m_pIDirect3DDevice9Ex->CreateRenderTargetEx(Width, Height, Format, MultiSample, MultisampleQuality, Lockable, ppSurface, pSharedHandle, Usage);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::GetDisplayModeEx(UINT iSwapChain, D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation)
{
return m_pIDirect3DDevice9Ex->GetDisplayModeEx(iSwapChain, pMode, pRotation);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::GetGPUThreadPriority(INT* pPriority)
{
return m_pIDirect3DDevice9Ex->GetGPUThreadPriority(pPriority);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::GetMaximumFrameLatency(UINT* pMaxLatency)
{
return m_pIDirect3DDevice9Ex->GetMaximumFrameLatency(pMaxLatency);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::PresentEx(const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion, DWORD dwFlags)
{
return m_pIDirect3DDevice9Ex->PresentEx(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::ResetEx(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode)
{
return m_pIDirect3DDevice9Ex->ResetEx(pPresentationParameters, pFullscreenDisplayMode);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::SetConvolutionMonoKernel(UINT Width, UINT Height, float* RowWeights, float* ColumnWeights)
{
return m_pIDirect3DDevice9Ex->SetConvolutionMonoKernel(Width, Height, RowWeights, ColumnWeights);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::SetGPUThreadPriority(INT pPriority)
{
return m_pIDirect3DDevice9Ex->SetGPUThreadPriority(pPriority);
}
HRESULT __stdcall uMod_IDirect3DDevice9Ex::SetMaximumFrameLatency(UINT pMaxLatency)
{
return m_pIDirect3DDevice9Ex->SetMaximumFrameLatency(pMaxLatency);
}
/*
HRESULT __stdcall uMod_IDirect3DDevice9Ex::TestCooperativeLevel()
{
return(m_pIDirect3DDevice9Ex->TestCooperativeLevel();
}
*/
HRESULT __stdcall uMod_IDirect3DDevice9Ex::WaitForVBlank(UINT SwapChainIndex)
{
return m_pIDirect3DDevice9Ex->WaitForVBlank(SwapChainIndex);
}
-348
View File
@@ -1,348 +0,0 @@
#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)
{
if (riid == IID_IDirect3D9) {
// This function should never be called with IID_IDirect3D9 by the game
// thus this call comes from our own dll to ask for the texture type
// 0x01000000L == uMod_IDirect3DTexture9
// 0x01000001L == uMod_IDirect3DVolumeTexture9
// 0x01000002L == uMod_IDirect3DCubeTexture9
*ppvObj = this;
return 0x01000000L;
}
HRESULT hRes;
if (CrossRef_D3Dtex != nullptr) {
hRes = CrossRef_D3Dtex->m_D3Dtex->QueryInterface(riid, ppvObj);
if (*ppvObj == CrossRef_D3Dtex->m_D3Dtex) {
*ppvObj = this;
}
}
else {
hRes = m_D3Dtex->QueryInterface(riid, ppvObj);
if (*ppvObj == m_D3Dtex) {
*ppvObj = this;
}
}
return hRes;
}
//this function yields for the non switched texture object
ULONG APIENTRY uMod_IDirect3DTexture9::AddRef()
{
if (FAKE) {
return 1; //bug, this case should never happen
}
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->AddRef();
}
return m_D3Dtex->AddRef();
}
//this function yields for the non switched texture object
ULONG APIENTRY uMod_IDirect3DTexture9::Release()
{
Message("uMod_IDirect3DTexture9::Release(): %p\n", this);
void* cpy;
const long ret = m_D3Ddev->QueryInterface(IID_IDirect3DTexture9, &cpy);
ULONG count;
if (FAKE) {
UnswitchTextures(this);
count = m_D3Dtex->Release(); //count must be zero, cause we don't call AddRef of fake_textures
}
else {
if (CrossRef_D3Dtex != nullptr) //if this texture is switched with a fake texture
{
uMod_IDirect3DTexture9* fake_texture = CrossRef_D3Dtex;
count = fake_texture->m_D3Dtex->Release(); //release the original texture
if (count == 0) //if texture is released we switch the textures back
{
UnswitchTextures(this);
fake_texture->Release(); // we release the fake texture
}
}
else {
count = m_D3Dtex->Release();
}
}
if (count == 0) //if this texture is released, we clean up
{
// if this texture is the LastCreatedTexture, the next time LastCreatedTexture would be added,
// the hash of a non existing texture would be calculated
if (ret == 0x01000000L) {
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetLastCreatedTexture() == this) {
static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->SetLastCreatedTexture(nullptr);
}
else {
static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetuMod_Client()->RemoveTexture(this); // remove this texture from the texture client
}
}
else {
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetLastCreatedTexture() == this) {
static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->SetLastCreatedTexture(nullptr);
}
else {
static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetuMod_Client()->RemoveTexture(this); // remove this texture from the texture client
}
}
delete this;
}
Message("uMod_IDirect3DTexture9::Release() end: %p\n", this);
return count;
}
HRESULT APIENTRY uMod_IDirect3DTexture9::GetDevice(IDirect3DDevice9** ppDevice)
{
*ppDevice = m_D3Ddev;
return D3D_OK;
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::SetPrivateData(REFGUID refguid,CONST void* pData, DWORD SizeOfData, DWORD Flags)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->SetPrivateData(refguid, pData, SizeOfData, Flags);
}
return m_D3Dtex->SetPrivateData(refguid, pData, SizeOfData, Flags);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::GetPrivateData(REFGUID refguid, void* pData, DWORD* pSizeOfData)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetPrivateData(refguid, pData, pSizeOfData);
}
return m_D3Dtex->GetPrivateData(refguid, pData, pSizeOfData);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::FreePrivateData(REFGUID refguid)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->FreePrivateData(refguid);
}
return m_D3Dtex->FreePrivateData(refguid);
}
DWORD APIENTRY uMod_IDirect3DTexture9::SetPriority(DWORD PriorityNew)
{
return m_D3Dtex->SetPriority(PriorityNew);
}
DWORD APIENTRY uMod_IDirect3DTexture9::GetPriority()
{
return m_D3Dtex->GetPriority();
}
void APIENTRY uMod_IDirect3DTexture9::PreLoad()
{
m_D3Dtex->PreLoad();
}
D3DRESOURCETYPE APIENTRY uMod_IDirect3DTexture9::GetType()
{
return m_D3Dtex->GetType();
}
DWORD APIENTRY uMod_IDirect3DTexture9::SetLOD(DWORD LODNew)
{
return m_D3Dtex->SetLOD(LODNew);
}
DWORD APIENTRY uMod_IDirect3DTexture9::GetLOD()
{
return m_D3Dtex->GetLOD();
}
DWORD APIENTRY uMod_IDirect3DTexture9::GetLevelCount()
{
return m_D3Dtex->GetLevelCount();
}
HRESULT APIENTRY uMod_IDirect3DTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType)
{
return m_D3Dtex->SetAutoGenFilterType(FilterType);
}
D3DTEXTUREFILTERTYPE APIENTRY uMod_IDirect3DTexture9::GetAutoGenFilterType()
{
return m_D3Dtex->GetAutoGenFilterType();
}
void APIENTRY uMod_IDirect3DTexture9::GenerateMipSubLevels()
{
m_D3Dtex->GenerateMipSubLevels();
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetLevelDesc(Level, pDesc);
}
return m_D3Dtex->GetLevelDesc(Level, pDesc);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetSurfaceLevel(Level, ppSurfaceLevel);
}
return m_D3Dtex->GetSurfaceLevel(Level, ppSurfaceLevel);
}
//this function yields for the non switched texture object
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);
}
return m_D3Dtex->LockRect(Level, pLockedRect, pRect, Flags);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::UnlockRect(UINT Level)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->UnlockRect(Level);
}
return m_D3Dtex->UnlockRect(Level);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DTexture9::AddDirtyRect(CONST RECT* pDirtyRect)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->AddDirtyRect(pDirtyRect);
}
return m_D3Dtex->AddDirtyRect(pDirtyRect);
}
HashTuple uMod_IDirect3DTexture9::GetHash() const
{
ASSERT(!FAKE);
IDirect3DTexture9* pTexture = m_D3Dtex;
if (CrossRef_D3Dtex != nullptr) {
pTexture = CrossRef_D3Dtex->m_D3Dtex;
}
IDirect3DSurface9* pOffscreenSurface = nullptr;
//IDirect3DTexture9 *pOffscreenTexture = NULL;
IDirect3DSurface9* pResolvedSurface = nullptr;
D3DLOCKED_RECT d3dlr;
D3DSURFACE_DESC desc;
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) //get the format and the size of the texture
{
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetLevelDesc \n");
return {};
}
Message("uMod_IDirect3DTexture9::GetHash() (%d %d) %d\n", desc.Width, desc.Height, desc.Format);
if (desc.Pool == D3DPOOL_DEFAULT) //get the raw data of the texture
{
//Message("uMod_IDirect3DTexture9::GetHash() (D3DPOOL_DEFAULT)\n");
IDirect3DSurface9* pSurfaceLevel_orig = nullptr;
if (pTexture->GetSurfaceLevel(0, &pSurfaceLevel_orig) != D3D_OK) {
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();
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();
Warning("uMod_IDirect3DTexture9::GetHash() Failed: StretchRect (D3DPOOL_DEFAULT)\n");
return {};
}
pSurfaceLevel_orig = pResolvedSurface;
}
if (D3D_OK != m_D3Ddev->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &pOffscreenSurface, nullptr)) {
pSurfaceLevel_orig->Release();
if (pResolvedSurface != nullptr) {
pResolvedSurface->Release();
}
Warning("uMod_IDirect3DTexture9::GetHash() Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
return {};
}
if (D3D_OK != m_D3Ddev->GetRenderTargetData(pSurfaceLevel_orig, pOffscreenSurface)) {
pSurfaceLevel_orig->Release();
if (pResolvedSurface != nullptr) {
pResolvedSurface->Release();
}
pOffscreenSurface->Release();
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
return {};
}
pSurfaceLevel_orig->Release();
if (pOffscreenSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
if (pResolvedSurface != nullptr) {
pResolvedSurface->Release();
}
pOffscreenSurface->Release();
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
return {};
}
}
else if (pTexture->LockRect(0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 1\n");
if (pTexture->GetSurfaceLevel(0, &pResolvedSurface) != D3D_OK) {
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel\n");
return {};
}
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 2\n");
return {};
}
}
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) {
pOffscreenSurface->UnlockRect();
pOffscreenSurface->Release();
if (pResolvedSurface != nullptr) {
pResolvedSurface->Release();
}
}
else if (pResolvedSurface != nullptr) {
pResolvedSurface->UnlockRect();
pResolvedSurface->Release();
}
else {
pTexture->UnlockRect(0);
}
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};
}
-280
View File
@@ -1,280 +0,0 @@
#include "Main.h"
import ModfileLoader;
import TextureClient;
import TextureFunction;
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::QueryInterface(REFIID riid, void** ppvObj)
{
if (riid == IID_IDirect3D9) {
// This function should never be called with IID_IDirect3D9 by the game
// thus this call comes from our own dll to ask for the texture type
// 0x01000000L == uMod_IDirect3DTexture9
// 0x01000001L == uMod_IDirect3DVolumeTexture9
// 0x01000002L == uMod_IDirect3DCubeTexture9
*ppvObj = this;
return 0x01000001L;
}
HRESULT hRes;
if (CrossRef_D3Dtex != nullptr) {
hRes = CrossRef_D3Dtex->m_D3Dtex->QueryInterface(riid, ppvObj);
if (*ppvObj == CrossRef_D3Dtex->m_D3Dtex) {
*ppvObj = this;
}
}
else {
hRes = m_D3Dtex->QueryInterface(riid, ppvObj);
if (*ppvObj == m_D3Dtex) {
*ppvObj = this;
}
}
return hRes;
}
//this function yields for the non switched texture object
ULONG APIENTRY uMod_IDirect3DVolumeTexture9::AddRef()
{
if (FAKE) {
return 1; //bug, this case should never happen
}
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->AddRef();
}
return m_D3Dtex->AddRef();
}
//this function yields for the non switched texture object
ULONG APIENTRY uMod_IDirect3DVolumeTexture9::Release()
{
Message("uMod_IDirect3DVolumeTexture9::Release(): %p\n", this);
void* cpy;
const long ret = m_D3Ddev->QueryInterface(IID_IDirect3DTexture9, &cpy);
ULONG count;
if (FAKE) {
UnswitchTextures(this);
count = m_D3Dtex->Release(); //count must be zero, cause we don't call AddRef of fake_textures
}
else {
if (CrossRef_D3Dtex != nullptr) //if this texture is switched with a fake texture
{
uMod_IDirect3DVolumeTexture9* fake_texture = CrossRef_D3Dtex;
count = fake_texture->m_D3Dtex->Release(); //release the original texture
if (count == 0) //if texture is released we switch the textures back
{
UnswitchTextures(this);
fake_texture->Release(); // we release the fake texture
}
}
else {
count = m_D3Dtex->Release();
}
}
if (count == 0) //if this texture is released, we clean up
{
// if this texture is the LastCreatedTexture, the next time LastCreatedTexture would be added,
// the hash of a non existing texture would be calculated
if (ret == 0x01000000L) {
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetLastCreatedVolumeTexture() == this) {
static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->SetLastCreatedVolumeTexture(nullptr);
}
else {
static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetuMod_Client()->RemoveTexture(this); // remove this texture from the texture client
}
}
else {
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetLastCreatedVolumeTexture() == this) {
static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->SetLastCreatedVolumeTexture(nullptr);
}
else {
static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetuMod_Client()->RemoveTexture(this); // remove this texture from the texture client
}
}
delete this;
}
return count;
}
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::GetDevice(IDirect3DDevice9** ppDevice)
{
*ppDevice = m_D3Ddev;
return D3D_OK;
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::SetPrivateData(REFGUID refguid,CONST void* pData, DWORD SizeOfData, DWORD Flags)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->SetPrivateData(refguid, pData, SizeOfData, Flags);
}
return m_D3Dtex->SetPrivateData(refguid, pData, SizeOfData, Flags);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::GetPrivateData(REFGUID refguid, void* pData, DWORD* pSizeOfData)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetPrivateData(refguid, pData, pSizeOfData);
}
return m_D3Dtex->GetPrivateData(refguid, pData, pSizeOfData);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::FreePrivateData(REFGUID refguid)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->FreePrivateData(refguid);
}
return m_D3Dtex->FreePrivateData(refguid);
}
DWORD APIENTRY uMod_IDirect3DVolumeTexture9::SetPriority(DWORD PriorityNew)
{
return m_D3Dtex->SetPriority(PriorityNew);
}
DWORD APIENTRY uMod_IDirect3DVolumeTexture9::GetPriority()
{
return m_D3Dtex->GetPriority();
}
void APIENTRY uMod_IDirect3DVolumeTexture9::PreLoad()
{
m_D3Dtex->PreLoad();
}
D3DRESOURCETYPE APIENTRY uMod_IDirect3DVolumeTexture9::GetType()
{
return m_D3Dtex->GetType();
}
DWORD APIENTRY uMod_IDirect3DVolumeTexture9::SetLOD(DWORD LODNew)
{
return m_D3Dtex->SetLOD(LODNew);
}
DWORD APIENTRY uMod_IDirect3DVolumeTexture9::GetLOD()
{
return m_D3Dtex->GetLOD();
}
DWORD APIENTRY uMod_IDirect3DVolumeTexture9::GetLevelCount()
{
return m_D3Dtex->GetLevelCount();
}
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType)
{
return m_D3Dtex->SetAutoGenFilterType(FilterType);
}
D3DTEXTUREFILTERTYPE APIENTRY uMod_IDirect3DVolumeTexture9::GetAutoGenFilterType()
{
return m_D3Dtex->GetAutoGenFilterType();
}
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)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->AddDirtyBox(pDirtyBox);
}
return m_D3Dtex->AddDirtyBox(pDirtyBox);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::GetLevelDesc(UINT Level, D3DVOLUME_DESC* pDesc)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetLevelDesc(Level, pDesc);
}
return m_D3Dtex->GetLevelDesc(Level, pDesc);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::GetVolumeLevel(UINT Level, IDirect3DVolume9** ppVolumeLevel)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->GetVolumeLevel(Level, ppVolumeLevel);
}
return m_D3Dtex->GetVolumeLevel(Level, ppVolumeLevel);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::LockBox(UINT Level, D3DLOCKED_BOX* pLockedVolume, CONST D3DBOX* pBox, DWORD Flags)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->LockBox(Level, pLockedVolume, pBox, Flags);
}
return m_D3Dtex->LockBox(Level, pLockedVolume, pBox, Flags);
}
//this function yields for the non switched texture object
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::UnlockBox(UINT Level)
{
if (CrossRef_D3Dtex != nullptr) {
return CrossRef_D3Dtex->m_D3Dtex->UnlockBox(Level);
}
return m_D3Dtex->UnlockBox(Level);
}
HashTuple uMod_IDirect3DVolumeTexture9::GetHash() const
{
if (FAKE) {
return {};
}
IDirect3DVolumeTexture9* pTexture = m_D3Dtex;
if (CrossRef_D3Dtex != nullptr) {
pTexture = CrossRef_D3Dtex->m_D3Dtex;
}
IDirect3DVolume9* pResolvedSurface = nullptr;
D3DLOCKED_BOX d3dlr;
D3DVOLUME_DESC desc;
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) //get the format and the size of the texture
{
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) {
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 1\n");
if (pTexture->GetVolumeLevel(0, &pResolvedSurface) != D3D_OK) {
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetSurfaceLevel\n");
return {};
}
if (pResolvedSurface->LockBox(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
pResolvedSurface->Release();
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 2\n");
return {};
}
}
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) {
pResolvedSurface->UnlockBox();
pResolvedSurface->Release();
}
else {
pTexture->UnlockBox(0);
}
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};
}
+9
View File
@@ -0,0 +1,9 @@
set(VCPKG_TARGET_ARCHITECTURE x86)
if(PORT MATCHES "dxsdk-d3dx")
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE dynamic)
else()
set(VCPKG_CRT_LINKAGE static)
set(VCPKG_LIBRARY_LINKAGE static)
endif()
+9 -1
View File
@@ -1,5 +1,13 @@
{
"dependencies": [
"dxsdk-d3dx"
"dxsdk-d3dx",
{
"name": "libzippp",
"features": [
"encryption"
]
},
"minhook",
"ms-gsl"
]
}