mirror of
https://github.com/gwdevhub/gMod.git
synced 2026-07-17 16:09:30 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 326b7086c9 | |||
| 485ecd1341 | |||
| 175002a9e4 | |||
| 93032262c3 | |||
| fd9d1af477 | |||
| 866455567d | |||
| 26b4f4ce4a | |||
| 5b1bcf6638 | |||
| 766e6439aa | |||
| bca0786cff | |||
| a1f32b5963 | |||
| 21c20c80e5 | |||
| 1692a5526c | |||
| f9d69fc91e | |||
| 7dbbdc480e | |||
| 9e593e83ee | |||
| b49428bafd | |||
| ae2c93fc32 | |||
| a1cadde802 | |||
| 69b06d94a2 | |||
| 514aefa371 | |||
| f07e180b53 | |||
| 13b7df3ae3 | |||
| ab2d8cdb0a |
+15
-58
@@ -1,6 +1,4 @@
|
||||
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: uMod CD Pipeline
|
||||
name: gMod CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -28,66 +26,26 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Config
|
||||
run: echo "DXSDK_DIR=DXSDK" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Cache
|
||||
id: cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: DXSDK
|
||||
key: DXSDK
|
||||
|
||||
- name: Cache create
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
curl -L https://download.microsoft.com/download/a/e/7/ae743f1f-632b-4809-87a9-aa1bb3458e31/DXSDK_Jun10.exe -o _DX2010_.exe
|
||||
7z x _DX2010_.exe DXSDK/Include
|
||||
7z x _DX2010_.exe DXSDK/Lib/x86
|
||||
shell: bash
|
||||
|
||||
- name: Echo cache
|
||||
run: echo ${{ env.DXSDK_DIR }}
|
||||
|
||||
- name: List dxsdk files
|
||||
run: |
|
||||
cd DXSDK
|
||||
ls
|
||||
cd Include
|
||||
ls
|
||||
cd ../Lib/x86
|
||||
ls
|
||||
|
||||
- name: Copy DirectX headers to project include directory
|
||||
run: Copy-Item -Path "${{ env.DXSDK_DIR }}/Include/*" -Destination header/ -Recurse -Force
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
shell: pwsh
|
||||
|
||||
- name: Ensure Lib directory exists and copy DirectX libraries
|
||||
run: |
|
||||
$libDir = "Lib/"
|
||||
if (-Not (Test-Path -Path $libDir)) {
|
||||
New-Item -ItemType Directory -Path $libDir
|
||||
}
|
||||
Copy-Item -Path "${{ env.DXSDK_DIR }}/Lib/x86/*" -Destination $libDir -Recurse -Force
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
shell: pwsh
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1
|
||||
|
||||
- name: Build CMake Files
|
||||
run: cmake -S . -B build -A Win32
|
||||
- name: Install vcpkg
|
||||
run: |
|
||||
git clone https://github.com/microsoft/vcpkg.git
|
||||
.\vcpkg\bootstrap-vcpkg.bat
|
||||
|
||||
- name: Set VCPKG_ROOT
|
||||
run: |
|
||||
echo "VCPKG_ROOT=$(Get-Location)\vcpkg" >> $env:GITHUB_ENV
|
||||
shell: powershell
|
||||
|
||||
- name: Build CMake Files with vcpkg toolchain
|
||||
run: cmake --preset=vcpkg
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
VCPKG_ROOT: ${{ env.VCPKG_ROOT }}
|
||||
|
||||
- name: Build binaries
|
||||
run: cmake --build build --config Release
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
|
||||
- name: Retrieve version
|
||||
id: set_version
|
||||
@@ -108,10 +66,9 @@ jobs:
|
||||
mode: update
|
||||
tag_name: v${{ steps.set_version.outputs.version }}
|
||||
release_name: gMod v${{ steps.set_version.outputs.version }}
|
||||
assets: .\bin\Release\gMod.dll
|
||||
assets: .\bin\Release\gMod.dll;.\bin\Release\TpfConvert.exe;.\bin\Release\d3dx9_43.dll
|
||||
github_token: ${{ env.GITHUB_TOKEN }}
|
||||
replace_assets: true
|
||||
body_mrkdwn: ${{ env.Changelog }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
+18
-60
@@ -1,15 +1,15 @@
|
||||
# This continuous integration pipeline is triggered anytime a user pushes code to the repo.
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: uMod CI Pipeline
|
||||
name: gMod CI Pipeline
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
strategy:
|
||||
@@ -28,65 +28,23 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
#https://stackoverflow.com/questions/61037714/how-to-install-an-old-version-of-the-direct-x-api-in-github-actions
|
||||
- name: Config
|
||||
run: echo "DXSDK_DIR=DXSDK" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Cache
|
||||
id: cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: DXSDK
|
||||
key: DXSDK
|
||||
|
||||
- name: Cache create
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
curl -L https://download.microsoft.com/download/a/e/7/ae743f1f-632b-4809-87a9-aa1bb3458e31/DXSDK_Jun10.exe -o _DX2010_.exe
|
||||
7z x _DX2010_.exe DXSDK/Include
|
||||
7z x _DX2010_.exe DXSDK/Lib/x86
|
||||
shell: bash
|
||||
|
||||
- name: Echo cache
|
||||
run: echo ${{ env.DXSDK_DIR }}
|
||||
|
||||
- name: List dxsdk files
|
||||
run: |
|
||||
cd DXSDK
|
||||
ls
|
||||
cd Include
|
||||
ls
|
||||
cd ../Lib/x86
|
||||
ls
|
||||
|
||||
- name: Copy DirectX headers to project include directory
|
||||
run: Copy-Item -Path "${{ env.DXSDK_DIR }}/Include/*" -Destination header/ -Recurse -Force
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
shell: pwsh
|
||||
|
||||
- name: Ensure Lib directory exists and copy DirectX libraries
|
||||
run: |
|
||||
$libDir = "Lib/"
|
||||
if (-Not (Test-Path -Path $libDir)) {
|
||||
New-Item -ItemType Directory -Path $libDir
|
||||
}
|
||||
Copy-Item -Path "${{ env.DXSDK_DIR }}/Lib/x86/*" -Destination $libDir -Recurse -Force
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
shell: pwsh
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1
|
||||
|
||||
- name: Build CMake Files
|
||||
run: cmake -S . -B build -A Win32
|
||||
- name: Install vcpkg
|
||||
run: |
|
||||
git clone https://github.com/microsoft/vcpkg.git
|
||||
.\vcpkg\bootstrap-vcpkg.bat
|
||||
|
||||
- name: Set VCPKG_ROOT
|
||||
run: |
|
||||
echo "VCPKG_ROOT=$(Get-Location)\vcpkg" >> $env:GITHUB_ENV
|
||||
shell: powershell
|
||||
|
||||
- name: Build CMake Files with vcpkg toolchain
|
||||
run: cmake --preset=vcpkg
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
VCPKG_ROOT: ${{ env.VCPKG_ROOT }}
|
||||
|
||||
- name: Build binaries
|
||||
run: cmake --build build --config Release
|
||||
env:
|
||||
DXSDK_DIR: ${{ env.DXSDK_DIR }}
|
||||
|
||||
+16
@@ -5,6 +5,15 @@
|
||||
*.vscode
|
||||
*.project
|
||||
*.cproject
|
||||
*.vcproj
|
||||
*.vcxproj
|
||||
*.vcxproj.filters
|
||||
**/CMakeFiles/**
|
||||
cmake_install.cmake
|
||||
CMakeCache.txt
|
||||
*.sln
|
||||
*.rc
|
||||
/*.dir
|
||||
|
||||
# Build directories
|
||||
Release
|
||||
@@ -14,6 +23,8 @@ bin/
|
||||
*/Release
|
||||
*/bin
|
||||
*/obj
|
||||
vcpkg
|
||||
vcpkg_installed
|
||||
|
||||
# Bloated Windows Databases
|
||||
*.sdf
|
||||
@@ -46,7 +57,12 @@ bin/
|
||||
*.opendb
|
||||
*.wixpdb
|
||||
|
||||
**/RelWithDebInfo/
|
||||
**/Debug/
|
||||
/bin
|
||||
/win32
|
||||
/out
|
||||
/build
|
||||
/_deps
|
||||
|
||||
.idea
|
||||
+35
-26
@@ -1,57 +1,64 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.29)
|
||||
|
||||
set(CMAKE_GENERATOR_PLATFORM win32)
|
||||
|
||||
project(gMod)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
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()
|
||||
|
||||
set(VERSION_MAJOR 1)
|
||||
set(VERSION_MINOR 5)
|
||||
set(VERSION_PATCH 3)
|
||||
set(VERSION_TWEAK 0)
|
||||
set(VERSION_MINOR 7)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_TWEAK 2)
|
||||
|
||||
set(VERSION_RC "${CMAKE_CURRENT_BINARY_DIR}/version.rc")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in" "${VERSION_RC}" @ONLY)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin/")
|
||||
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_property(GLOBAL PROPERTY USE_FOLDERS OFF)
|
||||
|
||||
add_compile_options(/MP /permissive-)
|
||||
|
||||
find_library(D3D9_LIB NAMES d3d9 PATHS $ENV{DXSDK_DIR}/lib/x86 NO_DEFAULT_PATH)
|
||||
find_library(D3DX9_LIB NAMES d3dx9 PATHS $ENV{DXSDK_DIR}/lib/x86 NO_DEFAULT_PATH)
|
||||
find_library(DXGUID_LIB NAMES dxguid PATHS $ENV{DXSDK_DIR}/lib/x86 NO_DEFAULT_PATH)
|
||||
|
||||
if(NOT D3D9_LIB)
|
||||
find_library(D3D9_LIB NAMES d3d9 PATHS ${CMAKE_SOURCE_DIR}/Lib)
|
||||
endif()
|
||||
|
||||
if(NOT D3DX9_LIB)
|
||||
find_library(D3DX9_LIB NAMES d3dx9 PATHS ${CMAKE_SOURCE_DIR}/Lib)
|
||||
endif()
|
||||
|
||||
if(NOT DXGUID_LIB)
|
||||
find_library(DXGUID_LIB NAMES dxguid PATHS ${CMAKE_SOURCE_DIR}/Lib)
|
||||
endif()
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||
find_package(libzippp CONFIG REQUIRED)
|
||||
find_package(minhook CONFIG REQUIRED)
|
||||
find_package(Microsoft.GSL CONFIG REQUIRED)
|
||||
include(dxtk)
|
||||
|
||||
add_library(gMod SHARED)
|
||||
|
||||
file(GLOB SOURCES
|
||||
"header/*.h"
|
||||
"source/*.cpp"
|
||||
"modules/*.ixx"
|
||||
${VERSION_RC}
|
||||
)
|
||||
|
||||
target_link_libraries(gMod PRIVATE ${D3D9_LIB} ${D3DX9_LIB} ${DXGUID_LIB})
|
||||
target_include_directories(gMod PRIVATE $ENV{DXSDK_DIR}/Include)
|
||||
target_include_directories(gMod PUBLIC "header")
|
||||
target_include_directories(gMod PRIVATE
|
||||
"header"
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
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
|
||||
psapi
|
||||
minhook::minhook
|
||||
directxtex
|
||||
Microsoft.GSL::GSL
|
||||
)
|
||||
target_link_options(gMod PRIVATE
|
||||
"$<$<CONFIG:DEBUG>:/NODEFAULTLIB:LIBCMT>"
|
||||
"/LARGEADDRESSAWARE"
|
||||
)
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES})
|
||||
target_sources(gMod PRIVATE ${SOURCES})
|
||||
target_compile_definitions(gMod PRIVATE
|
||||
@@ -61,4 +68,6 @@ target_compile_definitions(gMod PRIVATE
|
||||
"VC_EXTRALEAN"
|
||||
DIRECT_INJECTION
|
||||
LOG_MESSAGE
|
||||
)
|
||||
)
|
||||
|
||||
add_subdirectory(TpfConvert)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"version": 2,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "vcpkg",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -0,0 +1,44 @@
|
||||
***gMod***
|
||||
|
||||
Continuation of the uMod project to improve performance and stability. Integrated with [Guild Wars Launcher](https://github.com/gwdevhub/gwlauncher) and [Daybreak](https://github.com/gwdevhub/Daybreak).
|
||||
|
||||
*Usage is primarily intended with GW Launcher or Daybreak, but it can be used without.*
|
||||
|
||||
**Usage with manual gMod.dll injection:**
|
||||
- Create a file called modlist.txt in either the Guild Wars (Gw.exe) folder, or the gMod.dll folder.
|
||||
- Inject gMod.dll before d3d9.dll is loaded.
|
||||
|
||||
**Usage without dll injection:**
|
||||
- Create a file called modlist.txt in the Guild Wars (Gw.exe) folder.
|
||||
- Place gMod.dll in the Guild Wars folder
|
||||
- Rename gMod.dll to d3d9.dll
|
||||
- Launch Guild Wars
|
||||
|
||||
**Format of the modlist.txt file:**
|
||||
|
||||
Each line in the modlist.txt is the full path to a mod you want to load (eg. `D:\uMod\Borderless Cartography Made Easy 2015 1.3.tpf`)
|
||||
gMod will load all these files on startup
|
||||
|
||||
**Disclaimer about [Reshade](https://github.com/crosire/reshade)**
|
||||
|
||||
Reshade in versions > 5.0.1 is known to cause glitches with TexMod, uMod and also gMod.
|
||||
If you would like to use Reshade in combination with gMod, we recommend running version [5.0.1](https://github.com/crosire/reshade/releases/tag/v5.0.1) or [4.9.1](https://github.com/crosire/reshade/releases/tag/v4.9.1).
|
||||
|
||||
**Build from source**
|
||||
|
||||
Requirements:
|
||||
- Visual Studio 2022
|
||||
- CMake 3.29+, integrated into the Developer Powershell for VS 2022
|
||||
- vcpkg, integrated into the Developer Powershell for VS 2022
|
||||
|
||||
Compile:
|
||||
- cmake --preset=vcpkg
|
||||
- cmake --open build
|
||||
- compile
|
||||
|
||||
**TpfConvert**
|
||||
Small utility to convert old .tpf files with invalid images into .zip files with working images.
|
||||
Usage:
|
||||
- Put TpfConvert.exe and d3dx9.dll 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,9 +0,0 @@
|
||||
Requirements:
|
||||
- The DirectX SDK (I use June 2010)
|
||||
- Visual Studio (2010+)
|
||||
(- Maybe CMake if you don't want to use Visual Studio)
|
||||
|
||||
Usage:
|
||||
Create a file in the root GuildWars folder (where gw.exe is located) called modlist.txt
|
||||
Each line in the modlist.txt is the full path to a mod you want to load (eg. D:Games\uMod\Mods\Borderless Cartography Made Easy 2015 1.3.tpf)
|
||||
uMod will load all these files on startup
|
||||
@@ -0,0 +1,39 @@
|
||||
add_executable(TpfConvert)
|
||||
|
||||
# Find all .ixx files in the TpfConvert folder
|
||||
file(GLOB TPF_SOURCES "src/*.ixx")
|
||||
|
||||
# Add the .ixx files to the TpfConvert target
|
||||
target_sources(TpfConvert PRIVATE ${TPF_SOURCES})
|
||||
|
||||
set_target_properties(TpfConvert PROPERTIES
|
||||
CXX_STANDARD 23
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
|
||||
target_compile_definitions(TpfConvert PRIVATE
|
||||
"NOMINMAX"
|
||||
"_WIN32_WINNT=_WIN32_WINNT_WIN7"
|
||||
"WIN32_LEAN_AND_MEAN"
|
||||
"VC_EXTRALEAN"
|
||||
)
|
||||
|
||||
if(DEFINED ENV{VCPKG_ROOT})
|
||||
message(STATUS "VCPKG_ROOT: $ENV{VCPKG_ROOT}")
|
||||
else()
|
||||
message(STATUS "VCPKG_ROOT is not set")
|
||||
endif()
|
||||
|
||||
if(DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
message(STATUS "CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}")
|
||||
else()
|
||||
message(STATUS "CMAKE_TOOLCHAIN_FILE is not set")
|
||||
endif()
|
||||
|
||||
find_package(dxsdk-d3dx CONFIG REQUIRED)
|
||||
|
||||
target_link_libraries(TpfConvert PRIVATE
|
||||
libzippp::libzippp
|
||||
Microsoft::D3DX9
|
||||
d3d9
|
||||
)
|
||||
@@ -0,0 +1,179 @@
|
||||
export module ModfileLoader;
|
||||
|
||||
import std;
|
||||
import <libzippp.h>;
|
||||
import ModfileLoader.TpfReader;
|
||||
|
||||
export using HashType = uint64_t;
|
||||
|
||||
export struct TexEntry {
|
||||
std::vector<uint8_t> data{};
|
||||
HashType crc_hash = 0; // hash value
|
||||
std::string ext{};
|
||||
};
|
||||
|
||||
namespace {
|
||||
HashType GetCrcFromFilename(const std::string& filename) {
|
||||
const static std::regex re(R"(0x[0-9a-f]{4,16})", std::regex::optimize | std::regex::icase);
|
||||
std::smatch match;
|
||||
if (!std::regex_search(filename, match, re)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t crc64_hash = 0;
|
||||
const auto number_str = match.str();
|
||||
try {
|
||||
crc64_hash = std::stoull(number_str, nullptr, 16);
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
std::print(stderr, "Failed to parse {} as a hash\n", filename);
|
||||
return 0;
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
std::print(stderr, "Out of range while parsing {} as a hash\n", filename);
|
||||
return 0;
|
||||
}
|
||||
return crc64_hash;
|
||||
}
|
||||
}
|
||||
|
||||
export class ModfileLoader {
|
||||
std::filesystem::path file_name;
|
||||
const std::string TPF_PASSWORD{
|
||||
0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast<char>(0xA6), static_cast<char>(0xBD),
|
||||
0x7D, 0x65, 0x7E, 0x67, 0x61, 0x2A, 0x7F, 0x7F,
|
||||
0x74, 0x61, 0x67, 0x5B, 0x60, 0x70, 0x45, 0x74,
|
||||
0x5C, 0x22, 0x74, 0x5D, 0x6E, 0x6A, 0x73, 0x41,
|
||||
0x77, 0x6E, 0x46, 0x47, 0x77, 0x49, 0x0C, 0x4B,
|
||||
0x46, 0x6F
|
||||
};
|
||||
|
||||
public:
|
||||
ModfileLoader(const std::filesystem::path& fileName);
|
||||
|
||||
std::vector<TexEntry> GetContents() const;
|
||||
|
||||
private:
|
||||
|
||||
std::vector<TexEntry> GetTpfContents() const;
|
||||
|
||||
std::vector<TexEntry> GetFileContents() const;
|
||||
|
||||
static void LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries);
|
||||
};
|
||||
|
||||
ModfileLoader::ModfileLoader(const std::filesystem::path& fileName)
|
||||
{
|
||||
file_name = std::filesystem::absolute(fileName);
|
||||
}
|
||||
|
||||
std::vector<TexEntry> ModfileLoader::GetContents() const
|
||||
{
|
||||
try {
|
||||
return file_name.wstring().ends_with(L".tpf") ? GetTpfContents() : GetFileContents();
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
std::print(stderr, "Failed to open mod file: {}\n", file_name.string().c_str());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<TexEntry> ModfileLoader::GetTpfContents() const
|
||||
{
|
||||
std::vector<TexEntry> entries;
|
||||
auto tpf_reader = TpfReader(file_name);
|
||||
const auto buffer = tpf_reader.ReadToEnd();
|
||||
const auto zip_archive = libzippp::ZipArchive::fromBuffer(buffer.data(), buffer.size(), false, TPF_PASSWORD);
|
||||
if (!zip_archive) {
|
||||
std::print(stderr, "Failed to open tpf file: {} - {} uint8_ts!\n", file_name.string(), buffer.size());
|
||||
return {};
|
||||
}
|
||||
zip_archive->setErrorHandlerCallback(
|
||||
[](const std::string& message, const std::string& strerror, int zip_error_code, int system_error_code) -> void {
|
||||
std::print(stderr, "GetTpfContents: {} {} {} {}\n", message, strerror, zip_error_code, system_error_code);
|
||||
});
|
||||
zip_archive->open();
|
||||
LoadEntries(*zip_archive, entries);
|
||||
zip_archive->close();
|
||||
libzippp::ZipArchive::free(zip_archive);
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::vector<TexEntry> ModfileLoader::GetFileContents() const
|
||||
{
|
||||
std::vector<TexEntry> entries;
|
||||
|
||||
libzippp::ZipArchive zip_archive(file_name.string());
|
||||
zip_archive.open();
|
||||
LoadEntries(zip_archive, entries);
|
||||
zip_archive.close();
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
for (const auto& entry : archive.getEntries()) {
|
||||
if (!entry.isFile())
|
||||
continue;
|
||||
const auto crc_hash = GetCrcFromFilename(entry.getName());
|
||||
if (!crc_hash)
|
||||
continue;
|
||||
const auto data_ptr = static_cast<uint8_t*>(entry.readAsBinary());
|
||||
const auto size = entry.getSize();
|
||||
std::vector vec(data_ptr, data_ptr + size);
|
||||
std::filesystem::path tex_name(entry.getName());
|
||||
entries.emplace_back(std::move(vec), crc_hash, tex_name.extension().string());
|
||||
delete[] data_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
for (const auto& line : lines) {
|
||||
// 0xC57D73F7|GW.EXE_0xC57D73F7.tga\r\n
|
||||
// match[1] | match[2]
|
||||
const static auto address_file_regex = std::regex(R"(^[\\/.]*([^|]+)\|([^\r\n]+))", std::regex::optimize);
|
||||
std::smatch match;
|
||||
if (!std::regex_search(line, match, address_file_regex))
|
||||
continue;
|
||||
const auto address_string = match[1].str();
|
||||
const auto file_path = match[2].str();
|
||||
|
||||
const auto crc_hash = GetCrcFromFilename(address_string);
|
||||
if (!crc_hash)
|
||||
continue;
|
||||
|
||||
const auto entry = archive.getEntry(file_path);
|
||||
if (entry.isNull() || !entry.isFile())
|
||||
continue;
|
||||
|
||||
const auto data_ptr = static_cast<uint8_t*>(entry.readAsBinary());
|
||||
const auto size = static_cast<size_t>(entry.getSize());
|
||||
std::vector vec(data_ptr, data_ptr + size);
|
||||
const auto tex_name = std::filesystem::path(entry.getName());
|
||||
entries.emplace_back(std::move(vec), crc_hash, tex_name.extension().string());
|
||||
delete[] data_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ModfileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
const auto def_file = archive.getEntry("texmod.def");
|
||||
if (def_file.isNull() || !def_file.isFile()) {
|
||||
ParseSimpleArchive(archive, entries);
|
||||
}
|
||||
else {
|
||||
const auto def = def_file.readAsText();
|
||||
std::istringstream iss(def);
|
||||
std::vector<std::string> lines;
|
||||
std::string line;
|
||||
|
||||
while (std::getline(iss, line)) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
ParseTexmodArchive(lines, archive, entries);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
export module ModfileLoader.TpfReader;
|
||||
|
||||
import std;
|
||||
|
||||
export class TpfReader {
|
||||
public:
|
||||
TpfReader(const std::filesystem::path& path)
|
||||
{
|
||||
file_stream = std::ifstream(path, std::ios::binary);
|
||||
if (!file_stream.seekg(0, std::ios::end).good() || !file_stream.seekg(0, std::ios::beg).good()) {
|
||||
throw std::invalid_argument("Provided stream needs to have SEEK set to True");
|
||||
}
|
||||
}
|
||||
|
||||
~TpfReader()
|
||||
{
|
||||
file_stream.close();
|
||||
}
|
||||
|
||||
std::vector<char> ReadToEnd()
|
||||
{
|
||||
file_stream.seekg(0, std::ios::end);
|
||||
line_length = file_stream.tellg();
|
||||
file_stream.seekg(0, std::ios::beg); // Go to the beginning of the stream
|
||||
|
||||
std::vector<char> data(line_length);
|
||||
file_stream.read(data.data(), line_length);
|
||||
for (auto i = 0; i < data.size(); i++) {
|
||||
data[i] = XOR(data[i], i);
|
||||
}
|
||||
|
||||
for (int i = data.size() - 1; i > 0 && data[i] != 0; i--) {
|
||||
data[i] = 0;
|
||||
}
|
||||
|
||||
// in the other zip libraries, these had to be cut off, with libzip we need to zero them out
|
||||
// cutting them off makes the archive invalid
|
||||
//data.resize(last_zero);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ifstream file_stream;
|
||||
long line_length = 0;
|
||||
|
||||
[[nodiscard]] char XOR(const char b, const long position) const
|
||||
{
|
||||
if (position > line_length - 4) {
|
||||
return b ^ TPF_XOREven;
|
||||
}
|
||||
|
||||
return position % 2 == 0 ? b ^ TPF_XOREven : b ^ TPF_XOROdd;
|
||||
}
|
||||
|
||||
static constexpr char TPF_XOROdd = 0x3F;
|
||||
static constexpr char TPF_XOREven = static_cast<char>(0xA4);
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
#include <corecrt_wstdio.h>
|
||||
#include <Windows.h>
|
||||
#include <d3dx9.h>
|
||||
#include <d3d9.h>
|
||||
|
||||
import std;
|
||||
import ModfileLoader;
|
||||
import <libzippp.h>;
|
||||
|
||||
struct TexEntry;
|
||||
|
||||
namespace {
|
||||
IDirect3D9* pD3D = nullptr;
|
||||
IDirect3DDevice9* pDevice = nullptr;
|
||||
|
||||
bool InitializeDirect3D()
|
||||
{
|
||||
pD3D = Direct3DCreate9(D3D_SDK_VERSION);
|
||||
if (pD3D == nullptr) {
|
||||
std::print(stderr, "Failed to create Direct3D9 object\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
D3DPRESENT_PARAMETERS d3dpp = {};
|
||||
d3dpp.Windowed = TRUE;
|
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
d3dpp.hDeviceWindow = GetDesktopWindow();
|
||||
|
||||
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow(),
|
||||
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice))) {
|
||||
std::print(stderr, "Failed to create Direct3D9 device\n");
|
||||
pD3D->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CleanupDirect3D()
|
||||
{
|
||||
if (pDevice) pDevice->Release();
|
||||
if (pD3D) pD3D->Release();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::vector<uint8_t>> SaveAsDDS(const TexEntry& entry)
|
||||
{
|
||||
IDirect3DTexture9* pTexture = nullptr;
|
||||
ID3DXBuffer* pBuffer = nullptr;
|
||||
|
||||
HRESULT hr = D3DXCreateTextureFromFileInMemoryEx(pDevice,
|
||||
entry.data.data(), entry.data.size(),
|
||||
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0,
|
||||
D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_NONE,
|
||||
D3DX_FILTER_NONE, 0, NULL, NULL, &pTexture);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
std::print(stderr, "Failed to create texture from memory\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
hr = D3DXSaveTextureToFileInMemory(&pBuffer, D3DXIFF_DDS, pTexture, NULL);
|
||||
if (FAILED(hr)) {
|
||||
std::print(stderr, "Failed to save texture to DDS memory buffer\n");
|
||||
pTexture->Release();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string dds_filename = std::format("0x{:x}.dds", entry.crc_hash);
|
||||
std::vector<uint8_t> dds_data(pBuffer->GetBufferSize());
|
||||
std::memcpy(dds_data.data(), pBuffer->GetBufferPointer(), pBuffer->GetBufferSize());
|
||||
|
||||
pTexture->Release();
|
||||
pBuffer->Release();
|
||||
|
||||
return {dds_filename, dds_data};
|
||||
}
|
||||
|
||||
std::filesystem::path GetExecutablePath()
|
||||
{
|
||||
char buffer[MAX_PATH];
|
||||
GetModuleFileNameA(NULL, buffer, MAX_PATH);
|
||||
return std::filesystem::path(buffer).parent_path();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const std::filesystem::path path = argc > 1 ? argv[1] : GetExecutablePath();
|
||||
const auto backup_path = path / "backup";
|
||||
|
||||
if (!InitializeDirect3D()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(path)) {
|
||||
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();
|
||||
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 = path / (mod_path.stem().string() + ".zip");
|
||||
if (std::filesystem::exists(zip_filename)) {
|
||||
std::filesystem::remove(zip_filename);
|
||||
}
|
||||
|
||||
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) {
|
||||
auto [dds_filename, dds_data] = SaveAsDDS(entry);
|
||||
if (!dds_filename.empty()) {
|
||||
data_entries.emplace_back(dds_filename, std::move(dds_data));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [filename, data] : data_entries) {
|
||||
const auto success = zip_archive.addData(filename, data.data(), data.size());
|
||||
if (!success) {
|
||||
std::print(stderr, "Failed to add data to ZIP: {}\n", filename);
|
||||
}
|
||||
}
|
||||
|
||||
zip_archive.close();
|
||||
std::print("Saved to ZIP: {}\n", zip_filename.string());
|
||||
}
|
||||
}
|
||||
|
||||
CleanupDirect3D();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
include_guard()
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
DirectXTex
|
||||
GIT_REPOSITORY https://github.com/microsoft/DirectXTex
|
||||
GIT_TAG oct2023)
|
||||
FetchContent_GetProperties(directxtex)
|
||||
if (directxtex_POPULATED)
|
||||
return()
|
||||
endif()
|
||||
|
||||
FetchContent_Populate(directxtex)
|
||||
|
||||
add_library(directxtex)
|
||||
file(GLOB SOURCES
|
||||
"${directxtex_SOURCE_DIR}/DDSTextureLoader/DDSTextureLoader9.h"
|
||||
"${directxtex_SOURCE_DIR}/DDSTextureLoader/DDSTextureLoader9.cpp"
|
||||
"${directxtex_SOURCE_DIR}/WICTextureLoader/WICTextureLoader9.h"
|
||||
"${directxtex_SOURCE_DIR}/WICTextureLoader/WICTextureLoader9.cpp"
|
||||
"${directxtex_SOURCE_DIR}/DirectXTex/*.h"
|
||||
"${directxtex_SOURCE_DIR}/DirectXTex/*.cpp"
|
||||
)
|
||||
list(REMOVE_ITEM SOURCES
|
||||
"${directxtex_SOURCE_DIR}/DirectXTex/BCDirectCompute.cpp"
|
||||
)
|
||||
source_group(TREE ${directxtex_SOURCE_DIR} FILES ${SOURCES})
|
||||
target_sources(directxtex PRIVATE ${SOURCES})
|
||||
target_include_directories(directxtex PUBLIC "${directxtex_SOURCE_DIR}")
|
||||
|
||||
set_target_properties(directxtex PROPERTIES FOLDER "Dependencies/")
|
||||
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
//using HashType = DWORD32;
|
||||
using HashType = DWORD64;
|
||||
|
||||
struct HashTuple {
|
||||
HashType crc32;
|
||||
HashType crc64;
|
||||
|
||||
bool operator==(const HashTuple& other) const noexcept
|
||||
{
|
||||
return (other.crc32 == crc32) || (other.crc64 == crc64);
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return crc32 != 0 || crc64 != 0;
|
||||
}
|
||||
|
||||
explicit operator HashType() const noexcept
|
||||
{
|
||||
return crc32 ? crc32 : crc64;
|
||||
}
|
||||
};
|
||||
|
||||
struct TexEntry {
|
||||
std::vector<BYTE> data{};
|
||||
HashType crc_hash = 0; // hash value
|
||||
std::string ext{};
|
||||
};
|
||||
|
||||
struct TextureFileStruct {
|
||||
std::vector<BYTE> data{};
|
||||
HashType crc_hash = 0; // hash value
|
||||
};
|
||||
|
||||
inline void Message([[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([[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);
|
||||
[[maybe_unused]] const auto success = SetConsoleTextAttribute(hConsole, 6); // yellow
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// define return values, a value less than zero indicates an error
|
||||
#define RETURN_OK 0
|
||||
#define RETURN_EXISTS -70
|
||||
|
||||
#define RETURN_FATAL_ERROR -1
|
||||
#define RETURN_NO_MEMORY -2
|
||||
@@ -41,3 +42,11 @@
|
||||
#define uMod_ERROR_UPDATE 1u<<7
|
||||
#define uMod_ERROR_SERVER 1u<<8
|
||||
|
||||
__declspec(noreturn) void FatalAssert(
|
||||
const char* expr,
|
||||
const char* file,
|
||||
unsigned int line,
|
||||
const char* function);
|
||||
|
||||
#define ASSERT(expr) ((void)(!!(expr) || (FatalAssert(#expr, __FILE__, (unsigned)__LINE__, __FUNCTION__), 0)))
|
||||
|
||||
@@ -4,15 +4,19 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include "Utils.h"
|
||||
|
||||
#include <d3d9.h>
|
||||
#include <d3dx9.h>
|
||||
#include <gsl/gsl>
|
||||
|
||||
#include "uMod_GlobalDefines.h"
|
||||
#include "uMod_Error.h"
|
||||
#include "uMod_Defines.h"
|
||||
#include "uMod_DX9_dll.h"
|
||||
#include "uMod_TextureFunction.h"
|
||||
#include "Defines.h"
|
||||
#include "Error.h"
|
||||
#include "Defines.h"
|
||||
|
||||
#include "uMod_IDirect3D9.h"
|
||||
#include "uMod_IDirect3D9Ex.h"
|
||||
@@ -24,10 +28,7 @@
|
||||
#include "uMod_IDirect3DTexture9.h"
|
||||
#include "uMod_IDirect3DVolumeTexture9.h"
|
||||
|
||||
#include "uMod_ArrayHandler.h"
|
||||
#include "uMod_TextureServer.h"
|
||||
#include "uMod_TextureClient.h"
|
||||
|
||||
#pragma warning(disable : 4477)
|
||||
|
||||
extern unsigned int gl_ErrorState;
|
||||
extern HINSTANCE gl_hThisInstance;
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
template<typename T>
|
||||
void erase_first(std::vector<T>& vec, const T& elem)
|
||||
{
|
||||
const auto found = std::ranges::find(vec, elem);
|
||||
if (found != std::ranges::end(vec)) {
|
||||
vec.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::wstring utf8_to_wstring(const std::string& utf8str) {
|
||||
if (utf8str.empty()) return {};
|
||||
|
||||
// Calculate the number of wide characters needed for the conversion
|
||||
const int count = MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), -1, nullptr, 0);
|
||||
if (count == 0) throw std::runtime_error("Failed to convert UTF-8 to UTF-16");
|
||||
|
||||
std::wstring wstr(count, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), -1, wstr.data(), count);
|
||||
|
||||
return wstr;
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "uMod_GlobalDefines.h"
|
||||
#include "uMod_IDirect3DTexture9.h"
|
||||
extern unsigned int gl_ErrorState;
|
||||
|
||||
using TextureFileStruct = struct {
|
||||
bool ForceReload; // to force a reload of the texture (if it is already modded)
|
||||
char* pData; // store texture file as file in memory
|
||||
unsigned int Size; // size of file
|
||||
int NumberOfTextures;
|
||||
int Reference; // for a fast delete in the FileHandler
|
||||
IDirect3DBaseTexture9** Textures; // pointer to the fake textures
|
||||
MyTypeHash Hash; // hash value
|
||||
};
|
||||
|
||||
class uMod_FileHandler // array to store TextureFileStruct
|
||||
{
|
||||
public:
|
||||
uMod_FileHandler();
|
||||
~uMod_FileHandler();
|
||||
|
||||
int Add(TextureFileStruct* file);
|
||||
int Remove(TextureFileStruct* file);
|
||||
|
||||
int GetNumber() { return Number; }
|
||||
|
||||
TextureFileStruct* operator [](int i)
|
||||
{
|
||||
if (i < 0 || i >= Number) {
|
||||
return nullptr;
|
||||
}
|
||||
return Files[i / FieldLength][i % FieldLength];
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr int FieldLength = 1024;
|
||||
long Number;
|
||||
int FieldCounter;
|
||||
TextureFileStruct*** Files;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class uMod_TextureHandler // array to store uMod_IDirect3DTexture9, uMod_IDirect3DVolumeTexture9 or uMod_IDirect3DCubeTexture9
|
||||
{
|
||||
public:
|
||||
uMod_TextureHandler();
|
||||
~uMod_TextureHandler();
|
||||
|
||||
int Add(T* texture);
|
||||
int Remove(T* texture);
|
||||
|
||||
int GetNumber() { return Number; }
|
||||
|
||||
T* operator [](int i)
|
||||
{
|
||||
if (i < 0 || i >= Number) {
|
||||
return nullptr;
|
||||
}
|
||||
return Textures[i / FieldLength][i % FieldLength];
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int FieldLength = 1024;
|
||||
long Number;
|
||||
int FieldCounter;
|
||||
T*** Textures;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
uMod_TextureHandler<T>::uMod_TextureHandler()
|
||||
{
|
||||
Message("uMod_TextureHandler(): %lu\n", this);
|
||||
Number = 0;
|
||||
FieldCounter = 0;
|
||||
|
||||
Textures = NULL;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uMod_TextureHandler<T>::~uMod_TextureHandler()
|
||||
{
|
||||
Message("~uMod_TextureHandler(): %lu\n", this);
|
||||
if (Textures != nullptr) {
|
||||
for (int i = 0; i < FieldCounter; i++) {
|
||||
delete [] Textures[i];
|
||||
}
|
||||
delete [] Textures;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int uMod_TextureHandler<T>::Add(T* pTexture)
|
||||
{
|
||||
Message("uMod_TextureHandler::Add( %lu): %lu\n", pTexture, this);
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (pTexture->Reference >= 0) {
|
||||
return RETURN_TEXTURE_ALLREADY_ADDED;
|
||||
}
|
||||
|
||||
if (Number / FieldLength == FieldCounter) {
|
||||
T*** temp = nullptr;
|
||||
try { temp = new T**[FieldCounter + 10]; }
|
||||
catch (...) {
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_TEXTURE;
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (int i = 0; i < FieldCounter; i++) {
|
||||
temp[i] = Textures[i];
|
||||
}
|
||||
|
||||
for (int i = FieldCounter; i < FieldCounter + 10; i++) {
|
||||
temp[i] = NULL;
|
||||
}
|
||||
|
||||
FieldCounter += 10;
|
||||
|
||||
delete [] Textures;
|
||||
|
||||
Textures = temp;
|
||||
}
|
||||
if (Number % FieldLength == 0) {
|
||||
try {
|
||||
if (Textures[Number / FieldLength] == NULL) {
|
||||
Textures[Number / FieldLength] = new T*[FieldLength];
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
Textures[Number / FieldLength] = NULL;
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_TEXTURE;
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
Textures[Number / FieldLength][Number % FieldLength] = pTexture;
|
||||
pTexture->Reference = Number++;
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
int uMod_TextureHandler<T>::Remove(T* pTexture) //will be called, if a texture is completely released
|
||||
{
|
||||
Message("uMod_TextureHandler::Remove( %lu): %lu\n", pTexture, this);
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
||||
int ref = pTexture->Reference;
|
||||
if (ref < 0) {
|
||||
return RETURN_OK; // returning if no TextureHandlerRef is set
|
||||
}
|
||||
|
||||
if (ref < (--Number)) {
|
||||
Textures[ref / FieldLength][ref % FieldLength] = Textures[Number / FieldLength][Number % FieldLength];
|
||||
Textures[ref / FieldLength][ref % FieldLength]->Reference = ref;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
|
||||
void InitInstance(HINSTANCE hModule);
|
||||
void ExitInstance();
|
||||
void LoadOriginalDll();
|
||||
bool FindLoadedDll();
|
||||
bool IsDesiredModule(HMODULE hModule, HANDLE hProcess);
|
||||
bool HasDesiredMethods(HMODULE hModule, HANDLE hProcess);
|
||||
bool HookThisProgram(char* ret);
|
||||
DWORD WINAPI ServerThread(LPVOID lpParam);
|
||||
|
||||
void* DetourFunc(BYTE* src, const BYTE* dst, int len);
|
||||
bool RetourFunc(BYTE* src, BYTE* restore, int len);
|
||||
IDirect3D9*APIENTRY uMod_Direct3DCreate9(UINT SDKVersion);
|
||||
HRESULT APIENTRY uMod_Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D);
|
||||
|
||||
|
||||
#ifdef DIRECT_INJECTION
|
||||
void Nothing();
|
||||
#endif
|
||||
@@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef LOG_MESSAGE
|
||||
extern FILE* gl_File;
|
||||
|
||||
#define Message(...) { printf(__VA_ARGS__); }
|
||||
#ifdef HOOK_INJECTION
|
||||
#define OpenMessage(...) {if (fopen_s( &gl_File, "uMod_log.txt", "wt")) gl_File=NULL; else fprintf( gl_File, "HI R40: 0000000\n");}
|
||||
#endif
|
||||
|
||||
#ifdef DIRECT_INJECTION
|
||||
#define OpenMessage(...)
|
||||
#endif
|
||||
|
||||
#ifdef NO_INJECTION
|
||||
#define OpenMessage(...) {if (fopen_s( &gl_File, "uMod_log.txt", "wt")) gl_File=NULL; else fprintf( gl_File, "NI R40: 0000000\n");}
|
||||
#endif
|
||||
|
||||
#define CloseMessage(...)
|
||||
|
||||
|
||||
#else
|
||||
#define OpenMessage(...)
|
||||
#define Message(...)
|
||||
#define CloseMessage(...)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __CDT_PARSER__
|
||||
typedef unsigned long DWORD64;
|
||||
typedef unsigned long DWORD32;
|
||||
|
||||
#define STDMETHOD(method) virtual HRESULT method
|
||||
#define STDMETHOD_(ret, method) virtual ret method
|
||||
#define sprintf_s(...)
|
||||
#define fprintf(...)
|
||||
#define fclose(...)
|
||||
#define fseek(...)
|
||||
#define ftell(...) 0
|
||||
#define fflush(...)
|
||||
typedef LONG HRESULT;
|
||||
|
||||
#define UNREFERENCED_PARAMETER(...)
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "uMod_Main.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "uMod_Texture.h"
|
||||
|
||||
class uMod_File {
|
||||
public:
|
||||
uMod_File();
|
||||
uMod_File(std::string file);
|
||||
~uMod_File();
|
||||
|
||||
bool FileSupported();
|
||||
bool PackageFile();
|
||||
bool SingleFile();
|
||||
//int AddSingleFileToNode( uMod_TreeViewNode* node);
|
||||
int GetContentTemplate(const std::string& content);
|
||||
|
||||
/*
|
||||
int GetComment( wxString &tool_tip);
|
||||
int GetContent( AddTextureClass &tex, bool add);
|
||||
*/
|
||||
int GetContent();
|
||||
|
||||
int SetFile(const std::string file)
|
||||
{
|
||||
FileName = file;
|
||||
Loaded = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string GetFile() { return FileName; }
|
||||
std::vector<UModTexture> Textures;
|
||||
|
||||
private:
|
||||
int ReadFile();
|
||||
|
||||
int UnXOR();
|
||||
/*
|
||||
int GetCommentZip( wxString &tool_tip);
|
||||
int GetCommentTpf( wxString &tool_tip);
|
||||
*/
|
||||
int AddFile();
|
||||
int AddZip();
|
||||
int AddTpf();
|
||||
int AddContent(const char* pw);
|
||||
|
||||
std::string FileName;
|
||||
bool Loaded;
|
||||
bool XORed;
|
||||
char* FileInMemory;
|
||||
unsigned int MemoryLength;
|
||||
unsigned int FileLen;
|
||||
unsigned long long FileHash;
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//#define MyTypeHash DWORD64
|
||||
#define MyTypeHash DWORD32
|
||||
|
||||
#define BIG_BUFSIZE 1<<24
|
||||
#define SMALL_BUFSIZE 1<<10
|
||||
|
||||
using MsgStruct = struct {
|
||||
unsigned int Control;
|
||||
unsigned int Value;
|
||||
MyTypeHash Hash;
|
||||
};
|
||||
|
||||
using PipeStruct = struct {
|
||||
HANDLE In;
|
||||
HANDLE Out;
|
||||
};
|
||||
|
||||
|
||||
#define uMod_APP_DX9 L"uMod_DX9.txt"
|
||||
#define uMod_APP_DIR L"uMod"
|
||||
#define uMod_VERSION L"uMod V 1.0"
|
||||
|
||||
#define PIPE_uMod2Game L"\\\\.\\pipe\\uMod2Game"
|
||||
#define PIPE_Game2uMod L"\\\\.\\pipe\\Game2uMod"
|
||||
|
||||
#define CONTROL_ADD_TEXTURE 1
|
||||
#define CONTROL_FORCE_RELOAD_TEXTURE 2
|
||||
#define CONTROL_REMOVE_TEXTURE 3
|
||||
#define CONTROL_FORCE_RELOAD_TEXTURE_DATA 4
|
||||
#define CONTROL_ADD_TEXTURE_DATA 5
|
||||
#define CONTROL_MORE_TEXTURES 6
|
||||
|
||||
|
||||
#define CONTROL_SAVE_ALL 10
|
||||
#define CONTROL_SAVE_SINGLE 11
|
||||
#define CONTROL_SET_DIR 12
|
||||
|
||||
#define CONTROL_KEY_BACK 20
|
||||
#define CONTROL_KEY_SAVE 21
|
||||
#define CONTROL_KEY_NEXT 22
|
||||
|
||||
#define CONTROL_FONT_COLOUR 30
|
||||
#define CONTROL_TEXTURE_COLOUR 31
|
||||
@@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
#include "uMod_TextureServer.h"
|
||||
|
||||
class uMod_IDirect3D9 : public IDirect3D9 {
|
||||
public:
|
||||
uMod_IDirect3D9(IDirect3D9* pOriginal, uMod_TextureServer* server);
|
||||
uMod_IDirect3D9(IDirect3D9* pOriginal);
|
||||
virtual ~uMod_IDirect3D9();
|
||||
|
||||
// The original DX9 function definitions
|
||||
@@ -29,5 +28,4 @@ public:
|
||||
|
||||
private:
|
||||
IDirect3D9* m_pIDirect3D9;
|
||||
uMod_TextureServer* uMod_Server;
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
#include "uMod_TextureServer.h"
|
||||
|
||||
class uMod_IDirect3D9Ex : public IDirect3D9Ex {
|
||||
public:
|
||||
uMod_IDirect3D9Ex(IDirect3D9Ex* pOriginal, uMod_TextureServer* server);
|
||||
uMod_IDirect3D9Ex(IDirect3D9Ex* pOriginal);
|
||||
virtual ~uMod_IDirect3D9Ex();
|
||||
|
||||
// The original DX9 function definitions
|
||||
@@ -36,6 +35,5 @@ public:
|
||||
|
||||
private:
|
||||
IDirect3D9Ex* m_pIDirect3D9Ex;
|
||||
uMod_TextureServer* uMod_Server;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,27 +2,21 @@
|
||||
|
||||
#include <d3d9.h>
|
||||
|
||||
interface uMod_IDirect3DCubeTexture9 : IDirect3DCubeTexture9 {
|
||||
interface uMod_IDirect3DCubeTexture9 : IDirect3DCubeTexture9 {
|
||||
uMod_IDirect3DCubeTexture9(IDirect3DCubeTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
|
||||
{
|
||||
m_D3Dtex = *ppTex; //Texture which will be displayed and will be passed to the game
|
||||
m_D3Ddev = pIDirect3DDevice9; //device pointer
|
||||
CrossRef_D3Dtex = nullptr; //cross reference
|
||||
// fake texture: store the pointer to the original uMod_IDirect3DCubeTexture9 object, needed if a fake texture is unselected
|
||||
// original texture: stores the pointer to the fake texture object, is needed if original texture is deleted,
|
||||
// thus the fake texture can also be deleted
|
||||
Reference = -1; //need for fast deleting
|
||||
Hash = 0u;
|
||||
FAKE = false;
|
||||
}
|
||||
: m_D3Dtex(*ppTex),
|
||||
m_D3Ddev(pIDirect3DDevice9)
|
||||
{}
|
||||
|
||||
virtual ~uMod_IDirect3DCubeTexture9() = default;
|
||||
|
||||
// callback interface
|
||||
IDirect3DCubeTexture9* m_D3Dtex;
|
||||
uMod_IDirect3DCubeTexture9* CrossRef_D3Dtex;
|
||||
IDirect3DDevice9* m_D3Ddev;
|
||||
int Reference;
|
||||
MyTypeHash Hash;
|
||||
bool FAKE;
|
||||
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;
|
||||
@@ -50,38 +44,5 @@ interface uMod_IDirect3DCubeTexture9 : IDirect3DCubeTexture9 {
|
||||
STDMETHOD(UnlockRect)(D3DCUBEMAP_FACES FaceType, UINT Level) override;
|
||||
|
||||
|
||||
int GetHash(MyTypeHash& hash);
|
||||
[[nodiscard]] HashTuple GetHash() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline void UnswitchTextures(uMod_IDirect3DCubeTexture9* pTexture)
|
||||
{
|
||||
uMod_IDirect3DCubeTexture9* CrossRef = pTexture->CrossRef_D3Dtex;
|
||||
if (CrossRef != nullptr) {
|
||||
// switch textures back
|
||||
IDirect3DCubeTexture9* cpy = pTexture->m_D3Dtex;
|
||||
pTexture->m_D3Dtex = CrossRef->m_D3Dtex;
|
||||
CrossRef->m_D3Dtex = cpy;
|
||||
|
||||
// cancel the link
|
||||
CrossRef->CrossRef_D3Dtex = nullptr;
|
||||
pTexture->CrossRef_D3Dtex = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline int SwitchTextures(uMod_IDirect3DCubeTexture9* pTexture1, uMod_IDirect3DCubeTexture9* 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
|
||||
IDirect3DCubeTexture9* cpy = pTexture2->m_D3Dtex;
|
||||
pTexture2->m_D3Dtex = pTexture1->m_D3Dtex;
|
||||
pTexture1->m_D3Dtex = cpy;
|
||||
return RETURN_OK;
|
||||
}
|
||||
return RETURN_TEXTURE_NOT_SWITCHED;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
#include <d3dx9.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, uMod_TextureServer* server, int back_buffer_count);
|
||||
uMod_IDirect3DDevice9(IDirect3DDevice9* pOriginal, int back_buffer_count);
|
||||
virtual ~uMod_IDirect3DDevice9();
|
||||
|
||||
// START: The original DX9 function definitions
|
||||
@@ -135,61 +135,39 @@ public:
|
||||
HRESULT __stdcall CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery) override;
|
||||
// END: The original DX9 function definitions
|
||||
|
||||
|
||||
|
||||
uMod_TextureClient* GetuMod_Client() { return uMod_Client; }
|
||||
TextureClient* GetuMod_Client() { return uMod_Client; }
|
||||
|
||||
uMod_IDirect3DTexture9* GetLastCreatedTexture() { return LastCreatedTexture; }
|
||||
|
||||
int SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
|
||||
void SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
|
||||
{
|
||||
LastCreatedTexture = pTexture;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uMod_IDirect3DVolumeTexture9* GetLastCreatedVolumeTexture() { return LastCreatedVolumeTexture; }
|
||||
|
||||
int SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
|
||||
void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
|
||||
{
|
||||
LastCreatedVolumeTexture = pTexture;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uMod_IDirect3DCubeTexture9* GetLastCreatedCubeTexture() { return LastCreatedCubeTexture; }
|
||||
|
||||
int SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
|
||||
void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
|
||||
{
|
||||
LastCreatedCubeTexture = pTexture;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
uMod_IDirect3DTexture9* GetSingleTexture() { return SingleTexture; }
|
||||
uMod_IDirect3DVolumeTexture9* GetSingleVolumeTexture() { return SingleVolumeTexture; }
|
||||
uMod_IDirect3DCubeTexture9* GetSingleCubeTexture() { return SingleCubeTexture; }
|
||||
|
||||
private:
|
||||
int CreateSingleTexture();
|
||||
IDirect3DDevice9* m_pIDirect3DDevice9;
|
||||
IDirect3DDevice9* m_pIDirect3DDevice9 = nullptr;
|
||||
|
||||
int CounterSaveSingleTexture;
|
||||
uMod_IDirect3DTexture9* SingleTexture;
|
||||
uMod_IDirect3DVolumeTexture9* SingleVolumeTexture;
|
||||
uMod_IDirect3DCubeTexture9* SingleCubeTexture;
|
||||
char SingleTextureMod;
|
||||
|
||||
D3DCOLOR TextureColour;
|
||||
ID3DXFont* OSD_Font;
|
||||
//D3DCOLOR FontColour;
|
||||
int BackBufferCount;
|
||||
bool NormalRendering;
|
||||
bool NormalRendering = true;
|
||||
int uMod_Reference = 1;
|
||||
|
||||
int uMod_Reference;
|
||||
uMod_IDirect3DTexture9* LastCreatedTexture = nullptr;
|
||||
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture = nullptr;
|
||||
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture = nullptr;
|
||||
|
||||
uMod_IDirect3DTexture9* LastCreatedTexture;
|
||||
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture;
|
||||
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture;
|
||||
|
||||
uMod_TextureServer* uMod_Server;
|
||||
uMod_TextureClient* uMod_Client;
|
||||
TextureClient* uMod_Client;
|
||||
};
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
#include <d3dx9.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, uMod_TextureServer* server, int back_buffer_count);
|
||||
uMod_IDirect3DDevice9Ex(IDirect3DDevice9Ex* pOriginal, int back_buffer_count);
|
||||
virtual ~uMod_IDirect3DDevice9Ex();
|
||||
|
||||
// START: The original DX9 function definitions
|
||||
@@ -157,60 +157,40 @@ public:
|
||||
|
||||
// END: The original DX9 function definitions
|
||||
|
||||
|
||||
uMod_TextureClient* GetuMod_Client() { return uMod_Client; }
|
||||
TextureClient* GetuMod_Client() { return uMod_Client; }
|
||||
|
||||
uMod_IDirect3DTexture9* GetLastCreatedTexture() { return LastCreatedTexture; }
|
||||
|
||||
int SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
|
||||
void SetLastCreatedTexture(uMod_IDirect3DTexture9* pTexture)
|
||||
{
|
||||
LastCreatedTexture = pTexture;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uMod_IDirect3DVolumeTexture9* GetLastCreatedVolumeTexture() { return LastCreatedVolumeTexture; }
|
||||
|
||||
int SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
|
||||
void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* pTexture)
|
||||
{
|
||||
LastCreatedVolumeTexture = pTexture;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uMod_IDirect3DCubeTexture9* GetLastCreatedCubeTexture() { return LastCreatedCubeTexture; }
|
||||
|
||||
int SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
|
||||
void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* pTexture)
|
||||
{
|
||||
LastCreatedCubeTexture = pTexture;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
uMod_IDirect3DTexture9* GetSingleTexture() { return SingleTexture; }
|
||||
uMod_IDirect3DVolumeTexture9* GetSingleVolumeTexture() { return SingleVolumeTexture; }
|
||||
uMod_IDirect3DCubeTexture9* GetSingleCubeTexture() { return SingleCubeTexture; }
|
||||
|
||||
private:
|
||||
int CreateSingleTexture();
|
||||
IDirect3DDevice9Ex* m_pIDirect3DDevice9Ex;
|
||||
|
||||
int CounterSaveSingleTexture;
|
||||
uMod_IDirect3DTexture9* SingleTexture;
|
||||
uMod_IDirect3DVolumeTexture9* SingleVolumeTexture;
|
||||
uMod_IDirect3DCubeTexture9* SingleCubeTexture;
|
||||
char SingleTextureMod;
|
||||
|
||||
D3DCOLOR TextureColour;
|
||||
ID3DXFont* OSD_Font;
|
||||
//D3DCOLOR FontColour;
|
||||
int BackBufferCount;
|
||||
bool NormalRendering;
|
||||
bool NormalRendering = true;
|
||||
|
||||
int uMod_Reference;
|
||||
int uMod_Reference = 1;
|
||||
|
||||
uMod_IDirect3DTexture9* LastCreatedTexture;
|
||||
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture;
|
||||
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture;
|
||||
uMod_IDirect3DTexture9* LastCreatedTexture = nullptr;
|
||||
uMod_IDirect3DVolumeTexture9* LastCreatedVolumeTexture = nullptr;
|
||||
uMod_IDirect3DCubeTexture9* LastCreatedCubeTexture = nullptr;
|
||||
|
||||
uMod_TextureServer* uMod_Server;
|
||||
uMod_TextureClient* uMod_Client;
|
||||
TextureClient* uMod_Client = nullptr;
|
||||
};
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d9.h>
|
||||
#include "Defines.h"
|
||||
|
||||
interface uMod_IDirect3DTexture9 : public IDirect3DTexture9 {
|
||||
struct TextureFileStruct;
|
||||
interface uMod_IDirect3DTexture9 : IDirect3DTexture9 {
|
||||
uMod_IDirect3DTexture9(IDirect3DTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
|
||||
{
|
||||
m_D3Dtex = *ppTex; //Texture which will be displayed and will be passed to the game
|
||||
m_D3Ddev = pIDirect3DDevice9; //device pointer
|
||||
CrossRef_D3Dtex = nullptr; //cross reference
|
||||
// fake texture: store the pointer to the original uMod_IDirect3DTexture9 object, needed if a fake texture is unselected
|
||||
// original texture: stores the pointer to the fake texture object, is needed if original texture is deleted,
|
||||
// thus the fake texture can also be deleted
|
||||
Reference = -1; //need for fast deleting
|
||||
Hash = 0u;
|
||||
FAKE = false;
|
||||
}
|
||||
: m_D3Dtex(*ppTex),
|
||||
m_D3Ddev(pIDirect3DDevice9)
|
||||
{}
|
||||
|
||||
virtual ~uMod_IDirect3DTexture9() = default;
|
||||
|
||||
// callback interface
|
||||
IDirect3DTexture9* m_D3Dtex;
|
||||
uMod_IDirect3DTexture9* CrossRef_D3Dtex;
|
||||
IDirect3DDevice9* m_D3Ddev;
|
||||
int Reference;
|
||||
MyTypeHash Hash;
|
||||
bool FAKE;
|
||||
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;
|
||||
@@ -48,40 +44,5 @@ interface uMod_IDirect3DTexture9 : public IDirect3DTexture9 {
|
||||
STDMETHOD(UnlockRect)(UINT Level) override;
|
||||
STDMETHOD(AddDirtyRect)(CONST RECT* pDirtyRect) override;
|
||||
|
||||
int GetHash(MyTypeHash& hash);
|
||||
[[nodiscard]] HashTuple GetHash() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline void UnswitchTextures(uMod_IDirect3DTexture9* pTexture)
|
||||
{
|
||||
uMod_IDirect3DTexture9* CrossRef = pTexture->CrossRef_D3Dtex;
|
||||
if (CrossRef != nullptr) {
|
||||
// switch textures back
|
||||
IDirect3DTexture9* cpy = pTexture->m_D3Dtex;
|
||||
pTexture->m_D3Dtex = CrossRef->m_D3Dtex;
|
||||
CrossRef->m_D3Dtex = cpy;
|
||||
|
||||
// cancel the link
|
||||
CrossRef->CrossRef_D3Dtex = nullptr;
|
||||
pTexture->CrossRef_D3Dtex = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline int SwitchTextures(uMod_IDirect3DTexture9* pTexture1, uMod_IDirect3DTexture9* 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
|
||||
IDirect3DTexture9* cpy = pTexture2->m_D3Dtex;
|
||||
pTexture2->m_D3Dtex = pTexture1->m_D3Dtex;
|
||||
pTexture1->m_D3Dtex = cpy;
|
||||
return RETURN_OK;
|
||||
}
|
||||
return RETURN_TEXTURE_NOT_SWITCHED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,25 +4,19 @@
|
||||
|
||||
interface uMod_IDirect3DVolumeTexture9 : IDirect3DVolumeTexture9 {
|
||||
uMod_IDirect3DVolumeTexture9(IDirect3DVolumeTexture9** ppTex, IDirect3DDevice9* pIDirect3DDevice9)
|
||||
{
|
||||
m_D3Dtex = *ppTex; //Texture which will be displayed and will be passed to the game
|
||||
m_D3Ddev = pIDirect3DDevice9; //device pointer
|
||||
CrossRef_D3Dtex = nullptr; //cross reference
|
||||
// fake texture: store the pointer to the original uMod_IDirect3DVolumeTexture9 object, needed if a fake texture is unselected
|
||||
// original texture: stores the pointer to the fake texture object, is needed if original texture is deleted,
|
||||
// thus the fake texture can also be deleted
|
||||
Reference = -1; //need for fast deleting
|
||||
Hash = 0u;
|
||||
FAKE = false;
|
||||
}
|
||||
: m_D3Dtex(*ppTex),
|
||||
m_D3Ddev(pIDirect3DDevice9)
|
||||
{}
|
||||
|
||||
virtual ~uMod_IDirect3DVolumeTexture9() = default;
|
||||
|
||||
// callback interface
|
||||
IDirect3DVolumeTexture9* m_D3Dtex;
|
||||
uMod_IDirect3DVolumeTexture9* CrossRef_D3Dtex;
|
||||
IDirect3DDevice9* m_D3Ddev;
|
||||
int Reference;
|
||||
MyTypeHash Hash;
|
||||
bool FAKE;
|
||||
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;
|
||||
@@ -49,39 +43,5 @@ interface uMod_IDirect3DVolumeTexture9 : IDirect3DVolumeTexture9 {
|
||||
STDMETHOD(UnlockBox)(UINT Level) override;
|
||||
|
||||
|
||||
int GetHash(MyTypeHash& hash);
|
||||
[[nodiscard]] HashTuple GetHash() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline void UnswitchTextures(uMod_IDirect3DVolumeTexture9* pTexture)
|
||||
{
|
||||
uMod_IDirect3DVolumeTexture9* CrossRef = pTexture->CrossRef_D3Dtex;
|
||||
if (CrossRef != nullptr) {
|
||||
// switch textures back
|
||||
IDirect3DVolumeTexture9* cpy = pTexture->m_D3Dtex;
|
||||
pTexture->m_D3Dtex = CrossRef->m_D3Dtex;
|
||||
CrossRef->m_D3Dtex = cpy;
|
||||
|
||||
// cancel the link
|
||||
CrossRef->CrossRef_D3Dtex = nullptr;
|
||||
pTexture->CrossRef_D3Dtex = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline int SwitchTextures(uMod_IDirect3DVolumeTexture9* pTexture1, uMod_IDirect3DVolumeTexture9* 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
|
||||
IDirect3DVolumeTexture9* cpy = pTexture2->m_D3Dtex;
|
||||
pTexture2->m_D3Dtex = pTexture1->m_D3Dtex;
|
||||
pTexture1->m_D3Dtex = cpy;
|
||||
return RETURN_OK;
|
||||
}
|
||||
return RETURN_TEXTURE_NOT_SWITCHED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <Windows.h>
|
||||
|
||||
struct UModTexture {
|
||||
std::vector<char> data;
|
||||
std::string name;
|
||||
DWORD64 hash;
|
||||
};
|
||||
@@ -1,123 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "uMod_IDirect3DTexture9.h"
|
||||
#include "uMod_IDirect3DDevice9.h"
|
||||
#include "uMod_Error.h"
|
||||
#include "uMod_ArrayHandler.h"
|
||||
|
||||
|
||||
class uMod_TextureServer;
|
||||
|
||||
/*
|
||||
* An object of this class is owned by each d3d9 device.
|
||||
* functions called by the Server are called from the server thread instance.
|
||||
* All other functions are called from the render thread instance of the game itself.
|
||||
*/
|
||||
|
||||
class uMod_TextureClient {
|
||||
public:
|
||||
uMod_TextureClient(uMod_TextureServer* server, IDirect3DDevice9* device);
|
||||
~uMod_TextureClient();
|
||||
|
||||
int AddTexture(uMod_IDirect3DTexture9* tex); //called from uMod_IDirect3DDevice9::CreateTexture(...) or uMod_IDirect3DDevice9::BeginScene()
|
||||
int AddTexture(uMod_IDirect3DVolumeTexture9* tex); //called from uMod_IDirect3DVolumeTexture9::CreateTexture(...) or uMod_IDirect3DDevice9::BeginScene()
|
||||
int AddTexture(uMod_IDirect3DCubeTexture9* tex); //called from uMod_IDirect3DCubeTexture9::CreateTexture(...) or uMod_IDirect3DDevice9::BeginScene()
|
||||
|
||||
int RemoveTexture(uMod_IDirect3DTexture9* tex); //called from uMod_IDirect3DTexture9::Release()
|
||||
int RemoveTexture(uMod_IDirect3DVolumeTexture9* tex); //called from uMod_IDirect3DVolumeTexture9::Release()
|
||||
int RemoveTexture(uMod_IDirect3DCubeTexture9* tex); //called from uMod_IDirect3DCubeTexture9::Release()
|
||||
|
||||
int SaveAllTextures(bool val); //called from the Server
|
||||
int SaveSingleTexture(bool val); //called from the Server
|
||||
|
||||
int SetSaveDirectory(wchar_t* dir); //called from the Server
|
||||
int SetGameName(wchar_t* dir); //called from the Server
|
||||
|
||||
int SaveTexture(uMod_IDirect3DTexture9* pTexture); //called from uMod_IDirect3DDevice9::BeginScene() (save button) or from AddTexture(...) (SaveAllTextures)
|
||||
int SaveTexture(uMod_IDirect3DVolumeTexture9* pTexture); //called from uMod_IDirect3DDevice9::BeginScene() (save button) or from AddTexture(...) (SaveAllTextures)
|
||||
int SaveTexture(uMod_IDirect3DCubeTexture9* pTexture); //called from uMod_IDirect3DDevice9::BeginScene() (save button) or from AddTexture(...) (SaveAllTextures)
|
||||
|
||||
|
||||
|
||||
int SetKeyBack(int key)
|
||||
{
|
||||
if (key > 0) {
|
||||
KeyBack = key;
|
||||
}
|
||||
return RETURN_OK;
|
||||
} //called from the Server
|
||||
int SetKeySave(int key)
|
||||
{
|
||||
if (key > 0) {
|
||||
KeySave = key;
|
||||
}
|
||||
return RETURN_OK;
|
||||
} //called from the Server
|
||||
int SetKeyNext(int key)
|
||||
{
|
||||
if (key > 0) {
|
||||
KeyNext = key;
|
||||
}
|
||||
return RETURN_OK;
|
||||
} //called from the Server
|
||||
|
||||
int SetFontColour(DWORD r, DWORD g, DWORD b)
|
||||
{
|
||||
FontColour = D3DCOLOR_ARGB(255, r, g, b);
|
||||
return RETURN_OK;
|
||||
} //called from the Server
|
||||
int SetTextureColour(DWORD r, DWORD g, DWORD b)
|
||||
{
|
||||
TextureColour = D3DCOLOR_ARGB(255, r, g, b);
|
||||
return RETURN_OK;
|
||||
} //called from the Server
|
||||
|
||||
|
||||
int AddUpdate(TextureFileStruct* update, int number); //called from the Server, client object must delete update array
|
||||
int MergeUpdate(); //called from uMod_IDirect3DDevice9::BeginScene()
|
||||
|
||||
int LookUpToMod(uMod_IDirect3DTexture9* pTexture, int num_index_list = 0, int* index_list = nullptr); // called at the end AddTexture(...) and from Device->UpdateTexture(...)
|
||||
int LookUpToMod(uMod_IDirect3DVolumeTexture9* pTexture, int num_index_list = 0, int* index_list = nullptr); // called at the end AddTexture(...) and from Device->UpdateTexture(...)
|
||||
int LookUpToMod(uMod_IDirect3DCubeTexture9* pTexture, int num_index_list = 0, int* index_list = nullptr); // called at the end AddTexture(...) and from Device->UpdateTexture(...)
|
||||
|
||||
uMod_TextureHandler<uMod_IDirect3DTexture9> OriginalTextures; // stores the pointer to the uMod_IDirect3DTexture9 objects created by the game
|
||||
uMod_TextureHandler<uMod_IDirect3DVolumeTexture9> OriginalVolumeTextures; // stores the pointer to the uMod_IDirect3DVolumeTexture9 objects created by the game
|
||||
uMod_TextureHandler<uMod_IDirect3DCubeTexture9> OriginalCubeTextures; // stores the pointer to the uMod_IDirect3DCubeTexture9 objects created by the game
|
||||
|
||||
bool BoolSaveAllTextures;
|
||||
bool BoolSaveSingleTexture;
|
||||
int KeyBack;
|
||||
int KeySave;
|
||||
int KeyNext;
|
||||
|
||||
D3DCOLOR FontColour;
|
||||
D3DCOLOR TextureColour;
|
||||
|
||||
private:
|
||||
uMod_TextureServer* Server;
|
||||
IDirect3DDevice9* D3D9Device;
|
||||
wchar_t SavePath[MAX_PATH];
|
||||
wchar_t GameName[MAX_PATH];
|
||||
|
||||
TextureFileStruct* Update;
|
||||
int NumberOfUpdate;
|
||||
|
||||
int LockMutex();
|
||||
int UnlockMutex();
|
||||
HANDLE Mutex;
|
||||
|
||||
int NumberToMod; // number of texture to be modded
|
||||
TextureFileStruct* FileToMod; // array which stores the file in memory and the hash of each texture to be modded
|
||||
|
||||
|
||||
int LookUpToMod(MyTypeHash hash, int num_index_list, int* index_list); // called from LookUpToMod(...);
|
||||
int LoadTexture(TextureFileStruct* file_in_memory, uMod_IDirect3DTexture9** ppTexture); // called if a target texture is found
|
||||
int LoadTexture(TextureFileStruct* file_in_memory, uMod_IDirect3DVolumeTexture9** ppTexture); // called if a target texture is found
|
||||
int LoadTexture(TextureFileStruct* file_in_memory, uMod_IDirect3DCubeTexture9** ppTexture); // called if a target texture is found
|
||||
|
||||
// and the corresponding fake texture should be loaded
|
||||
|
||||
//MyTypeHash GetHash(unsigned char *str, int len);
|
||||
//unsigned int GetCRC32(char *pcDatabuf, unsigned int ulDatalen);
|
||||
};
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
unsigned int GetCRC32(char* pcDatabuf, unsigned int ulDatalen);
|
||||
/*
|
||||
case D3DFMT_MULTI2_ARGB8:
|
||||
case D3DFMT_VERTEXDATA:
|
||||
*/
|
||||
inline int GetBitsFromFormat(D3DFORMAT format)
|
||||
{
|
||||
switch (format) //switch trough the formats to calculate the size of the raw data
|
||||
{
|
||||
case D3DFMT_A1: // 1-bit monochrome.
|
||||
{
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DFMT_R3G3B2: // 8-bit RGB texture format using 3 bits for red, 3 bits for green, and 2 bits for blue.
|
||||
case D3DFMT_A8: // 8-bit alpha only.
|
||||
case D3DFMT_A8P8: // 8-bit color indexed with 8 bits of alpha.
|
||||
case D3DFMT_P8: // 8-bit color indexed.
|
||||
case D3DFMT_L8: // 8-bit luminance only.
|
||||
case D3DFMT_A4L4: // 8-bit using 4 bits each for alpha and luminance.
|
||||
case D3DFMT_FORCE_DWORD:
|
||||
case D3DFMT_S8_LOCKABLE: // A lockable 8-bit stencil buffer.
|
||||
{
|
||||
return 8;
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DFMT_D16_LOCKABLE: //16-bit z-buffer bit depth.
|
||||
case D3DFMT_D15S1: // 16-bit z-buffer bit depth where 15 bits are reserved for the depth channel and 1 bit is reserved for the stencil channel.
|
||||
case D3DFMT_L6V5U5: // 16-bit bump-map format with luminance using 6 bits for luminance, and 5 bits each for v and u.
|
||||
case D3DFMT_V8U8: // 16-bit bump-map format using 8 bits each for u and v data.
|
||||
case D3DFMT_CxV8U8: // 16-bit normal compression format. The texture sampler computes the C channel from: C = sqrt(1 - U2 - V2).
|
||||
case D3DFMT_R5G6B5: // 16-bit RGB pixel format with 5 bits for red, 6 bits for green, and 5 bits for blue.
|
||||
case D3DFMT_X1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color.
|
||||
case D3DFMT_A1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color and 1 bit is reserved for alpha.
|
||||
case D3DFMT_A4R4G4B4: // 16-bit ARGB pixel format with 4 bits for each channel.
|
||||
case D3DFMT_A8R3G3B2: // 16-bit ARGB texture format using 8 bits for alpha, 3 bits each for red and green, and 2 bits for blue.
|
||||
case D3DFMT_X4R4G4B4: // 16-bit RGB pixel format using 4 bits for each color.
|
||||
case D3DFMT_L16: // 16-bit luminance only.
|
||||
case D3DFMT_R16F: // 16-bit float format using 16 bits for the red channel.
|
||||
case D3DFMT_A8L8: // 16-bit using 8 bits each for alpha and luminance.
|
||||
case D3DFMT_D16: // 16-bit z-buffer bit depth.
|
||||
case D3DFMT_INDEX16: // 16-bit index buffer bit depth.
|
||||
case D3DFMT_G8R8_G8B8: // ??
|
||||
case D3DFMT_R8G8_B8G8: // ??
|
||||
case D3DFMT_UYVY: // ??
|
||||
case D3DFMT_YUY2: // ??
|
||||
{
|
||||
return 16;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case D3DFMT_R8G8B8: //24-bit RGB pixel format with 8 bits per channel.
|
||||
{
|
||||
return 24;
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DFMT_R32F: // 32-bit float format using 32 bits for the red channel.
|
||||
case D3DFMT_X8L8V8U8: // 32-bit bump-map format with luminance using 8 bits for each channel.
|
||||
case D3DFMT_A2W10V10U10: // 32-bit bump-map format using 2 bits for alpha and 10 bits each for w, v, and u.
|
||||
case D3DFMT_Q8W8V8U8: // 32-bit bump-map format using 8 bits for each channel.
|
||||
case D3DFMT_V16U16: // 32-bit bump-map format using 16 bits for each channel.
|
||||
case D3DFMT_A8R8G8B8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel.
|
||||
case D3DFMT_X8R8G8B8: // 32-bit RGB pixel format, where 8 bits are reserved for each color.
|
||||
case D3DFMT_A2B10G10R10: // 32-bit pixel format using 10 bits for each color and 2 bits for alpha.
|
||||
case D3DFMT_A8B8G8R8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel.
|
||||
case D3DFMT_X8B8G8R8: // 32-bit RGB pixel format, where 8 bits are reserved for each color.
|
||||
case D3DFMT_G16R16: // 32-bit pixel format using 16 bits each for green and red.
|
||||
case D3DFMT_G16R16F: // 32-bit float format using 16 bits for the red channel and 16 bits for the green channel.
|
||||
case D3DFMT_A2R10G10B10: // 32-bit pixel format using 10 bits each for red, green, and blue, and 2 bits for alpha.
|
||||
case D3DFMT_D32: // 32-bit z-buffer bit depth.
|
||||
case D3DFMT_D24S8: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 8 bits for the stencil channel.
|
||||
case D3DFMT_D24X8: //32-bit z-buffer bit depth using 24 bits for the depth channel.
|
||||
case D3DFMT_D24X4S4: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 4 bits for the stencil channel.
|
||||
case D3DFMT_D32F_LOCKABLE: // A lockable format where the depth value is represented as a standard IEEE floating-point number.
|
||||
case D3DFMT_D24FS8: // A non-lockable format that contains 24 bits of depth (in a 24-bit floating point format - 20e4) and 8 bits of stencil.
|
||||
case D3DFMT_D32_LOCKABLE: // A lockable 32-bit depth buffer.
|
||||
case D3DFMT_INDEX32: // 32-bit index buffer bit depth.
|
||||
//case : //
|
||||
//case : //
|
||||
//case : //
|
||||
//case : //
|
||||
{
|
||||
return 32;
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DFMT_G32R32F: // 64-bit float format using 32 bits for the red channel and 32 bits for the green channel.
|
||||
case D3DFMT_Q16W16V16U16: // 64-bit bump-map format using 16 bits for each component.
|
||||
case D3DFMT_A16B16G16R16: // 64-bit pixel format using 16 bits for each component.
|
||||
case D3DFMT_A16B16G16R16F: // 64-bit float format using 16 bits for the each channel (alpha, blue, green, red).
|
||||
{
|
||||
return 64;
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DFMT_A32B32G32R32F: // 128-bit float format using 32 bits for the each channel (alpha, blue, green, red).
|
||||
{
|
||||
return 128;
|
||||
break;
|
||||
}
|
||||
case D3DFMT_DXT2:
|
||||
case D3DFMT_DXT3:
|
||||
case D3DFMT_DXT4:
|
||||
case D3DFMT_DXT5: {
|
||||
return 8;
|
||||
break;
|
||||
}
|
||||
case D3DFMT_DXT1: {
|
||||
return 4;
|
||||
break;
|
||||
}
|
||||
default: //compressed formats
|
||||
{
|
||||
return 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "uMod_GlobalDefines.h"
|
||||
#include "uMod_ArrayHandler.h"
|
||||
|
||||
|
||||
/*
|
||||
* An object of this class is created only once.
|
||||
* The Mainloop functions is executed by a server thread,
|
||||
* which listen on a pipe.
|
||||
*
|
||||
* Functions called by the Client are called from the a thread instance of the game itself.
|
||||
* Nearly all other functions are called from the server thread instance.
|
||||
*/
|
||||
|
||||
|
||||
class uMod_TextureClient;
|
||||
|
||||
class uMod_TextureServer {
|
||||
public:
|
||||
uMod_TextureServer(char* name, char* uModName);
|
||||
~uMod_TextureServer();
|
||||
|
||||
int AddClient(uMod_TextureClient* client, TextureFileStruct** update, int* number); // called from a Client
|
||||
int RemoveClient(uMod_TextureClient* client); // called from a Client
|
||||
|
||||
int MainLoop(); // is executed in a server thread
|
||||
|
||||
|
||||
// following functions are only public for testing purpose !!
|
||||
// they should be private and only be called from the Mainloop
|
||||
|
||||
int AddFile(char* buffer, unsigned int size, MyTypeHash hash, bool force); // called from Mainloop(), if the content of the texture is sent
|
||||
int AddFile(wchar_t* file_name, MyTypeHash hash, bool force); // called from Mainloop(), if the name and the path to the file is sent
|
||||
int RemoveFile(MyTypeHash hash); // called from Mainloop()
|
||||
|
||||
int SaveAllTextures(bool val); // called from Mainloop()
|
||||
int SaveSingleTexture(bool val); // called from Mainloop()
|
||||
|
||||
int SetSaveDirectory(wchar_t* dir); // called from Mainloop()
|
||||
|
||||
|
||||
int SetKeyBack(int key); // called from Mainloop()
|
||||
int SetKeySave(int key); // called from Mainloop()
|
||||
int SetKeyNext(int key); // called from Mainloop()
|
||||
|
||||
int SetFontColour(DWORD colour); // called from Mainloop()
|
||||
int SetTextureColour(DWORD colour); // called from Mainloop()
|
||||
|
||||
private:
|
||||
bool BoolSaveAllTextures;
|
||||
bool BoolSaveSingleTexture;
|
||||
wchar_t SavePath[MAX_PATH];
|
||||
wchar_t GameName[MAX_PATH];
|
||||
char UModName[MAX_PATH];
|
||||
|
||||
void LoadModsFromFile(char* source);
|
||||
int PropagateUpdate(uMod_TextureClient* client = nullptr); // called from Mainloop() if texture are loaded or removed
|
||||
int PrepareUpdate(TextureFileStruct** update, int* number); // called from PropagateUpdate() and AddClient()
|
||||
// generate a copy of the current texture to be modded
|
||||
// the file content of the textures are not copied, the clients get the pointer to the file content
|
||||
// but the arrays allocate by this function, must be deleted by the client
|
||||
|
||||
int LockMutex();
|
||||
int UnlockMutex();
|
||||
HANDLE Mutex;
|
||||
|
||||
|
||||
int KeyBack;
|
||||
int KeySave;
|
||||
int KeyNext;
|
||||
|
||||
DWORD FontColour;
|
||||
DWORD TextureColour;
|
||||
|
||||
|
||||
PipeStruct Pipe;
|
||||
|
||||
uMod_TextureClient** Clients;
|
||||
int NumberOfClients;
|
||||
int LenghtOfClients;
|
||||
|
||||
uMod_FileHandler CurrentMod; // hold the file content of texture
|
||||
uMod_FileHandler OldMod; // hold the file content of texture which were added previously but are not needed any more
|
||||
// this is needed, because a texture clients might not have merged the last update and thus hold pointers to the file content of old textures
|
||||
};
|
||||
-214
@@ -1,214 +0,0 @@
|
||||
#ifndef _unzip_H
|
||||
#define _unzip_H
|
||||
//#define TCHAR char
|
||||
// UNZIPPING functions -- for unzipping.
|
||||
// This file is a repackaged form of extracts from the zlib code available
|
||||
// at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original
|
||||
// copyright notice may be found in unzip.cpp. The repackaging was done
|
||||
// by Lucian Wischik to simplify and extend its use in Windows/C++. Also
|
||||
// encryption and unicode filenames have been added.
|
||||
|
||||
|
||||
#ifndef _zip_H
|
||||
DECLARE_HANDLE(HZIP);
|
||||
#endif
|
||||
// An HZIP identifies a zip file that has been opened
|
||||
|
||||
typedef DWORD ZRESULT;
|
||||
// return codes from any of the zip functions. Listed later.
|
||||
|
||||
typedef struct {
|
||||
int index; // index of this file within the zip
|
||||
TCHAR name[MAX_PATH]; // filename within the zip
|
||||
DWORD attr; // attributes, as in GetFileAttributes.
|
||||
FILETIME atime, ctime, mtime;// access, create, modify filetimes
|
||||
long comp_size; // sizes of item, compressed and uncompressed. These
|
||||
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
|
||||
} ZIPENTRY;
|
||||
|
||||
|
||||
HZIP OpenZip(const TCHAR* fn, const char* password);
|
||||
HZIP OpenZip(void* z, unsigned int len, const char* password);
|
||||
HZIP OpenZipHandle(HANDLE h, const char* password);
|
||||
// OpenZip - opens a zip file and returns a handle with which you can
|
||||
// subsequently examine its contents. You can open a zip file from:
|
||||
// from a pipe: OpenZipHandle(hpipe_read,0);
|
||||
// from a file (by handle): OpenZipHandle(hfile,0);
|
||||
// from a file (by name): OpenZip("c:\\test.zip","password");
|
||||
// from a memory block: OpenZip(bufstart, buflen,0);
|
||||
// If the file is opened through a pipe, then items may only be
|
||||
// accessed in increasing order, and an item may only be unzipped once,
|
||||
// although GetZipItem can be called immediately before and after unzipping
|
||||
// it. If it's opened in any other way, then full random access is possible.
|
||||
// Note: pipe input is not yet implemented.
|
||||
// Note: zip passwords are ascii, not unicode.
|
||||
// Note: for windows-ce, you cannot close the handle until after CloseZip.
|
||||
// but for real windows, the zip makes its own copy of your handle, so you
|
||||
// can close yours anytime.
|
||||
|
||||
ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY* ze);
|
||||
// GetZipItem - call this to get information about an item in the zip.
|
||||
// If index is -1 and the file wasn't opened through a pipe,
|
||||
// then it returns information about the whole zipfile
|
||||
// (and in particular ze.index returns the number of index items).
|
||||
// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
// See below for notes on what happens when you unzip such an item.
|
||||
// Note: if you are opening the zip through a pipe, then random access
|
||||
// is not possible and GetZipItem(-1) fails and you can't discover the number
|
||||
// of items except by calling GetZipItem on each one of them in turn,
|
||||
// starting at 0, until eventually the call fails. Also, in the event that
|
||||
// you are opening through a pipe and the zip was itself created into a pipe,
|
||||
// then then comp_size and sometimes unc_size as well may not be known until
|
||||
// after the item has been unzipped.
|
||||
|
||||
ZRESULT FindZipItem(HZIP hz, const TCHAR* name, bool ic, int* index, ZIPENTRY* ze);
|
||||
// FindZipItem - finds an item by name. ic means 'insensitive to case'.
|
||||
// It returns the index of the item, and returns information about it.
|
||||
// If nothing was found, then index is set to -1 and the function returns
|
||||
// an error code.
|
||||
|
||||
ZRESULT UnzipItem(HZIP hz, int index, const TCHAR* fn);
|
||||
ZRESULT UnzipItem(HZIP hz, int index, void* z, unsigned int len);
|
||||
ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h);
|
||||
// UnzipItem - given an index to an item, unzips it. You can unzip to:
|
||||
// to a pipe: UnzipItemHandle(hz,i, hpipe_write);
|
||||
// to a file (by handle): UnzipItemHandle(hz,i, hfile);
|
||||
// to a file (by name): UnzipItem(hz,i, ze.name);
|
||||
// to a memory block: UnzipItem(hz,i, buf,buflen);
|
||||
// In the final case, if the buffer isn't large enough to hold it all,
|
||||
// then the return code indicates that more is yet to come. If it was
|
||||
// large enough, and you want to know precisely how big, GetZipItem.
|
||||
// Note: zip files are normally stored with relative pathnames. If you
|
||||
// unzip with ZIP_FILENAME a relative pathname then the item gets created
|
||||
// relative to the current directory - it first ensures that all necessary
|
||||
// subdirectories have been created. Also, the item may itself be a directory.
|
||||
// If you unzip a directory with ZIP_FILENAME, then the directory gets created.
|
||||
// If you unzip it to a handle or a memory block, then nothing gets created
|
||||
// and it emits 0 bytes.
|
||||
ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR* dir);
|
||||
// if unzipping to a filename, and it's a relative filename, then it will be relative to here.
|
||||
// (defaults to current-directory).
|
||||
|
||||
|
||||
ZRESULT CloseZip(HZIP hz);
|
||||
// CloseZip - the zip handle must be closed with this function.
|
||||
|
||||
unsigned int FormatZipMessage(ZRESULT code, TCHAR* buf, unsigned int len);
|
||||
// FormatZipMessage - given an error code, formats it as a string.
|
||||
// It returns the length of the error message. If buf/len points
|
||||
// to a real buffer, then it also writes as much as possible into there.
|
||||
|
||||
|
||||
// These are the result codes:
|
||||
#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned,
|
||||
#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage.
|
||||
// The following come from general system stuff (e.g. files not openable)
|
||||
#define ZR_GENMASK 0x0000FF00
|
||||
#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
|
||||
#define ZR_NOFILE 0x00000200 // couldn't create/open the file
|
||||
#define ZR_NOALLOC 0x00000300 // failed to allocate some resource
|
||||
#define ZR_WRITE 0x00000400 // a general error writing to the file
|
||||
#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
|
||||
#define ZR_MORE 0x00000600 // there's still more data to be unzipped
|
||||
#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
|
||||
#define ZR_READ 0x00000800 // a general error reading the file
|
||||
#define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file
|
||||
// The following come from mistakes on the part of the caller
|
||||
#define ZR_CALLERMASK 0x00FF0000
|
||||
#define ZR_ARGS 0x00010000 // general mistake with the arguments
|
||||
#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
|
||||
#define ZR_MEMSIZE 0x00030000 // the memory size is too small
|
||||
#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
|
||||
#define ZR_ENDED 0x00050000 // the zip creation has already been closed
|
||||
#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
|
||||
#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
|
||||
#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
|
||||
// The following come from bugs within the zip library itself
|
||||
#define ZR_BUGMASK 0xFF000000
|
||||
#define ZR_NOTINITED 0x01000000 // initialisation didn't work
|
||||
#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
|
||||
#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
|
||||
#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// e.g.
|
||||
//
|
||||
// SetCurrentDirectory("c:\\docs\\stuff");
|
||||
// HZIP hz = OpenZip("c:\\stuff.zip",0);
|
||||
// ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index;
|
||||
// for (int i=0; i<numitems; i++)
|
||||
// { GetZipItem(hz,i,&ze);
|
||||
// UnzipItem(hz,i,ze.name);
|
||||
// }
|
||||
// CloseZip(hz);
|
||||
//
|
||||
//
|
||||
// HRSRC hrsrc = FindResource(hInstance,MAKEINTRESOURCE(1),RT_RCDATA);
|
||||
// HANDLE hglob = LoadResource(hInstance,hrsrc);
|
||||
// void *zipbuf=LockResource(hglob);
|
||||
// unsigned int ziplen=SizeofResource(hInstance,hrsrc);
|
||||
// HZIP hz = OpenZip(zipbuf, ziplen, 0);
|
||||
// - unzip to a membuffer -
|
||||
// ZIPENTRY ze; int i; FindZipItem(hz,"file.dat",true,&i,&ze);
|
||||
// char *ibuf = new char[ze.unc_size];
|
||||
// UnzipItem(hz,i, ibuf, ze.unc_size);
|
||||
// delete[] ibuf;
|
||||
// - unzip to a fixed membuff -
|
||||
// ZIPENTRY ze; int i; FindZipItem(hz,"file.dat",true,&i,&ze);
|
||||
// char ibuf[1024]; ZRESULT zr=ZR_MORE; unsigned long totsize=0;
|
||||
// while (zr==ZR_MORE)
|
||||
// { zr = UnzipItem(hz,i, ibuf,1024);
|
||||
// unsigned long bufsize=1024; if (zr==ZR_OK) bufsize=ze.unc_size-totsize;
|
||||
// totsize+=bufsize;
|
||||
// }
|
||||
// - unzip to a pipe -
|
||||
// HANDLE hwrite; HANDLE hthread=CreateWavReaderThread(&hwrite);
|
||||
// int i; ZIPENTRY ze; FindZipItem(hz,"sound.wav",true,&i,&ze);
|
||||
// UnzipItemHandle(hz,i, hwrite);
|
||||
// CloseHandle(hwrite);
|
||||
// WaitForSingleObject(hthread,INFINITE);
|
||||
// CloseHandle(hwrite); CloseHandle(hthread);
|
||||
// - finished -
|
||||
// CloseZip(hz);
|
||||
// // note: no need to free resources obtained through Find/Load/LockResource
|
||||
//
|
||||
//
|
||||
// SetCurrentDirectory("c:\\docs\\pipedzipstuff");
|
||||
// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,0,0);
|
||||
// CreateZipWriterThread(hwrite);
|
||||
// HZIP hz = OpenZipHandle(hread,0);
|
||||
// for (int i=0; ; i++)
|
||||
// { ZIPENTRY ze;
|
||||
// ZRESULT zr=GetZipItem(hz,i,&ze); if (zr!=ZR_OK) break; // no more
|
||||
// UnzipItem(hz,i, ze.name);
|
||||
// }
|
||||
// CloseZip(hz);
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
// Now we indulge in a little skullduggery so that the code works whether
|
||||
// the user has included just zip or both zip and unzip.
|
||||
// Idea: if header files for both zip and unzip are present, then presumably
|
||||
// the cpp files for zip and unzip are both present, so we will call
|
||||
// one or the other of them based on a dynamic choice. If the header file
|
||||
// for only one is present, then we will bind to that particular one.
|
||||
ZRESULT CloseZipU(HZIP hz);
|
||||
unsigned int FormatZipMessageU(ZRESULT code, TCHAR* buf, unsigned int len);
|
||||
bool IsZipHandleU(HZIP hz);
|
||||
#ifdef _zip_H
|
||||
#undef CloseZip
|
||||
#define CloseZip(hz) (IsZipHandleU(hz)?CloseZipU(hz):CloseZipZ(hz))
|
||||
#else
|
||||
#define CloseZip CloseZipU
|
||||
#define FormatZipMessage FormatZipMessageU
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // _unzip_H
|
||||
-157
@@ -1,157 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <Windows.h>
|
||||
|
||||
void ReplaceAll(std::wstring& str, const std::wstring& from, const std::wstring& to)
|
||||
{
|
||||
if (from.empty()) {
|
||||
return;
|
||||
}
|
||||
size_t startPos = 0;
|
||||
while ((startPos = str.find(from, startPos)) != std::wstring::npos) {
|
||||
str.replace(startPos, from.length(), to);
|
||||
startPos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
void ReplaceAll(std::string& str, const std::string& from, const std::string& to)
|
||||
{
|
||||
if (from.empty()) {
|
||||
return;
|
||||
}
|
||||
size_t startPos = 0;
|
||||
while ((startPos = str.find(from, startPos)) != std::string::npos) {
|
||||
str.replace(startPos, from.length(), to);
|
||||
startPos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring AfterFirst(const std::wstring& str, wchar_t delimiter)
|
||||
{
|
||||
const size_t pos = str.find(delimiter);
|
||||
if (pos != std::wstring::npos) {
|
||||
// Return the substring after the delimiter
|
||||
return str.substr(pos + 1);
|
||||
}
|
||||
// If the delimiter is not found, return an empty string
|
||||
return L"";
|
||||
}
|
||||
|
||||
std::string AfterFirst(const std::string& str, char delimiter)
|
||||
{
|
||||
const size_t pos = str.find(delimiter);
|
||||
if (pos != std::string::npos) {
|
||||
// Return the substring after the delimiter
|
||||
return str.substr(pos + 1);
|
||||
}
|
||||
// If the delimiter is not found, return an empty string
|
||||
return "";
|
||||
}
|
||||
|
||||
std::wstring BeforeFirst(const std::wstring& str, wchar_t delimiter)
|
||||
{
|
||||
const size_t pos = str.find(delimiter);
|
||||
return pos != std::wstring::npos ? str.substr(0, pos) : str;
|
||||
}
|
||||
|
||||
std::string BeforeFirst(const std::string& str, char delimiter)
|
||||
{
|
||||
const size_t pos = str.find(delimiter);
|
||||
return pos != std::string::npos ? str.substr(0, pos) : str;
|
||||
}
|
||||
|
||||
std::string BeforeLast(const std::string& file_path, char separator)
|
||||
{
|
||||
// Find the last occurrence of '.'
|
||||
const std::size_t last_dot_pos = file_path.find_last_of(separator);
|
||||
|
||||
// If there is a dot, and it is not at the beginning of the filename
|
||||
if (last_dot_pos != std::string::npos && last_dot_pos != 0) {
|
||||
// Extract the substring from the dot to the end of the string
|
||||
return file_path.substr(0, last_dot_pos);
|
||||
}
|
||||
// If the dot is not found, or is the first character, return an empty string
|
||||
return "";
|
||||
}
|
||||
|
||||
std::wstring BeforeLast(const std::wstring& file_path, wchar_t separator)
|
||||
{
|
||||
// Find the last occurrence of '.'
|
||||
const std::size_t last_dot_pos = file_path.find_last_of(separator);
|
||||
|
||||
// If there is a dot, and it is not at the beginning of the filename
|
||||
if (last_dot_pos != std::wstring::npos && last_dot_pos != 0) {
|
||||
// Extract the substring from the dot to the end of the string
|
||||
return file_path.substr(0, last_dot_pos);
|
||||
}
|
||||
// If the dot is not found, or is the first character, return an empty string
|
||||
return L"";
|
||||
}
|
||||
|
||||
std::string AfterLast(const std::string& file_path, char separator)
|
||||
{
|
||||
// Find the last occurrence of '.'
|
||||
const std::size_t last_dot_pos = file_path.find_last_of(separator);
|
||||
|
||||
// If there is a dot, and it is not at the beginning of the filename
|
||||
if (last_dot_pos != std::string::npos && last_dot_pos != 0) {
|
||||
// Extract the substring from the dot to the end of the string
|
||||
return file_path.substr(last_dot_pos + 1);
|
||||
}
|
||||
// If the dot is not found, or is the first character, return an empty string
|
||||
return "";
|
||||
}
|
||||
|
||||
std::wstring AfterLast(const std::wstring& file_path, wchar_t separator)
|
||||
{
|
||||
// Find the last occurrence of '.'
|
||||
const std::size_t last_dot_pos = file_path.find_last_of(separator);
|
||||
|
||||
// If there is a dot, and it is not at the beginning of the filename
|
||||
if (last_dot_pos != std::wstring::npos && last_dot_pos != 0) {
|
||||
// Extract the substring from the dot to the end of the string
|
||||
return file_path.substr(last_dot_pos + 1);
|
||||
}
|
||||
// If the dot is not found, or is the first character, return an empty string
|
||||
return L"";
|
||||
}
|
||||
|
||||
std::string GetFileExtension(const std::string& file_path)
|
||||
{
|
||||
// Find the last occurrence of '.'
|
||||
const std::size_t last_dot_pos = file_path.find_last_of(".");
|
||||
|
||||
// If there is a dot, and it is not at the beginning of the filename
|
||||
if (last_dot_pos != std::string::npos && last_dot_pos != 0) {
|
||||
// Extract the substring from the dot to the end of the string
|
||||
return file_path.substr(last_dot_pos + 1);
|
||||
}
|
||||
// If the dot is not found, or is the first character, return an empty string
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string WideStringToString(const std::wstring& wstr)
|
||||
{
|
||||
if (wstr.empty()) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), nullptr, 0, nullptr, nullptr);
|
||||
std::string strTo(size_needed, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), &strTo[0], size_needed, nullptr, nullptr);
|
||||
return strTo;
|
||||
}
|
||||
|
||||
|
||||
std::wstring StringToWString(const std::string& str)
|
||||
{
|
||||
if (str.empty()) {
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
const int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
|
||||
std::wstring wstrTo(size_needed, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), &wstrTo[0], size_needed);
|
||||
return wstrTo;
|
||||
}
|
||||
-205
@@ -1,205 +0,0 @@
|
||||
#include <Windows.h>
|
||||
#include <cstdlib>
|
||||
#ifndef _zip_H
|
||||
#define _zip_H
|
||||
|
||||
|
||||
// ZIP functions -- for creating zip files
|
||||
// This file is a repackaged form of the Info-Zip source code available
|
||||
// at www.info-zip.org. The original copyright notice may be found in
|
||||
// zip.cpp. The repackaging was done by Lucian Wischik to simplify and
|
||||
// extend its use in Windows/C++. Also to add encryption and unicode.
|
||||
|
||||
|
||||
#ifndef _unzip_H
|
||||
DECLARE_HANDLE(HZIP);
|
||||
#endif
|
||||
// An HZIP identifies a zip file that is being created
|
||||
|
||||
typedef DWORD ZRESULT;
|
||||
// return codes from any of the zip functions. Listed later.
|
||||
|
||||
|
||||
|
||||
HZIP CreateZip(const TCHAR* fn, const char* password);
|
||||
HZIP CreateZip(void* buf, unsigned int len, const char* password);
|
||||
HZIP CreateZipHandle(HANDLE h, const char* password);
|
||||
// CreateZip - call this to start the creation of a zip file.
|
||||
// As the zip is being created, it will be stored somewhere:
|
||||
// to a pipe: CreateZipHandle(hpipe_write);
|
||||
// in a file (by handle): CreateZipHandle(hfile);
|
||||
// in a file (by name): CreateZip("c:\\test.zip");
|
||||
// in memory: CreateZip(buf, len);
|
||||
// or in pagefile memory: CreateZip(0, len);
|
||||
// The final case stores it in memory backed by the system paging file,
|
||||
// where the zip may not exceed len bytes. This is a bit friendlier than
|
||||
// allocating memory with new[]: it won't lead to fragmentation, and the
|
||||
// memory won't be touched unless needed. That means you can give very
|
||||
// large estimates of the maximum-size without too much worry.
|
||||
// As for the password, it lets you encrypt every file in the archive.
|
||||
// (This api doesn't support per-file encryption.)
|
||||
// Note: because pipes don't allow random access, the structure of a zipfile
|
||||
// created into a pipe is slightly different from that created into a file
|
||||
// or memory. In particular, the compressed-size of the item cannot be
|
||||
// stored in the zipfile until after the item itself. (Also, for an item added
|
||||
// itself via a pipe, the uncompressed-size might not either be known until
|
||||
// after.) This is not normally a problem. But if you try to unzip via a pipe
|
||||
// as well, then the unzipper will not know these things about the item until
|
||||
// after it has been unzipped. Therefore: for unzippers which don't just write
|
||||
// each item to disk or to a pipe, but instead pre-allocate memory space into
|
||||
// which to unzip them, then either you have to create the zip not to a pipe,
|
||||
// or you have to add items not from a pipe, or at least when adding items
|
||||
// from a pipe you have to specify the length.
|
||||
// Note: for windows-ce, you cannot close the handle until after CloseZip.
|
||||
// but for real windows, the zip makes its own copy of your handle, so you
|
||||
// can close yours anytime.
|
||||
|
||||
|
||||
ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, const TCHAR* fn);
|
||||
ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, void* src, unsigned int len);
|
||||
ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h);
|
||||
ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h, unsigned int len);
|
||||
ZRESULT ZipAddFolder(HZIP hz, const TCHAR* dstzn);
|
||||
// ZipAdd - call this for each file to be added to the zip.
|
||||
// dstzn is the name that the file will be stored as in the zip file.
|
||||
// The file to be added to the zip can come
|
||||
// from a pipe: ZipAddHandle(hz,"file.dat", hpipe_read);
|
||||
// from a file: ZipAddHandle(hz,"file.dat", hfile);
|
||||
// from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat");
|
||||
// from memory: ZipAdd(hz,"subdir\\file.dat", buf,len);
|
||||
// (folder): ZipAddFolder(hz,"subdir");
|
||||
// Note: if adding an item from a pipe, and if also creating the zip file itself
|
||||
// to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle
|
||||
// function. This will let the zipfile store the item's size ahead of the
|
||||
// compressed item itself, which in turn makes it easier when unzipping the
|
||||
// zipfile from a pipe.
|
||||
|
||||
ZRESULT ZipGetMemory(HZIP hz, void** buf, unsigned long* len);
|
||||
// ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len),
|
||||
// then this function will return information about that memory block.
|
||||
// buf will receive a pointer to its start, and len its length.
|
||||
// Note: you can't add any more after calling this.
|
||||
|
||||
ZRESULT CloseZip(HZIP hz);
|
||||
// CloseZip - the zip handle must be closed with this function.
|
||||
|
||||
unsigned int FormatZipMessage(ZRESULT code, TCHAR* buf, unsigned int len);
|
||||
// FormatZipMessage - given an error code, formats it as a string.
|
||||
// It returns the length of the error message. If buf/len points
|
||||
// to a real buffer, then it also writes as much as possible into there.
|
||||
|
||||
|
||||
|
||||
// These are the result codes:
|
||||
#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned,
|
||||
#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage.
|
||||
// The following come from general system stuff (e.g. files not openable)
|
||||
#define ZR_GENMASK 0x0000FF00
|
||||
#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
|
||||
#define ZR_NOFILE 0x00000200 // couldn't create/open the file
|
||||
#define ZR_NOALLOC 0x00000300 // failed to allocate some resource
|
||||
#define ZR_WRITE 0x00000400 // a general error writing to the file
|
||||
#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
|
||||
#define ZR_MORE 0x00000600 // there's still more data to be unzipped
|
||||
#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
|
||||
#define ZR_READ 0x00000800 // a general error reading the file
|
||||
// The following come from mistakes on the part of the caller
|
||||
#define ZR_CALLERMASK 0x00FF0000
|
||||
#define ZR_ARGS 0x00010000 // general mistake with the arguments
|
||||
#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
|
||||
#define ZR_MEMSIZE 0x00030000 // the memory size is too small
|
||||
#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
|
||||
#define ZR_ENDED 0x00050000 // the zip creation has already been closed
|
||||
#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
|
||||
#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
|
||||
#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
|
||||
// The following come from bugs within the zip library itself
|
||||
#define ZR_BUGMASK 0xFF000000
|
||||
#define ZR_NOTINITED 0x01000000 // initialisation didn't work
|
||||
#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
|
||||
#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
|
||||
#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// e.g.
|
||||
//
|
||||
// (1) Traditional use, creating a zipfile from existing files
|
||||
// HZIP hz = CreateZip("c:\\simple1.zip",0);
|
||||
// ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp");
|
||||
// ZipAdd(hz,"znsimple.txt", "c:\\simple.txt");
|
||||
// CloseZip(hz);
|
||||
//
|
||||
// (2) Memory use, creating an auto-allocated mem-based zip file from various sources
|
||||
// HZIP hz = CreateZip(0,100000, 0);
|
||||
// // adding a conventional file...
|
||||
// ZipAdd(hz,"src1.txt", "c:\\src1.txt");
|
||||
// // adding something from memory...
|
||||
// char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F);
|
||||
// ZipAdd(hz,"file.dat", buf,1000);
|
||||
// // adding something from a pipe...
|
||||
// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0);
|
||||
// HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0);
|
||||
// ZipAdd(hz,"unz3.dat", hread,1000); // the '1000' is optional.
|
||||
// WaitForSingleObject(hthread,INFINITE);
|
||||
// CloseHandle(hthread); CloseHandle(hread);
|
||||
// ... meanwhile DWORD WINAPI ThreadFunc(void *dat)
|
||||
// { HANDLE hwrite = (HANDLE)dat;
|
||||
// char buf[1000]={17};
|
||||
// DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL);
|
||||
// CloseHandle(hwrite);
|
||||
// return 0;
|
||||
// }
|
||||
// // and now that the zip is created, let's do something with it:
|
||||
// void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen);
|
||||
// HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
|
||||
// DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL);
|
||||
// CloseHandle(hfz);
|
||||
// CloseZip(hz);
|
||||
//
|
||||
// (3) Handle use, for file handles and pipes
|
||||
// HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0);
|
||||
// HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0);
|
||||
// HZIP hz = CreateZipHandle(hzwrite,0);
|
||||
// // ... add to it
|
||||
// CloseZip(hz);
|
||||
// CloseHandle(hzwrite);
|
||||
// WaitForSingleObject(hthread,INFINITE);
|
||||
// CloseHandle(hthread);
|
||||
// ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat)
|
||||
// { HANDLE hread = (HANDLE)dat;
|
||||
// char buf[1000];
|
||||
// while (true)
|
||||
// { DWORD red; ReadFile(hread,buf,1000,&red,NULL);
|
||||
// // ... and do something with this zip data we're receiving
|
||||
// if (red==0) break;
|
||||
// }
|
||||
// CloseHandle(hread);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// Now we indulge in a little skullduggery so that the code works whether
|
||||
// the user has included just zip or both zip and unzip.
|
||||
// Idea: if header files for both zip and unzip are present, then presumably
|
||||
// the cpp files for zip and unzip are both present, so we will call
|
||||
// one or the other of them based on a dynamic choice. If the header file
|
||||
// for only one is present, then we will bind to that particular one.
|
||||
ZRESULT CloseZipZ(HZIP hz);
|
||||
unsigned int FormatZipMessageZ(ZRESULT code, char* buf, unsigned int len);
|
||||
bool IsZipHandleZ(HZIP hz);
|
||||
#ifdef _unzip_H
|
||||
#undef CloseZip
|
||||
#define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz))
|
||||
#else
|
||||
#define CloseZip CloseZipZ
|
||||
#define FormatZipMessage FormatZipMessageZ
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
module;
|
||||
|
||||
#include "Main.h"
|
||||
#include "Defines.h"
|
||||
|
||||
export module ModfileLoader;
|
||||
|
||||
import std;
|
||||
import <libzippp.h>;
|
||||
import ModfileLoader.TpfReader;
|
||||
import TextureFunction;
|
||||
|
||||
namespace {
|
||||
bool use_64_bit_crc = false;
|
||||
|
||||
HashType GetCrcFromFilename(const std::string& filename) {
|
||||
const static std::regex re(R"(0x[0-9a-f]{4,16})", std::regex::optimize | std::regex::icase);
|
||||
std::smatch match;
|
||||
if (!std::regex_search(filename, match, re)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t crc64_hash = 0;
|
||||
const auto number_str = match.str();
|
||||
try {
|
||||
crc64_hash = std::stoull(number_str, nullptr, 16);
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
Warning("Failed to parse %s as a hash\n", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
Warning("Out of range while parsing %s as a hash\n", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
use_64_bit_crc = use_64_bit_crc || crc64_hash > 0xFFFFFFFF;
|
||||
return crc64_hash;
|
||||
}
|
||||
}
|
||||
|
||||
namespace HashCheck {
|
||||
export bool Use64BitCrc() {
|
||||
return use_64_bit_crc;
|
||||
}
|
||||
}
|
||||
|
||||
export class ModfileLoader {
|
||||
std::filesystem::path file_name;
|
||||
const std::string TPF_PASSWORD{
|
||||
0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast<char>(0xA6), static_cast<char>(0xBD),
|
||||
0x7D, 0x65, 0x7E, 0x67, 0x61, 0x2A, 0x7F, 0x7F,
|
||||
0x74, 0x61, 0x67, 0x5B, 0x60, 0x70, 0x45, 0x74,
|
||||
0x5C, 0x22, 0x74, 0x5D, 0x6E, 0x6A, 0x73, 0x41,
|
||||
0x77, 0x6E, 0x46, 0x47, 0x77, 0x49, 0x0C, 0x4B,
|
||||
0x46, 0x6F
|
||||
};
|
||||
|
||||
public:
|
||||
ModfileLoader(const std::filesystem::path& fileName);
|
||||
|
||||
std::vector<TexEntry> GetContents() const;
|
||||
|
||||
private:
|
||||
|
||||
std::vector<TexEntry> GetTpfContents() const;
|
||||
|
||||
std::vector<TexEntry> GetFileContents() const;
|
||||
|
||||
static void LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries);
|
||||
};
|
||||
|
||||
ModfileLoader::ModfileLoader(const std::filesystem::path& fileName)
|
||||
{
|
||||
file_name = std::filesystem::absolute(fileName);
|
||||
}
|
||||
|
||||
std::vector<TexEntry> ModfileLoader::GetContents() const
|
||||
{
|
||||
try {
|
||||
return file_name.wstring().ends_with(L".tpf") ? GetTpfContents() : GetFileContents();
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
Warning("Failed to open mod file: %s\n", file_name.c_str());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<TexEntry> ModfileLoader::GetTpfContents() const
|
||||
{
|
||||
std::vector<TexEntry> entries;
|
||||
auto tpf_reader = TpfReader(file_name);
|
||||
const auto buffer = tpf_reader.ReadToEnd();
|
||||
const auto zip_archive = libzippp::ZipArchive::fromBuffer(buffer.data(), buffer.size(), false, TPF_PASSWORD);
|
||||
if (!zip_archive) {
|
||||
Warning("Failed to open tpf file: %s - %u bytes!", file_name.c_str(), buffer.size());
|
||||
return {};
|
||||
}
|
||||
zip_archive->setErrorHandlerCallback(
|
||||
[](const std::string& message, const std::string& strerror, int zip_error_code, int system_error_code) -> void {
|
||||
Message("GetTpfContents: %s %s %d %d\n", message.c_str(), strerror.c_str(), zip_error_code, system_error_code);
|
||||
});
|
||||
zip_archive->open();
|
||||
LoadEntries(*zip_archive, entries);
|
||||
zip_archive->close();
|
||||
libzippp::ZipArchive::free(zip_archive);
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::vector<TexEntry> ModfileLoader::GetFileContents() const
|
||||
{
|
||||
std::vector<TexEntry> entries;
|
||||
|
||||
libzippp::ZipArchive zip_archive(file_name.string());
|
||||
zip_archive.open();
|
||||
LoadEntries(zip_archive, entries);
|
||||
zip_archive.close();
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
void ParseSimpleArchive(const libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
for (const auto& entry : archive.getEntries()) {
|
||||
if (!entry.isFile())
|
||||
continue;
|
||||
const auto crc_hash = GetCrcFromFilename(entry.getName());
|
||||
if (!crc_hash)
|
||||
continue;
|
||||
const auto data_ptr = static_cast<BYTE*>(entry.readAsBinary());
|
||||
const auto size = entry.getSize();
|
||||
std::vector vec(data_ptr, data_ptr + size);
|
||||
std::filesystem::path tex_name(entry.getName());
|
||||
entries.emplace_back(std::move(vec), crc_hash, tex_name.extension().string());
|
||||
delete[] data_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ParseTexmodArchive(std::vector<std::string>& lines, libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
for (const auto& line : lines) {
|
||||
// 0xC57D73F7|GW.EXE_0xC57D73F7.tga\r\n
|
||||
// match[1] | match[2]
|
||||
const static auto address_file_regex = std::regex(R"(^[\\/.]*([^|]+)\|([^\r\n]+))", std::regex::optimize);
|
||||
std::smatch match;
|
||||
if (!std::regex_search(line, match, address_file_regex))
|
||||
continue;
|
||||
const auto address_string = match[1].str();
|
||||
const auto file_path = match[2].str();
|
||||
|
||||
const auto crc_hash = GetCrcFromFilename(address_string);
|
||||
if (!crc_hash)
|
||||
continue;
|
||||
|
||||
const auto entry = archive.getEntry(file_path);
|
||||
if (entry.isNull() || !entry.isFile())
|
||||
continue;
|
||||
|
||||
const auto data_ptr = static_cast<BYTE*>(entry.readAsBinary());
|
||||
const auto size = static_cast<size_t>(entry.getSize());
|
||||
std::vector vec(data_ptr, data_ptr + size);
|
||||
const auto tex_name = std::filesystem::path(entry.getName());
|
||||
entries.emplace_back(std::move(vec), crc_hash, tex_name.extension().string());
|
||||
delete[] data_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ModfileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector<TexEntry>& entries)
|
||||
{
|
||||
const auto def_file = archive.getEntry("texmod.def");
|
||||
if (def_file.isNull() || !def_file.isFile()) {
|
||||
ParseSimpleArchive(archive, entries);
|
||||
}
|
||||
else {
|
||||
const auto def = def_file.readAsText();
|
||||
std::istringstream iss(def);
|
||||
std::vector<std::string> lines;
|
||||
std::string line;
|
||||
|
||||
while (std::getline(iss, line)) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
ParseTexmodArchive(lines, archive, entries);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
export module ModfileLoader.TpfReader;
|
||||
|
||||
import std;
|
||||
|
||||
export class TpfReader {
|
||||
public:
|
||||
TpfReader(const std::filesystem::path& path)
|
||||
{
|
||||
file_stream = std::ifstream(path, std::ios::binary);
|
||||
if (!file_stream.seekg(0, std::ios::end).good() || !file_stream.seekg(0, std::ios::beg).good()) {
|
||||
throw std::invalid_argument("Provided stream needs to have SEEK set to True");
|
||||
}
|
||||
}
|
||||
|
||||
~TpfReader()
|
||||
{
|
||||
file_stream.close();
|
||||
}
|
||||
|
||||
std::vector<char> ReadToEnd()
|
||||
{
|
||||
file_stream.seekg(0, std::ios::end);
|
||||
line_length = file_stream.tellg();
|
||||
file_stream.seekg(0, std::ios::beg); // Go to the beginning of the stream
|
||||
|
||||
std::vector<char> data(static_cast<long>(line_length));
|
||||
file_stream.read(data.data(), line_length);
|
||||
for (auto i = 0u; i < data.size(); i++) {
|
||||
data[i] = XOR(data[i], 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);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ifstream file_stream;
|
||||
std::streamoff line_length = 0;
|
||||
|
||||
[[nodiscard]] char XOR(const char b, const long position) const
|
||||
{
|
||||
if (position > line_length - 4) {
|
||||
return b ^ TPF_XOREven;
|
||||
}
|
||||
|
||||
return position % 2 == 0 ? b ^ TPF_XOREven : b ^ TPF_XOROdd;
|
||||
}
|
||||
|
||||
static constexpr char TPF_XOROdd = 0x3F;
|
||||
static constexpr char TPF_XOREven = static_cast<char>(0xA4);
|
||||
};
|
||||
@@ -0,0 +1,373 @@
|
||||
module;
|
||||
|
||||
#include "Main.h"
|
||||
#include "Error.h"
|
||||
#include "uMod_IDirect3DTexture9.h"
|
||||
#include <DDSTextureLoader/DDSTextureLoader9.h>
|
||||
#include <DirectXTex/DirectXTex.h>
|
||||
|
||||
export module TextureClient;
|
||||
import TextureFunction;
|
||||
import ModfileLoader;
|
||||
|
||||
export std::vector<std::pair<std::string, std::string>> modlists_contents;
|
||||
/*
|
||||
* An object of this class is owned by each d3d9 device.
|
||||
* All other functions are called from the render thread instance of the game itself.
|
||||
*/
|
||||
export class TextureClient {
|
||||
public:
|
||||
TextureClient(IDirect3DDevice9* device);
|
||||
~TextureClient();
|
||||
|
||||
int AddTexture(uModTexturePtr auto pTexture);
|
||||
int RemoveTexture(uModTexturePtr auto pTexture); //called from uMod_IDirect3DTexture9::Release()
|
||||
int LookUpToMod(uModTexturePtr auto pTexture);
|
||||
// called at the end AddTexture(...) and from Device->UpdateTexture(...)
|
||||
|
||||
int MergeUpdate(); //called from uMod_IDirect3DDevice9::BeginScene()
|
||||
void Initialize();
|
||||
|
||||
std::vector<uMod_IDirect3DTexture9*> OriginalTextures;
|
||||
// stores the pointer to the uMod_IDirect3DTexture9 objects created by the game
|
||||
std::vector<uMod_IDirect3DVolumeTexture9*> OriginalVolumeTextures;
|
||||
// stores the pointer to the uMod_IDirect3DVolumeTexture9 objects created by the game
|
||||
std::vector<uMod_IDirect3DCubeTexture9*> OriginalCubeTextures;
|
||||
// stores the pointer to the uMod_IDirect3DCubeTexture9 objects created by the game
|
||||
|
||||
private:
|
||||
IDirect3DDevice9* D3D9Device;
|
||||
// Cached info about whether this id a dx9ex device or not; used for proxy functions
|
||||
bool isDirectXExDevice = false;
|
||||
|
||||
// DX9 proxy functions
|
||||
void SetLastCreatedTexture(uMod_IDirect3DTexture9*);
|
||||
void SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9*);
|
||||
void SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9*);
|
||||
|
||||
bool should_update = false;
|
||||
|
||||
int LockMutex();
|
||||
int UnlockMutex();
|
||||
HANDLE hMutex;
|
||||
|
||||
std::unordered_map<HashType, gsl::owner<TextureFileStruct*>> modded_textures;
|
||||
// array which stores the file in memory and the hash of each texture to be modded
|
||||
|
||||
// called if a target texture is found
|
||||
int LoadTexture(TextureFileStruct* file_in_memory, uModTexturePtrPtr auto ppTexture);
|
||||
|
||||
void LoadModsFromModlist(std::pair<std::string, std::string> modfile_tuple);
|
||||
std::filesystem::path dll_path; // path to gmod dll
|
||||
};
|
||||
|
||||
TextureClient::TextureClient(IDirect3DDevice9* device)
|
||||
{
|
||||
Message("TextureClient::TextureClient(): %p\n", this);
|
||||
D3D9Device = device;
|
||||
|
||||
void* cpy;
|
||||
isDirectXExDevice = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy) == 0x01000001L;
|
||||
|
||||
hMutex = CreateMutex(nullptr, false, nullptr);
|
||||
}
|
||||
|
||||
TextureClient::~TextureClient()
|
||||
{
|
||||
Message("TextureClient::~TextureClient(): %p\n", this);
|
||||
if (hMutex != nullptr) {
|
||||
CloseHandle(hMutex);
|
||||
}
|
||||
for (const auto texture_file_struct : modded_textures | std::views::values) {
|
||||
delete texture_file_struct;
|
||||
}
|
||||
modded_textures.clear();
|
||||
}
|
||||
|
||||
int TextureClient::MergeUpdate()
|
||||
{
|
||||
if (!should_update) return RETURN_OK;
|
||||
should_update = false;
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_TEXTURE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Message("MergeUpdate(): %p\n", this);
|
||||
|
||||
for (const auto pTexture : OriginalTextures) {
|
||||
if (pTexture->CrossRef_D3Dtex == nullptr) {
|
||||
LookUpToMod(pTexture);
|
||||
}
|
||||
}
|
||||
for (const auto pTexture : OriginalVolumeTextures) {
|
||||
if (pTexture->CrossRef_D3Dtex == nullptr) {
|
||||
LookUpToMod(pTexture);
|
||||
}
|
||||
}
|
||||
for (const auto pTexture : OriginalCubeTextures) {
|
||||
if (pTexture->CrossRef_D3Dtex == nullptr) {
|
||||
LookUpToMod(pTexture);
|
||||
}
|
||||
}
|
||||
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
void TextureClient::SetLastCreatedTexture(uMod_IDirect3DTexture9* texture)
|
||||
{
|
||||
if (isDirectXExDevice)
|
||||
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedTexture(texture);
|
||||
}
|
||||
|
||||
void TextureClient::SetLastCreatedVolumeTexture(uMod_IDirect3DVolumeTexture9* texture)
|
||||
{
|
||||
if (isDirectXExDevice)
|
||||
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedVolumeTexture(texture);
|
||||
}
|
||||
|
||||
void TextureClient::SetLastCreatedCubeTexture(uMod_IDirect3DCubeTexture9* texture)
|
||||
{
|
||||
if (isDirectXExDevice)
|
||||
return static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedCubeTexture(texture);
|
||||
return static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedCubeTexture(texture);
|
||||
}
|
||||
|
||||
int TextureClient::LockMutex()
|
||||
{
|
||||
if ((gl_ErrorState & (uMod_ERROR_FATAL | uMod_ERROR_MUTEX))) {
|
||||
return RETURN_NO_MUTEX;
|
||||
}
|
||||
if (WAIT_OBJECT_0 != WaitForSingleObject(hMutex, 100)) {
|
||||
return RETURN_MUTEX_LOCK; //waiting 100ms, to wait infinite pass INFINITE
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int TextureClient::UnlockMutex()
|
||||
{
|
||||
if (ReleaseMutex(hMutex) == 0) {
|
||||
return RETURN_MUTEX_UNLOCK;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
gsl::owner<TextureFileStruct*> AddFile(TexEntry& entry, const bool compress, const std::filesystem::path& dll_path)
|
||||
{
|
||||
const auto texture_file_struct = new TextureFileStruct();
|
||||
texture_file_struct->crc_hash = entry.crc_hash;
|
||||
const auto dds_blob = TextureFunction::ConvertToCompressedDDS(entry, compress, dll_path);
|
||||
texture_file_struct->data.assign(static_cast<BYTE*>(dds_blob.GetBufferPointer()), static_cast<BYTE*>(dds_blob.GetBufferPointer()) + dds_blob.GetBufferSize());
|
||||
return texture_file_struct;
|
||||
}
|
||||
|
||||
std::vector<gsl::owner<TextureFileStruct*>> ProcessModfile(const std::filesystem::path& modfile, const std::filesystem::path& dll_path, const bool compress)
|
||||
{
|
||||
const auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
if (FAILED(hr)) return {};
|
||||
Message("Initialize: loading file %s... ", modfile.c_str());
|
||||
auto file_loader = ModfileLoader(modfile);
|
||||
auto entries = file_loader.GetContents();
|
||||
if (entries.empty()) {
|
||||
Message("No entries found.\n");
|
||||
return {};
|
||||
}
|
||||
Message("%zu textures... ", entries.size());
|
||||
std::vector<gsl::owner<TextureFileStruct*>> texture_file_structs;
|
||||
texture_file_structs.reserve(entries.size());
|
||||
unsigned file_bytes_loaded = 0;
|
||||
for (auto& tpf_entry : entries) {
|
||||
const auto tex_file_struct = AddFile(tpf_entry, compress, dll_path);
|
||||
texture_file_structs.push_back(tex_file_struct);
|
||||
file_bytes_loaded += texture_file_structs.back()->data.size();
|
||||
}
|
||||
entries.clear();
|
||||
Message("%d bytes loaded.\n", file_bytes_loaded);
|
||||
CoUninitialize();
|
||||
return texture_file_structs;
|
||||
}
|
||||
|
||||
void TextureClient::LoadModsFromModlist(std::pair<std::string, std::string> modfile_tuple)
|
||||
{
|
||||
static std::vector<std::filesystem::path> loaded_modfiles{};
|
||||
|
||||
std::locale::global(std::locale(""));
|
||||
std::istringstream file(modfile_tuple.second);
|
||||
std::string line;
|
||||
std::vector<std::filesystem::path> modfiles;
|
||||
while (std::getline(file, line)) {
|
||||
// Remove newline character
|
||||
line.erase(std::ranges::remove(line, '\r').begin(), line.end());
|
||||
line.erase(std::ranges::remove(line, '\n').begin(), line.end());
|
||||
|
||||
const auto wline = utils::utf8_to_wstring(line);
|
||||
const auto fsline = std::filesystem::path(wline);
|
||||
|
||||
if (!std::ranges::contains(loaded_modfiles, fsline)) {
|
||||
modfiles.push_back(fsline);
|
||||
loaded_modfiles.push_back(fsline);
|
||||
}
|
||||
}
|
||||
auto files_size = 0ull;
|
||||
for (const auto modfile : modfiles) {
|
||||
if (std::filesystem::exists(modfile)) {
|
||||
files_size += std::filesystem::file_size(modfile);
|
||||
}
|
||||
}
|
||||
std::vector<std::future<std::vector<gsl::owner<TextureFileStruct*>>>> futures;
|
||||
for (const auto modfile : modfiles) {
|
||||
futures.emplace_back(std::async(std::launch::async, ProcessModfile, modfile, dll_path, files_size > 400'000'000));
|
||||
}
|
||||
auto loaded_size = 0u;
|
||||
for (auto& future : futures) {
|
||||
const auto texture_file_structs = future.get();
|
||||
for (const auto texture_file_struct : texture_file_structs) {
|
||||
if (!texture_file_struct->crc_hash) continue;
|
||||
if (!modded_textures.contains(texture_file_struct->crc_hash)) {
|
||||
modded_textures.emplace(texture_file_struct->crc_hash, texture_file_struct);
|
||||
loaded_size += texture_file_struct->data.size();
|
||||
}
|
||||
else {
|
||||
delete texture_file_struct;
|
||||
}
|
||||
}
|
||||
should_update = true;
|
||||
}
|
||||
Message("Finished loading mods from %s: Loaded %u bytes (%u mb)", modfile_tuple.first.c_str(), loaded_size, loaded_size / 1024 / 1024);
|
||||
}
|
||||
|
||||
void TextureClient::Initialize()
|
||||
{
|
||||
const auto t1 = std::chrono::high_resolution_clock::now();
|
||||
Info("Initialize: begin\n");
|
||||
for (const auto& modlists_content : modlists_contents) {
|
||||
LoadModsFromModlist(modlists_content);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,415 @@
|
||||
module;
|
||||
|
||||
#include "Main.h"
|
||||
#include <d3d9types.h>
|
||||
#include <DirectXTex/DirectXTex.h>
|
||||
|
||||
export module TextureFunction;
|
||||
|
||||
export template <typename T>
|
||||
concept uModTexturePtr = requires(T a)
|
||||
{
|
||||
std::same_as<uMod_IDirect3DTexture9*, T> ||
|
||||
std::same_as<uMod_IDirect3DVolumeTexture9*, T> ||
|
||||
std::same_as<uMod_IDirect3DCubeTexture9*, T>;
|
||||
};
|
||||
|
||||
export template <typename T>
|
||||
concept uModTexturePtrPtr = uModTexturePtr<std::remove_pointer_t<T>>;
|
||||
|
||||
export template <typename T> requires uModTexturePtr<T>
|
||||
void UnswitchTextures(T pTexture)
|
||||
{
|
||||
decltype(pTexture) CrossRef = pTexture->CrossRef_D3Dtex;
|
||||
if (CrossRef != nullptr) {
|
||||
std::swap(pTexture->m_D3Dtex, CrossRef->m_D3Dtex);
|
||||
|
||||
// cancel the link
|
||||
CrossRef->CrossRef_D3Dtex = nullptr;
|
||||
pTexture->CrossRef_D3Dtex = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
export template <typename T> requires uModTexturePtr<T>
|
||||
int SwitchTextures(T pTexture1, T pTexture2)
|
||||
{
|
||||
if (pTexture1->m_D3Ddev == pTexture2->m_D3Ddev && pTexture1->CrossRef_D3Dtex == nullptr && pTexture2->CrossRef_D3Dtex == nullptr) {
|
||||
// make cross reference
|
||||
pTexture1->CrossRef_D3Dtex = pTexture2;
|
||||
pTexture2->CrossRef_D3Dtex = pTexture1;
|
||||
|
||||
// switch textures
|
||||
std::swap(pTexture1->m_D3Dtex, pTexture2->m_D3Dtex);
|
||||
return RETURN_OK;
|
||||
}
|
||||
return RETURN_TEXTURE_NOT_SWITCHED;
|
||||
}
|
||||
|
||||
constexpr auto crctab64 = std::to_array({
|
||||
0x0000000000000000ULL, 0x7ad870c830358979ULL, 0xf5b0e190606b12f2ULL,
|
||||
0x8f689158505e9b8bULL, 0xc038e5739841b68fULL, 0xbae095bba8743ff6ULL,
|
||||
0x358804e3f82aa47dULL, 0x4f50742bc81f2d04ULL, 0xab28ecb46814fe75ULL,
|
||||
0xd1f09c7c5821770cULL, 0x5e980d24087fec87ULL, 0x24407dec384a65feULL,
|
||||
0x6b1009c7f05548faULL, 0x11c8790fc060c183ULL, 0x9ea0e857903e5a08ULL,
|
||||
0xe478989fa00bd371ULL, 0x7d08ff3b88be6f81ULL, 0x07d08ff3b88be6f8ULL,
|
||||
0x88b81eabe8d57d73ULL, 0xf2606e63d8e0f40aULL, 0xbd301a4810ffd90eULL,
|
||||
0xc7e86a8020ca5077ULL, 0x4880fbd87094cbfcULL, 0x32588b1040a14285ULL,
|
||||
0xd620138fe0aa91f4ULL, 0xacf86347d09f188dULL, 0x2390f21f80c18306ULL,
|
||||
0x594882d7b0f40a7fULL, 0x1618f6fc78eb277bULL, 0x6cc0863448deae02ULL,
|
||||
0xe3a8176c18803589ULL, 0x997067a428b5bcf0ULL, 0xfa11fe77117cdf02ULL,
|
||||
0x80c98ebf2149567bULL, 0x0fa11fe77117cdf0ULL, 0x75796f2f41224489ULL,
|
||||
0x3a291b04893d698dULL, 0x40f16bccb908e0f4ULL, 0xcf99fa94e9567b7fULL,
|
||||
0xb5418a5cd963f206ULL, 0x513912c379682177ULL, 0x2be1620b495da80eULL,
|
||||
0xa489f35319033385ULL, 0xde51839b2936bafcULL, 0x9101f7b0e12997f8ULL,
|
||||
0xebd98778d11c1e81ULL, 0x64b116208142850aULL, 0x1e6966e8b1770c73ULL,
|
||||
0x8719014c99c2b083ULL, 0xfdc17184a9f739faULL, 0x72a9e0dcf9a9a271ULL,
|
||||
0x08719014c99c2b08ULL, 0x4721e43f0183060cULL, 0x3df994f731b68f75ULL,
|
||||
0xb29105af61e814feULL, 0xc849756751dd9d87ULL, 0x2c31edf8f1d64ef6ULL,
|
||||
0x56e99d30c1e3c78fULL, 0xd9810c6891bd5c04ULL, 0xa3597ca0a188d57dULL,
|
||||
0xec09088b6997f879ULL, 0x96d1784359a27100ULL, 0x19b9e91b09fcea8bULL,
|
||||
0x636199d339c963f2ULL, 0xdf7adabd7a6e2d6fULL, 0xa5a2aa754a5ba416ULL,
|
||||
0x2aca3b2d1a053f9dULL, 0x50124be52a30b6e4ULL, 0x1f423fcee22f9be0ULL,
|
||||
0x659a4f06d21a1299ULL, 0xeaf2de5e82448912ULL, 0x902aae96b271006bULL,
|
||||
0x74523609127ad31aULL, 0x0e8a46c1224f5a63ULL, 0x81e2d7997211c1e8ULL,
|
||||
0xfb3aa75142244891ULL, 0xb46ad37a8a3b6595ULL, 0xceb2a3b2ba0eececULL,
|
||||
0x41da32eaea507767ULL, 0x3b024222da65fe1eULL, 0xa2722586f2d042eeULL,
|
||||
0xd8aa554ec2e5cb97ULL, 0x57c2c41692bb501cULL, 0x2d1ab4dea28ed965ULL,
|
||||
0x624ac0f56a91f461ULL, 0x1892b03d5aa47d18ULL, 0x97fa21650afae693ULL,
|
||||
0xed2251ad3acf6feaULL, 0x095ac9329ac4bc9bULL, 0x7382b9faaaf135e2ULL,
|
||||
0xfcea28a2faafae69ULL, 0x8632586aca9a2710ULL, 0xc9622c4102850a14ULL,
|
||||
0xb3ba5c8932b0836dULL, 0x3cd2cdd162ee18e6ULL, 0x460abd1952db919fULL,
|
||||
0x256b24ca6b12f26dULL, 0x5fb354025b277b14ULL, 0xd0dbc55a0b79e09fULL,
|
||||
0xaa03b5923b4c69e6ULL, 0xe553c1b9f35344e2ULL, 0x9f8bb171c366cd9bULL,
|
||||
0x10e3202993385610ULL, 0x6a3b50e1a30ddf69ULL, 0x8e43c87e03060c18ULL,
|
||||
0xf49bb8b633338561ULL, 0x7bf329ee636d1eeaULL, 0x012b592653589793ULL,
|
||||
0x4e7b2d0d9b47ba97ULL, 0x34a35dc5ab7233eeULL, 0xbbcbcc9dfb2ca865ULL,
|
||||
0xc113bc55cb19211cULL, 0x5863dbf1e3ac9decULL, 0x22bbab39d3991495ULL,
|
||||
0xadd33a6183c78f1eULL, 0xd70b4aa9b3f20667ULL, 0x985b3e827bed2b63ULL,
|
||||
0xe2834e4a4bd8a21aULL, 0x6debdf121b863991ULL, 0x1733afda2bb3b0e8ULL,
|
||||
0xf34b37458bb86399ULL, 0x8993478dbb8deae0ULL, 0x06fbd6d5ebd3716bULL,
|
||||
0x7c23a61ddbe6f812ULL, 0x3373d23613f9d516ULL, 0x49aba2fe23cc5c6fULL,
|
||||
0xc6c333a67392c7e4ULL, 0xbc1b436e43a74e9dULL, 0x95ac9329ac4bc9b5ULL,
|
||||
0xef74e3e19c7e40ccULL, 0x601c72b9cc20db47ULL, 0x1ac40271fc15523eULL,
|
||||
0x5594765a340a7f3aULL, 0x2f4c0692043ff643ULL, 0xa02497ca54616dc8ULL,
|
||||
0xdafce7026454e4b1ULL, 0x3e847f9dc45f37c0ULL, 0x445c0f55f46abeb9ULL,
|
||||
0xcb349e0da4342532ULL, 0xb1eceec59401ac4bULL, 0xfebc9aee5c1e814fULL,
|
||||
0x8464ea266c2b0836ULL, 0x0b0c7b7e3c7593bdULL, 0x71d40bb60c401ac4ULL,
|
||||
0xe8a46c1224f5a634ULL, 0x927c1cda14c02f4dULL, 0x1d148d82449eb4c6ULL,
|
||||
0x67ccfd4a74ab3dbfULL, 0x289c8961bcb410bbULL, 0x5244f9a98c8199c2ULL,
|
||||
0xdd2c68f1dcdf0249ULL, 0xa7f41839ecea8b30ULL, 0x438c80a64ce15841ULL,
|
||||
0x3954f06e7cd4d138ULL, 0xb63c61362c8a4ab3ULL, 0xcce411fe1cbfc3caULL,
|
||||
0x83b465d5d4a0eeceULL, 0xf96c151de49567b7ULL, 0x76048445b4cbfc3cULL,
|
||||
0x0cdcf48d84fe7545ULL, 0x6fbd6d5ebd3716b7ULL, 0x15651d968d029fceULL,
|
||||
0x9a0d8ccedd5c0445ULL, 0xe0d5fc06ed698d3cULL, 0xaf85882d2576a038ULL,
|
||||
0xd55df8e515432941ULL, 0x5a3569bd451db2caULL, 0x20ed197575283bb3ULL,
|
||||
0xc49581ead523e8c2ULL, 0xbe4df122e51661bbULL, 0x3125607ab548fa30ULL,
|
||||
0x4bfd10b2857d7349ULL, 0x04ad64994d625e4dULL, 0x7e7514517d57d734ULL,
|
||||
0xf11d85092d094cbfULL, 0x8bc5f5c11d3cc5c6ULL, 0x12b5926535897936ULL,
|
||||
0x686de2ad05bcf04fULL, 0xe70573f555e26bc4ULL, 0x9ddd033d65d7e2bdULL,
|
||||
0xd28d7716adc8cfb9ULL, 0xa85507de9dfd46c0ULL, 0x273d9686cda3dd4bULL,
|
||||
0x5de5e64efd965432ULL, 0xb99d7ed15d9d8743ULL, 0xc3450e196da80e3aULL,
|
||||
0x4c2d9f413df695b1ULL, 0x36f5ef890dc31cc8ULL, 0x79a59ba2c5dc31ccULL,
|
||||
0x037deb6af5e9b8b5ULL, 0x8c157a32a5b7233eULL, 0xf6cd0afa9582aa47ULL,
|
||||
0x4ad64994d625e4daULL, 0x300e395ce6106da3ULL, 0xbf66a804b64ef628ULL,
|
||||
0xc5bed8cc867b7f51ULL, 0x8aeeace74e645255ULL, 0xf036dc2f7e51db2cULL,
|
||||
0x7f5e4d772e0f40a7ULL, 0x05863dbf1e3ac9deULL, 0xe1fea520be311aafULL,
|
||||
0x9b26d5e88e0493d6ULL, 0x144e44b0de5a085dULL, 0x6e963478ee6f8124ULL,
|
||||
0x21c640532670ac20ULL, 0x5b1e309b16452559ULL, 0xd476a1c3461bbed2ULL,
|
||||
0xaeaed10b762e37abULL, 0x37deb6af5e9b8b5bULL, 0x4d06c6676eae0222ULL,
|
||||
0xc26e573f3ef099a9ULL, 0xb8b627f70ec510d0ULL, 0xf7e653dcc6da3dd4ULL,
|
||||
0x8d3e2314f6efb4adULL, 0x0256b24ca6b12f26ULL, 0x788ec2849684a65fULL,
|
||||
0x9cf65a1b368f752eULL, 0xe62e2ad306bafc57ULL, 0x6946bb8b56e467dcULL,
|
||||
0x139ecb4366d1eea5ULL, 0x5ccebf68aecec3a1ULL, 0x2616cfa09efb4ad8ULL,
|
||||
0xa97e5ef8cea5d153ULL, 0xd3a62e30fe90582aULL, 0xb0c7b7e3c7593bd8ULL,
|
||||
0xca1fc72bf76cb2a1ULL, 0x45775673a732292aULL, 0x3faf26bb9707a053ULL,
|
||||
0x70ff52905f188d57ULL, 0x0a2722586f2d042eULL, 0x854fb3003f739fa5ULL,
|
||||
0xff97c3c80f4616dcULL, 0x1bef5b57af4dc5adULL, 0x61372b9f9f784cd4ULL,
|
||||
0xee5fbac7cf26d75fULL, 0x9487ca0fff135e26ULL, 0xdbd7be24370c7322ULL,
|
||||
0xa10fceec0739fa5bULL, 0x2e675fb4576761d0ULL, 0x54bf2f7c6752e8a9ULL,
|
||||
0xcdcf48d84fe75459ULL, 0xb71738107fd2dd20ULL, 0x387fa9482f8c46abULL,
|
||||
0x42a7d9801fb9cfd2ULL, 0x0df7adabd7a6e2d6ULL, 0x772fdd63e7936bafULL,
|
||||
0xf8474c3bb7cdf024ULL, 0x829f3cf387f8795dULL, 0x66e7a46c27f3aa2cULL,
|
||||
0x1c3fd4a417c62355ULL, 0x935745fc4798b8deULL, 0xe98f353477ad31a7ULL,
|
||||
0xa6df411fbfb21ca3ULL, 0xdc0731d78f8795daULL, 0x536fa08fdfd90e51ULL,
|
||||
0x29b7d047efec8728ULL
|
||||
});
|
||||
|
||||
export namespace TextureFunction {
|
||||
|
||||
uint64_t get_crc64(const char* data, unsigned int length) {
|
||||
uint64_t crc = 0xFFFFFFFFFFFFFFFFULL;
|
||||
|
||||
while (length--) {
|
||||
crc = crctab64[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t get_crc32(const char* data_ptr, const unsigned int length)
|
||||
{
|
||||
constexpr static auto crc32_poly = 0xEDB88320u;
|
||||
constexpr static auto ul_crc_in = 0xffffffff;
|
||||
unsigned int crc = ul_crc_in;
|
||||
for (unsigned int idx = 0u; idx < length; idx++) {
|
||||
unsigned int data = *data_ptr++;
|
||||
for (unsigned int bit = 0u; bit < 8u; bit++, data >>= 1) {
|
||||
crc = crc >> 1 ^ ((crc ^ data) & 1 ? crc32_poly : 0);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int GetBitsFromFormat(D3DFORMAT format)
|
||||
{
|
||||
switch (format) //switch trough the formats to calculate the size of the raw data
|
||||
{
|
||||
case D3DFMT_A1: // 1-bit monochrome.
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
case D3DFMT_R3G3B2: // 8-bit RGB texture format using 3 bits for red, 3 bits for green, and 2 bits for blue.
|
||||
case D3DFMT_A8: // 8-bit alpha only.
|
||||
case D3DFMT_A8P8: // 8-bit color indexed with 8 bits of alpha.
|
||||
case D3DFMT_P8: // 8-bit color indexed.
|
||||
case D3DFMT_L8: // 8-bit luminance only.
|
||||
case D3DFMT_A4L4: // 8-bit using 4 bits each for alpha and luminance.
|
||||
case D3DFMT_FORCE_DWORD:
|
||||
case D3DFMT_S8_LOCKABLE: // A lockable 8-bit stencil buffer.
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
case D3DFMT_D16_LOCKABLE: //16-bit z-buffer bit depth.
|
||||
case D3DFMT_D15S1: // 16-bit z-buffer bit depth where 15 bits are reserved for the depth channel and 1 bit is reserved for the stencil channel.
|
||||
case D3DFMT_L6V5U5: // 16-bit bump-map format with luminance using 6 bits for luminance, and 5 bits each for v and u.
|
||||
case D3DFMT_V8U8: // 16-bit bump-map format using 8 bits each for u and v data.
|
||||
case D3DFMT_CxV8U8: // 16-bit normal compression format. The texture sampler computes the C channel from: C = sqrt(1 - U2 - V2).
|
||||
case D3DFMT_R5G6B5: // 16-bit RGB pixel format with 5 bits for red, 6 bits for green, and 5 bits for blue.
|
||||
case D3DFMT_X1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color.
|
||||
case D3DFMT_A1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color and 1 bit is reserved for alpha.
|
||||
case D3DFMT_A4R4G4B4: // 16-bit ARGB pixel format with 4 bits for each channel.
|
||||
case D3DFMT_A8R3G3B2: // 16-bit ARGB texture format using 8 bits for alpha, 3 bits each for red and green, and 2 bits for blue.
|
||||
case D3DFMT_X4R4G4B4: // 16-bit RGB pixel format using 4 bits for each color.
|
||||
case D3DFMT_L16: // 16-bit luminance only.
|
||||
case D3DFMT_R16F: // 16-bit float format using 16 bits for the red channel.
|
||||
case D3DFMT_A8L8: // 16-bit using 8 bits each for alpha and luminance.
|
||||
case D3DFMT_D16: // 16-bit z-buffer bit depth.
|
||||
case D3DFMT_INDEX16: // 16-bit index buffer bit depth.
|
||||
case D3DFMT_G8R8_G8B8: // ??
|
||||
case D3DFMT_R8G8_B8G8: // ??
|
||||
case D3DFMT_UYVY: // ??
|
||||
case D3DFMT_YUY2: // ??
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
|
||||
case D3DFMT_R8G8B8: //24-bit RGB pixel format with 8 bits per channel.
|
||||
{
|
||||
return 24;
|
||||
}
|
||||
|
||||
case D3DFMT_R32F: // 32-bit float format using 32 bits for the red channel.
|
||||
case D3DFMT_X8L8V8U8: // 32-bit bump-map format with luminance using 8 bits for each channel.
|
||||
case D3DFMT_A2W10V10U10: // 32-bit bump-map format using 2 bits for alpha and 10 bits each for w, v, and u.
|
||||
case D3DFMT_Q8W8V8U8: // 32-bit bump-map format using 8 bits for each channel.
|
||||
case D3DFMT_V16U16: // 32-bit bump-map format using 16 bits for each channel.
|
||||
case D3DFMT_A8R8G8B8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel.
|
||||
case D3DFMT_X8R8G8B8: // 32-bit RGB pixel format, where 8 bits are reserved for each color.
|
||||
case D3DFMT_A2B10G10R10: // 32-bit pixel format using 10 bits for each color and 2 bits for alpha.
|
||||
case D3DFMT_A8B8G8R8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel.
|
||||
case D3DFMT_X8B8G8R8: // 32-bit RGB pixel format, where 8 bits are reserved for each color.
|
||||
case D3DFMT_G16R16: // 32-bit pixel format using 16 bits each for green and red.
|
||||
case D3DFMT_G16R16F: // 32-bit float format using 16 bits for the red channel and 16 bits for the green channel.
|
||||
case D3DFMT_A2R10G10B10: // 32-bit pixel format using 10 bits each for red, green, and blue, and 2 bits for alpha.
|
||||
case D3DFMT_D32: // 32-bit z-buffer bit depth.
|
||||
case D3DFMT_D24S8: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 8 bits for the stencil channel.
|
||||
case D3DFMT_D24X8: //32-bit z-buffer bit depth using 24 bits for the depth channel.
|
||||
case D3DFMT_D24X4S4: // 32-bit z-buffer bit depth using 24 bits for the depth channel and 4 bits for the stencil channel.
|
||||
case D3DFMT_D32F_LOCKABLE: // A lockable format where the depth value is represented as a standard IEEE floating-point number.
|
||||
case D3DFMT_D24FS8: // A non-lockable format that contains 24 bits of depth (in a 24-bit floating point format - 20e4) and 8 bits of stencil.
|
||||
case D3DFMT_D32_LOCKABLE: // A lockable 32-bit depth buffer.
|
||||
case D3DFMT_INDEX32: // 32-bit index buffer bit depth.
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
case D3DFMT_G32R32F: // 64-bit float format using 32 bits for the red channel and 32 bits for the green channel.
|
||||
case D3DFMT_Q16W16V16U16: // 64-bit bump-map format using 16 bits for each component.
|
||||
case D3DFMT_A16B16G16R16: // 64-bit pixel format using 16 bits for each component.
|
||||
case D3DFMT_A16B16G16R16F: // 64-bit float format using 16 bits for the each channel (alpha, blue, green, red).
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
case D3DFMT_A32B32G32R32F: // 128-bit float format using 32 bits for the each channel (alpha, blue, green, red).
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
case D3DFMT_DXT2:
|
||||
case D3DFMT_DXT3:
|
||||
case D3DFMT_DXT4:
|
||||
case D3DFMT_DXT5: {
|
||||
return 8;
|
||||
}
|
||||
case D3DFMT_DXT1: {
|
||||
return 4;
|
||||
}
|
||||
default: //compressed formats
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DirectX::ScratchImage ImageConvertToBGRA(DirectX::ScratchImage& image, const TexEntry& entry)
|
||||
{
|
||||
if (image.GetMetadata().format == DXGI_FORMAT_B8G8R8A8_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC1_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC2_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC3_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC4_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC5_UNORM) {
|
||||
return std::move(image);
|
||||
}
|
||||
DirectX::ScratchImage bgra_image;
|
||||
const HRESULT hr = DirectX::Convert(
|
||||
image.GetImages(),
|
||||
image.GetImageCount(),
|
||||
image.GetMetadata(),
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
DirectX::TEX_FILTER_DEFAULT,
|
||||
DirectX::TEX_THRESHOLD_DEFAULT,
|
||||
bgra_image);
|
||||
if (FAILED(hr)) {
|
||||
Warning("ImageConvertToBGRA (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str());
|
||||
bgra_image = std::move(image);
|
||||
}
|
||||
image.Release();
|
||||
return bgra_image;
|
||||
}
|
||||
|
||||
DirectX::ScratchImage ImageGenerateMipMaps(DirectX::ScratchImage& image, const TexEntry& entry)
|
||||
{
|
||||
if (entry.ext == ".dds") {
|
||||
return std::move(image);
|
||||
}
|
||||
DirectX::ScratchImage mipmapped_image;
|
||||
const auto hr = DirectX::GenerateMipMaps(
|
||||
image.GetImages(),
|
||||
image.GetImageCount(),
|
||||
image.GetMetadata(),
|
||||
DirectX::TEX_FILTER_DEFAULT,
|
||||
0,
|
||||
mipmapped_image);
|
||||
if (FAILED(hr)) {
|
||||
Warning("GenerateMipMaps (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str());
|
||||
mipmapped_image = std::move(image);
|
||||
}
|
||||
image.Release();
|
||||
return mipmapped_image;
|
||||
}
|
||||
|
||||
DirectX::ScratchImage ImageCompress(DirectX::ScratchImage& image, const TexEntry& entry)
|
||||
{
|
||||
if (image.GetMetadata().format == DXGI_FORMAT_BC1_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC2_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC3_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC4_UNORM ||
|
||||
image.GetMetadata().format == DXGI_FORMAT_BC5_UNORM) {
|
||||
return std::move(image);
|
||||
}
|
||||
DirectX::ScratchImage compressed_image;
|
||||
const auto hr = DirectX::Compress(
|
||||
image.GetImages(),
|
||||
image.GetImageCount(),
|
||||
image.GetMetadata(),
|
||||
DXGI_FORMAT_BC3_UNORM,
|
||||
DirectX::TEX_COMPRESS_DEFAULT,
|
||||
DirectX::TEX_THRESHOLD_DEFAULT,
|
||||
compressed_image);
|
||||
if (FAILED(hr)) {
|
||||
Warning("ImageCompress (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str());
|
||||
compressed_image = std::move(image);
|
||||
}
|
||||
image.Release();
|
||||
return compressed_image;
|
||||
}
|
||||
|
||||
void ImageSave(const DirectX::ScratchImage& image, const TexEntry& entry, const std::filesystem::path& dll_path)
|
||||
{
|
||||
const auto file_name = std::format("0x{:x}.dds", entry.crc_hash);
|
||||
const auto file_out = dll_path / "textures" / file_name;
|
||||
try {
|
||||
if (std::filesystem::exists(file_out)) {
|
||||
return;
|
||||
}
|
||||
if (!std::filesystem::exists(file_out.parent_path())) {
|
||||
std::filesystem::create_directory(file_out.parent_path());
|
||||
}
|
||||
const auto hr = DirectX::SaveToDDSFile(
|
||||
image.GetImages(),
|
||||
image.GetImageCount(),
|
||||
image.GetMetadata(),
|
||||
DirectX::DDS_FLAGS_NONE,
|
||||
file_out.c_str());
|
||||
if (FAILED(hr)) {
|
||||
Warning("SaveDDSImageToDisk (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str());
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Warning("SaveDDSImageToDisk (%#lX%s): %s\n", entry.crc_hash, entry.ext.c_str(), e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DirectX::Blob ConvertToCompressedDDS(TexEntry& entry, const bool compress, [[maybe_unused]] const std::filesystem::path& dll_path)
|
||||
{
|
||||
DirectX::ScratchImage image;
|
||||
HRESULT hr = 0;
|
||||
|
||||
if (entry.ext == ".dds") {
|
||||
hr = DirectX::LoadFromDDSMemory(entry.data.data(), entry.data.size(), DirectX::DDS_FLAGS_NONE, nullptr, image);
|
||||
}
|
||||
else if (entry.ext == ".tga") {
|
||||
hr = DirectX::LoadFromTGAMemory(entry.data.data(), entry.data.size(), DirectX::TGA_FLAGS_BGR, nullptr, image);
|
||||
}
|
||||
else if (entry.ext == ".hdr") {
|
||||
hr = DirectX::LoadFromHDRMemory(entry.data.data(), entry.data.size(), nullptr, image);
|
||||
}
|
||||
else {
|
||||
hr = DirectX::LoadFromWICMemory(entry.data.data(), entry.data.size(), DirectX::WIC_FLAGS_NONE, nullptr, image);
|
||||
if (image.GetMetadata().format == DXGI_FORMAT_B8G8R8X8_UNORM) {
|
||||
image.OverrideFormat(DXGI_FORMAT_B8G8R8A8_UNORM);
|
||||
}
|
||||
}
|
||||
entry.data.clear();
|
||||
if (FAILED(hr)) {
|
||||
Warning("LoadImageFromMemory (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
auto bgra_image = ImageConvertToBGRA(image, entry);
|
||||
auto mipmapped_image = ImageGenerateMipMaps(bgra_image, entry);
|
||||
const auto compressed_image = compress ? ImageCompress(mipmapped_image, entry) : std::move(mipmapped_image);
|
||||
|
||||
DirectX::Blob dds_blob;
|
||||
hr = DirectX::SaveToDDSMemory(
|
||||
compressed_image.GetImages(),
|
||||
compressed_image.GetImageCount(),
|
||||
compressed_image.GetMetadata(),
|
||||
DirectX::DDS_FLAGS_NONE,
|
||||
dds_blob);
|
||||
if (FAILED(hr)) {
|
||||
Warning("SaveDDSImageToMemory (%#lX%s): FAILED\n", entry.crc_hash, entry.ext.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
ImageSave(compressed_image, entry, dll_path);
|
||||
#endif
|
||||
return dds_blob;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "Error.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <cstdio>
|
||||
#include <process.h>
|
||||
#include <Main.h>
|
||||
|
||||
__declspec(noreturn) void FatalAssert(
|
||||
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_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);
|
||||
|
||||
|
||||
MessageBox(0, buf, "uMod Assertion Failure", MB_OK | MB_ICONERROR);
|
||||
|
||||
delete[] buf;
|
||||
abort();
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
#include "Main.h"
|
||||
#include <Psapi.h>
|
||||
#include "MinHook.h"
|
||||
|
||||
import TextureClient;
|
||||
|
||||
void ExitInstance();
|
||||
void InitInstance(HINSTANCE hModule);
|
||||
|
||||
namespace {
|
||||
|
||||
#define DISABLE_HOOK(var) if(var) { MH_DisableHook(var);}
|
||||
|
||||
using Direct3DCreate9_type = IDirect3D9* (APIENTRY*)(UINT);
|
||||
using Direct3DCreate9Ex_type = HRESULT(APIENTRY*)(UINT SDKVersion, IDirect3D9Ex** ppD3D);
|
||||
using GetProcAddress_type = FARPROC(APIENTRY*)(HMODULE, LPCSTR);
|
||||
|
||||
// Pointer to original address of Direct3DCreate9
|
||||
Direct3DCreate9_type Direct3DCreate9_ret = nullptr;
|
||||
|
||||
// Pointer to original address of Direct3DCreate9
|
||||
Direct3DCreate9Ex_type Direct3DCreate9Ex_ret = nullptr;
|
||||
|
||||
GetProcAddress_type GetProcAddress_fn = nullptr;
|
||||
GetProcAddress_type GetProcAddress_ret = nullptr;
|
||||
|
||||
FILE* stdout_proxy;
|
||||
FILE* stderr_proxy;
|
||||
|
||||
HMODULE gMod_Loaded_d3d9_Module_Handle = nullptr;
|
||||
|
||||
HMODULE FindLoadedModuleByName(const char* name, bool include_this_module = false)
|
||||
{
|
||||
HMODULE hModules[1024];
|
||||
HANDLE hProcess;
|
||||
DWORD cbNeeded;
|
||||
unsigned int i;
|
||||
|
||||
// Get a handle to the current process.
|
||||
hProcess = GetCurrentProcess();
|
||||
if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded))
|
||||
return nullptr;
|
||||
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
|
||||
if (hModules[i] == gl_hThisInstance && !include_this_module)
|
||||
continue;
|
||||
TCHAR szModuleName[MAX_PATH];
|
||||
ASSERT(GetModuleFileName(hModules[i], szModuleName, _countof(szModuleName)) > 0);
|
||||
const auto basename = strrchr(szModuleName, '\\');
|
||||
if (basename && _stricmp(basename + 1, name) == 0)
|
||||
return hModules[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HMODULE LoadD3d9Dll()
|
||||
{
|
||||
HMODULE found = FindLoadedModuleByName("d3d9.dll");
|
||||
if (!found) {
|
||||
char executable_path[MAX_PATH]{};
|
||||
ASSERT(GetModuleFileName(GetModuleHandle(nullptr), executable_path, _countof(executable_path)) > 0);
|
||||
|
||||
char dll_path[MAX_PATH]{};
|
||||
ASSERT(GetModuleFileName(gl_hThisInstance, dll_path, _countof(dll_path)) > 0);
|
||||
|
||||
const auto exe_path = std::filesystem::path(executable_path);
|
||||
const auto gmod_path = std::filesystem::path(dll_path);
|
||||
|
||||
if (exe_path.parent_path() != gmod_path.parent_path()
|
||||
|| gmod_path.filename() != "d3d9.dll") {
|
||||
// Call basic LoadLibrary function; we're not in the same directory as the exe.
|
||||
gMod_Loaded_d3d9_Module_Handle = LoadLibrary("d3d9.dll");
|
||||
}
|
||||
if (!gMod_Loaded_d3d9_Module_Handle) {
|
||||
// Tried resolving d3d9.dll locally, didn't work. Try system directory
|
||||
char buffer[MAX_PATH];
|
||||
ASSERT(GetSystemDirectory(buffer, _countof(buffer)) > 0); //get the system directory, we need to open the original d3d9.dll
|
||||
|
||||
// Append dll name
|
||||
strcat_s(buffer, _countof(buffer), "\\d3d9.dll");
|
||||
gMod_Loaded_d3d9_Module_Handle = LoadLibrary(buffer);
|
||||
}
|
||||
|
||||
ASSERT(gMod_Loaded_d3d9_Module_Handle);
|
||||
|
||||
found = FindLoadedModuleByName("d3d9.dll");
|
||||
ASSERT(found && found == gMod_Loaded_d3d9_Module_Handle);
|
||||
}
|
||||
|
||||
DISABLE_HOOK(GetProcAddress_fn);
|
||||
// GetProcAddress, hooked via OnGetProcAddress
|
||||
Direct3DCreate9_ret = reinterpret_cast<Direct3DCreate9_type>(GetProcAddress(found, "Direct3DCreate9"));
|
||||
Direct3DCreate9Ex_ret = reinterpret_cast<Direct3DCreate9Ex_type>(GetProcAddress(found, "Direct3DCreate9Ex"));
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
FARPROC APIENTRY OnGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
|
||||
{
|
||||
ASSERT(GetProcAddress_ret);
|
||||
if ((int)lpProcName < 0xffff)
|
||||
return GetProcAddress_ret(hModule, lpProcName); // lpProcName is ordinal offset, not string
|
||||
|
||||
if (strcmp(lpProcName, "Direct3DCreate9") == 0) {
|
||||
Direct3DCreate9_ret = reinterpret_cast<Direct3DCreate9_type>(GetProcAddress_ret(hModule, lpProcName));
|
||||
return reinterpret_cast<FARPROC>(Direct3DCreate9);
|
||||
}
|
||||
if (strcmp(lpProcName, "Direct3DCreate9Ex") == 0) {
|
||||
Direct3DCreate9Ex_ret = reinterpret_cast<Direct3DCreate9Ex_type>(GetProcAddress_ret(hModule, lpProcName));
|
||||
return reinterpret_cast<FARPROC>(Direct3DCreate9Ex);
|
||||
}
|
||||
return GetProcAddress_ret(hModule, lpProcName);
|
||||
}
|
||||
|
||||
// If the original d3d9 function is nullptr or points to gMod, load the actual d3d9 dll and redirect the addresses
|
||||
void CheckLoadD3d9Dll()
|
||||
{
|
||||
if (!(Direct3DCreate9_ret && Direct3DCreate9_ret != Direct3DCreate9)) {
|
||||
ASSERT(LoadD3d9Dll());
|
||||
ASSERT(Direct3DCreate9_ret && Direct3DCreate9_ret != Direct3DCreate9);
|
||||
}
|
||||
if (!(Direct3DCreate9Ex_ret && Direct3DCreate9Ex_ret != Direct3DCreate9Ex)) {
|
||||
ASSERT(LoadD3d9Dll());
|
||||
ASSERT(Direct3DCreate9Ex_ret && Direct3DCreate9Ex_ret != Direct3DCreate9Ex);
|
||||
}
|
||||
}
|
||||
|
||||
// There may be a sitation where more than 1 gmod is loaded; avoid recursions!
|
||||
bool creating_d3d9 = false;
|
||||
}
|
||||
|
||||
unsigned int gl_ErrorState = 0;
|
||||
HINSTANCE gl_hThisInstance = nullptr;
|
||||
|
||||
IDirect3D9* APIENTRY Direct3DCreate9(UINT SDKVersion)
|
||||
{
|
||||
Message("uMod_Direct3DCreate9: uMod %p\n", Direct3DCreate9);
|
||||
|
||||
ASSERT(!creating_d3d9);
|
||||
creating_d3d9 = true;
|
||||
|
||||
DISABLE_HOOK(GetProcAddress_fn);
|
||||
CheckLoadD3d9Dll();
|
||||
|
||||
IDirect3D9* pIDirect3D9_orig = Direct3DCreate9_ret(SDKVersion); //creating the original IDirect3D9 object
|
||||
ASSERT(pIDirect3D9_orig);
|
||||
|
||||
creating_d3d9 = false;
|
||||
|
||||
return new uMod_IDirect3D9(pIDirect3D9_orig); //return our object instead of the "real one"
|
||||
}
|
||||
|
||||
HRESULT APIENTRY Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D)
|
||||
{
|
||||
Message("uMod_Direct3DCreate9Ex: uMod %p\n", Direct3DCreate9Ex);
|
||||
|
||||
ASSERT(!creating_d3d9);
|
||||
creating_d3d9 = true;
|
||||
|
||||
|
||||
DISABLE_HOOK(GetProcAddress_fn);
|
||||
CheckLoadD3d9Dll();
|
||||
|
||||
IDirect3D9Ex* pIDirect3D9Ex_orig = nullptr;
|
||||
HRESULT ret = Direct3DCreate9Ex_ret(SDKVersion, &pIDirect3D9Ex_orig); //creating the original IDirect3D9 object
|
||||
|
||||
creating_d3d9 = false;
|
||||
|
||||
if (ret != S_OK)
|
||||
return ret;
|
||||
|
||||
// @Cleanup: should be we freeing pIDirect3D9Ex at the end of our own lifecycle?
|
||||
const auto pIDirect3D9Ex = new uMod_IDirect3D9Ex(pIDirect3D9Ex_orig);
|
||||
// original umod does not do this for some reason
|
||||
*ppD3D = static_cast<IDirect3D9Ex*>(pIDirect3D9Ex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* dll entry routine, here we initialize or clean up
|
||||
*/
|
||||
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
|
||||
AllocConsole();
|
||||
SetConsoleTitleA("gMod Console");
|
||||
freopen_s(&stdout_proxy, "CONOUT$", "w", stdout);
|
||||
freopen_s(&stderr_proxy, "CONOUT$", "w", stderr);
|
||||
#endif
|
||||
InitInstance(hModule);
|
||||
break;
|
||||
}
|
||||
case DLL_PROCESS_DETACH: {
|
||||
ExitInstance();
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Store the handle to this module
|
||||
gl_hThisInstance = hModule;
|
||||
|
||||
LoadModlists();
|
||||
DisableThreadLibraryCalls(hModule); //reduce overhead
|
||||
|
||||
// d3d9.dll shouldn't be loaded at this point.
|
||||
[[maybe_unused]] const auto d3d9_loaded = FindLoadedModuleByName("d3d9.dll");
|
||||
//ASSERT(!d3d9_loaded);
|
||||
|
||||
MH_Initialize();
|
||||
|
||||
// Hook into LoadLibraryA - we'll do our hooks on the flip side
|
||||
GetProcAddress_fn = reinterpret_cast<GetProcAddress_type>(GetProcAddress);
|
||||
ASSERT(GetProcAddress_fn);
|
||||
if (GetProcAddress_fn) {
|
||||
MH_CreateHook(GetProcAddress_fn, OnGetProcAddress, (void**)&GetProcAddress_ret);
|
||||
MH_EnableHook(GetProcAddress_fn);
|
||||
}
|
||||
}
|
||||
|
||||
void ExitInstance()
|
||||
{
|
||||
DISABLE_HOOK(GetProcAddress_fn);
|
||||
|
||||
MH_Uninitialize();
|
||||
|
||||
if (gMod_Loaded_d3d9_Module_Handle)
|
||||
FreeLibrary(gMod_Loaded_d3d9_Module_Handle);
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (stdout_proxy)
|
||||
fclose(stdout_proxy);
|
||||
if (stderr_proxy)
|
||||
fclose(stderr_proxy);
|
||||
__try {
|
||||
FreeConsole();
|
||||
}
|
||||
__except (EXCEPTION_CONTINUE_EXECUTION) { }
|
||||
#endif
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
#include "uMod_Main.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uMod_FileHandler::uMod_FileHandler()
|
||||
{
|
||||
Message("uMod_FileHandler(): %lu\n", this);
|
||||
Number = 0;
|
||||
FieldCounter = 0;
|
||||
Files = nullptr;
|
||||
}
|
||||
|
||||
uMod_FileHandler::~uMod_FileHandler()
|
||||
{
|
||||
Message("~uMod_FileHandler(): %lu\n", this);
|
||||
if (Files != nullptr) {
|
||||
for (int i = 0; i < FieldCounter; i++) {
|
||||
delete [] Files[i];
|
||||
}
|
||||
delete [] Files;
|
||||
}
|
||||
}
|
||||
|
||||
int uMod_FileHandler::Add(TextureFileStruct* file)
|
||||
{
|
||||
Message("uMod_FileHandler::Add(%lu): %lu\n", file, this);
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (file->Reference >= 0) {
|
||||
return RETURN_UPDATE_ALLREADY_ADDED;
|
||||
}
|
||||
|
||||
if (Number / FieldLength == FieldCounter) // get more memory
|
||||
{
|
||||
TextureFileStruct*** temp = nullptr;
|
||||
try { temp = new TextureFileStruct**[FieldCounter + 10]; }
|
||||
catch (...) {
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_TEXTURE;
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (int i = 0; i < FieldCounter; i++) {
|
||||
temp[i] = Files[i]; //copy to new allocated memory
|
||||
}
|
||||
|
||||
for (int i = FieldCounter; i < FieldCounter + 10; i++) {
|
||||
temp[i] = nullptr; // initialize unused parts to zero
|
||||
}
|
||||
|
||||
FieldCounter += 10;
|
||||
|
||||
delete [] Files;
|
||||
|
||||
Files = temp;
|
||||
}
|
||||
if (Number % FieldLength == 0) // maybe we need to get more memory
|
||||
{
|
||||
try {
|
||||
if (Files[Number / FieldLength] == nullptr) {
|
||||
Files[Number / FieldLength] = new TextureFileStruct*[FieldLength];
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
Files[Number / FieldLength] = nullptr;
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_TEXTURE;
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
Files[Number / FieldLength][Number % FieldLength] = file;
|
||||
file->Reference = Number++; //set the reference for a fast deleting
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
int uMod_FileHandler::Remove(TextureFileStruct* file)
|
||||
{
|
||||
Message("uMod_FileHandler::Remove(%lu): %lu\n", file, this);
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
const int ref = file->Reference;
|
||||
|
||||
if (ref < 0) {
|
||||
return RETURN_OK; // returning if no Reference is set
|
||||
}
|
||||
file->Reference = -1; //set reference outside of bound
|
||||
if (ref < (--Number)) //if reference is unequal to Number-1 we copy the last entry to the index "ref"
|
||||
{
|
||||
Files[ref / FieldLength][ref % FieldLength] = Files[Number / FieldLength][Number % FieldLength];
|
||||
Files[ref / FieldLength][ref % FieldLength]->Reference = ref; //set the new reference entry
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
@@ -1,365 +0,0 @@
|
||||
#include "uMod_DX9_dll.h"
|
||||
#include "uMod_Main.h"
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h>
|
||||
#include <TlHelp32.h>
|
||||
#pragma comment(lib, "Psapi.lib")
|
||||
//#include "detours.h"
|
||||
//#include "detourxs/detourxs/detourxs.h"
|
||||
|
||||
/*
|
||||
#include "detourxs/detourxs/ADE32.cpp"
|
||||
#include "detourxs/detourxs/detourxs.cpp"
|
||||
*/
|
||||
/*
|
||||
* global variable which are not linked external
|
||||
*/
|
||||
HINSTANCE gl_hOriginalDll = nullptr;
|
||||
HINSTANCE gl_hThisInstance = nullptr;
|
||||
uMod_TextureServer* gl_TextureServer = nullptr;
|
||||
HANDLE gl_ServerThread = nullptr;
|
||||
|
||||
using Direct3DCreate9_type = IDirect3D9* (APIENTRY*)(UINT);
|
||||
using Direct3DCreate9Ex_type = HRESULT(APIENTRY*)(UINT SDKVersion, IDirect3D9Ex** ppD3D);
|
||||
|
||||
Direct3DCreate9_type Direct3DCreate9_fn; // we need to store the pointer to the original Direct3DCreate9 function after we have done a detour
|
||||
Direct3DCreate9Ex_type Direct3DCreate9Ex_fn; // we need to store the pointer to the original Direct3DCreate9 function after we have done a detour
|
||||
HHOOK gl_hHook = nullptr;
|
||||
|
||||
static FILE* stdout_proxy;
|
||||
static FILE* stderr_proxy;
|
||||
|
||||
/*
|
||||
* global variable which are linked external
|
||||
*/
|
||||
unsigned int gl_ErrorState = 0u;
|
||||
|
||||
#ifdef LOG_MESSAGE
|
||||
FILE* gl_File = nullptr;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DIRECT_INJECTION
|
||||
void Nothing() { (void)NULL; }
|
||||
#endif
|
||||
/*
|
||||
* 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 BUILD_TYPE_DEBUG
|
||||
AllocConsole();
|
||||
SetConsoleTitleA("uMod Console");
|
||||
freopen_s(&stdout_proxy, "CONOUT$", "w", stdout);
|
||||
freopen_s(&stderr_proxy, "CONOUT$", "w", stderr);
|
||||
#endif
|
||||
InitInstance(hModule);
|
||||
break;
|
||||
}
|
||||
case DLL_PROCESS_DETACH: {
|
||||
ExitInstance();
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI ServerThread(LPVOID lpParam)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(lpParam);
|
||||
if (gl_TextureServer != nullptr) {
|
||||
gl_TextureServer->MainLoop(); //This is and endless mainloop, it sleep till something is written into the pipe.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InitInstance(HINSTANCE hModule)
|
||||
{
|
||||
DisableThreadLibraryCalls(hModule); //reduce overhead
|
||||
gl_hThisInstance = hModule;
|
||||
|
||||
char game[MAX_PATH];
|
||||
if (HookThisProgram(game)) //ask if we need to hook this program
|
||||
{
|
||||
OpenMessage();
|
||||
Message("InitInstance: %lu\n", hModule);
|
||||
char uMod[MAX_PATH];
|
||||
for (auto i = 0; i < MAX_PATH; i++) {
|
||||
uMod[i] = 0;
|
||||
}
|
||||
|
||||
GetModuleFileNameA(hModule, uMod, MAX_PATH);
|
||||
Message("InitInstance: %s\n", uMod);
|
||||
gl_TextureServer = new uMod_TextureServer(game, uMod); //create the server which listen on the pipe and prepare the update for the texture clients
|
||||
LoadOriginalDll();
|
||||
if (gl_hOriginalDll) {
|
||||
Direct3DCreate9_fn = (Direct3DCreate9_type)GetProcAddress(gl_hOriginalDll, "Direct3DCreate9");
|
||||
if (Direct3DCreate9_fn != nullptr) {
|
||||
Message("Detour: Direct3DCreate9\n");
|
||||
Direct3DCreate9_fn = static_cast<Direct3DCreate9_type>(DetourFunc((BYTE*)Direct3DCreate9_fn, (BYTE*)uMod_Direct3DCreate9, 5));
|
||||
}
|
||||
|
||||
Direct3DCreate9Ex_fn = (Direct3DCreate9Ex_type)GetProcAddress(gl_hOriginalDll, "Direct3DCreate9Ex");
|
||||
if (Direct3DCreate9Ex_fn != nullptr) {
|
||||
Message("Detour: Direct3DCreate9Ex\n");
|
||||
Direct3DCreate9Ex_fn = static_cast<Direct3DCreate9Ex_type>(DetourFunc((BYTE*)Direct3DCreate9Ex_fn, (BYTE*)uMod_Direct3DCreate9Ex, 7));
|
||||
}
|
||||
}
|
||||
gl_ServerThread = CreateThread(nullptr, 0, ServerThread, nullptr, 0, nullptr); //creating a thread for the mainloop
|
||||
if (gl_ServerThread == nullptr) { Message("InitInstance: Serverthread not started\n"); }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool HasDesiredMethods(HMODULE hModule, HANDLE hProcess)
|
||||
{
|
||||
const auto d3dcreate9Addr = GetProcAddress(hModule, "Direct3DCreate9");
|
||||
if (!d3dcreate9Addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto d3dcreate9ExAddr = GetProcAddress(hModule, "Direct3DCreate9Ex");
|
||||
if (!d3dcreate9ExAddr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsDesiredModule(HMODULE hModule, HANDLE hProcess)
|
||||
{
|
||||
TCHAR szModuleName[MAX_PATH];
|
||||
GetModuleBaseName(hProcess, hModule, szModuleName, sizeof(szModuleName) / sizeof(TCHAR));
|
||||
return strcmp(szModuleName, TEXT("d3d9.dll")) == 0;
|
||||
}
|
||||
|
||||
bool FindLoadedDll()
|
||||
{
|
||||
HMODULE hModules[1024];
|
||||
HANDLE hProcess;
|
||||
DWORD cbNeeded;
|
||||
unsigned int i;
|
||||
|
||||
// Get a handle to the current process.
|
||||
hProcess = GetCurrentProcess();
|
||||
if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) {
|
||||
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
|
||||
if (IsDesiredModule(hModules[i], hProcess)) {
|
||||
// If the module is d3d9.dll, store the handle or do your hooking here.
|
||||
gl_hOriginalDll = hModules[i];
|
||||
break;
|
||||
}
|
||||
if (HasDesiredMethods(hModules[i], hProcess)) {
|
||||
// If the module has the two specific methods, store the handle or do your hooking here.
|
||||
gl_hOriginalDll = hModules[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gl_hOriginalDll) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LoadOriginalDll()
|
||||
{
|
||||
if (FindLoadedDll()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[MAX_PATH];
|
||||
GetSystemDirectory(buffer, MAX_PATH); //get the system directory, we need to open the original d3d9.dll
|
||||
|
||||
// Append dll name
|
||||
strcat_s(buffer, MAX_PATH, "\\d3d9.dll");
|
||||
|
||||
// try to load the system's d3d9.dll, if pointer empty
|
||||
if (!gl_hOriginalDll) {
|
||||
gl_hOriginalDll = LoadLibrary(buffer);
|
||||
}
|
||||
|
||||
if (!gl_hOriginalDll) {
|
||||
ExitProcess(0); // exit the hard way
|
||||
}
|
||||
}
|
||||
|
||||
void ExitInstance()
|
||||
{
|
||||
if (gl_ServerThread != nullptr) {
|
||||
CloseHandle(gl_ServerThread); // kill the server thread
|
||||
gl_ServerThread = nullptr;
|
||||
}
|
||||
if (gl_TextureServer != nullptr) {
|
||||
delete gl_TextureServer; //delete the texture server
|
||||
gl_TextureServer = nullptr;
|
||||
}
|
||||
|
||||
// Release the system's d3d9.dll
|
||||
if (gl_hOriginalDll != nullptr) {
|
||||
FreeLibrary(gl_hOriginalDll);
|
||||
gl_hOriginalDll = nullptr;
|
||||
}
|
||||
|
||||
#ifdef BUILD_TYPE_DEBUG
|
||||
if (stdout_proxy)
|
||||
fclose(stdout_proxy);
|
||||
if (stderr_proxy)
|
||||
fclose(stderr_proxy);
|
||||
FreeConsole();
|
||||
#endif
|
||||
CloseMessage();
|
||||
}
|
||||
|
||||
/*
|
||||
* We inject the dll into the game, thus we retour the original Direct3DCreate9 function to our MyDirect3DCreate9 function
|
||||
*/
|
||||
|
||||
IDirect3D9* APIENTRY uMod_Direct3DCreate9(UINT SDKVersion)
|
||||
{
|
||||
Message("uMod_Direct3DCreate9: original %lu, uMod %lu\n", Direct3DCreate9_fn, uMod_Direct3DCreate9);
|
||||
|
||||
// in the Internet are many tutorials for detouring functions and all of them will work without the following 5 marked lines
|
||||
// but somehow, for me it only works, if I retour the function and calling afterward the original function
|
||||
|
||||
// BEGIN
|
||||
|
||||
LoadOriginalDll();
|
||||
|
||||
RetourFunc((BYTE*)GetProcAddress(gl_hOriginalDll, "Direct3DCreate9"), (BYTE*)Direct3DCreate9_fn, 5);
|
||||
Direct3DCreate9_fn = (Direct3DCreate9_type)GetProcAddress(gl_hOriginalDll, "Direct3DCreate9");
|
||||
|
||||
/*
|
||||
if (Direct3DCreate9Ex_fn!=NULL)
|
||||
{
|
||||
RetourFunc((BYTE*) GetProcAddress( gl_hOriginalDll, "Direct3DCreate9Ex"), (BYTE*)Direct3DCreate9Ex_fn, 7);
|
||||
Direct3DCreate9Ex_fn = (Direct3DCreate9Ex_type) GetProcAddress( gl_hOriginalDll, "Direct3DCreate9Ex");
|
||||
}
|
||||
*/
|
||||
// END
|
||||
|
||||
IDirect3D9* pIDirect3D9_orig = nullptr;
|
||||
if (Direct3DCreate9_fn) {
|
||||
pIDirect3D9_orig = Direct3DCreate9_fn(SDKVersion); //creating the original IDirect3D9 object
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
uMod_IDirect3D9* pIDirect3D9;
|
||||
if (pIDirect3D9_orig) {
|
||||
pIDirect3D9 = new uMod_IDirect3D9(pIDirect3D9_orig, gl_TextureServer); //creating our uMod_IDirect3D9 object
|
||||
}
|
||||
|
||||
// we detour again
|
||||
Direct3DCreate9_fn = static_cast<Direct3DCreate9_type>(DetourFunc((BYTE*)Direct3DCreate9_fn, (BYTE*)uMod_Direct3DCreate9, 5));
|
||||
/*
|
||||
if (Direct3DCreate9Ex_fn!=NULL)
|
||||
{
|
||||
Direct3DCreate9Ex_fn = (Direct3DCreate9Ex_type)DetourFunc( (BYTE*) Direct3DCreate9Ex_fn, (BYTE*)uMod_Direct3DCreate9Ex,7);
|
||||
}
|
||||
*/
|
||||
return pIDirect3D9; //return our object instead of the "real one"
|
||||
}
|
||||
|
||||
HRESULT APIENTRY uMod_Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppD3D)
|
||||
{
|
||||
Message("uMod_Direct3DCreate9Ex: original %lu, uMod %lu\n", Direct3DCreate9Ex_fn, uMod_Direct3DCreate9Ex);
|
||||
|
||||
// in the Internet are many tutorials for detouring functions and all of them will work without the following 5 marked lines
|
||||
// but somehow, for me it only works, if I retour the function and calling afterward the original function
|
||||
|
||||
// BEGIN
|
||||
|
||||
LoadOriginalDll();
|
||||
/*
|
||||
if (Direct3DCreate9_fn!=NULL)
|
||||
{
|
||||
RetourFunc((BYTE*) GetProcAddress( gl_hOriginalDll, "Direct3DCreate9"), (BYTE*)Direct3DCreate9_fn, 5);
|
||||
Direct3DCreate9_fn = (Direct3DCreate9_type) GetProcAddress( gl_hOriginalDll, "Direct3DCreate9");
|
||||
}
|
||||
*/
|
||||
RetourFunc((BYTE*)GetProcAddress(gl_hOriginalDll, "Direct3DCreate9Ex"), (BYTE*)Direct3DCreate9Ex_fn, 7);
|
||||
Direct3DCreate9Ex_fn = (Direct3DCreate9Ex_type)GetProcAddress(gl_hOriginalDll, "Direct3DCreate9Ex");
|
||||
// END
|
||||
|
||||
IDirect3D9Ex* pIDirect3D9Ex_orig = nullptr;
|
||||
HRESULT ret;
|
||||
if (Direct3DCreate9Ex_fn) {
|
||||
ret = Direct3DCreate9Ex_fn(SDKVersion, &pIDirect3D9Ex_orig); //creating the original IDirect3D9 object
|
||||
}
|
||||
else {
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
}
|
||||
|
||||
if (ret != S_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uMod_IDirect3D9Ex* pIDirect3D9Ex;
|
||||
if (pIDirect3D9Ex_orig) {
|
||||
pIDirect3D9Ex = new uMod_IDirect3D9Ex(pIDirect3D9Ex_orig, gl_TextureServer); //creating our uMod_IDirect3D9 object
|
||||
}
|
||||
|
||||
// we detour again
|
||||
/*
|
||||
if (Direct3DCreate9_fn!=NULL)
|
||||
{
|
||||
Direct3DCreate9_fn = (Direct3DCreate9_type)DetourFunc( (BYTE*) Direct3DCreate9_fn, (BYTE*)uMod_Direct3DCreate9,5);
|
||||
}
|
||||
*/
|
||||
Direct3DCreate9Ex_fn = static_cast<Direct3DCreate9Ex_type>(DetourFunc((BYTE*)Direct3DCreate9Ex_fn, (BYTE*)uMod_Direct3DCreate9Ex, 7));
|
||||
ppD3D = (IDirect3D9Ex**)&pIDirect3D9Ex; //return our object instead of the "real one"
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool HookThisProgram(char* ret)
|
||||
{
|
||||
char Game[MAX_PATH];
|
||||
GetModuleFileName(GetModuleHandle(nullptr), Game, MAX_PATH); //ask for name and path of this executable
|
||||
|
||||
// we inject directly
|
||||
int i = 0;
|
||||
while (Game[i]) {
|
||||
ret[i] = Game[i];
|
||||
i++;
|
||||
}
|
||||
ret[i] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void* DetourFunc(BYTE* src, const BYTE* dst, const int len)
|
||||
{
|
||||
auto jmp = static_cast<BYTE*>(malloc(len + 5));
|
||||
DWORD dwback = 0;
|
||||
VirtualProtect(jmp, len + 5, PAGE_EXECUTE_READWRITE, &dwback); //This is the addition needed for Windows 7 RC
|
||||
VirtualProtect(src, len, PAGE_READWRITE, &dwback);
|
||||
memcpy(jmp, src, len);
|
||||
jmp += len;
|
||||
jmp[0] = 0xE9;
|
||||
*(DWORD*)(jmp + 1) = static_cast<DWORD>(src + len - jmp) - 5;
|
||||
memset(src, 0x90, len);
|
||||
src[0] = 0xE9;
|
||||
*(DWORD*)(src + 1) = static_cast<DWORD>(dst - src) - 5;
|
||||
VirtualProtect(src, len, dwback, &dwback);
|
||||
return jmp - len;
|
||||
}
|
||||
|
||||
bool RetourFunc(BYTE* src, BYTE* restore, const int len)
|
||||
{
|
||||
DWORD dwback;
|
||||
if (!VirtualProtect(src, len, PAGE_READWRITE, &dwback)) { return false; }
|
||||
if (!memcpy(src, restore, len)) { return false; }
|
||||
restore[0] = 0xE9;
|
||||
*(DWORD*)(restore + 1) = static_cast<DWORD>(src - restore) - 5;
|
||||
if (!VirtualProtect(src, len, dwback, &dwback)) { return false; }
|
||||
return true;
|
||||
}
|
||||
@@ -1,485 +0,0 @@
|
||||
#include "uMod_Main.h"
|
||||
#include "unzip.h"
|
||||
#include "uMod_File.h"
|
||||
#include "utils.h"
|
||||
#include "uMod_Texture.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef __CDT_PARSER__
|
||||
#define FindZipItem(...) 0
|
||||
#define UnzipItem(...) 0
|
||||
#define CloseZip(...) 0
|
||||
#define GetZipItem(...) 0
|
||||
#endif
|
||||
|
||||
|
||||
uMod_File::uMod_File()
|
||||
{
|
||||
Loaded = false;
|
||||
XORed = false;
|
||||
FileInMemory = static_cast<char*>(nullptr);
|
||||
MemoryLength = 0u;
|
||||
FileLen = 0u;
|
||||
}
|
||||
|
||||
uMod_File::uMod_File(const std::string file)
|
||||
{
|
||||
Loaded = false;
|
||||
XORed = false;
|
||||
FileInMemory = static_cast<char*>(nullptr);
|
||||
MemoryLength = 0u;
|
||||
FileLen = 0u;
|
||||
SetFile(file);
|
||||
}
|
||||
|
||||
|
||||
uMod_File::~uMod_File()
|
||||
{
|
||||
if (FileInMemory != static_cast<char*>(nullptr)) {
|
||||
delete[] FileInMemory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool uMod_File::FileSupported()
|
||||
{
|
||||
const std::string file_type = GetFileExtension(FileName);
|
||||
if (file_type == "zip") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "tpf") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "bmp") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "jpg") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "tga") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "png") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "dds") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "ppm") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool uMod_File::PackageFile()
|
||||
{
|
||||
const std::string file_type = GetFileExtension(FileName);
|
||||
if (file_type == "zip") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "tpf") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool uMod_File::SingleFile()
|
||||
{
|
||||
const std::string file_type = GetFileExtension(FileName);
|
||||
if (file_type == "bmp") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "jpg") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "tga") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "png") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "dds") {
|
||||
return true;
|
||||
}
|
||||
if (file_type == "ppm") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int uMod_File::GetContent()
|
||||
{
|
||||
const std::string file_type = GetFileExtension(FileName);
|
||||
if (file_type == "zip") {
|
||||
AddZip();
|
||||
}
|
||||
else if (file_type == "tpf") {
|
||||
AddTpf();
|
||||
}
|
||||
else if (SingleFile()) {
|
||||
AddFile();
|
||||
}
|
||||
else {
|
||||
printf(FileName.c_str());
|
||||
printf(" Not supported\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uMod_File::ReadFile()
|
||||
{
|
||||
if (Loaded) {
|
||||
return 0;
|
||||
}
|
||||
XORed = false;
|
||||
|
||||
const auto name = FileName;
|
||||
std::ifstream inputFile(name, std::ios::binary);
|
||||
if (!inputFile ||
|
||||
!inputFile.is_open()) {
|
||||
printf(name.c_str());
|
||||
printf(" Could not open\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const std::vector<char> buffer(std::istreambuf_iterator<char>(inputFile), {});
|
||||
if (FileInMemory) {
|
||||
delete[] FileInMemory;
|
||||
}
|
||||
|
||||
FileInMemory = new char[buffer.size()];
|
||||
for (auto i = 0; i < buffer.size(); i++) {
|
||||
FileInMemory[i] = buffer[i];
|
||||
}
|
||||
|
||||
FileLen = buffer.size();
|
||||
inputFile.close();
|
||||
FileInMemory[FileLen] = 0;
|
||||
printf(name.c_str());
|
||||
printf("%d\n", FileLen);
|
||||
|
||||
Loaded = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uMod_File::UnXOR()
|
||||
{
|
||||
if (XORed) {
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* BIG THANKS TO Tonttu
|
||||
* (TPFcreate 1.5)
|
||||
*
|
||||
*/
|
||||
const auto buff = (unsigned int*)FileInMemory;
|
||||
const unsigned int TPF_XOR = 0x3FA43FA4u;
|
||||
const unsigned int size = FileLen / 4u;
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
buff[i] ^= TPF_XOR;
|
||||
}
|
||||
for (unsigned int i = size * 4u; i < size * 4u + FileLen % 4u; i++) {
|
||||
((unsigned char*)FileInMemory)[i] ^= static_cast<unsigned char>(TPF_XOR);
|
||||
}
|
||||
|
||||
|
||||
unsigned int pos = FileLen - 1;
|
||||
while (pos > 0u && FileInMemory[pos]) {
|
||||
pos--;
|
||||
}
|
||||
if (pos > 0u && pos < FileLen - 1) {
|
||||
FileLen = pos + 1;
|
||||
}
|
||||
XORed = true;
|
||||
|
||||
/*
|
||||
* original code by Tonttu
|
||||
* The last bytes are not revealed correctly
|
||||
unsigned int j=0;
|
||||
while ( j <= result - 4 )
|
||||
{
|
||||
*( unsigned int* )( &buffer[j] ) ^= TPF_XOR;
|
||||
j += 4;
|
||||
}
|
||||
|
||||
while ( j < result )
|
||||
{
|
||||
buffer[j] ^= (unsigned char )( TPF_XOR >> 24 );
|
||||
TPF_XOR <<= 4;
|
||||
j++;
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uMod_File::AddFile()
|
||||
{
|
||||
DWORD64 temp_hash;
|
||||
|
||||
std::string name = AfterLast(FileName, '_');
|
||||
name = BeforeLast(name, '.');
|
||||
|
||||
try {
|
||||
// Convert hexadecimal string to unsigned long long
|
||||
temp_hash = std::stoull(name, nullptr, 16);
|
||||
}
|
||||
catch (const std::invalid_argument& e) {
|
||||
printf("Encountered error");
|
||||
printf(e.what());
|
||||
}
|
||||
catch (const std::out_of_range& e) {
|
||||
printf("Encountered error");
|
||||
printf(e.what());
|
||||
}
|
||||
|
||||
if (const int ret = ReadFile()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
FileHash = temp_hash;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uMod_File::AddZip()
|
||||
{
|
||||
if (const int ret = ReadFile()) {
|
||||
return ret;
|
||||
}
|
||||
return AddContent(nullptr);
|
||||
}
|
||||
|
||||
int uMod_File::AddTpf()
|
||||
{
|
||||
if (const int ret = ReadFile()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
UnXOR();
|
||||
|
||||
constexpr char pw[] = {
|
||||
0x73, 0x2A, 0x63, 0x7D, 0x5F, 0x0A, static_cast<char>(0xA6), static_cast<char>(0xBD),
|
||||
0x7D, 0x65, 0x7E, 0x67, 0x61, 0x2A, 0x7F, 0x7F,
|
||||
0x74, 0x61, 0x67, 0x5B, 0x60, 0x70, 0x45, 0x74,
|
||||
0x5C, 0x22, 0x74, 0x5D, 0x6E, 0x6A, 0x73, 0x41,
|
||||
0x77, 0x6E, 0x46, 0x47, 0x77, 0x49, 0x0C, 0x4B,
|
||||
0x46, 0x6F, '\0'
|
||||
};
|
||||
|
||||
return AddContent(pw);
|
||||
}
|
||||
|
||||
|
||||
int uMod_File::AddContent(const char* pw)
|
||||
{
|
||||
// Thats is really nasty code, but atm I am happy that it works. I should try an other unzip api,
|
||||
// This one seems to behave very strange.
|
||||
// I know, that also a bug in my code could be reason for the crashes, but UnzipItem( ... ) unzipes wrong files
|
||||
// and GetZipItem( ... ) returns garbage as file names, and the next call of GetZipItem( ... ) blows up the program.
|
||||
//
|
||||
// I have commented line 3519 in unzip.cpp.
|
||||
// It was stated this is a bug, but it did not solve my problems.
|
||||
//
|
||||
// closing and reopen the zip handle did the trick.
|
||||
//
|
||||
|
||||
const auto& name = FileName;
|
||||
HZIP ZIP_Handle = OpenZip(FileInMemory, FileLen, pw);
|
||||
if (ZIP_Handle == static_cast<HZIP>(nullptr)) {
|
||||
printf(name.c_str());
|
||||
printf(" Failed to unzip file\n");
|
||||
return -1;
|
||||
}
|
||||
ZIPENTRY ze;
|
||||
int index;
|
||||
FindZipItem(ZIP_Handle, "texmod.def", false, &index, &ze);
|
||||
if (index >= 0) //if texmod.def is present in the zip file
|
||||
{
|
||||
printf(name.c_str());
|
||||
printf(" Unzipping based on texmod.def of size %d\n", ze.unc_size);
|
||||
char* def;
|
||||
int len = ze.unc_size;
|
||||
try { def = new char[len + 1]; }
|
||||
catch (...) {
|
||||
printf(name.c_str());
|
||||
printf(" Memory error\n");
|
||||
return -1;
|
||||
}
|
||||
ZRESULT zr = UnzipItem(ZIP_Handle, index, def, len);
|
||||
|
||||
if (zr != ZR_OK && zr != ZR_MORE) {
|
||||
delete[] def;
|
||||
return -1;
|
||||
}
|
||||
def[len] = 0;
|
||||
|
||||
std::stringstream tokenStream(def);
|
||||
std::string token;
|
||||
DWORD64 temp_hash;
|
||||
std::string entry;
|
||||
std::string file;
|
||||
|
||||
while (std::getline(tokenStream, token)) {
|
||||
entry = token;
|
||||
printf(name.c_str());
|
||||
printf(" Parsing token %s\n", token.c_str());
|
||||
file = BeforeFirst(token, '|');
|
||||
try {
|
||||
temp_hash = std::stoull(file, nullptr, 16);
|
||||
// Successful conversion; can continue processing...
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
// Handle invalid argument
|
||||
printf(name.c_str());
|
||||
printf(" Invalid hash\n");
|
||||
continue; // Skip the rest of the current loop iteration
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
// Handle out of range
|
||||
printf(name.c_str());
|
||||
printf(" Invalid hash\n");
|
||||
continue; // Skip the rest of the current loop iteration
|
||||
}
|
||||
|
||||
file = AfterFirst(entry, '|');
|
||||
ReplaceAll(file, "\r", "");
|
||||
|
||||
while ((!file.empty() && file[0] == '.' && (file.size() > 1 && (file[1] == '/' || file[1] == '\\')))
|
||||
|| (!file.empty() && (file[0] == '/' || file[0] == '\\'))) {
|
||||
file.erase(0, 1);
|
||||
}
|
||||
|
||||
FindZipItem(ZIP_Handle, file.c_str(), false, &index, &ze); // look for texture
|
||||
if (index >= 0) {
|
||||
std::vector<char> data;
|
||||
UModTexture texture;
|
||||
data.resize(ze.unc_size);
|
||||
|
||||
ZRESULT rz = UnzipItem(ZIP_Handle, index, data.data(), ze.unc_size);
|
||||
if (rz != ZR_OK && rz != ZR_MORE) {
|
||||
printf(name.c_str());
|
||||
printf(" Unzip error\n");
|
||||
}
|
||||
else {
|
||||
texture.hash = temp_hash;
|
||||
texture.data = data;
|
||||
texture.name = file;
|
||||
Textures.push_back(texture);
|
||||
printf(name.c_str());
|
||||
printf(" Added texture of size %d %s\n", data.size(), file.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf(name.c_str());
|
||||
printf(" Unzip error\n");
|
||||
CloseZip(ZIP_Handle); //somehow we need to close and to reopen the zip handle, otherwise the program crashes
|
||||
ZIP_Handle = OpenZip(FileInMemory, FileLen, pw);
|
||||
}
|
||||
}
|
||||
delete[] def;
|
||||
|
||||
CloseZip(ZIP_Handle);
|
||||
if (Textures.size() == 0) {
|
||||
printf(name.c_str());
|
||||
printf(" No textures parsed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//we load each dds file
|
||||
{
|
||||
printf(name.c_str());
|
||||
printf(" Unzipping without texmode.def\n");
|
||||
CloseZip(ZIP_Handle); //somehow we need to close and to reopen the zip handle, otherwise the program crashes
|
||||
ZIP_Handle = OpenZip(FileInMemory, FileLen, pw);
|
||||
if (ZIP_Handle == static_cast<HZIP>(nullptr)) {
|
||||
printf(name.c_str());
|
||||
printf(" Failed to unzip file");
|
||||
return -1;
|
||||
}
|
||||
std::string file;
|
||||
GetZipItem(ZIP_Handle, -1, &ze); //ask for number of entries
|
||||
int num = ze.index;
|
||||
DWORD64 temp_hash;
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (GetZipItem(ZIP_Handle, i, &ze) != ZR_OK) {
|
||||
continue; //ask for name and size
|
||||
}
|
||||
int len = ze.unc_size;
|
||||
|
||||
printf(name.c_str());
|
||||
printf(" Parsing token %s\n", ze.name);
|
||||
std::vector<char> data;
|
||||
UModTexture texture;
|
||||
data.resize(ze.unc_size);
|
||||
|
||||
ZRESULT rz = UnzipItem(ZIP_Handle, i, data.data(), len);
|
||||
if (rz != ZR_OK && rz != ZR_MORE) {
|
||||
printf(name.c_str());
|
||||
printf(" Unzip error\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
file = ze.name;
|
||||
if (file.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file == "Comment.txt") // skip comment
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto entryName = AfterLast(file, '.');
|
||||
if (entryName != "dds") {
|
||||
continue;
|
||||
}
|
||||
|
||||
entryName = AfterLast(file, L'_');
|
||||
entryName = BeforeLast(entryName, L'.');
|
||||
|
||||
try {
|
||||
temp_hash = std::stoull(entryName, nullptr, 16); // Convert hex string to number
|
||||
}
|
||||
catch (const std::invalid_argument& e) {
|
||||
printf(name.c_str());
|
||||
printf(" Invalid hash\n");
|
||||
continue;
|
||||
}
|
||||
catch (const std::out_of_range& e) {
|
||||
printf(name.c_str());
|
||||
printf(" Invalid hash\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
texture.hash = temp_hash;
|
||||
texture.name = entryName;
|
||||
texture.data = data;
|
||||
Textures.push_back(texture);
|
||||
printf(name.c_str());
|
||||
printf(" Added texture of size %d %s\n", data.size(), entryName.c_str());
|
||||
}
|
||||
|
||||
CloseZip(ZIP_Handle);
|
||||
if (Textures.size() == 0) {
|
||||
printf(name.c_str());
|
||||
printf(" No textures parsed\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
#include "uMod_Main.h"
|
||||
#include "Main.h"
|
||||
|
||||
#ifndef PRE_MESSAGE
|
||||
#define PRE_MESSAGE "uMod_IDirect3D9"
|
||||
#endif
|
||||
|
||||
uMod_IDirect3D9::uMod_IDirect3D9(IDirect3D9* pOriginal, uMod_TextureServer* server)
|
||||
uMod_IDirect3D9::uMod_IDirect3D9(IDirect3D9* pOriginal)
|
||||
{
|
||||
Message(PRE_MESSAGE "::" PRE_MESSAGE "( %lu, %lu): %lu\n", pOriginal, server, this);
|
||||
Message(PRE_MESSAGE "::" PRE_MESSAGE " (%p): %p\n", pOriginal, this);
|
||||
m_pIDirect3D9 = pOriginal;
|
||||
uMod_Server = server;
|
||||
}
|
||||
|
||||
uMod_IDirect3D9::~uMod_IDirect3D9()
|
||||
{
|
||||
Message(PRE_MESSAGE "::~" PRE_MESSAGE "(): %lu\n", this);
|
||||
Message(PRE_MESSAGE "::~" PRE_MESSAGE "(): %p\n", this);
|
||||
}
|
||||
|
||||
HRESULT __stdcall uMod_IDirect3D9::QueryInterface(REFIID riid, void** ppvObj)
|
||||
@@ -118,7 +117,7 @@ HMONITOR __stdcall uMod_IDirect3D9::GetAdapterMonitor(UINT Adapter)
|
||||
|
||||
HRESULT __stdcall uMod_IDirect3D9::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface)
|
||||
{
|
||||
Message(PRE_MESSAGE "::CreateDevice(): %lu\n", this);
|
||||
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);
|
||||
|
||||
@@ -126,7 +125,7 @@ HRESULT __stdcall uMod_IDirect3D9::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceT
|
||||
if (pPresentationParameters != nullptr) {
|
||||
count = pPresentationParameters->BackBufferCount;
|
||||
}
|
||||
const auto pIDirect3DDevice9 = new uMod_IDirect3DDevice9(*ppReturnedDeviceInterface, uMod_Server, count);
|
||||
const auto pIDirect3DDevice9 = new uMod_IDirect3DDevice9(*ppReturnedDeviceInterface, count);
|
||||
|
||||
// store our pointer (the fake one) for returning it to the calling program
|
||||
*ppReturnedDeviceInterface = pIDirect3DDevice9;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "uMod_Main.h"
|
||||
#include "Main.h"
|
||||
|
||||
#define IDirect3D9 IDirect3D9Ex
|
||||
#define uMod_IDirect3D9 uMod_IDirect3D9Ex
|
||||
@@ -11,7 +11,7 @@
|
||||
HRESULT __stdcall uMod_IDirect3D9Ex::CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode,
|
||||
IDirect3DDevice9Ex** ppReturnedDeviceInterface)
|
||||
{
|
||||
Message("uMod_IDirect3D9Ex::CreateDeviceEx: %lu\n", this);
|
||||
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);
|
||||
|
||||
@@ -19,7 +19,7 @@ HRESULT __stdcall uMod_IDirect3D9Ex::CreateDeviceEx(UINT Adapter, D3DDEVTYPE Dev
|
||||
if (pPresentationParameters != nullptr) {
|
||||
count = pPresentationParameters->BackBufferCount;
|
||||
}
|
||||
const auto pIDirect3DDevice9Ex = new uMod_IDirect3DDevice9Ex(*ppReturnedDeviceInterface, uMod_Server, count);
|
||||
const auto pIDirect3DDevice9Ex = new uMod_IDirect3DDevice9Ex(*ppReturnedDeviceInterface, count);
|
||||
|
||||
// store our pointer (the fake one) for returning it to the calling program
|
||||
*ppReturnedDeviceInterface = pIDirect3DDevice9Ex;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#include "uMod_Main.h"
|
||||
#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)
|
||||
@@ -44,7 +48,7 @@ ULONG APIENTRY uMod_IDirect3DCubeTexture9::AddRef()
|
||||
//this function yields for the non switched texture object
|
||||
ULONG APIENTRY uMod_IDirect3DCubeTexture9::Release()
|
||||
{
|
||||
Message("uMod_IDirect3DCubeTexture9::Release(): %lu\n", this);
|
||||
Message("uMod_IDirect3DCubeTexture9::Release(): %p\n", this);
|
||||
|
||||
void* cpy;
|
||||
const long ret = m_D3Ddev->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
@@ -62,16 +66,7 @@ ULONG APIENTRY uMod_IDirect3DCubeTexture9::Release()
|
||||
if (count == 0) //if texture is released we switch the textures back
|
||||
{
|
||||
UnswitchTextures(this);
|
||||
if (ret == 0x01000000L) {
|
||||
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetSingleCubeTexture() != fake_texture) {
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetSingleCubeTexture() != fake_texture) {
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -100,7 +95,7 @@ ULONG APIENTRY uMod_IDirect3DCubeTexture9::Release()
|
||||
}
|
||||
}
|
||||
|
||||
delete(this);
|
||||
delete this;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -233,120 +228,47 @@ HRESULT APIENTRY uMod_IDirect3DCubeTexture9::UnlockRect(D3DCUBEMAP_FACES FaceTyp
|
||||
return m_D3Dtex->UnlockRect(FaceType, Level);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uMod_IDirect3DCubeTexture9::GetHash(MyTypeHash& hash)
|
||||
HashTuple uMod_IDirect3DCubeTexture9::GetHash() const
|
||||
{
|
||||
hash = 0u;
|
||||
if (FAKE) {
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
return {};
|
||||
}
|
||||
IDirect3DCubeTexture9* pTexture = m_D3Dtex;
|
||||
if (CrossRef_D3Dtex != nullptr) {
|
||||
pTexture = CrossRef_D3Dtex->m_D3Dtex;
|
||||
}
|
||||
|
||||
//IDirect3DSurface9 *pOffscreenSurface = NULL;
|
||||
//IDirect3DCubeTexture9 *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
|
||||
{
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetLevelDesc \n");
|
||||
return RETURN_GetLevelDesc_FAILED;
|
||||
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetLevelDesc \n");
|
||||
return {};
|
||||
}
|
||||
|
||||
Message("uMod_IDirect3DCubeTexture9::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_IDirect3DCubeTexture9::GetHash() (D3DPOOL_DEFAULT)\n");
|
||||
|
||||
IDirect3DSurface9 *pSurfaceLevel_orig = NULL;
|
||||
if (pTexture->GetSurfaceLevel( 0, &pSurfaceLevel_orig)!=D3D_OK)
|
||||
if (pTexture->LockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK)
|
||||
{
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetSurfaceLevel 1 (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
|
||||
if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
|
||||
{
|
||||
//Message("uMod_IDirect3DCubeTexture9::GetHash() MultiSampleType\n");
|
||||
if (D3D_OK!=m_D3Ddev->CreateRenderTarget( desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pResolvedSurface, NULL ))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: CreateRenderTarget (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
if (D3D_OK!=m_D3Ddev->StretchRect( pSurfaceLevel_orig, NULL, pResolvedSurface, NULL, D3DTEXF_NONE ))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: StretchRect (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
|
||||
pSurfaceLevel_orig = pResolvedSurface;
|
||||
}
|
||||
|
||||
|
||||
if (D3D_OK!=m_D3Ddev->CreateOffscreenPlainSurface( desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &pOffscreenSurface, NULL))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_TEXTURE_NOT_LOADED);
|
||||
}
|
||||
|
||||
if (D3D_OK!=m_D3Ddev->GetRenderTargetData( pSurfaceLevel_orig, pOffscreenSurface))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
pOffscreenSurface->Release();
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
pSurfaceLevel_orig->Release();
|
||||
|
||||
if (pOffscreenSurface->LockRect( &d3dlr, NULL, D3DLOCK_READONLY)!=D3D_OK)
|
||||
{
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
pOffscreenSurface->Release();
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
}
|
||||
else
|
||||
*/
|
||||
if (pTexture->LockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 1\n");
|
||||
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 1\n");
|
||||
if (pTexture->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_X, 0, &pResolvedSurface) != D3D_OK) {
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetSurfaceLevel\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: GetSurfaceLevel\n");
|
||||
return {};
|
||||
}
|
||||
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
|
||||
pResolvedSurface->Release();
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 2\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DCubeTexture9::GetHash() Failed: LockRect 2\n");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const auto 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;
|
||||
|
||||
const int size = (GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8;
|
||||
|
||||
hash = GetCRC32(static_cast<char*>(d3dlr.pBits), size); //calculate the crc32 of the texture
|
||||
/*
|
||||
if (pOffscreenSurface!=NULL)
|
||||
{
|
||||
pOffscreenSurface->UnlockRect();
|
||||
pOffscreenSurface->Release();
|
||||
//pOffscreenTexture->Release();
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
}
|
||||
else
|
||||
*/
|
||||
// Only release surfaces after we're finished with d3dlr
|
||||
if (pResolvedSurface != nullptr) {
|
||||
pResolvedSurface->UnlockRect();
|
||||
pResolvedSurface->Release();
|
||||
@@ -355,6 +277,7 @@ int uMod_IDirect3DCubeTexture9::GetHash(MyTypeHash& hash)
|
||||
pTexture->UnlockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0); //unlock the raw data
|
||||
}
|
||||
|
||||
Message("uMod_IDirect3DCubeTexture9::GetHash() %#lX (%d %d) %d = %d\n", hash, desc.Width, desc.Height, desc.Format, size);
|
||||
return RETURN_OK;
|
||||
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};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "uMod_Main.h"
|
||||
#include "Main.h"
|
||||
import TextureClient;
|
||||
|
||||
#ifndef RETURN_QueryInterface
|
||||
#define RETURN_QueryInterface 0x01000000L
|
||||
@@ -8,136 +9,20 @@
|
||||
#define PRE_MESSAGE "uMod_IDirect3DDevice9"
|
||||
#endif
|
||||
|
||||
|
||||
int uMod_IDirect3DDevice9::CreateSingleTexture()
|
||||
uMod_IDirect3DDevice9::uMod_IDirect3DDevice9(IDirect3DDevice9* pOriginal, int back_buffer_count)
|
||||
{
|
||||
if (SingleTexture != nullptr && SingleVolumeTexture != nullptr && SingleCubeTexture != nullptr && TextureColour == uMod_Client->TextureColour) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
TextureColour = uMod_Client->TextureColour;
|
||||
if (SingleTexture == nullptr) //create texture
|
||||
{
|
||||
if (D3D_OK != CreateTexture(8, 8, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, (IDirect3DTexture9**)&SingleTexture, nullptr)) {
|
||||
Message(PRE_MESSAGE "::CreateSingleTexture(): CreateTexture Failed\n");
|
||||
SingleTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
LastCreatedTexture = nullptr; // set LastCreatedTexture to NULL, cause LastCreatedTexture is equal SingleTexture
|
||||
SingleTexture->FAKE = true; //this is no texture created from by game
|
||||
SingleTexture->Reference = -2;
|
||||
}
|
||||
|
||||
{
|
||||
D3DLOCKED_RECT d3dlr;
|
||||
IDirect3DTexture9* pD3Dtex = SingleTexture->m_D3Dtex;
|
||||
|
||||
if (D3D_OK != pD3Dtex->LockRect(0, &d3dlr, nullptr, 0)) {
|
||||
Message(PRE_MESSAGE "::CreateSingleTexture(): LockRect Failed\n");
|
||||
SingleTexture->Release();
|
||||
SingleTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
const auto pDst = static_cast<DWORD*>(d3dlr.pBits);
|
||||
|
||||
for (int i = 0; i < 8 * 8; i++) {
|
||||
pDst[i] = TextureColour;
|
||||
}
|
||||
pD3Dtex->UnlockRect(0);
|
||||
}
|
||||
|
||||
if (SingleVolumeTexture == nullptr) //create texture
|
||||
{
|
||||
if (D3D_OK != CreateVolumeTexture(8, 8, 8, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, (IDirect3DVolumeTexture9**)&SingleVolumeTexture, nullptr)) {
|
||||
Message(PRE_MESSAGE "::CreateSingleTexture(): CreateVolumeTexture Failed\n");
|
||||
SingleVolumeTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
LastCreatedVolumeTexture = nullptr; // set LastCreatedTexture to NULL, cause LastCreatedTexture is equal SingleTexture
|
||||
SingleVolumeTexture->FAKE = true; //this is no texture created from by game
|
||||
SingleVolumeTexture->Reference = -2;
|
||||
}
|
||||
|
||||
{
|
||||
D3DLOCKED_BOX d3dlr;
|
||||
IDirect3DVolumeTexture9* pD3Dtex = SingleVolumeTexture->m_D3Dtex;
|
||||
//LockBox)(UINT Level, D3DLOCKED_BOX *pLockedVolume, CONST D3DBOX *pBox,
|
||||
if (D3D_OK != pD3Dtex->LockBox(0, &d3dlr, nullptr, 0)) {
|
||||
Message(PRE_MESSAGE "::CreateSingleTexture(): LockBox Failed\n");
|
||||
SingleVolumeTexture->Release();
|
||||
SingleVolumeTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
const auto pDst = static_cast<DWORD*>(d3dlr.pBits);
|
||||
|
||||
for (int i = 0; i < 8 * 8 * 8; i++) {
|
||||
pDst[i] = TextureColour;
|
||||
}
|
||||
pD3Dtex->UnlockBox(0);
|
||||
}
|
||||
if (SingleCubeTexture == nullptr) //create texture
|
||||
{
|
||||
if (D3D_OK != CreateCubeTexture(8, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, (IDirect3DCubeTexture9**)&SingleCubeTexture, nullptr)) {
|
||||
Message(PRE_MESSAGE "::CreateSingleTexture(): CreateCubeTexture Failed\n");
|
||||
SingleCubeTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
LastCreatedCubeTexture = nullptr; // set LastCreatedTexture to NULL, cause LastCreatedTexture is equal SingleTexture
|
||||
SingleCubeTexture->FAKE = true; //this is no texture created from by game
|
||||
SingleCubeTexture->Reference = -2;
|
||||
}
|
||||
|
||||
{
|
||||
D3DLOCKED_RECT d3dlr;
|
||||
IDirect3DCubeTexture9* pD3Dtex = SingleCubeTexture->m_D3Dtex;
|
||||
|
||||
for (int c = 0; c < 6; c++) {
|
||||
if (D3D_OK != pD3Dtex->LockRect(static_cast<D3DCUBEMAP_FACES>(c), 0, &d3dlr, nullptr, 0)) {
|
||||
Message(PRE_MESSAGE "::CreateSingleTexture(): LockRect (Cube) Failed\n");
|
||||
SingleCubeTexture->Release();
|
||||
SingleCubeTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
const auto pDst = static_cast<DWORD*>(d3dlr.pBits);
|
||||
|
||||
for (int i = 0; i < 8 * 8; i++) {
|
||||
pDst[i] = TextureColour;
|
||||
}
|
||||
pD3Dtex->UnlockRect(static_cast<D3DCUBEMAP_FACES>(c), 0);
|
||||
}
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
uMod_IDirect3DDevice9::uMod_IDirect3DDevice9(IDirect3DDevice9* pOriginal, uMod_TextureServer* server, int back_buffer_count)
|
||||
{
|
||||
Message(PRE_MESSAGE "::" PRE_MESSAGE "( %lu, %lu): %lu\n", pOriginal, server, this);
|
||||
Message(PRE_MESSAGE "::" PRE_MESSAGE " (%p): %p\n", pOriginal, this);
|
||||
|
||||
BackBufferCount = back_buffer_count;
|
||||
NormalRendering = true;
|
||||
|
||||
uMod_Server = server;
|
||||
uMod_Client = new uMod_TextureClient(uMod_Server, this); //get a new texture client for this device
|
||||
|
||||
LastCreatedTexture = nullptr;
|
||||
LastCreatedVolumeTexture = nullptr;
|
||||
LastCreatedCubeTexture = nullptr;
|
||||
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
|
||||
TextureColour = D3DCOLOR_ARGB(255, 0, 255, 0);
|
||||
|
||||
CounterSaveSingleTexture = -20;
|
||||
|
||||
SingleTextureMod = 0;
|
||||
SingleTexture = nullptr;
|
||||
SingleVolumeTexture = nullptr;
|
||||
SingleCubeTexture = nullptr;
|
||||
OSD_Font = nullptr;
|
||||
uMod_Reference = 1;
|
||||
}
|
||||
|
||||
uMod_IDirect3DDevice9::~uMod_IDirect3DDevice9()
|
||||
{
|
||||
Message(PRE_MESSAGE "::~" PRE_MESSAGE "(): %lu\n", this);
|
||||
Message(PRE_MESSAGE "::~" PRE_MESSAGE "(): %p\n", this);
|
||||
}
|
||||
|
||||
HRESULT uMod_IDirect3DDevice9::QueryInterface(REFIID riid, void** ppvObj)
|
||||
@@ -150,7 +35,7 @@ HRESULT uMod_IDirect3DDevice9::QueryInterface(REFIID riid, void** ppvObj)
|
||||
}
|
||||
|
||||
*ppvObj = nullptr;
|
||||
Message(PRE_MESSAGE "::QueryInterface(): %lu\n", this);
|
||||
Message(PRE_MESSAGE "::QueryInterface(): %p\n", this);
|
||||
const HRESULT hRes = m_pIDirect3DDevice9->QueryInterface(riid, ppvObj);
|
||||
|
||||
if (*ppvObj == m_pIDirect3DDevice9) {
|
||||
@@ -164,7 +49,7 @@ HRESULT uMod_IDirect3DDevice9::QueryInterface(REFIID riid, void** ppvObj)
|
||||
ULONG uMod_IDirect3DDevice9::AddRef()
|
||||
{
|
||||
uMod_Reference++; //increasing our counter
|
||||
Message("%lu = " PRE_MESSAGE "::AddRef(): %lu\n", uMod_Reference, this);
|
||||
Message("%p = " PRE_MESSAGE "::AddRef(): %p\n", uMod_Reference, this);
|
||||
return m_pIDirect3DDevice9->AddRef();
|
||||
}
|
||||
|
||||
@@ -175,33 +60,15 @@ ULONG uMod_IDirect3DDevice9::Release()
|
||||
// we must not release the fake textures, cause they are released if the target textures are released
|
||||
// and the target textures are released by the game.
|
||||
|
||||
if (SingleTexture != nullptr) {
|
||||
SingleTexture->Release(); //this is the only texture we must release by ourself
|
||||
}
|
||||
if (SingleVolumeTexture != nullptr) {
|
||||
SingleVolumeTexture->Release(); //this is the only texture we must release by ourself
|
||||
}
|
||||
if (SingleCubeTexture != nullptr) {
|
||||
SingleCubeTexture->Release(); //this is the only texture we must release by ourself
|
||||
}
|
||||
if (OSD_Font != nullptr) {
|
||||
OSD_Font->Release();
|
||||
}
|
||||
|
||||
if (uMod_Client != nullptr) {
|
||||
delete uMod_Client; //must be deleted at the end, because other releases might call a function of this object
|
||||
}
|
||||
|
||||
delete uMod_Client; //must be deleted at the end, because other releases might call a function of this object
|
||||
uMod_Client = nullptr;
|
||||
SingleTexture = nullptr;
|
||||
OSD_Font = nullptr;
|
||||
}
|
||||
|
||||
const ULONG count = m_pIDirect3DDevice9->Release();
|
||||
Message("%lu = " PRE_MESSAGE "::Release(): %lu\n", count, this);
|
||||
if (uMod_Reference != count) //bug
|
||||
Message("%p = " PRE_MESSAGE "::Release(): %p\n", count, this);
|
||||
if (uMod_Reference != static_cast<int>(count)) //bug
|
||||
{
|
||||
Message("Error in " PRE_MESSAGE "::Release(): %lu!=%lu\n", uMod_Reference, count);
|
||||
Message("Error in " PRE_MESSAGE "::Release(): %p!=%p\n", uMod_Reference, count);
|
||||
}
|
||||
|
||||
if (count == 0u) {
|
||||
@@ -277,10 +144,6 @@ UINT uMod_IDirect3DDevice9::GetNumberOfSwapChains()
|
||||
|
||||
HRESULT uMod_IDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters)
|
||||
{
|
||||
if (OSD_Font != nullptr) {
|
||||
OSD_Font->Release();
|
||||
OSD_Font = nullptr;
|
||||
} //the game will crashes if the font is not released before the game is minimized!
|
||||
return m_pIDirect3DDevice9->Reset(pPresentationParameters);
|
||||
}
|
||||
|
||||
@@ -317,23 +180,18 @@ void uMod_IDirect3DDevice9::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp)
|
||||
HRESULT uMod_IDirect3DDevice9::CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle)
|
||||
{
|
||||
//create real texture
|
||||
//Message("uMod_IDirect3DDevice9::CreateTexture()\n");
|
||||
Message("uMod_IDirect3DDevice9::CreateTexture()\n");
|
||||
const HRESULT ret = m_pIDirect3DDevice9->CreateTexture(Width, Height, Levels, Usage, Format, Pool, ppTexture, pSharedHandle);
|
||||
if (ret != D3D_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//create fake texture
|
||||
const auto texture = new uMod_IDirect3DTexture9(ppTexture, this);
|
||||
if (texture) {
|
||||
*ppTexture = texture;
|
||||
}
|
||||
*ppTexture = texture;
|
||||
|
||||
if (LastCreatedTexture != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
|
||||
if (LastCreatedTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
|
||||
{
|
||||
if (uMod_Client != nullptr) {
|
||||
uMod_Client->AddTexture(LastCreatedTexture);
|
||||
}
|
||||
uMod_Client->AddTexture(LastCreatedTexture);
|
||||
}
|
||||
LastCreatedTexture = texture;
|
||||
return ret;
|
||||
@@ -342,7 +200,7 @@ HRESULT uMod_IDirect3DDevice9::CreateTexture(UINT Width, UINT Height, UINT Level
|
||||
HRESULT uMod_IDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle)
|
||||
{
|
||||
//create real texture
|
||||
//Message("uMod_IDirect3DDevice9::CreateVolumeTexture()\n");
|
||||
Message("uMod_IDirect3DDevice9::CreateVolumeTexture()\n");
|
||||
const HRESULT ret = m_pIDirect3DDevice9->CreateVolumeTexture(Width, Height, Depth, Levels, Usage, Format, Pool, ppVolumeTexture, pSharedHandle);
|
||||
if (ret != D3D_OK) {
|
||||
return ret;
|
||||
@@ -350,15 +208,11 @@ HRESULT uMod_IDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT
|
||||
|
||||
//create fake texture
|
||||
const auto texture = new uMod_IDirect3DVolumeTexture9(ppVolumeTexture, this);
|
||||
if (texture) {
|
||||
*ppVolumeTexture = texture;
|
||||
}
|
||||
*ppVolumeTexture = texture;
|
||||
|
||||
if (LastCreatedVolumeTexture != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
|
||||
if (LastCreatedVolumeTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
|
||||
{
|
||||
if (uMod_Client != nullptr) {
|
||||
uMod_Client->AddTexture(LastCreatedVolumeTexture);
|
||||
}
|
||||
uMod_Client->AddTexture(LastCreatedVolumeTexture);
|
||||
}
|
||||
LastCreatedVolumeTexture = texture;
|
||||
return ret;
|
||||
@@ -367,7 +221,7 @@ HRESULT uMod_IDirect3DDevice9::CreateVolumeTexture(UINT Width, UINT Height, UINT
|
||||
HRESULT uMod_IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle)
|
||||
{
|
||||
//create real texture
|
||||
//Message("uMod_IDirect3DDevice9::CreateCubeTexture()\n");
|
||||
Message("uMod_IDirect3DDevice9::CreateCubeTexture()\n");
|
||||
const HRESULT ret = m_pIDirect3DDevice9->CreateCubeTexture(EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle);
|
||||
if (ret != D3D_OK) {
|
||||
return ret;
|
||||
@@ -375,15 +229,11 @@ HRESULT uMod_IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength, UINT Levels, D
|
||||
|
||||
//create fake texture
|
||||
const auto texture = new uMod_IDirect3DCubeTexture9(ppCubeTexture, this);
|
||||
if (texture) {
|
||||
*ppCubeTexture = texture;
|
||||
}
|
||||
*ppCubeTexture = texture;
|
||||
|
||||
if (LastCreatedCubeTexture != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
|
||||
if (LastCreatedCubeTexture != nullptr && uMod_Client != nullptr) //if a texture was loaded before, hopefully this texture contains now the data, so we can add it
|
||||
{
|
||||
if (uMod_Client != nullptr) {
|
||||
uMod_Client->AddTexture(LastCreatedCubeTexture);
|
||||
}
|
||||
uMod_Client->AddTexture(LastCreatedCubeTexture);
|
||||
}
|
||||
LastCreatedCubeTexture = texture;
|
||||
return ret;
|
||||
@@ -416,7 +266,7 @@ HRESULT uMod_IDirect3DDevice9::UpdateSurface(IDirect3DSurface9* pSourceSurface,C
|
||||
|
||||
HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture)
|
||||
{
|
||||
Message(PRE_MESSAGE "::UpdateTexture( %lu, %lu): %lu\n", pSourceTexture, pDestinationTexture, this);
|
||||
Message(PRE_MESSAGE "::UpdateTexture( %p, %p): %p\n", pSourceTexture, pDestinationTexture, this);
|
||||
// we must pass the real texture objects
|
||||
|
||||
|
||||
@@ -425,12 +275,11 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
|
||||
uMod_IDirect3DCubeTexture9* pSourceCube = nullptr;
|
||||
IDirect3DBaseTexture9* cpy;
|
||||
if (pSourceTexture != nullptr) {
|
||||
long int ret = pSourceTexture->QueryInterface(IID_IDirect3D9, (void**)&cpy);
|
||||
switch (ret) {
|
||||
const auto hash = pSource->GetHash();
|
||||
switch (pSourceTexture->QueryInterface(IID_IDirect3D9, (void**)&cpy)) {
|
||||
case 0x01000000L: {
|
||||
MyTypeHash hash;
|
||||
pSource = static_cast<uMod_IDirect3DTexture9*>(pSourceTexture);
|
||||
if (pSource->GetHash(hash) == RETURN_OK) {
|
||||
if (hash) {
|
||||
if (hash != pSource->Hash) // this hash has changed !!
|
||||
{
|
||||
pSource->Hash = hash;
|
||||
@@ -454,9 +303,8 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
|
||||
break;
|
||||
}
|
||||
case 0x01000001L: {
|
||||
MyTypeHash hash;
|
||||
pSourceVolume = static_cast<uMod_IDirect3DVolumeTexture9*>(pSourceTexture);
|
||||
if (pSourceVolume->GetHash(hash) == RETURN_OK) {
|
||||
if (hash) {
|
||||
if (hash != pSourceVolume->Hash) // this hash has changed !!
|
||||
{
|
||||
pSourceVolume->Hash = hash;
|
||||
@@ -480,9 +328,8 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
|
||||
break;
|
||||
}
|
||||
case 0x01000002L: {
|
||||
MyTypeHash hash;
|
||||
pSourceCube = static_cast<uMod_IDirect3DCubeTexture9*>(pSourceTexture);
|
||||
if (pSourceCube->GetHash(hash) == RETURN_OK) {
|
||||
if (hash) {
|
||||
if (hash != pSourceCube->Hash) // this hash has changed !!
|
||||
{
|
||||
pSourceCube->Hash = hash;
|
||||
@@ -512,18 +359,17 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
|
||||
|
||||
|
||||
if (pDestinationTexture != nullptr) {
|
||||
long int ret = pSourceTexture->QueryInterface(IID_IDirect3D9, (void**)&cpy);
|
||||
switch (ret) {
|
||||
switch (pSourceTexture->QueryInterface(IID_IDirect3D9, (void**)&cpy)) {
|
||||
case 0x01000000L: {
|
||||
auto pDest = static_cast<uMod_IDirect3DTexture9*>(pDestinationTexture);
|
||||
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;
|
||||
uMod_IDirect3DTexture9* cpy2 = pSource->CrossRef_D3Dtex;
|
||||
UnswitchTextures(pSource);
|
||||
SwitchTextures(cpy, pDest);
|
||||
SwitchTextures(cpy2, pDest);
|
||||
}
|
||||
}
|
||||
if (pDest->CrossRef_D3Dtex != nullptr) {
|
||||
@@ -535,15 +381,15 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
|
||||
break;
|
||||
}
|
||||
case 0x01000001L: {
|
||||
auto pDest = static_cast<uMod_IDirect3DVolumeTexture9*>(pDestinationTexture);
|
||||
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;
|
||||
uMod_IDirect3DVolumeTexture9* cpy2 = pSourceVolume->CrossRef_D3Dtex;
|
||||
UnswitchTextures(pSourceVolume);
|
||||
SwitchTextures(cpy, pDest);
|
||||
SwitchTextures(cpy2, pDest);
|
||||
}
|
||||
}
|
||||
if (pDest->CrossRef_D3Dtex != nullptr) {
|
||||
@@ -561,9 +407,9 @@ HRESULT uMod_IDirect3DDevice9::UpdateTexture(IDirect3DBaseTexture9* pSourceTextu
|
||||
pDest->Hash = pSourceCube->Hash; // take over the hash
|
||||
UnswitchTextures(pDest);
|
||||
if (pSourceCube->CrossRef_D3Dtex != nullptr) {
|
||||
uMod_IDirect3DCubeTexture9* cpy = pSourceCube->CrossRef_D3Dtex;
|
||||
uMod_IDirect3DCubeTexture9* cpy2 = pSourceCube->CrossRef_D3Dtex;
|
||||
UnswitchTextures(pSourceCube);
|
||||
SwitchTextures(cpy, pDest);
|
||||
SwitchTextures(cpy2, pDest);
|
||||
}
|
||||
}
|
||||
if (pDest->CrossRef_D3Dtex != nullptr) {
|
||||
@@ -637,215 +483,25 @@ HRESULT uMod_IDirect3DDevice9::GetDepthStencilSurface(IDirect3DSurface9** ppZSte
|
||||
|
||||
HRESULT uMod_IDirect3DDevice9::BeginScene()
|
||||
{
|
||||
//if ( NormalRendering )
|
||||
if (LastCreatedTexture != nullptr) // add the last created texture
|
||||
{
|
||||
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
|
||||
|
||||
if (uMod_Client->BoolSaveSingleTexture) {
|
||||
if (CreateSingleTexture() == 0) {
|
||||
if (uMod_Client->KeyBack > 0 && (GetAsyncKeyState(uMod_Client->KeyBack) & 1)) //ask for the status of the back key
|
||||
{
|
||||
UnswitchTextures(SingleTexture); // can be called, even if texture is not switched
|
||||
UnswitchTextures(SingleVolumeTexture); // can be called, even if texture is not switched
|
||||
UnswitchTextures(SingleCubeTexture); // can be called, even if texture is not switched
|
||||
|
||||
if (CounterSaveSingleTexture < -10) {
|
||||
CounterSaveSingleTexture = 0;
|
||||
SingleTextureMod = 0;
|
||||
} //first initialization of the counter
|
||||
else if (--CounterSaveSingleTexture < 0) {
|
||||
if (--SingleTextureMod < 0) {
|
||||
SingleTextureMod = 2;
|
||||
}
|
||||
switch (SingleTextureMod) {
|
||||
case 0:
|
||||
CounterSaveSingleTexture = uMod_Client->OriginalTextures.GetNumber() - 1;
|
||||
break;
|
||||
case 1:
|
||||
CounterSaveSingleTexture = uMod_Client->OriginalVolumeTextures.GetNumber() - 1;
|
||||
break;
|
||||
case 2:
|
||||
CounterSaveSingleTexture = uMod_Client->OriginalCubeTextures.GetNumber() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (CounterSaveSingleTexture >= 0) {
|
||||
switch (SingleTextureMod) {
|
||||
case 0:
|
||||
SwitchTextures(SingleTexture, uMod_Client->OriginalTextures[CounterSaveSingleTexture]);
|
||||
SingleTexture->Hash = uMod_Client->OriginalTextures[CounterSaveSingleTexture]->Hash; //set the hash for the display
|
||||
break;
|
||||
case 1:
|
||||
SwitchTextures(SingleVolumeTexture, uMod_Client->OriginalVolumeTextures[CounterSaveSingleTexture]);
|
||||
SingleVolumeTexture->Hash = uMod_Client->OriginalVolumeTextures[CounterSaveSingleTexture]->Hash; //set the hash for the display
|
||||
break;
|
||||
case 2:
|
||||
SwitchTextures(SingleCubeTexture, uMod_Client->OriginalCubeTextures[CounterSaveSingleTexture]);
|
||||
SingleCubeTexture->Hash = uMod_Client->OriginalCubeTextures[CounterSaveSingleTexture]->Hash; //set the hash for the display
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uMod_Client->KeySave > 0 && (GetAsyncKeyState(uMod_Client->KeySave) & 1)) //ask for the status of the save key
|
||||
{
|
||||
switch (SingleTextureMod) {
|
||||
case 0:
|
||||
uMod_Client->SaveTexture(SingleTexture); //after switching the SingleTexture holds the pointer to the original texture object
|
||||
break;
|
||||
case 1:
|
||||
uMod_Client->SaveTexture(SingleVolumeTexture); //after switching the SingleTexture holds the pointer to the original texture object
|
||||
break;
|
||||
case 2:
|
||||
uMod_Client->SaveTexture(SingleCubeTexture); //after switching the SingleTexture holds the pointer to the original texture object
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uMod_Client->KeyNext > 0 && (GetAsyncKeyState(uMod_Client->KeyNext) & 1)) //ask for the status of the next key
|
||||
{
|
||||
UnswitchTextures(SingleTexture); // can be called, even if texture is not switched
|
||||
UnswitchTextures(SingleVolumeTexture); // can be called, even if texture is not switched
|
||||
UnswitchTextures(SingleCubeTexture); // can be called, even if texture is not switched
|
||||
|
||||
if (CounterSaveSingleTexture < -10) {
|
||||
CounterSaveSingleTexture = 0;
|
||||
SingleTextureMod = 0;
|
||||
} //first initialization of the counter
|
||||
else {
|
||||
int num = 0;
|
||||
switch (SingleTextureMod) {
|
||||
case 0:
|
||||
num = uMod_Client->OriginalTextures.GetNumber();
|
||||
break;
|
||||
case 1:
|
||||
num = uMod_Client->OriginalVolumeTextures.GetNumber();
|
||||
break;
|
||||
case 2:
|
||||
num = uMod_Client->OriginalCubeTextures.GetNumber();
|
||||
break;
|
||||
}
|
||||
if (++CounterSaveSingleTexture >= num) {
|
||||
if (++SingleTextureMod > 2) {
|
||||
SingleTextureMod = 0;
|
||||
}
|
||||
switch (SingleTextureMod) {
|
||||
case 0:
|
||||
CounterSaveSingleTexture = uMod_Client->OriginalTextures.GetNumber() > 0 ? 0 : -1;
|
||||
break;
|
||||
case 1:
|
||||
CounterSaveSingleTexture = uMod_Client->OriginalVolumeTextures.GetNumber() > 0 ? 0 : -1;
|
||||
break;
|
||||
case 2:
|
||||
CounterSaveSingleTexture = uMod_Client->OriginalCubeTextures.GetNumber() > 0 ? 0 : -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CounterSaveSingleTexture >= 0) {
|
||||
switch (SingleTextureMod) {
|
||||
case 0:
|
||||
SwitchTextures(SingleTexture, uMod_Client->OriginalTextures[CounterSaveSingleTexture]);
|
||||
SingleTexture->Hash = uMod_Client->OriginalTextures[CounterSaveSingleTexture]->Hash; //set the hash for the display
|
||||
break;
|
||||
case 1:
|
||||
SwitchTextures(SingleVolumeTexture, uMod_Client->OriginalVolumeTextures[CounterSaveSingleTexture]);
|
||||
SingleVolumeTexture->Hash = uMod_Client->OriginalVolumeTextures[CounterSaveSingleTexture]->Hash; //set the hash for the display
|
||||
break;
|
||||
case 2:
|
||||
SwitchTextures(SingleCubeTexture, uMod_Client->OriginalCubeTextures[CounterSaveSingleTexture]);
|
||||
SingleCubeTexture->Hash = uMod_Client->OriginalCubeTextures[CounterSaveSingleTexture]->Hash; //set the hash for the display
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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()
|
||||
{
|
||||
if (NormalRendering && uMod_Client->BoolSaveSingleTexture && SingleTexture != nullptr && SingleVolumeTexture != nullptr && SingleCubeTexture != nullptr) {
|
||||
if (OSD_Font == nullptr) // create the font
|
||||
{
|
||||
if (D3D_OK != D3DXCreateFontA(m_pIDirect3DDevice9, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &OSD_Font)) {
|
||||
OSD_Font = nullptr;
|
||||
return m_pIDirect3DDevice9->EndScene();
|
||||
}
|
||||
}
|
||||
|
||||
char buffer[100];
|
||||
buffer[0] = 0;
|
||||
switch (SingleTextureMod) {
|
||||
case 0: {
|
||||
if (SingleTexture->CrossRef_D3Dtex != nullptr) {
|
||||
sprintf_s(buffer, 100, "normal texture: %4d (1..%d): %#lX", CounterSaveSingleTexture + 1, uMod_Client->OriginalTextures.GetNumber(), SingleTexture->Hash);
|
||||
}
|
||||
else {
|
||||
if (uMod_Client->OriginalTextures.GetNumber() > 0) {
|
||||
sprintf_s(buffer, 100, "normal texture: nothing selected (1..%d)", uMod_Client->OriginalTextures.GetNumber());
|
||||
}
|
||||
else {
|
||||
sprintf_s(buffer, 100, "normal texture: nothing loaded");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (SingleVolumeTexture->CrossRef_D3Dtex != nullptr) {
|
||||
sprintf_s(buffer, 100, "volume texture: %4d (1..%d): %#lX", CounterSaveSingleTexture + 1, uMod_Client->OriginalVolumeTextures.GetNumber(), SingleVolumeTexture->Hash);
|
||||
}
|
||||
else {
|
||||
if (uMod_Client->OriginalVolumeTextures.GetNumber() > 0) {
|
||||
sprintf_s(buffer, 100, "volume texture: nothing selected (1..%d)", uMod_Client->OriginalVolumeTextures.GetNumber());
|
||||
}
|
||||
else {
|
||||
sprintf_s(buffer, 100, "volume texture: nothing loaded");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
if (SingleCubeTexture->CrossRef_D3Dtex != nullptr) {
|
||||
sprintf_s(buffer, 100, "cube texture: %4d (1..%d): %#lX", CounterSaveSingleTexture + 1, uMod_Client->OriginalCubeTextures.GetNumber(), SingleCubeTexture->Hash);
|
||||
}
|
||||
else {
|
||||
if (uMod_Client->OriginalCubeTextures.GetNumber() > 0) {
|
||||
sprintf_s(buffer, 100, "cube texture: nothing selected (1..%d)", uMod_Client->OriginalCubeTextures.GetNumber());
|
||||
}
|
||||
else {
|
||||
sprintf_s(buffer, 100, "cube texture: nothing loaded");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
D3DVIEWPORT9 viewport;
|
||||
GetViewport(&viewport);
|
||||
RECT rct;
|
||||
rct.left = viewport.X + 10;
|
||||
rct.right = 0; //size of box is calculated automatically (DT_NOCLIP)
|
||||
rct.top = viewport.Y + 10;
|
||||
rct.bottom = 0; //size of box is calculated automatically (DT_NOCLIP)
|
||||
OSD_Font->DrawTextA(nullptr, buffer, -1, &rct, DT_NOCLIP, uMod_Client->FontColour);
|
||||
}
|
||||
return m_pIDirect3DDevice9->EndScene();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "uMod_Main.h"
|
||||
#include "Main.h"
|
||||
|
||||
#define uMod_IDirect3DDevice9 uMod_IDirect3DDevice9Ex
|
||||
#define IDirect3DDevice9 IDirect3DDevice9Ex
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#include "uMod_Main.h"
|
||||
#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)
|
||||
@@ -44,7 +48,7 @@ ULONG APIENTRY uMod_IDirect3DTexture9::AddRef()
|
||||
//this function yields for the non switched texture object
|
||||
ULONG APIENTRY uMod_IDirect3DTexture9::Release()
|
||||
{
|
||||
Message("uMod_IDirect3DTexture9::Release(): %lu\n", this);
|
||||
Message("uMod_IDirect3DTexture9::Release(): %p\n", this);
|
||||
|
||||
void* cpy;
|
||||
const long ret = m_D3Ddev->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
@@ -62,16 +66,7 @@ ULONG APIENTRY uMod_IDirect3DTexture9::Release()
|
||||
if (count == 0) //if texture is released we switch the textures back
|
||||
{
|
||||
UnswitchTextures(this);
|
||||
if (ret == 0x01000000L) {
|
||||
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetSingleTexture() != fake_texture) {
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetSingleTexture() != fake_texture) {
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -100,10 +95,10 @@ ULONG APIENTRY uMod_IDirect3DTexture9::Release()
|
||||
}
|
||||
}
|
||||
|
||||
delete(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
Message("uMod_IDirect3DTexture9::Release() end: %lu\n", this);
|
||||
Message("uMod_IDirect3DTexture9::Release() end: %p\n", this);
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -209,7 +204,7 @@ HRESULT APIENTRY uMod_IDirect3DTexture9::GetSurfaceLevel(UINT Level, IDirect3DSu
|
||||
}
|
||||
|
||||
//this function yields for the non switched texture object
|
||||
HRESULT APIENTRY uMod_IDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect,CONST RECT* pRect, DWORD Flags)
|
||||
HRESULT APIENTRY uMod_IDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
|
||||
{
|
||||
if (CrossRef_D3Dtex != nullptr) {
|
||||
return CrossRef_D3Dtex->m_D3Dtex->LockRect(Level, pLockedRect, pRect, Flags);
|
||||
@@ -236,12 +231,9 @@ HRESULT APIENTRY uMod_IDirect3DTexture9::AddDirtyRect(CONST RECT* pDirtyRect)
|
||||
}
|
||||
|
||||
|
||||
int uMod_IDirect3DTexture9::GetHash(MyTypeHash& hash)
|
||||
HashTuple uMod_IDirect3DTexture9::GetHash() const
|
||||
{
|
||||
hash = 0u;
|
||||
if (FAKE) {
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
}
|
||||
ASSERT(!FAKE);
|
||||
IDirect3DTexture9* pTexture = m_D3Dtex;
|
||||
if (CrossRef_D3Dtex != nullptr) {
|
||||
pTexture = CrossRef_D3Dtex->m_D3Dtex;
|
||||
@@ -255,8 +247,8 @@ int uMod_IDirect3DTexture9::GetHash(MyTypeHash& hash)
|
||||
|
||||
if (pTexture->GetLevelDesc(0, &desc) != D3D_OK) //get the format and the size of the texture
|
||||
{
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetLevelDesc \n");
|
||||
return RETURN_GetLevelDesc_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetLevelDesc \n");
|
||||
return {};
|
||||
}
|
||||
|
||||
Message("uMod_IDirect3DTexture9::GetHash() (%d %d) %d\n", desc.Width, desc.Height, desc.Format);
|
||||
@@ -268,21 +260,21 @@ int uMod_IDirect3DTexture9::GetHash(MyTypeHash& hash)
|
||||
|
||||
IDirect3DSurface9* pSurfaceLevel_orig = nullptr;
|
||||
if (pTexture->GetSurfaceLevel(0, &pSurfaceLevel_orig) != D3D_OK) {
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel 1 (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel 1 (D3DPOOL_DEFAULT)\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) {
|
||||
//Message("uMod_IDirect3DTexture9::GetHash() MultiSampleType\n");
|
||||
if (D3D_OK != m_D3Ddev->CreateRenderTarget(desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pResolvedSurface, nullptr)) {
|
||||
pSurfaceLevel_orig->Release();
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: CreateRenderTarget (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: CreateRenderTarget (D3DPOOL_DEFAULT)\n");
|
||||
return {};
|
||||
}
|
||||
if (D3D_OK != m_D3Ddev->StretchRect(pSurfaceLevel_orig, nullptr, pResolvedSurface, nullptr, D3DTEXF_NONE)) {
|
||||
pSurfaceLevel_orig->Release();
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: StretchRect (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: StretchRect (D3DPOOL_DEFAULT)\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
pSurfaceLevel_orig = pResolvedSurface;
|
||||
@@ -293,8 +285,8 @@ int uMod_IDirect3DTexture9::GetHash(MyTypeHash& hash)
|
||||
if (pResolvedSurface != nullptr) {
|
||||
pResolvedSurface->Release();
|
||||
}
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (D3D_OK != m_D3Ddev->GetRenderTargetData(pSurfaceLevel_orig, pOffscreenSurface)) {
|
||||
@@ -303,8 +295,8 @@ int uMod_IDirect3DTexture9::GetHash(MyTypeHash& hash)
|
||||
pResolvedSurface->Release();
|
||||
}
|
||||
pOffscreenSurface->Release();
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
|
||||
return {};
|
||||
}
|
||||
pSurfaceLevel_orig->Release();
|
||||
|
||||
@@ -313,27 +305,28 @@ int uMod_IDirect3DTexture9::GetHash(MyTypeHash& hash)
|
||||
pResolvedSurface->Release();
|
||||
}
|
||||
pOffscreenSurface->Release();
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else if (pTexture->LockRect(0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 1\n");
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 1\n");
|
||||
if (pTexture->GetSurfaceLevel(0, &pResolvedSurface) != D3D_OK) {
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: GetSurfaceLevel\n");
|
||||
return {};
|
||||
}
|
||||
if (pResolvedSurface->LockRect(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
|
||||
pResolvedSurface->Release();
|
||||
Message("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 2\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DTexture9::GetHash() Failed: LockRect 2\n");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const int size = (GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8;
|
||||
|
||||
hash = GetCRC32(static_cast<char*>(d3dlr.pBits), size); //calculate the crc32 of the texture
|
||||
const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height) / 8;
|
||||
const auto crc32 = TextureFunction::get_crc32(static_cast<char*>(d3dlr.pBits), size);
|
||||
const auto crc64 = HashCheck::Use64BitCrc() ? TextureFunction::get_crc64(static_cast<char*>(d3dlr.pBits), size) : 0;
|
||||
|
||||
// Only release surfaces after we're finished with d3dlr
|
||||
if (pOffscreenSurface != nullptr) {
|
||||
pOffscreenSurface->UnlockRect();
|
||||
pOffscreenSurface->Release();
|
||||
@@ -349,6 +342,7 @@ int uMod_IDirect3DTexture9::GetHash(MyTypeHash& hash)
|
||||
pTexture->UnlockRect(0);
|
||||
}
|
||||
|
||||
Message("uMod_IDirect3DTexture9::GetHash() %#lX (%d %d) %d = %d\n", hash, desc.Width, desc.Height, desc.Format, size);
|
||||
return RETURN_OK;
|
||||
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};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#include "uMod_Main.h"
|
||||
#include "Main.h"
|
||||
|
||||
import ModfileLoader;
|
||||
import TextureClient;
|
||||
import TextureFunction;
|
||||
|
||||
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::QueryInterface(REFIID riid, void** ppvObj)
|
||||
{
|
||||
@@ -43,7 +47,7 @@ ULONG APIENTRY uMod_IDirect3DVolumeTexture9::AddRef()
|
||||
//this function yields for the non switched texture object
|
||||
ULONG APIENTRY uMod_IDirect3DVolumeTexture9::Release()
|
||||
{
|
||||
Message("uMod_IDirect3DVolumeTexture9::Release(): %lu\n", this);
|
||||
Message("uMod_IDirect3DVolumeTexture9::Release(): %p\n", this);
|
||||
|
||||
void* cpy;
|
||||
const long ret = m_D3Ddev->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
@@ -61,16 +65,7 @@ ULONG APIENTRY uMod_IDirect3DVolumeTexture9::Release()
|
||||
if (count == 0) //if texture is released we switch the textures back
|
||||
{
|
||||
UnswitchTextures(this);
|
||||
if (ret == 0x01000000L) {
|
||||
if (static_cast<uMod_IDirect3DDevice9*>(m_D3Ddev)->GetSingleVolumeTexture() != fake_texture) {
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (static_cast<uMod_IDirect3DDevice9Ex*>(m_D3Ddev)->GetSingleVolumeTexture() != fake_texture) {
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
fake_texture->Release(); // we release the fake texture
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -99,7 +94,7 @@ ULONG APIENTRY uMod_IDirect3DVolumeTexture9::Release()
|
||||
}
|
||||
}
|
||||
|
||||
delete(this);
|
||||
delete this;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -187,8 +182,6 @@ void APIENTRY uMod_IDirect3DVolumeTexture9::GenerateMipSubLevels()
|
||||
m_D3Dtex->GenerateMipSubLevels();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//this function yields for the non switched texture object
|
||||
HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::AddDirtyBox(CONST D3DBOX* pDirtyBox)
|
||||
{
|
||||
@@ -234,145 +227,45 @@ HRESULT APIENTRY uMod_IDirect3DVolumeTexture9::UnlockBox(UINT Level)
|
||||
return m_D3Dtex->UnlockBox(Level);
|
||||
}
|
||||
|
||||
|
||||
int uMod_IDirect3DVolumeTexture9::GetHash(MyTypeHash& hash)
|
||||
HashTuple uMod_IDirect3DVolumeTexture9::GetHash() const
|
||||
{
|
||||
hash = 0u;
|
||||
if (FAKE) {
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
return {};
|
||||
}
|
||||
IDirect3DVolumeTexture9* pTexture = m_D3Dtex;
|
||||
if (CrossRef_D3Dtex != nullptr) {
|
||||
pTexture = CrossRef_D3Dtex->m_D3Dtex;
|
||||
}
|
||||
|
||||
//IDirect3DVolume9 *pOffscreenSurface = NULL;
|
||||
//IDirect3DVolumeTexture9 *pOffscreenTexture = NULL;
|
||||
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
|
||||
{
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetLevelDesc \n");
|
||||
return RETURN_GetLevelDesc_FAILED;
|
||||
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 (desc.Pool==D3DPOOL_DEFAULT) //get the raw data of the texture
|
||||
{
|
||||
//Message("uMod_IDirect3DVolumeTexture9::GetHash() (D3DPOOL_DEFAULT)\n");
|
||||
|
||||
IDirect3DSurface9 *pSurfaceLevel_orig = NULL;
|
||||
if (pTexture->GetSurfaceLevel( 0, &pSurfaceLevel_orig)!=D3D_OK)
|
||||
{
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetSurfaceLevel 1 (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
/*
|
||||
if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
|
||||
{
|
||||
//Message("uMod_IDirect3DVolumeTexture9::GetHash() MultiSampleType\n");
|
||||
if (D3D_OK!=m_D3Ddev->CreateRenderTarget( desc.Width, desc.Height, desc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pResolvedSurface, NULL ))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: CreateRenderTarget (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
if (D3D_OK!=m_D3Ddev->StretchRect( pSurfaceLevel_orig, NULL, pResolvedSurface, NULL, D3DTEXF_NONE ))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: StretchRect (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
|
||||
pSurfaceLevel_orig = pResolvedSurface;
|
||||
}
|
||||
*/
|
||||
//CreateTexture(8, 8, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, (IDirect3DVolumeTexture9**) &SingleTexture, NULL)
|
||||
/*
|
||||
if (D3D_OK!=m_D3Ddev->CreateTexture( desc.Width, desc.Height, 1, 0, desc.Format, D3DPOOL_SYSTEMMEM, &pOffscreenTexture, NULL))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: CreateTexture (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_TEXTURE_NOT_LOADED);
|
||||
}
|
||||
if (pOffscreenTexture->GetSurfaceLevel( 0, &pOffscreenSurface)!=D3D_OK)
|
||||
{
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetSurfaceLevel 2 (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
|
||||
if (D3D_OK!=m_D3Ddev->GetRenderTargetData( pSurfaceLevel_orig, pOffscreenSurface))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
pOffscreenSurface->Release();
|
||||
pOffscreenTexture->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
pSurfaceLevel_orig->Release();
|
||||
|
||||
if (pOffscreenSurface->LockRect( &d3dlr, NULL, D3DLOCK_READONLY)!=D3D_OK)
|
||||
{
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
pOffscreenSurface->Release();
|
||||
pOffscreenTexture->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (D3D_OK!=m_D3Ddev->CreateOffscreenPlainSurface( desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &pOffscreenSurface, NULL))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: CreateOffscreenPlainSurface (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_TEXTURE_NOT_LOADED);
|
||||
}
|
||||
|
||||
if (D3D_OK!=m_D3Ddev->GetRenderTargetData( pSurfaceLevel_orig, pOffscreenSurface))
|
||||
{
|
||||
pSurfaceLevel_orig->Release();
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
pOffscreenSurface->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetRenderTargetData (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
pSurfaceLevel_orig->Release();
|
||||
|
||||
if (pOffscreenSurface->LockRect( &d3dlr, NULL, D3DLOCK_READONLY)!=D3D_OK)
|
||||
{
|
||||
if (pResolvedSurface!=NULL) pResolvedSurface->Release();
|
||||
pOffscreenSurface->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect (D3DPOOL_DEFAULT)\n");
|
||||
return RETURN_LockRect_FAILED);
|
||||
}
|
||||
}
|
||||
else
|
||||
*/
|
||||
if (pTexture->LockBox(0, &d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 1\n");
|
||||
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 1\n");
|
||||
if (pTexture->GetVolumeLevel(0, &pResolvedSurface) != D3D_OK) {
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetSurfaceLevel\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: GetSurfaceLevel\n");
|
||||
return {};
|
||||
}
|
||||
if (pResolvedSurface->LockBox(&d3dlr, nullptr, D3DLOCK_READONLY) != D3D_OK) {
|
||||
pResolvedSurface->Release();
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 2\n");
|
||||
return RETURN_LockRect_FAILED;
|
||||
Warning("uMod_IDirect3DVolumeTexture9::GetHash() Failed: LockRect 2\n");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const int size = (GetBitsFromFormat(desc.Format) * desc.Width * desc.Height * desc.Depth) / 8;
|
||||
|
||||
hash = GetCRC32(static_cast<char*>(d3dlr.pBits), size); //calculate the crc32 of the texture
|
||||
|
||||
const int size = (TextureFunction::GetBitsFromFormat(desc.Format) * desc.Width * desc.Height * desc.Depth) / 8;
|
||||
const auto crc32 = TextureFunction::get_crc32(static_cast<char*>(d3dlr.pBits), size);
|
||||
const auto crc64 = HashCheck::Use64BitCrc() ? TextureFunction::get_crc64(static_cast<char*>(d3dlr.pBits), size) : 0;
|
||||
|
||||
// Only release surfaces after we're finished with d3dlr
|
||||
if (pResolvedSurface != nullptr) {
|
||||
pResolvedSurface->UnlockBox();
|
||||
pResolvedSurface->Release();
|
||||
@@ -381,6 +274,7 @@ int uMod_IDirect3DVolumeTexture9::GetHash(MyTypeHash& hash)
|
||||
pTexture->UnlockBox(0);
|
||||
}
|
||||
|
||||
Message("uMod_IDirect3DVolumeTexture9::GetHash() %#lX (%d %d) %d = %d\n", hash, desc.Width, desc.Height, desc.Format, size);
|
||||
return RETURN_OK;
|
||||
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};
|
||||
}
|
||||
|
||||
@@ -1,995 +0,0 @@
|
||||
#include "uMod_Main.h"
|
||||
|
||||
uMod_TextureClient::uMod_TextureClient(uMod_TextureServer* server, IDirect3DDevice9* device)
|
||||
{
|
||||
Message("uMod_TextureClient::uMod_TextureClient(): %lu\n", this);
|
||||
Server = server;
|
||||
D3D9Device = device;
|
||||
BoolSaveAllTextures = false;
|
||||
BoolSaveSingleTexture = false;
|
||||
KeyBack = 0;
|
||||
KeySave = 0;
|
||||
KeyNext = 0;
|
||||
SavePath[0] = 0;
|
||||
GameName[0] = 0;
|
||||
|
||||
NumberToMod = 0;
|
||||
FileToMod = nullptr;
|
||||
|
||||
if (Server != nullptr) {
|
||||
if (Server->AddClient(this, &FileToMod, &NumberToMod)) {
|
||||
Server = nullptr;
|
||||
NumberToMod = 0;
|
||||
FileToMod = nullptr;
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < NumberToMod; i++) {
|
||||
FileToMod[i].NumberOfTextures = 0;
|
||||
FileToMod[i].Textures = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
Mutex = CreateMutex(nullptr, false, nullptr);
|
||||
|
||||
Update = nullptr;
|
||||
NumberOfUpdate = -1;
|
||||
FontColour = D3DCOLOR_ARGB(255, 255, 0, 0);
|
||||
TextureColour = D3DCOLOR_ARGB(255, 0, 255, 0);
|
||||
}
|
||||
|
||||
uMod_TextureClient::~uMod_TextureClient()
|
||||
{
|
||||
Message("uMod_TextureClient::~uMod_TextureClient(): %lu\n", this);
|
||||
if (Server != nullptr) {
|
||||
Server->RemoveClient(this);
|
||||
}
|
||||
|
||||
if (Mutex != nullptr) {
|
||||
CloseHandle(Mutex);
|
||||
}
|
||||
|
||||
delete [] Update;
|
||||
|
||||
if (FileToMod != nullptr) {
|
||||
for (int i = 0; i < NumberToMod; i++) {
|
||||
|
||||
delete [] FileToMod[i].Textures;
|
||||
|
||||
}
|
||||
delete [] FileToMod;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uMod_TextureClient::AddTexture(uMod_IDirect3DTexture9* pTexture)
|
||||
{
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
|
||||
if (pTexture->FAKE) {
|
||||
return RETURN_OK; // this is a fake texture
|
||||
}
|
||||
|
||||
Message("uMod_TextureClient::AddTexture( %lu): %lu (thread: %lu)\n", pTexture, this, GetCurrentThreadId());
|
||||
|
||||
MyTypeHash hash;
|
||||
if (const int ret = pTexture->GetHash(hash)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pTexture->Hash = hash;
|
||||
|
||||
if (BoolSaveAllTextures) {
|
||||
SaveTexture(pTexture);
|
||||
}
|
||||
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
||||
OriginalTextures.Add(pTexture); // add the texture to the list of original texture
|
||||
|
||||
return LookUpToMod(pTexture); // check if this texture should be modded
|
||||
}
|
||||
|
||||
int uMod_TextureClient::AddTexture(uMod_IDirect3DVolumeTexture9* pTexture)
|
||||
{
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedVolumeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedVolumeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
|
||||
if (pTexture->FAKE) {
|
||||
return RETURN_OK; // this is a fake texture
|
||||
}
|
||||
|
||||
Message("uMod_TextureClient::AddTexture( Volume: %lu): %lu (thread: %lu)\n", pTexture, this, GetCurrentThreadId());
|
||||
|
||||
MyTypeHash hash;
|
||||
if (const int ret = pTexture->GetHash(hash)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pTexture->Hash = hash;
|
||||
|
||||
if (BoolSaveAllTextures) {
|
||||
SaveTexture(pTexture);
|
||||
}
|
||||
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
||||
OriginalVolumeTextures.Add(pTexture); // add the texture to the list of original texture
|
||||
|
||||
return LookUpToMod(pTexture); // check if this texture should be modded
|
||||
}
|
||||
|
||||
int uMod_TextureClient::AddTexture(uMod_IDirect3DCubeTexture9* pTexture)
|
||||
{
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedCubeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedCubeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
|
||||
if (pTexture->FAKE) {
|
||||
return RETURN_OK; // this is a fake texture
|
||||
}
|
||||
|
||||
Message("uMod_TextureClient::AddTexture( Cube: %lu): %lu (thread: %lu)\n", pTexture, this, GetCurrentThreadId());
|
||||
|
||||
MyTypeHash hash;
|
||||
if (const int ret = pTexture->GetHash(hash)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pTexture->Hash = hash;
|
||||
|
||||
if (BoolSaveAllTextures) {
|
||||
SaveTexture(pTexture);
|
||||
}
|
||||
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
||||
OriginalCubeTextures.Add(pTexture); // add the texture to the list of original texture
|
||||
|
||||
return LookUpToMod(pTexture); // check if this texture should be modded
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uMod_TextureClient::RemoveTexture(uMod_IDirect3DTexture9* pTexture) // is called from a texture, if it is finally released
|
||||
{
|
||||
Message("uMod_TextureClient::RemoveTexture( %lu, %#lX): %lu\n", pTexture, pTexture->Hash, this);
|
||||
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
if (pTexture->FAKE) {
|
||||
// we need to set the corresponding FileToMod[X].pTexture to NULL, to avoid a link to a non existing texture object
|
||||
const int ref = pTexture->Reference;
|
||||
if (ref >= 0 && ref < NumberToMod) {
|
||||
for (int i = 0; i < FileToMod[ref].NumberOfTextures; i++) {
|
||||
if (FileToMod[ref].Textures[i] == pTexture) {
|
||||
FileToMod[ref].NumberOfTextures--;
|
||||
for (int j = i; j < FileToMod[ref].NumberOfTextures; j++) {
|
||||
FileToMod[ref].Textures[j] = FileToMod[ref].Textures[j + 1];
|
||||
}
|
||||
FileToMod[ref].Textures[FileToMod[ref].NumberOfTextures] = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return OriginalTextures.Remove(pTexture); //remove this texture form the list
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::RemoveTexture(uMod_IDirect3DVolumeTexture9* pTexture) // is called from a texture, if it is finally released
|
||||
{
|
||||
Message("uMod_TextureClient::RemoveTexture( Volume %lu, %#lX): %lu\n", pTexture, pTexture->Hash, this);
|
||||
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
if (pTexture->FAKE) {
|
||||
// we need to set the corresponding FileToMod[X].pTexture to NULL, to avoid a link to a non existing texture object
|
||||
const int ref = pTexture->Reference;
|
||||
if (ref >= 0 && ref < NumberToMod) {
|
||||
for (int i = 0; i < FileToMod[ref].NumberOfTextures; i++) {
|
||||
if (FileToMod[ref].Textures[i] == pTexture) {
|
||||
FileToMod[ref].NumberOfTextures--;
|
||||
for (int j = i; j < FileToMod[ref].NumberOfTextures; j++) {
|
||||
FileToMod[ref].Textures[j] = FileToMod[ref].Textures[j + 1];
|
||||
}
|
||||
FileToMod[ref].Textures[FileToMod[ref].NumberOfTextures] = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return OriginalVolumeTextures.Remove(pTexture); //remove this texture form the list
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::RemoveTexture(uMod_IDirect3DCubeTexture9* pTexture) // is called from a texture, if it is finally released
|
||||
{
|
||||
Message("uMod_TextureClient::RemoveTexture( Cube %lu, %#lX): %lu\n", pTexture, pTexture->Hash, this);
|
||||
|
||||
if (gl_ErrorState & uMod_ERROR_FATAL) {
|
||||
return RETURN_FATAL_ERROR;
|
||||
}
|
||||
if (pTexture->FAKE) {
|
||||
// we need to set the corresponding FileToMod[X].pTexture to NULL, to avoid a link to a non existing texture object
|
||||
const int ref = pTexture->Reference;
|
||||
if (ref >= 0 && ref < NumberToMod) {
|
||||
for (int i = 0; i < FileToMod[ref].NumberOfTextures; i++) {
|
||||
if (FileToMod[ref].Textures[i] == pTexture) {
|
||||
FileToMod[ref].NumberOfTextures--;
|
||||
for (int j = i; j < FileToMod[ref].NumberOfTextures; j++) {
|
||||
FileToMod[ref].Textures[j] = FileToMod[ref].Textures[j + 1];
|
||||
}
|
||||
FileToMod[ref].Textures[FileToMod[ref].NumberOfTextures] = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return OriginalCubeTextures.Remove(pTexture); //remove this texture form the list
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
int uMod_TextureClient::SaveAllTextures(bool val)
|
||||
{
|
||||
Message("uMod_TextureClient::SaveAllTextures( %d): %lu\n", val, this);
|
||||
BoolSaveAllTextures = val;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::SaveSingleTexture(bool val)
|
||||
{
|
||||
Message("uMod_TextureClient::SaveSingleTexture( %d): %lu\n", val, this);
|
||||
if (BoolSaveSingleTexture && !val) //if BoolSaveSingleTexture is set to false and was previously true we switch the SingleTexture back
|
||||
{
|
||||
uMod_IDirect3DTexture9* pTexture;
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
pTexture = static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->GetSingleTexture(); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
pTexture = static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->GetSingleTexture(); //this texture must no be added twice
|
||||
}
|
||||
|
||||
if (pTexture != nullptr) {
|
||||
UnswitchTextures(pTexture);
|
||||
}
|
||||
}
|
||||
BoolSaveSingleTexture = val;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
int uMod_TextureClient::SetSaveDirectory(wchar_t* dir)
|
||||
{
|
||||
Message("uMod_TextureClient::SetSaveDirectory( %ls): %lu\n", dir, this);
|
||||
int i = 0;
|
||||
for (i = 0; i < MAX_PATH && (dir[i]); i++) {
|
||||
SavePath[i] = dir[i];
|
||||
}
|
||||
if (i == MAX_PATH) {
|
||||
SavePath[0] = 0;
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
}
|
||||
SavePath[i] = 0;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::SetGameName(wchar_t* name)
|
||||
{
|
||||
Message("uMod_TextureClient::SetGameName( %ls): %lu\n", name, this);
|
||||
int i = 0;
|
||||
for (i = 0; i < MAX_PATH && (name[i]); i++) {
|
||||
GameName[i] = name[i];
|
||||
}
|
||||
if (i == MAX_PATH) {
|
||||
GameName[0] = 0;
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
}
|
||||
GameName[i] = 0;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uMod_TextureClient::SaveTexture(uMod_IDirect3DTexture9* pTexture)
|
||||
{
|
||||
if (pTexture == nullptr) {
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
}
|
||||
if (SavePath[0] == 0) {
|
||||
Message("uMod_TextureClient::SaveTexture( %#lX, %lu): %lu, SavePath not set\n", pTexture->Hash, pTexture->m_D3Dtex, this);
|
||||
return RETURN_TEXTURE_NOT_SAVED;
|
||||
}
|
||||
|
||||
wchar_t file[MAX_PATH];
|
||||
if (GameName[0]) {
|
||||
swprintf_s(file, MAX_PATH, L"%ls\\%ls_T_%#lX.dds", SavePath, GameName, pTexture->Hash);
|
||||
}
|
||||
else {
|
||||
swprintf_s(file, MAX_PATH, L"%ls\\T_%#lX.dds", SavePath, pTexture->Hash);
|
||||
}
|
||||
Message("uMod_TextureClient::SaveTexture( %ls): %lu\n", file, this);
|
||||
|
||||
if (D3D_OK != D3DXSaveTextureToFileW(file, D3DXIFF_DDS, pTexture->m_D3Dtex, nullptr)) {
|
||||
return RETURN_TEXTURE_NOT_SAVED;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::SaveTexture(uMod_IDirect3DVolumeTexture9* pTexture)
|
||||
{
|
||||
if (pTexture == nullptr) {
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
}
|
||||
if (SavePath[0] == 0) {
|
||||
Message("uMod_TextureClient::SaveTexture( %#lX, %lu): %lu, SavePath not set\n", pTexture->Hash, pTexture->m_D3Dtex, this);
|
||||
return RETURN_TEXTURE_NOT_SAVED;
|
||||
}
|
||||
|
||||
wchar_t file[MAX_PATH];
|
||||
if (GameName[0]) {
|
||||
swprintf_s(file, MAX_PATH, L"%ls\\%ls_V_%#lX.dds", SavePath, GameName, pTexture->Hash);
|
||||
}
|
||||
else {
|
||||
swprintf_s(file, MAX_PATH, L"%ls\\V_%#lX.dds", SavePath, pTexture->Hash);
|
||||
}
|
||||
Message("uMod_TextureClient::SaveTexture( %ls): %lu\n", file, this);
|
||||
|
||||
if (D3D_OK != D3DXSaveTextureToFileW(file, D3DXIFF_DDS, pTexture->m_D3Dtex, nullptr)) {
|
||||
return RETURN_TEXTURE_NOT_SAVED;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::SaveTexture(uMod_IDirect3DCubeTexture9* pTexture)
|
||||
{
|
||||
if (pTexture == nullptr) {
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
}
|
||||
if (SavePath[0] == 0) {
|
||||
Message("uMod_TextureClient::SaveTexture( %#lX, %lu): %lu, SavePath not set\n", pTexture->Hash, pTexture->m_D3Dtex, this);
|
||||
return RETURN_TEXTURE_NOT_SAVED;
|
||||
}
|
||||
|
||||
wchar_t file[MAX_PATH];
|
||||
if (GameName[0]) {
|
||||
swprintf_s(file, MAX_PATH, L"%ls\\%ls_C_%#lX.dds", SavePath, GameName, pTexture->Hash);
|
||||
}
|
||||
else {
|
||||
swprintf_s(file, MAX_PATH, L"%ls\\C_%#lX.dds", SavePath, pTexture->Hash);
|
||||
}
|
||||
Message("uMod_TextureClient::SaveTexture( %ls): %lu\n", file, this);
|
||||
|
||||
if (D3D_OK != D3DXSaveTextureToFileW(file, D3DXIFF_DDS, pTexture->m_D3Dtex, nullptr)) {
|
||||
return RETURN_TEXTURE_NOT_SAVED;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int uMod_TextureClient::AddUpdate(TextureFileStruct* update, int number) //client must delete the update array
|
||||
{
|
||||
Message("AddUpdate( %lu, %d): %lu\n", update, number, this);
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_TEXTURE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
delete [] Update;
|
||||
|
||||
Update = update;
|
||||
NumberOfUpdate = number;
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uMod_TextureClient::MergeUpdate()
|
||||
{
|
||||
if (NumberOfUpdate < 0) { return RETURN_OK; }
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_TEXTURE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Message("MergeUpdate(): %lu\n", this);
|
||||
|
||||
for (int i = 0; i < NumberOfUpdate; i++) {
|
||||
Update[i].NumberOfTextures = 0;
|
||||
Update[i].Textures = nullptr;
|
||||
} // this is already done, but safety comes first ^^
|
||||
|
||||
int pos_old = 0;
|
||||
int pos_new = 0;
|
||||
int* to_lookup = nullptr;
|
||||
if (NumberOfUpdate > 0) {
|
||||
to_lookup = new int[NumberOfUpdate];
|
||||
}
|
||||
int num_to_lookup = 0;
|
||||
|
||||
/*
|
||||
* FileToMod contains the old files (textures) which should replace the target textures (if they are loaded by the game)
|
||||
* Update contains the new files (textures) which should replace the target textures (if they are loaded by the game)
|
||||
*
|
||||
* Both arrays (FileToMod and Update) are sorted according to their hash values.
|
||||
*
|
||||
* First we go through both arrays linearly and
|
||||
* 1) take over the old entry if the hash is the same,
|
||||
* 2) release old fake texture (if target texture exist and is not in the Update)
|
||||
* 3) or mark newly added fake texture (if they are not in FileToMod)
|
||||
*/
|
||||
|
||||
while (pos_old < NumberToMod && pos_new < NumberOfUpdate) {
|
||||
if (FileToMod[pos_old].Hash > Update[pos_new].Hash) // this fake texture is new
|
||||
{
|
||||
to_lookup[num_to_lookup++] = pos_new++; // keep this fake texture in mind, we must search later for it through all original textures
|
||||
// we increase only the new counter by one
|
||||
}
|
||||
else if (FileToMod[pos_old].Hash < Update[pos_new].Hash) // this fake texture is not in the update
|
||||
{
|
||||
for (int i = FileToMod[pos_old].NumberOfTextures - 1; i >= 0; i--) {
|
||||
FileToMod[pos_old].Textures[i]->Release(); // we release the fake textures
|
||||
}
|
||||
|
||||
delete [] FileToMod[pos_old].Textures; // we delete the memory
|
||||
|
||||
FileToMod[pos_old].NumberOfTextures = 0;
|
||||
FileToMod[pos_old].Textures = nullptr;
|
||||
|
||||
pos_old++; // we increase only the old counter by one
|
||||
}
|
||||
else // the hash value is the same, thus this texture is in the array FileToMod as well as in the array Update
|
||||
{
|
||||
if (Update[pos_new].ForceReload) {
|
||||
if (FileToMod[pos_old].NumberOfTextures > 0) {
|
||||
Update[pos_new].Textures = new IDirect3DBaseTexture9*[FileToMod[pos_old].NumberOfTextures];
|
||||
}
|
||||
for (int i = 0; i < FileToMod[pos_old].NumberOfTextures; i++) {
|
||||
IDirect3DBaseTexture9* base_texture;
|
||||
int ret = FileToMod[pos_old].Textures[i]->QueryInterface(IID_IDirect3D9, (void**)&base_texture);
|
||||
switch (ret) {
|
||||
case 0x01000000L: {
|
||||
auto pTexture = static_cast<uMod_IDirect3DTexture9*>(FileToMod[pos_old].Textures[i]);//
|
||||
uMod_IDirect3DTexture9* pRefTexture = pTexture->CrossRef_D3Dtex;
|
||||
pTexture->Release();
|
||||
i--; //after the Release of the old fake texture FileToMod[pos_old].Textures[i] is overwritten by entries with index greater than i
|
||||
|
||||
uMod_IDirect3DTexture9* fake_Texture;
|
||||
if (int ret = LoadTexture(&(Update[pos_new]), &fake_Texture)) {
|
||||
return ret;
|
||||
}
|
||||
if (SwitchTextures(fake_Texture, pRefTexture)) {
|
||||
Message("MergeUpdate(): textures not switched %#lX\n", pRefTexture->Hash);
|
||||
fake_Texture->Release();
|
||||
}
|
||||
else {
|
||||
Update[pos_new].Textures[Update[pos_new].NumberOfTextures++] = fake_Texture;
|
||||
fake_Texture->Reference = pos_new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01000001L: {
|
||||
auto pTexture = static_cast<uMod_IDirect3DVolumeTexture9*>(FileToMod[pos_old].Textures[i]);//
|
||||
uMod_IDirect3DVolumeTexture9* pRefTexture = pTexture->CrossRef_D3Dtex;
|
||||
pTexture->Release();
|
||||
i--; //after the Release of the old fake texture FileToMod[pos_old].Textures[i] is overwritten by entries with index greater than i
|
||||
|
||||
uMod_IDirect3DVolumeTexture9* fake_Texture;
|
||||
if (int ret = LoadTexture(&(Update[pos_new]), &fake_Texture)) {
|
||||
return ret;
|
||||
}
|
||||
if (SwitchTextures(fake_Texture, pRefTexture)) {
|
||||
Message("MergeUpdate(): textures not switched %#lX\n", pRefTexture->Hash);
|
||||
fake_Texture->Release();
|
||||
}
|
||||
else {
|
||||
Update[pos_new].Textures[Update[pos_new].NumberOfTextures++] = fake_Texture;
|
||||
fake_Texture->Reference = pos_new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01000002L: {
|
||||
auto pTexture = static_cast<uMod_IDirect3DCubeTexture9*>(FileToMod[pos_old].Textures[i]);//
|
||||
uMod_IDirect3DCubeTexture9* pRefTexture = pTexture->CrossRef_D3Dtex;
|
||||
pTexture->Release();
|
||||
i--; //after the Release of the old fake texture FileToMod[pos_old].Textures[i] is overwritten by entries with index greater than i
|
||||
|
||||
uMod_IDirect3DCubeTexture9* fake_Texture;
|
||||
if (int ret = LoadTexture(&Update[pos_new], &fake_Texture)) {
|
||||
return ret;
|
||||
}
|
||||
if (SwitchTextures(fake_Texture, pRefTexture)) {
|
||||
Message("MergeUpdate(): textures not switched %#lX\n", pRefTexture->Hash);
|
||||
fake_Texture->Release();
|
||||
}
|
||||
else {
|
||||
Update[pos_new].Textures[Update[pos_new].NumberOfTextures++] = fake_Texture;
|
||||
fake_Texture->Reference = pos_new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break; // this is no fake texture and QueryInterface failed, because IDirect3DBaseTexture9 object cannot be a IDirect3D9 object ;)
|
||||
}
|
||||
}
|
||||
}
|
||||
else // the texture might be loaded or not
|
||||
{
|
||||
Update[pos_new].NumberOfTextures = FileToMod[pos_old].NumberOfTextures;
|
||||
Update[pos_new].Textures = FileToMod[pos_old].Textures;
|
||||
FileToMod[pos_old].NumberOfTextures = 0;
|
||||
FileToMod[pos_old].Textures = nullptr;
|
||||
}
|
||||
// we increase both counters by one
|
||||
pos_old++;
|
||||
pos_new++;
|
||||
}
|
||||
}
|
||||
|
||||
while (pos_old < NumberToMod) //this fake textures are not in the Update
|
||||
{
|
||||
for (int i = FileToMod[pos_old].NumberOfTextures - 1; i >= 0; i--) {
|
||||
FileToMod[pos_old].Textures[i]->Release(); // we release the fake textures
|
||||
}
|
||||
//for (int i=0; i<FileToMod[pos_old].NumberOfTextures; i++) FileToMod[pos_old].Textures[i]->Release(); // we release the fake textures
|
||||
|
||||
delete [] FileToMod[pos_old].Textures; // we delete the memory
|
||||
|
||||
FileToMod[pos_old].Textures = nullptr;
|
||||
pos_old++;
|
||||
}
|
||||
while (pos_new < NumberOfUpdate) //this fake textures are newly added
|
||||
{
|
||||
to_lookup[num_to_lookup++] = pos_new++; //keep this fake texture in mind, we must search later for it through all original textures
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* if (num_to_lookup>0) we need to look through all original textures
|
||||
* because there were newly added textures and we don't know
|
||||
* if the corresponding target textures are loaded by the game or not.
|
||||
*
|
||||
* Note: to_lookup[num_to_lookup++] = pos_new++; is in ascending order,
|
||||
* thus Update[to_lookup[pos]].Hash is also sorted ascending!
|
||||
*/
|
||||
/*
|
||||
uMod_IDirect3DTexture9 *single_texture = ((uMod_IDirect3DDevice9*)D3D9Device)->GetSingleTexture();
|
||||
if (num_to_lookup>0)
|
||||
{
|
||||
int num = OriginalTextures.GetNumber();
|
||||
for (int i=0; i<num; i++)
|
||||
if (OriginalTextures[i]->CrossRef_D3Dtex==NULL || OriginalTextures[i]->CrossRef_D3Dtex==single_texture)
|
||||
// We need look only for textures, that are not switched or switched with the single_texture.
|
||||
// The single_texture is a special texture, which you can toggle through all original texture, if save single texture is turned on.
|
||||
{
|
||||
MyTypeHash hash = OriginalTextures[i]->Hash;
|
||||
|
||||
if (hash<Update[to_lookup[0]].Hash || hash>Update[to_lookup[num_to_lookup-1]].Hash) continue;
|
||||
|
||||
int index = -1;
|
||||
int pos = num_to_lookup/2;
|
||||
int begin = 0;
|
||||
int end = num_to_lookup-1;
|
||||
|
||||
// We look in the middle of the interval and each step we halve the interval,
|
||||
// unless we find the texture or the size of the interval is less than 3.
|
||||
// Note: contradicting to normal C-code here the interval includes the index "begin" and "end"!
|
||||
while (begin+1<end) // as long as the interval is longer than two
|
||||
{
|
||||
if (hash > Update[to_lookup[pos]].Hash) // the new interval is the right half of the actual interval
|
||||
{
|
||||
begin = pos+1; // the new interval does not contain the index "pos"
|
||||
pos = (begin + end)/2; // set "pos" somewhere inside the new intervall
|
||||
}
|
||||
else if (hash < Update[to_lookup[pos]].Hash) // the new interval is the left half of the actual interval
|
||||
{
|
||||
end = pos-1; // the new interval does not contain the index "pos"
|
||||
pos = (begin + end)/2; // set "pos" somewhere inside the new intervall
|
||||
}
|
||||
else {index = to_lookup[pos]; break;} // we hit the correct hash
|
||||
}
|
||||
if (index<0) // if we did not find the hash, it might be in the last interval
|
||||
{
|
||||
for (int i=begin; i<=end; i++) if (Update[to_lookup[i]].Hash==hash) index = to_lookup[i];
|
||||
}
|
||||
|
||||
if (index>=0) // target texture is loaded by the game
|
||||
{
|
||||
if (OriginalTextures[i]->CrossRef_D3Dtex!=NULL) UnswitchTextures(OriginalTextures[i]); // this texture was switched with the single texture
|
||||
|
||||
uMod_IDirect3DTexture9 *fake_Texture;
|
||||
if (int ret = LoadTexture( & (Update[index]), &fake_Texture)) return ret;
|
||||
if (SwitchTextures( fake_Texture, OriginalTextures[i]))
|
||||
{
|
||||
Message("uMod_TextureClient::LookUpToMod(): textures not switched %#lX\n", FileToMod[index].Hash);
|
||||
fake_Texture->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
IDirect3DBaseTexture9 **temp = new IDirect3DBaseTexture9*[Update[index].NumberOfTextures+1];
|
||||
for (int j=0; j<Update[index].NumberOfTextures; j++) temp[j] = Update[index].Textures[j];
|
||||
|
||||
if (Update[index].Textures!=NULL) delete [] Update[index].Textures;
|
||||
Update[index].Textures = temp;
|
||||
|
||||
Update[index].Textures[Update[index].NumberOfTextures++] = fake_Texture;
|
||||
fake_Texture->Reference = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
//for (int i=0; i<NumberToMod; i++) if (FileToMod[i].Textures!=NULL) delete [] FileToMod[i].Textures;
|
||||
delete [] FileToMod;
|
||||
|
||||
|
||||
FileToMod = Update;
|
||||
NumberToMod = NumberOfUpdate;
|
||||
|
||||
NumberOfUpdate = -1;
|
||||
Update = nullptr;
|
||||
|
||||
|
||||
if (num_to_lookup > 0) {
|
||||
uMod_IDirect3DTexture9* single_texture;
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
single_texture = static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->GetSingleTexture(); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
single_texture = static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->GetSingleTexture(); //this texture must no be added twice
|
||||
}
|
||||
|
||||
int num = OriginalTextures.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (OriginalTextures[i]->CrossRef_D3Dtex == nullptr || OriginalTextures[i]->CrossRef_D3Dtex == single_texture) {
|
||||
UnswitchTextures(OriginalTextures[i]); //this we can do always, so we unswitch the single texture
|
||||
LookUpToMod(OriginalTextures[i], num_to_lookup, to_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
uMod_IDirect3DVolumeTexture9* single_volume_texture;
|
||||
if (ret == 0x01000000L) {
|
||||
single_volume_texture = static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->GetSingleVolumeTexture(); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
single_volume_texture = static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->GetSingleVolumeTexture(); //this texture must no be added twice
|
||||
}
|
||||
num = OriginalVolumeTextures.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (OriginalVolumeTextures[i]->CrossRef_D3Dtex == nullptr || OriginalVolumeTextures[i]->CrossRef_D3Dtex == single_volume_texture) {
|
||||
UnswitchTextures(OriginalVolumeTextures[i]); //this we can do always, so we unswitch the single texture
|
||||
LookUpToMod(OriginalVolumeTextures[i], num_to_lookup, to_lookup);
|
||||
}
|
||||
}
|
||||
|
||||
uMod_IDirect3DCubeTexture9* single_cube_texture;
|
||||
if (ret == 0x01000000L) {
|
||||
single_cube_texture = static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->GetSingleCubeTexture(); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
single_cube_texture = static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->GetSingleCubeTexture(); //this texture must no be added twice
|
||||
}
|
||||
num = OriginalCubeTextures.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (OriginalCubeTextures[i]->CrossRef_D3Dtex == nullptr || OriginalCubeTextures[i]->CrossRef_D3Dtex == single_cube_texture) {
|
||||
UnswitchTextures(OriginalCubeTextures[i]); //this we can do always, so we unswitch the single texture
|
||||
LookUpToMod(OriginalCubeTextures[i], num_to_lookup, to_lookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] to_lookup;
|
||||
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int uMod_TextureClient::LockMutex()
|
||||
{
|
||||
if ((gl_ErrorState & (uMod_ERROR_FATAL | uMod_ERROR_MUTEX))) {
|
||||
return RETURN_NO_MUTEX;
|
||||
}
|
||||
if (WAIT_OBJECT_0 != WaitForSingleObject(Mutex, 100)) {
|
||||
return RETURN_MUTEX_LOCK; //waiting 100ms, to wait infinite pass INFINITE
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::UnlockMutex()
|
||||
{
|
||||
if (ReleaseMutex(Mutex) == 0) {
|
||||
return RETURN_MUTEX_UNLOCK;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
int uMod_TextureClient::LookUpToMod(MyTypeHash hash, int num_index_list, int* index_list)
|
||||
{
|
||||
if (NumberToMod > 0) {
|
||||
if (index_list == nullptr || num_index_list == 0) {
|
||||
if (hash < FileToMod[0].Hash || hash > FileToMod[NumberToMod - 1].Hash) {
|
||||
return -1;
|
||||
}
|
||||
int pos = NumberToMod / 2;
|
||||
int begin = 0;
|
||||
int end = NumberToMod - 1;
|
||||
|
||||
// We look in the middle of the interval and each step we halve the interval,
|
||||
// unless we find the texture or the size of the interval is less than 3.
|
||||
// Note: contradicting to normal C-code here the interval includes the index "begin" and "end"!
|
||||
while (begin + 1 < end) // as long as the interval is longer than two
|
||||
{
|
||||
if (hash > FileToMod[pos].Hash) // the new interval is the right half of the actual interval
|
||||
{
|
||||
begin = pos + 1; // the new interval does not contain the index "pos"
|
||||
pos = (begin + end) / 2; // set "pos" somewhere inside the new interval
|
||||
}
|
||||
else if (hash < FileToMod[pos].Hash) // the new interval is the left half of the actual interval
|
||||
{
|
||||
end = pos - 1; // the new interval does not contain the index "pos"
|
||||
pos = (begin + end) / 2; // set "pos" somewhere inside the new interval
|
||||
}
|
||||
else {
|
||||
return pos;
|
||||
break;
|
||||
} // we hit the correct hash
|
||||
}
|
||||
for (pos = begin; pos <= end; pos++) {
|
||||
if (FileToMod[pos].Hash == hash) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hash < FileToMod[index_list[0]].Hash || hash > FileToMod[index_list[num_index_list - 1]].Hash) {
|
||||
return -1;
|
||||
}
|
||||
int pos = num_index_list / 2;
|
||||
int begin = 0;
|
||||
int end = num_index_list - 1;
|
||||
|
||||
// We look in the middle of the interval and each step we halve the interval,
|
||||
// unless we find the texture or the size of the interval is less than 3.
|
||||
// Note: contradicting to normal C-code here the interval includes the index "begin" and "end"!
|
||||
while (begin + 1 < end) // as long as the interval is longer than two
|
||||
{
|
||||
if (hash > FileToMod[index_list[pos]].Hash) // the new interval is the right half of the actual interval
|
||||
{
|
||||
begin = pos + 1; // the new interval does not contain the index "pos"
|
||||
pos = (begin + end) / 2; // set "pos" somewhere inside the new interval
|
||||
}
|
||||
else if (hash < FileToMod[index_list[pos]].Hash) // the new interval is the left half of the actual interval
|
||||
{
|
||||
end = pos - 1; // the new interval does not contain the index "pos"
|
||||
pos = (begin + end) / 2; // set "pos" somewhere inside the new interval
|
||||
}
|
||||
else {
|
||||
return index_list[pos];
|
||||
break;
|
||||
} // we hit the correct hash
|
||||
}
|
||||
for (pos = begin; pos <= end; pos++) {
|
||||
if (FileToMod[index_list[pos]].Hash == hash) {
|
||||
return index_list[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::LookUpToMod(uMod_IDirect3DTexture9* pTexture, int num_index_list, int* index_list) // should only be called for original textures
|
||||
{
|
||||
Message("uMod_TextureClient::LookUpToMod( %lu): hash: %#lX, %lu\n", pTexture, pTexture->Hash, this);
|
||||
if (pTexture->CrossRef_D3Dtex != nullptr) {
|
||||
return RETURN_OK; // bug, this texture is already switched
|
||||
}
|
||||
const int index = LookUpToMod(pTexture->Hash, num_index_list, index_list);
|
||||
if (index >= 0) {
|
||||
uMod_IDirect3DTexture9* fake_Texture;
|
||||
if (const int ret = LoadTexture(&(FileToMod[index]), &fake_Texture)) {
|
||||
return ret;
|
||||
}
|
||||
if (SwitchTextures(fake_Texture, pTexture)) {
|
||||
Message("uMod_TextureClient::LookUpToMod(): textures not switched %#lX\n", FileToMod[index].Hash);
|
||||
fake_Texture->Release();
|
||||
}
|
||||
else {
|
||||
const auto temp = new IDirect3DBaseTexture9*[FileToMod[index].NumberOfTextures + 1];
|
||||
for (int j = 0; j < FileToMod[index].NumberOfTextures; j++) {
|
||||
temp[j] = FileToMod[index].Textures[j];
|
||||
}
|
||||
|
||||
delete [] FileToMod[index].Textures;
|
||||
|
||||
FileToMod[index].Textures = temp;
|
||||
|
||||
FileToMod[index].Textures[FileToMod[index].NumberOfTextures++] = fake_Texture;
|
||||
fake_Texture->Reference = index;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::LookUpToMod(uMod_IDirect3DVolumeTexture9* pTexture, int num_index_list, int* index_list) // should only be called for original textures
|
||||
{
|
||||
Message("uMod_TextureClient::LookUpToMod( Volume %lu): hash: %#lX, %lu\n", pTexture, pTexture->Hash, this);
|
||||
if (pTexture->CrossRef_D3Dtex != nullptr) {
|
||||
return RETURN_OK; // bug, this texture is already switched
|
||||
}
|
||||
const int index = LookUpToMod(pTexture->Hash, num_index_list, index_list);
|
||||
if (index >= 0) {
|
||||
uMod_IDirect3DVolumeTexture9* fake_Texture;
|
||||
if (const int ret = LoadTexture(&(FileToMod[index]), &fake_Texture)) {
|
||||
return ret;
|
||||
}
|
||||
if (SwitchTextures(fake_Texture, pTexture)) {
|
||||
Message("uMod_TextureClient::LookUpToMod(): textures not switched %#lX\n", FileToMod[index].Hash);
|
||||
fake_Texture->Release();
|
||||
}
|
||||
else {
|
||||
const auto temp = new IDirect3DBaseTexture9*[FileToMod[index].NumberOfTextures + 1];
|
||||
for (int j = 0; j < FileToMod[index].NumberOfTextures; j++) {
|
||||
temp[j] = FileToMod[index].Textures[j];
|
||||
}
|
||||
|
||||
delete [] FileToMod[index].Textures;
|
||||
|
||||
FileToMod[index].Textures = temp;
|
||||
|
||||
FileToMod[index].Textures[FileToMod[index].NumberOfTextures++] = fake_Texture;
|
||||
fake_Texture->Reference = index;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::LookUpToMod(uMod_IDirect3DCubeTexture9* pTexture, int num_index_list, int* index_list) // should only be called for original textures
|
||||
{
|
||||
Message("uMod_TextureClient::LookUpToMod( Cube %lu): hash: %#lX, %lu\n", pTexture, pTexture->Hash, this);
|
||||
if (pTexture->CrossRef_D3Dtex != nullptr) {
|
||||
return RETURN_OK; // bug, this texture is already switched
|
||||
}
|
||||
const int index = LookUpToMod(pTexture->Hash, num_index_list, index_list);
|
||||
if (index >= 0) {
|
||||
uMod_IDirect3DCubeTexture9* fake_Texture;
|
||||
if (const int ret = LoadTexture(&(FileToMod[index]), &fake_Texture)) {
|
||||
return ret;
|
||||
}
|
||||
if (SwitchTextures(fake_Texture, pTexture)) {
|
||||
Message("uMod_TextureClient::LookUpToMod(): textures not switched %#lX\n", FileToMod[index].Hash);
|
||||
fake_Texture->Release();
|
||||
}
|
||||
else {
|
||||
const auto temp = new IDirect3DBaseTexture9*[FileToMod[index].NumberOfTextures + 1];
|
||||
for (int j = 0; j < FileToMod[index].NumberOfTextures; j++) {
|
||||
temp[j] = FileToMod[index].Textures[j];
|
||||
}
|
||||
|
||||
delete [] FileToMod[index].Textures;
|
||||
FileToMod[index].Textures = temp;
|
||||
|
||||
FileToMod[index].Textures[FileToMod[index].NumberOfTextures++] = fake_Texture;
|
||||
fake_Texture->Reference = index;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::LoadTexture(TextureFileStruct* file_in_memory, uMod_IDirect3DTexture9** ppTexture) // to load fake texture from a file in memory
|
||||
{
|
||||
Message("LoadTexture( %lu, %lu, %#lX): %lu\n", file_in_memory, ppTexture, file_in_memory->Hash, this);
|
||||
if (D3D_OK != D3DXCreateTextureFromFileInMemoryEx(D3D9Device, file_in_memory->pData, file_in_memory->Size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, nullptr, nullptr,
|
||||
(IDirect3DTexture9**)ppTexture))
|
||||
//if (D3D_OK != D3DXCreateTextureFromFileInMemory( D3D9Device, file_in_memory->pData, file_in_memory->Size, (IDirect3DTexture9 **) ppTexture))
|
||||
{
|
||||
*ppTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
(*ppTexture)->FAKE = true;
|
||||
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
|
||||
Message("LoadTexture( %lu, %#lX): DONE\n", *ppTexture, file_in_memory->Hash);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::LoadTexture(TextureFileStruct* file_in_memory, uMod_IDirect3DVolumeTexture9** ppTexture) // to load fake texture from a file in memory
|
||||
{
|
||||
Message("LoadTexture( Volume %lu, %lu, %#lX): %lu\n", file_in_memory, ppTexture, file_in_memory->Hash, this);
|
||||
if (D3D_OK != D3DXCreateVolumeTextureFromFileInMemoryEx(D3D9Device, file_in_memory->pData, file_in_memory->Size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, nullptr,
|
||||
nullptr,
|
||||
(IDirect3DVolumeTexture9**)ppTexture))
|
||||
//if (D3D_OK != D3DXCreateVolumeTextureFromFileInMemory( D3D9Device, file_in_memory->pData, file_in_memory->Size, (IDirect3DVolumeTexture9 **) ppTexture))
|
||||
{
|
||||
*ppTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
(*ppTexture)->FAKE = true;
|
||||
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedVolumeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedVolumeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
|
||||
Message("LoadTexture( Volume %lu, %#lX): DONE\n", *ppTexture, file_in_memory->Hash);
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureClient::LoadTexture(TextureFileStruct* file_in_memory, uMod_IDirect3DCubeTexture9** ppTexture) // to load fake texture from a file in memory
|
||||
{
|
||||
Message("LoadTexture( Cube %lu, %lu, %#lX): %lu\n", file_in_memory, ppTexture, file_in_memory->Hash, this);
|
||||
if (D3D_OK != D3DXCreateCubeTextureFromFileInMemoryEx(D3D9Device, file_in_memory->pData, file_in_memory->Size, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, nullptr, nullptr,
|
||||
(IDirect3DCubeTexture9**)ppTexture))
|
||||
//if (D3D_OK != D3DXCreateCubeTextureFromFileInMemory( D3D9Device, file_in_memory->pData, file_in_memory->Size, (IDirect3DCubeTexture9 **) ppTexture))
|
||||
{
|
||||
*ppTexture = nullptr;
|
||||
return RETURN_TEXTURE_NOT_LOADED;
|
||||
}
|
||||
(*ppTexture)->FAKE = true;
|
||||
|
||||
void* cpy;
|
||||
const long ret = D3D9Device->QueryInterface(IID_IDirect3DTexture9, &cpy);
|
||||
if (ret == 0x01000000L) {
|
||||
static_cast<uMod_IDirect3DDevice9*>(D3D9Device)->SetLastCreatedCubeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
else {
|
||||
static_cast<uMod_IDirect3DDevice9Ex*>(D3D9Device)->SetLastCreatedCubeTexture(nullptr); //this texture must no be added twice
|
||||
}
|
||||
|
||||
Message("LoadTexture( Cube %lu, %#lX): DONE\n", *ppTexture, file_in_memory->Hash);
|
||||
return RETURN_OK;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#include "uMod_Main.h"
|
||||
|
||||
/*
|
||||
MyTypeHash GetHash(unsigned char *str, int len) // estimate the hash
|
||||
{
|
||||
MyTypeHash hash = 0;
|
||||
for (int i=0; i<len; i++) hash = str[i] + (hash << 6) + (hash << 16) - hash;
|
||||
return hash);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* BIG THANKS TO RS !!
|
||||
*
|
||||
* who gave me his hashing algorithm (well or crc32 algorithm^^)
|
||||
*
|
||||
The hash function is CRC32 using polynomial 0xEDB88320.
|
||||
However, the hashed data is calculated incorrectly in TexMod: it's simply BytesPerPixel * Width * Height, from the beginning of the data (that is mapped using LockRect).
|
||||
The problem is that it doesn't take the pitch into account and BytesPerPixel may be wrong for some rare formats (not sure about that).
|
||||
*/
|
||||
|
||||
|
||||
#define CRC32POLY 0xEDB88320u /* CRC-32 Polynom */
|
||||
#define ulCrc_in 0xffffffff
|
||||
|
||||
unsigned int GetCRC32(char* pcDatabuf, unsigned int ulDatalen)
|
||||
{
|
||||
unsigned int crc = ulCrc_in;
|
||||
for (unsigned int idx = 0u; idx < ulDatalen; idx++) {
|
||||
unsigned int data = *pcDatabuf++;
|
||||
for (unsigned int bit = 0u; bit < 8u; bit++, data >>= 1) {
|
||||
crc = crc >> 1 ^ ((crc ^ data) & 1 ? CRC32POLY : 0);
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
@@ -1,680 +0,0 @@
|
||||
#include "uMod_Main.h"
|
||||
#include "uMod_File.h"
|
||||
|
||||
uMod_TextureServer::uMod_TextureServer(char* game, char* uModName)
|
||||
{
|
||||
Message("uMod_TextureServer(): %lu\n", this);
|
||||
|
||||
Mutex = CreateMutex(nullptr, false, nullptr);
|
||||
|
||||
Clients = nullptr;
|
||||
NumberOfClients = 0;
|
||||
LenghtOfClients = 0;
|
||||
BoolSaveAllTextures = false;
|
||||
BoolSaveSingleTexture = false;
|
||||
SavePath[0] = 0;
|
||||
|
||||
int len = 0;
|
||||
int path_pos = 0;
|
||||
int dot_pos = 0;
|
||||
for (len = 0; len < MAX_PATH && (game[len]); len++) {
|
||||
if (game[len] == '\\' || game[len] == '/') {
|
||||
path_pos = len + 1;
|
||||
}
|
||||
else if (game[len] == '.') {
|
||||
dot_pos = len;
|
||||
}
|
||||
}
|
||||
|
||||
if (dot_pos > path_pos) {
|
||||
len = dot_pos - path_pos;
|
||||
}
|
||||
else {
|
||||
len -= path_pos;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
GameName[i] = game[i + path_pos];
|
||||
}
|
||||
|
||||
if (len < MAX_PATH) {
|
||||
GameName[len] = 0;
|
||||
}
|
||||
else {
|
||||
GameName[0] = 0;
|
||||
}
|
||||
|
||||
for (len = 0; len < MAX_PATH; len++) {
|
||||
UModName[len] = uModName[len];
|
||||
}
|
||||
|
||||
KeyBack = 0;
|
||||
KeySave = 0;
|
||||
KeyNext = 0;
|
||||
|
||||
FontColour = 0u;
|
||||
TextureColour = 0u;
|
||||
|
||||
Pipe.In = INVALID_HANDLE_VALUE;
|
||||
Pipe.Out = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
uMod_TextureServer::~uMod_TextureServer()
|
||||
{
|
||||
Message("~uMod_TextureServer(): %lu\n", this);
|
||||
if (Mutex != nullptr) {
|
||||
CloseHandle(Mutex);
|
||||
}
|
||||
|
||||
//delete the files in memory
|
||||
int num = CurrentMod.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
delete[] CurrentMod[i]->pData; //delete the file content of the texture
|
||||
}
|
||||
|
||||
num = OldMod.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
delete[] OldMod[i]->pData; //delete the file content of the texture
|
||||
}
|
||||
|
||||
if (Pipe.In != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(Pipe.In);
|
||||
}
|
||||
Pipe.In = INVALID_HANDLE_VALUE;
|
||||
if (Pipe.Out != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(Pipe.Out);
|
||||
}
|
||||
Pipe.Out = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
int uMod_TextureServer::AddClient(uMod_TextureClient* client, TextureFileStruct** update, int* number) // called from a client
|
||||
{
|
||||
Message("AddClient(%lu): %lu\n", client, this);
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// the following functions must not change the original uMod_IDirect3DDevice9 object
|
||||
// somehow on game start some uMod_IDirect3DDevice9 object are created, which must rest unchanged!!
|
||||
// these objects are released and are not used for rendering
|
||||
client->SetGameName(GameName);
|
||||
client->SaveAllTextures(BoolSaveAllTextures);
|
||||
client->SaveSingleTexture(BoolSaveSingleTexture);
|
||||
client->SetSaveDirectory(SavePath);
|
||||
if (KeyBack > 0) {
|
||||
client->SetKeyBack(KeyBack);
|
||||
}
|
||||
if (KeySave > 0) {
|
||||
client->SetKeySave(KeySave);
|
||||
}
|
||||
if (KeyNext > 0) {
|
||||
client->SetKeyNext(KeyNext);
|
||||
}
|
||||
|
||||
if (FontColour > 0u) {
|
||||
const DWORD r = FontColour >> 16 & 0xFF;
|
||||
const DWORD g = FontColour >> 8 & 0xFF;
|
||||
const DWORD b = FontColour & 0xFF;
|
||||
client->SetFontColour(r, g, b);
|
||||
}
|
||||
if (TextureColour > 0u) {
|
||||
const DWORD r = TextureColour >> 16 & 0xFF;
|
||||
const DWORD g = TextureColour >> 8 & 0xFF;
|
||||
const DWORD b = TextureColour & 0xFF;
|
||||
client->SetTextureColour(r, g, b);
|
||||
}
|
||||
|
||||
|
||||
if (const int ret = PrepareUpdate(update, number)) {
|
||||
return ret; // get a copy of all texture to be modded
|
||||
}
|
||||
|
||||
|
||||
if (NumberOfClients == LenghtOfClients) //allocate more memory
|
||||
{
|
||||
uMod_TextureClient** temp = nullptr;
|
||||
try { temp = new uMod_TextureClient*[LenghtOfClients + 10]; }
|
||||
catch (...) {
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
|
||||
if (const int ret = UnlockMutex()) {
|
||||
return ret;
|
||||
}
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
for (int i = 0; i < LenghtOfClients; i++) {
|
||||
temp[i] = Clients[i];
|
||||
}
|
||||
|
||||
delete[] Clients;
|
||||
|
||||
Clients = temp;
|
||||
LenghtOfClients += 10;
|
||||
}
|
||||
Clients[NumberOfClients++] = client;
|
||||
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::RemoveClient(uMod_TextureClient* client) // called from a client
|
||||
{
|
||||
Message("RemoveClient(): %lu\n", client);
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
if (client == Clients[i]) {
|
||||
NumberOfClients--;
|
||||
Clients[i] = Clients[NumberOfClients];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::AddFile(char* buffer, unsigned int size, MyTypeHash hash, bool force) // called from Mainloop()
|
||||
{
|
||||
Message("uMod_TextureServer::AddFile( %lu %lu, %#lX, %d): %lu\n", buffer, size, hash, force, this);
|
||||
|
||||
TextureFileStruct* temp = nullptr;
|
||||
|
||||
int num = CurrentMod.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (CurrentMod[i]->Hash == hash) //look through all current textures
|
||||
{
|
||||
if (force) {
|
||||
temp = CurrentMod[i];
|
||||
break;
|
||||
} // we need to reload it
|
||||
return RETURN_OK; // we still have added this texture
|
||||
}
|
||||
}
|
||||
if (temp == nullptr) // if not found, look through all old textures
|
||||
{
|
||||
num = OldMod.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (OldMod[i]->Hash == hash) {
|
||||
temp = OldMod[i];
|
||||
OldMod.Remove(temp);
|
||||
CurrentMod.Add(temp);
|
||||
if (force) {
|
||||
break; // we must reload it
|
||||
}
|
||||
return RETURN_OK; // we should not reload it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool new_file = true;
|
||||
if (temp != nullptr) //if it was found, we delete the old file content
|
||||
{
|
||||
new_file = false;
|
||||
|
||||
delete[] temp->pData;
|
||||
|
||||
temp->pData = nullptr;
|
||||
}
|
||||
else //if it was not found, we need to create a new object
|
||||
{
|
||||
new_file = true;
|
||||
temp = new TextureFileStruct;
|
||||
temp->Reference = -1;
|
||||
}
|
||||
|
||||
try {
|
||||
temp->pData = new char[size];
|
||||
}
|
||||
catch (...) {
|
||||
if (!new_file) {
|
||||
CurrentMod.Remove(temp); // if this is a not a new file it is in the list of the CurrentMod
|
||||
}
|
||||
delete temp;
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
temp->pData[i] = buffer[i];
|
||||
}
|
||||
|
||||
temp->Size = size;
|
||||
temp->NumberOfTextures = 0;
|
||||
temp->Textures = nullptr;
|
||||
temp->Hash = hash;
|
||||
|
||||
//if (new_file) temp->ForceReload = false; // no need to force a load of the texture
|
||||
//else
|
||||
temp->ForceReload = force;
|
||||
|
||||
Message("End AddFile(%#lX)\n", hash);
|
||||
if (new_file) {
|
||||
return CurrentMod.Add(temp); // new files must be added to the list of the CurrentMod
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureServer::AddFile(wchar_t* file_name, MyTypeHash hash, bool force) // called from Mainloop
|
||||
// this functions does the same, but loads the file content from disk
|
||||
{
|
||||
Message("uMod_TextureServer::AddFile( %ls, %#lX, %d): %lu\n", file_name, hash, force, this);
|
||||
|
||||
TextureFileStruct* temp = nullptr;
|
||||
|
||||
int num = CurrentMod.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (CurrentMod[i]->Hash == hash) {
|
||||
if (force) {
|
||||
temp = CurrentMod[i];
|
||||
break;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
}
|
||||
if (temp == nullptr) {
|
||||
num = OldMod.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (OldMod[i]->Hash == hash) {
|
||||
temp = OldMod[i];
|
||||
OldMod.Remove(temp);
|
||||
CurrentMod.Add(temp);
|
||||
if (force) {
|
||||
break;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FILE* file;
|
||||
if (_wfopen_s(&file, file_name, L"rb") != 0) {
|
||||
Message("AddFile( ): file not found\n");
|
||||
return RETURN_FILE_NOT_LOADED;
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
const unsigned int size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
bool new_file = true;
|
||||
if (temp != nullptr) {
|
||||
new_file = false;
|
||||
|
||||
delete[] temp->pData;
|
||||
|
||||
temp->pData = nullptr;
|
||||
}
|
||||
else {
|
||||
new_file = true;
|
||||
temp = new TextureFileStruct;
|
||||
temp->Reference = -1;
|
||||
}
|
||||
|
||||
try {
|
||||
temp->pData = new char[size];
|
||||
}
|
||||
catch (...) {
|
||||
if (!new_file) {
|
||||
CurrentMod.Remove(temp);
|
||||
}
|
||||
delete temp;
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
const int result = fread(temp->pData, 1, size, file);
|
||||
fclose(file);
|
||||
if (result != size) {
|
||||
delete[] temp->pData;
|
||||
if (!new_file) {
|
||||
CurrentMod.Remove(temp);
|
||||
}
|
||||
delete temp;
|
||||
return RETURN_FILE_NOT_LOADED;
|
||||
}
|
||||
|
||||
temp->Size = size;
|
||||
temp->NumberOfTextures = 0;
|
||||
temp->Textures = nullptr;
|
||||
temp->Hash = hash;
|
||||
|
||||
if (new_file) {
|
||||
temp->ForceReload = false;
|
||||
}
|
||||
else {
|
||||
temp->ForceReload = force;
|
||||
}
|
||||
|
||||
Message("End AddFile(%#lX)\n", hash);
|
||||
if (new_file) {
|
||||
return CurrentMod.Add(temp);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureServer::RemoveFile(MyTypeHash hash) // called from Mainloop()
|
||||
{
|
||||
Message("RemoveFile( %lu): %lu\n", hash, this);
|
||||
|
||||
const int num = CurrentMod.GetNumber();
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (CurrentMod[i]->Hash == hash) {
|
||||
TextureFileStruct* temp = CurrentMod[i];
|
||||
CurrentMod.Remove(temp);
|
||||
return OldMod.Add(temp);
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SaveAllTextures(bool val) // called from Mainloop()
|
||||
{
|
||||
if (BoolSaveAllTextures == val) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
BoolSaveAllTextures = val;
|
||||
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SaveAllTextures(BoolSaveAllTextures);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SaveSingleTexture(bool val) // called from Mainloop()
|
||||
{
|
||||
if (BoolSaveSingleTexture == val) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
BoolSaveSingleTexture = val;
|
||||
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SaveSingleTexture(BoolSaveSingleTexture);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SetSaveDirectory(wchar_t* dir) // called from Mainloop()
|
||||
{
|
||||
Message("uMod_TextureServer::SetSaveDirectory( %ls): %lu\n", dir, this);
|
||||
int i = 0;
|
||||
for (i = 0; i < MAX_PATH && dir[i]; i++) {
|
||||
SavePath[i] = dir[i];
|
||||
}
|
||||
if (i == MAX_PATH) {
|
||||
SavePath[0] = 0;
|
||||
return RETURN_BAD_ARGUMENT;
|
||||
}
|
||||
SavePath[i] = 0;
|
||||
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SetSaveDirectory(SavePath);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SetKeyBack(int key) // called from Mainloop()
|
||||
{
|
||||
if (KeyBack == key || KeySave == key || KeyNext == key) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
KeyBack = key;
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SetKeyBack(key);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SetKeySave(int key) // called from Mainloop()
|
||||
{
|
||||
if (KeyBack == key || KeySave == key || KeyNext == key) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
KeySave = key;
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SetKeySave(key);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SetKeyNext(int key) // called from Mainloop()
|
||||
{
|
||||
if (KeyBack == key || KeySave == key || KeyNext == key) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
KeyNext = key;
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SetKeyNext(key);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SetFontColour(DWORD colour) // called from Mainloop()
|
||||
{
|
||||
if (colour == 0u) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
FontColour = colour;
|
||||
const DWORD r = (FontColour >> 16) & 0xFF;
|
||||
const DWORD g = (FontColour >> 8) & 0xFF;
|
||||
const DWORD b = (FontColour) & 0xFF;
|
||||
Message("uMod_TextureServer::SetFontColour( %u %u %u): %lu\n", r, g, b, this);
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SetFontColour(r, g, b);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::SetTextureColour(DWORD colour) // called from Mainloop()
|
||||
{
|
||||
if (colour == 0u) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_SERVER;
|
||||
return ret;
|
||||
}
|
||||
TextureColour = colour;
|
||||
const DWORD r = (TextureColour >> 16) & 0xFF;
|
||||
const DWORD g = (TextureColour >> 8) & 0xFF;
|
||||
const DWORD b = (TextureColour) & 0xFF;
|
||||
Message("uMod_TextureServer::SetTextureColour( %u %u %u): %lu\n", r, g, b, this);
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
Clients[i]->SetTextureColour(r, g, b);
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
int uMod_TextureServer::PropagateUpdate(uMod_TextureClient* client) // called from Mainloop(), send the update to all clients
|
||||
{
|
||||
Message("PropagateUpdate(%lu): %lu\n", client, this);
|
||||
if (const int ret = LockMutex()) {
|
||||
gl_ErrorState |= uMod_ERROR_TEXTURE;
|
||||
return ret;
|
||||
}
|
||||
if (client != nullptr) {
|
||||
TextureFileStruct* update;
|
||||
int number;
|
||||
if (const int ret = PrepareUpdate(&update, &number)) {
|
||||
return ret;
|
||||
}
|
||||
client->AddUpdate(update, number);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < NumberOfClients; i++) {
|
||||
TextureFileStruct* update;
|
||||
int number;
|
||||
if (const int ret = PrepareUpdate(&update, &number)) {
|
||||
return ret;
|
||||
}
|
||||
Clients[i]->AddUpdate(update, number);
|
||||
}
|
||||
}
|
||||
return UnlockMutex();
|
||||
}
|
||||
|
||||
#define cpy_file_struct( a, b) \
|
||||
{ \
|
||||
a.ForceReload = b.ForceReload; \
|
||||
a.pData = b.pData; \
|
||||
a.Size = b.Size; \
|
||||
a.NumberOfTextures = b.NumberOfTextures; \
|
||||
a.Reference = b.Reference; \
|
||||
a.Textures = b.Textures; \
|
||||
a.Hash = b.Hash; }
|
||||
|
||||
int TextureFileStruct_Compare(const void* elem1, const void* elem2)
|
||||
{
|
||||
const auto tex1 = (TextureFileStruct*)elem1;
|
||||
const auto tex2 = (TextureFileStruct*)elem2;
|
||||
if (tex1->Hash < tex2->Hash) {
|
||||
return -1;
|
||||
}
|
||||
if (tex1->Hash > tex2->Hash) {
|
||||
return +1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uMod_TextureServer::PrepareUpdate(TextureFileStruct** update, int* number) // called from the PropagateUpdate() and AddClient.
|
||||
// Prepare an update for one client. The allocated memory must deleted by the client.
|
||||
{
|
||||
Message("PrepareUpdate(%lu, %d): %lu\n", update, number, this);
|
||||
|
||||
TextureFileStruct* temp = nullptr;
|
||||
const int num = CurrentMod.GetNumber();
|
||||
if (num > 0) {
|
||||
try { temp = new TextureFileStruct[num]; }
|
||||
catch (...) {
|
||||
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
|
||||
return RETURN_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num; i++) cpy_file_struct(temp[i], (*(CurrentMod[i])));
|
||||
qsort(temp, num, sizeof(TextureFileStruct), TextureFileStruct_Compare);
|
||||
}
|
||||
|
||||
|
||||
*update = temp;
|
||||
*number = num;
|
||||
return RETURN_OK;
|
||||
}
|
||||
#undef cpy_file_struct
|
||||
|
||||
int uMod_TextureServer::LockMutex()
|
||||
{
|
||||
if ((gl_ErrorState & (uMod_ERROR_FATAL | uMod_ERROR_MUTEX))) {
|
||||
return RETURN_NO_MUTEX;
|
||||
}
|
||||
if (WAIT_OBJECT_0 != WaitForSingleObject(Mutex, 100)) {
|
||||
return RETURN_MUTEX_LOCK; //waiting 100ms, to wait infinite pass INFINITE
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
int uMod_TextureServer::UnlockMutex()
|
||||
{
|
||||
if (ReleaseMutex(Mutex) == 0) {
|
||||
return RETURN_MUTEX_UNLOCK;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void uMod_TextureServer::LoadModsFromFile(char* source)
|
||||
{
|
||||
Message("MainLoop: searching in %s\n", source);
|
||||
// Attempt to open the file
|
||||
FILE* file = fopen(source, "r");
|
||||
if (file) {
|
||||
Message("MainLoop: found modlist.txt. Reading\n");
|
||||
// Read each line from the file
|
||||
char line[MAX_PATH];
|
||||
while (fgets(line, sizeof(line), file) != nullptr) {
|
||||
Message("MainLoop: loading file %s\n", line);
|
||||
for (auto i = 0; i < MAX_PATH; i++) {
|
||||
if (line[i] == '\n') {
|
||||
line[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const auto file = new uMod_File(line);
|
||||
const auto result = file->GetContent();
|
||||
if (file->Textures.size() > 0) {
|
||||
if (!result) {
|
||||
Message("MainLoop: WARNING! GetContent returned failure, but some textures have been loaded for %s\n", line);
|
||||
}
|
||||
|
||||
Message("MainLoop: Texture count %d %s\n", file->Textures.size(), line);
|
||||
for (auto& texture : file->Textures) {
|
||||
AddFile(texture.data.data(), texture.data.size(), texture.hash, true);
|
||||
}
|
||||
|
||||
PropagateUpdate(nullptr);
|
||||
}
|
||||
else {
|
||||
Message("MainLoop: Failed to load any textures for %s\n", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uMod_TextureServer::MainLoop() // run as a separated thread
|
||||
{
|
||||
Message("MainLoop: searching for modlist.txt\n");
|
||||
char gwpath[MAX_PATH];
|
||||
GetModuleFileName(GetModuleHandle(nullptr), gwpath, MAX_PATH); //ask for name and path of this executable
|
||||
char* last_backslash = strrchr(gwpath, '\\');
|
||||
if (last_backslash != nullptr) {
|
||||
// Terminate the string at the last backslash to remove the executable name
|
||||
*last_backslash = '\0';
|
||||
}
|
||||
|
||||
strcat(gwpath, "\\modlist.txt");
|
||||
LoadModsFromFile(gwpath);
|
||||
|
||||
char umodpath[MAX_PATH];
|
||||
strcpy(umodpath, UModName);
|
||||
|
||||
last_backslash = strrchr(umodpath, '\\');
|
||||
if (last_backslash != nullptr) {
|
||||
// Terminate the string at the last backslash to remove the executable name
|
||||
*last_backslash = '\0';
|
||||
}
|
||||
|
||||
strcat(umodpath, "\\modlist.txt");
|
||||
LoadModsFromFile(umodpath);
|
||||
|
||||
Message("MainLoop: begin\n");
|
||||
for (auto i = 0; i < 10; i++) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
||||
-4163
File diff suppressed because it is too large
Load Diff
-3152
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"default-registry": {
|
||||
"kind": "git",
|
||||
"baseline": "7f9f0e44db287e8e67c0e888141bfa200ab45121",
|
||||
"repository": "https://github.com/microsoft/vcpkg"
|
||||
},
|
||||
"registries": [
|
||||
{
|
||||
"kind": "artifact",
|
||||
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
|
||||
"name": "microsoft"
|
||||
}
|
||||
]
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"dxsdk-d3dx",
|
||||
{
|
||||
"name": "libzippp",
|
||||
"features": [
|
||||
"encryption"
|
||||
]
|
||||
},
|
||||
"minhook",
|
||||
"ms-gsl"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user