Compare commits

...

41 Commits
v5.26 ... v5.27

Author SHA1 Message Date
icex2
71f0a66408 Update changelog 2019-10-12 20:44:51 +02:00
Will Xyen
0f04d5ef19 bio2emu: cleanup setupapi code a bit 2019-10-12 14:16:55 -04:00
Will Xyen
0c1bbe08c0 iidxhook8: Rename bi2a structs to be more clear 2019-10-12 14:16:22 -04:00
Will Xyen
1c415eb207 bio2emu: Remove requirement for bio2emu_init_end to be called
Instead bio2emu_setupapi_hook_init is called during init, this is safe because the game's IO thread isn't initialized at this point, and nothing could be attempting to open devices at this point in time.
2019-10-12 14:15:28 -04:00
Will Xyen
b6216c696e bio2emu: Add missing CM hooks for device index retrieval
Used by games that access the BIO2 through libacio
2019-10-12 05:37:47 -04:00
Will Xyen
a492cee93e docs: Update misc. docs for Rootage support 2019-10-12 04:40:30 -04:00
Will Xyen
e495bfb8f1 bio2emu: Refactor out the BIO2 emulation code so that it can be reused
Also make it support multiple BIO2 devices if needed (DRS)
2019-10-12 04:33:50 -04:00
icex2
073392407a architecture doc minor update 2019-10-07 20:12:33 +02:00
icex2
0a499b38a7 Add initial draft of architecture document.
Still has a bunch of TODOs where more information is required.
This commit adds the first few sections and some information
about iidxhook.
2019-10-07 20:02:32 +02:00
icex2
79495ea687 Add dev doc about IIDX's rendering loops for up-/downscaling feature 2019-10-07 19:02:28 +02:00
icex2
29526e02ec Update changelog 2019-10-07 18:20:01 +02:00
icex2
b83033587f doc/iidxhook: Update doc for iidxhook1/2 2019-10-07 16:04:27 +00:00
icex2
ff6bad2495 iidxhook1/2 config: Remove deprecated use_d3d9_hooks param 2019-10-07 16:04:26 +00:00
icex2
d64f8b2d8d iidxhook-util: Remove d3d8 module
Remove this module because it doesn't really provide any value
anymore. Using the d3d8to9 wrapper lib does not only fix some
odd d3d8 issues but also allows us to run all (IIDX) games over
d3d9. Thus and in order to reduce quite a lot of maintanance effort,
we remove this module.

Please use the d3d8to9 wrapper lib from now on in combination with
any d3d8 games and in order to use bemanitools gfx hook features.
2019-10-07 16:04:26 +00:00
icex2
8c998f6461 Add inject.exe to test package
Required by d3d9hoook test
2019-10-07 16:04:26 +00:00
icex2
a10132f62d dist/iidx: Fix default values for override window size 2019-10-07 16:04:26 +00:00
icex2
d9cc873eec iidxhook8: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
f4c0810ee3 iidxhook7: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
b1871a475d iidxhook6: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
a626e9e635 iidxhook5: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
5183547ba9 iidxhook4: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
53d61dcbbd iidxhook3: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
f201bff9ca iidxhook2: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
e0d7596f20 iidxhook1: Refactor to use new d3d9 module 2019-10-07 16:04:26 +00:00
icex2
3e60300273 iidxhook-util: Adapt enum name of upscaling filter names 2019-10-07 16:04:26 +00:00
icex2
77906205b5 test/check: Add check_failed func 2019-10-07 16:04:26 +00:00
icex2
c5d39d82d5 iidxhook-util: Major refactoring of d3d9 module
Uses the hook/d3d9 module with IRP handlers now. All previously
available features are implemented.

Furthermore, a new overhauled up-/downscaling method is implemented
which supports all IIDX versions now.
2019-10-07 16:04:26 +00:00
icex2
d169ee84b3 test/hook: Add tests for d3d9 hook module
Creates a simple d3d9 context and render loop allowing us to run
quick and easy integration tests of the hooking infrastructure.
2019-10-07 16:04:26 +00:00
icex2
60050d0d09 hook: Add d3d9 hook module
This module serves as a general base for any d3d9 hooks to be
implemented. It implements the IRP pattern like the iohook module.
This allows us to create irp handlers which can be chained, easier
structured and maintained compared to static IAT hooking. The latter
was the previous solution and did not work out well anymore for IIDX
which grew regarding d3d9 features.
2019-10-07 16:04:26 +00:00
Will Xyen
3436838b85 sdvxio-kfca: Add KFCA sdvxio driver 2019-09-28 17:41:27 -04:00
Will Xyen
bda056f0e4 aciotest: Add KFCA test handler 2019-09-28 17:41:27 -04:00
Will Xyen
2788b27a6f aciodrv: Add KFCA support 2019-09-28 17:41:15 -04:00
Will Xyen
89e3bbd2a3 hooklib: Allow proper passthrough of serial calls to real hardware (#26)
Only enabled / tested on IIDX CB and SDVX5

The point of this, is to allow rs232 hooks for only the descriptors that we hook.
This is because the emulation here is incomplete.
Although the IOCTL's do end up being passed to the real hardware, the game rejects some of the responses and hangs.
By short circuiting out, and calling the real Comm functions instead, it works.
And hence, card-reader passthrough works on IIDX25+/SDVX5+ finally without eamio-real
2019-09-28 17:36:22 -04:00
Will Xyen
1a567aa8ba Minor accuracy changes for KFCA emulation 2019-09-28 17:36:22 -04:00
icex2
a6386ac472 Update gitlab bug template, add config file and cmd arg sections 2019-09-28 22:47:55 +02:00
icex2
6582eff48b Add more gitlab templates
Add issue template for teatures and merge request templates for
bugfixes and features.
2019-09-28 00:50:39 +02:00
icex2
df0390e6f1 Add fork instructions to CONTRIBUTING.md 2019-09-28 00:24:31 +02:00
icex2
9874882774 README: Move contributing section from README.md to dedicated file 2019-09-27 23:36:52 +02:00
icex2
2aaaf2a864 iidxhook3: Update readme with FAQ about htpac'd assets 2019-09-27 23:25:52 +02:00
icex2
8d03db1b3d Bump version for next release to 5.27 2019-09-27 23:25:45 +02:00
icex2
b5f3eddba1 Add gitlab template for bug reporting. 2019-09-27 23:03:01 +02:00
93 changed files with 4394 additions and 2539 deletions

View File

@@ -0,0 +1,53 @@
## Summary
<!--- Provide a general summary of the issue in the Title above -->
## Expected behavior
<!--- Tell us what should happen -->
## Current behavior
<!--- Tell us what happens instead of the expected behavior -->
## Detailed Description
<!--- Provide a detailed description of the issue. Include links to screenshots or videos if necessary -->
## Steps to reproduce
<!--- Provide a detailed step by step description how to reproduce this issue -->
1.
2.
3.
4.
## Possible solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
## Context (Environment)
### Bemanitools version(s) affected
* <!--- Add one or multiple versions as a bullet list -->
### Game(s) and version(s) affected
* <!--- Add one or multiple game versions as a bullet list -->
### Log output
See attachment.
<!--- Provide log output as attachment. Make sure to censor sensitive data like PCBIDs or device names if necessary -->
### Configuration files
See attachment.
<!--- Provide any configuration files that you used, e.g. iidxhook-XX.conf. Make sure to censor sensitive data like
PCBIDs -->
### Command line arguments
<!--- Provide how you run the game from the command line, e.g. which gamestart.bat you used and any additional arguments
that you provided to it. Also provide the contents of the gamestart.bat you used if you altered it. -->
### APIs used
* <!--- List all APIs you used as a bullet list, e.g. iidxio-keyboard, eamio-keyboard -->
### OS version
<!--- Provide the version of Windows you used with whatever update/build identifier -->
### Hardware specs
* CPU: <!--- Insert, e.g. Core i7 2600k 3.20ghz -->
* RAM: <!--- Insert, e.g. 16 GB -->
* GPU: <!--- Insert, e.g. Nvidia GeForce GTX 970, 4GB -->
* Controllers/IO: <!--- Insert, e.g. DJ Dao RE over USB -->

View File

@@ -0,0 +1,14 @@
## Summary
<!--- Provide a general summary of your changes in the Title above -->
## Detailed description
<!--- Describe your feature in detail -->
## Benefits
<!--- Describe the value/benefits of the feature in detail -->
## Drawbacks
<!--- Describe any drawbacks that might be introduced with this feature -->
## Current blockers
<!--- Describe any blockers that need to be resolved before implementing this feature -->

View File

@@ -0,0 +1,16 @@
## Summary
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

View File

@@ -0,0 +1,16 @@
## Summary
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

View File

@@ -1,4 +1,16 @@
# Release history
## 5.27
* Various documentation updates regarding development and how to contribute
* KFCA emulation accuracy fixes
* Fix passthrough of serial calls when using real hardware (e.g. card reader passthrough IIDX25+/SDVX5+)
* Add sdvxio-kfca driver to talk to real SDVX hardware
* Refactor d3d9 hook module to improve maintainability. Also fixes upscaling not working on IIDX20+.
* Remove d3d8 hook module to improve maintainability. Make old d3d8 based games, e.g. iidxhook1/2, use d3d9 instead.
Requires usage of d3d8to9 wrapper library to use gfx patching features.
* Add dev doc about IIDX rendering loops
* Add an initial draft of an architecture document (will be worked on in iterations)
* Refactor BIO2 emulation to make it re-usable by other games
## 5.26
* iidxio-ezusb: Reduce sleep time to Sleep(1) to avoid framerate issues on some versions of iidx.
* Bugfix: iidx d3d9 games, mainly the newer ones iidx 20-25, freezing. Happened on boot, during song selection or during the song.

30
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,30 @@
# Contributing
Please have a look at the issue board about what's currently going on. If you see an issue that is not assigned yet and
that you can and want to work on, please leave a comment to reach out to one of our developers. You can also ask
questions and discuss the issue.
# Bug reports
Please check if the bug was already reported by searching the existing issues. If it does, feel free to leave a comment
that you also have this issue. Add additional information, screenshots, log files etc. The more information and details
we have, the easier it might get to solve the issue.
When creating new issues, use our template for reporting bugs. It tells you what kind of information we need.
# Pull requests: bugfixes, new features or other code contributions
Pull requests are welcome! May it be a PR to an already known issue or a new feature that you consider as a valuable
contribution, please open a PR. If you want to start working on a new feature that was proposed in an issue, yet, it
is recommended to reach out to the developers about this, first, to discuss if this contribution is valuable to the
project. Otherwise, you might waste your time on implementing something that won't make it into master.
Please read our [development guidelines](doc/development.md) as they contain valuable information that your contribution
meets our standards.
Fork the upstream repository and start developing on your personal fork. Make sure to test your changes with games that
are affected by them. Pay attention to the target platform/hardware you are testing on! This is valuable information
that should be included in the PR.
Once you completed your implementation, open a pull request on the upstream repository to propose your changes. We will review your contribution and get back to you about any changes or when we merge them to our upstream repository. Your changes, once approved, will be included in the next release.
# Roadmap
No concrete roadmap or timeline exists. We want to continue adding support for new games as well as old games (some of
the old games supported by BT4 are not supported, yet).

View File

@@ -54,11 +54,12 @@ libs :=
avsdlls :=
avsexes :=
testdlls :=
testexes :=
include Module.mk
modules := $(dlls) $(exes) $(libs) $(avsdlls) $(avsexes) $(testexes)
modules := $(dlls) $(exes) $(libs) $(avsdlls) $(avsexes) $(testdlls) $(testexes)
#
# $1: Bitness
@@ -94,6 +95,7 @@ $$(eval $$(foreach lib,$(libs),$$(call t_archive,$1,indep,$$(lib))))
$$(eval $$(foreach avsver,$$(avsvers_$1),$$(call t_avsver,$1,$$(avsver))))
$$(eval $$(foreach dll,$(testdlls),$$(call t_linkdll,$1,indep,$$(dll))))
$$(eval $$(foreach exe,$(testexes),$$(call t_linkexe,$1,indep,$$(exe))))
endef

View File

@@ -42,7 +42,7 @@
# 15: Patch 8: DanceDanceRevolution (2013)
# beatmania IIDX 20 tricoro
# pop'n music 21 Sunny Park
# SOUND VOLTEX (all known versions)
# SOUND VOLTEX (1-4)
# jubeat prop
#
# 16: Patch 1: beatmania IIDX 21 SPADA
@@ -53,6 +53,9 @@
# "Patch" 7: Steel Chronicle VicTroopers (not a Bemani, w/e)
#
# 17: Patch 0: beatmania IIDX 25 CANNON BALLERS
# beatmania IIDX 26 Rootage
#
# Patch 3: SOUND VOLTEX VIVID WAVE
#
cflags += \
@@ -74,6 +77,7 @@ imps += avs avs-ea3
include src/main/aciodrv/Module.mk
include src/main/acioemu/Module.mk
include src/main/aciotest/Module.mk
include src/main/bio2emu/Module.mk
include src/main/bsthook/Module.mk
include src/main/bstio/Module.mk
include src/main/cconfig/Module.mk
@@ -130,12 +134,14 @@ include src/main/p4ioemu/Module.mk
include src/main/pcbidgen/Module.mk
include src/main/sdvxhook/Module.mk
include src/main/sdvxio/Module.mk
include src/main/sdvxio-kfca/Module.mk
include src/main/security/Module.mk
include src/main/unicorntail/Module.mk
include src/main/util/Module.mk
include src/main/vefxio/Module.mk
include src/test/cconfig/Module.mk
include src/test/d3d9hook/Module.mk
include src/test/iidxhook-util/Module.mk
include src/test/security/Module.mk
include src/test/test/Module.mk
@@ -336,7 +342,7 @@ $(zipdir)/iidx-21-to-24.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/iidx-25.zip: \
$(zipdir)/iidx-25-to-26.zip: \
build/bin/avs2_1700-64/iidxhook8.dll \
build/bin/avs2_1700-64/launcher.exe \
build/bin/indep-64/config.exe \
@@ -402,6 +408,7 @@ $(zipdir)/sdvx.zip: \
build/bin/indep-32/eamio.dll \
build/bin/indep-32/geninput.dll \
build/bin/indep-32/sdvxio.dll \
build/bin/indep-32/sdvxio-kfca.dll \
dist/sdvx/config.bat \
dist/sdvx/gamestart.bat \
| $(zipdir)/
@@ -456,10 +463,13 @@ $(BUILDDIR)/tests.zip: \
build/bin/indep-32/cconfig-test.exe \
build/bin/indep-32/cconfig-util-test.exe \
build/bin/indep-32/cconfig-cmd-test.exe \
build/bin/indep-32/d3d9hook.dll \
build/bin/indep-32/d3d9hook-test.exe \
build/bin/indep-32/iidxhook-util-config-eamuse-test.exe \
build/bin/indep-32/iidxhook-util-config-gfx-test.exe \
build/bin/indep-32/iidxhook-util-config-misc-test.exe \
build/bin/indep-32/iidxhook-util-config-sec-test.exe \
build/bin/indep-32/inject.exe \
build/bin/indep-32/security-id-test.exe \
build/bin/indep-32/security-mcode-test.exe \
build/bin/indep-32/security-rp-test.exe \
@@ -483,7 +493,7 @@ $(BUILDDIR)/bemanitools.zip: \
$(zipdir)/iidx-19.zip \
$(zipdir)/iidx-20.zip \
$(zipdir)/iidx-21-to-24.zip \
$(zipdir)/iidx-25.zip \
$(zipdir)/iidx-25-to-26.zip \
$(zipdir)/jb-01.zip \
$(zipdir)/jb-05-to-07.zip \
$(zipdir)/jb-08.zip \

View File

@@ -1,5 +1,5 @@
# Bemanitools 5
Version: 5.26</br>
Version: 5.27</br>
[Release history](CHANGELOG.md)
A collection of tools to run [various Bemani arcade games](#list-of-supported-games).
@@ -36,7 +36,8 @@ authentic gameplay experience, and easier support for a broader range of release
* Beatmania IIDX 22 PENDUAL (iidx-21-to-24.zip)
* Beatmania IIDX 23 copula (iidx-21-to-24.zip)
* Beatmania IIDX 24 SINOBUZ (iidx-21-to-24.zip)
* Beatmania IIDX 25 CANNON BALLERS (iidx-25.zip)
* Beatmania IIDX 25 CANNON BALLERS (iidx-25-to-26.zip)
* Beatmania IIDX 26 Rootage (iidx-25-to-26.zip)
* jubeat
* jubeat (experimental/buggy) (jb-01.zip)
* jubeat saucer (fulfill) (jb-05-to-07.zip)
@@ -63,7 +64,14 @@ You will find *.md files in various sub-packages that give you further instructi
or FAQ. We advice you to read them as your questions and concerns might already be answered by them. If not, let us
know if there is any information that you consider helpful or important to know and should be added.
# Contributions
Please refer to the [dedicated documentation](CONTRIBUTING.md).
# Development
## Architecture
A dedicate [architecture document](doc/architecture.md) outlines the architecture of Bemanitools and points out the most
important aspects you should know before you get started with development.
## API
Please refer to the [API documentation](doc/api.md).
@@ -71,31 +79,6 @@ Please refer to the [API documentation](doc/api.md).
The source code is included with this distribution package (src.zip). Please refer to the
[development document](doc/development.md) for further details.
## Bugs and TODOs
We have our own issue tracker for this. If you want to contribute or have any bugs to report, please reach out to us on
the various channels we are available on. Please help us by providing a detailed description of your concern including:
* The version of bemanitools you are using
* The games affected including version
* Log output of bemanitools and the game
* The APIs you have been using with bemanitools, e.g. iidxio-keyboard, eamio-keyboard.
* The OS version you are running this on
* Specs of your hardware including CPU, RAM, GPU
* A detailed description of your issue. Describe the symptoms and the steps to trigger and reproduce them. Videos and
screenshots might be helpful depending on the issue.
## Contributions
Patches are welcome! Let us know if you have any contributions, e.g. bugfixes, and send us a patch file. Please read
our [development guidelines](doc/development.md) as they contain valuable information that your contribution meets our
standards.
Once submitted, we will review your contribution and get back to you about any changes or when we merge them to our
upstream repository. Your changes, once approved, will be included in the next release.
## Roadmap
No concrete roadmap or timeline exists. We want to continue adding support for new games as well as old games (some of
the old games supported by BT4 are not supported, yet). However, our time and workforce is limited. If you are
interested in contributing, please check the [contribution section](#contributions).
# License
Source code license is the Unlicense; you are permitted to do with this as thou wilt. For details, please refer to the
[LICENSE file](LICENSE) included with the source code.

View File

@@ -25,11 +25,11 @@ gfx.monitor_check=-1.000000
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0
@@ -43,9 +43,6 @@ gfx.scale_back_buffer_filter=none
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Use d3d9 hooks instead of d3d8 to enable d3d9 hook features not available on d3d8 (e.g. upscaling). Requires d3d8to9 wrapper library to be used with this game.
misc.use_d3d9_hooks=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false

View File

@@ -25,11 +25,11 @@ gfx.monitor_check=-1.000000
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0
@@ -43,9 +43,6 @@ gfx.scale_back_buffer_filter=none
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Use d3d9 hooks instead of d3d8 to enable d3d9 hook features not available on d3d8 (e.g. upscaling). Requires d3d8to9 wrapper library to be used with this game.
misc.use_d3d9_hooks=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false

View File

@@ -25,11 +25,11 @@ gfx.monitor_check=-1.000000
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0
@@ -43,9 +43,6 @@ gfx.scale_back_buffer_filter=none
# Disable operator clock setting system clock time
misc.disable_clock_set=false
# Use d3d9 hooks instead of d3d8 to enable d3d9 hook features not available on d3d8 (e.g. upscaling). Requires d3d8to9 wrapper library to be used with this game.
misc.use_d3d9_hooks=false
# Stub calls to rteffect.dll (10th to DistorteD)
misc.rteffect_stub=false

View File

@@ -25,11 +25,11 @@ gfx.monitor_check=-1.000000
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0
@@ -43,9 +43,6 @@ gfx.scale_back_buffer_filter=none
# Fix broken 3D background on Happy Sky's music select (if appearing completely white)
misc.happy_sky_ms_bg_fix=false
# Use d3d9 hooks instead of d3d8 to enable d3d9 hook features not available on d3d8 (e.g. upscaling). Requires d3d8to9 wrapper library to be used with this game.
misc.use_d3d9_hooks=false
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -25,11 +25,11 @@ gfx.monitor_check=-1.000000
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0
@@ -43,9 +43,6 @@ gfx.scale_back_buffer_filter=none
# Fix broken 3D background on DistorteD's music select (if appearing completely black)
misc.distorted_ms_bg_fix=false
# Use d3d9 hooks instead of d3d8 to enable d3d9 hook features not available on d3d8 (e.g. upscaling). Requires d3d8to9 wrapper library to be used with this game.
misc.use_d3d9_hooks=false
# Disable operator clock setting system clock time
misc.disable_clock_set=false

View File

@@ -22,11 +22,11 @@ gfx.monitor_check=-1.000000
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -22,11 +22,11 @@ gfx.monitor_check=-1.000000
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -25,11 +25,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -25,11 +25,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -16,11 +16,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -13,11 +13,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -13,11 +13,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -13,11 +13,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -13,11 +13,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -13,11 +13,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -13,11 +13,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -13,11 +13,11 @@ gfx.pci_id=1002:7146
# Run the game windowed
gfx.windowed=false
# Windowed width, -1 for default size
gfx.window_width=-1
# Windowed width, 0 for default size
gfx.window_width=0
# Windowed height, -1 for default size
gfx.window_height=-1
# Windowed height, 0 for default size
gfx.window_height=0
# Up-/downscale the back buffer's width. This does not change the game's rendering resolution but scales the final frame. Use this to target the native resolution of your monitor/TV, e.g. to avoid over-/underscan, bad image quality or latency caused by the monitors internal upscaler. 0 to disable this feature. Must be set in combination with the corresponding height parameter.
gfx.scale_back_buffer_width=0

View File

@@ -25,4 +25,6 @@ wine ./security-rp2-test.exe
wine ./security-rp3-test.exe
wine ./util-net-test.exe
wine ./inject.exe d3d9hook.dll d3d9hook-test.exe
echo "All tests successful."

182
doc/architecture.md Normal file
View File

@@ -0,0 +1,182 @@
# Bemanitools architecture
This document gives you an overview of the architecture of Bemanitools (5). Why do we need this? This helps document the
various design decisions and how everything comes together, in the end. At some point when things are evolving and other
developers want to pick up the project, this might give them answers to why some things were done well or not so well.
This allows them to iterate on the current design (document) to analyze if a change they want to apply might work out
or not.
Anway, enough preface...I guess you got the idea. This document will be split into several sections which address
different aspects of the architecture.
## The big picture
TODO create a graphic that presents the key modules and ideas.
## Detouring library functions, IAT hooking
One of Bemanitools's goals is to avoid patching of executables, libraries or any game data and instead rely on
intercepting calls to libraries to patch bugs or introduce new features. To support a game on a non native platform
transparently, e.g. your home desktop, this allows us to intercept I/O communication to emulate hardware or
files/filesystem features the game expects to be available.
We create a so called "hook library/hook.dll" which gets injected to the target process (the game) before the game
runs any of its application code. This is well known by the terms of dll injection and will not be further discussed
here (google it). The injected dll will replace the function addresses in the IATs to detour any calls to our own
handler functions before, eventually, calling the real function. This way, we can intercept the call and do cool things.
These features are covered by the modules in the following subfolders in src/main:
* hook: Essentially, this is capnhook: https://github.com/decafcode/capnhook. General tools for hooking Win32 API calls.
* hooklib: Some additional helper modules to take care of specific issues in Bemanitools, e.g. rs232 related stuff for
ACIO.
Check the modules for details.
## Hooking and IRP
IRP stands for "I/O request packet" and is a kernel mode structure used in Windows drivers for communication with the
OS. The data structure describes an I/O request with parameters for that request avoiding function calls with large
number of arguments to a driver.
We make use of that "IRP pattern" by creating a flexible and maintainable abstraction layer for the following hooking
modules:
* iohook: Hook I/O (e.g. file) related calls
* d3d9: Hook d3d9 graphics API calls
An IRP handler is implemented to handle selected IRP calls based on the specified operation type. IRP handlers can be
chained which allows splitting up different features/interceptors to different functions and modules allowing you to
create a clear structure. At the end of the forwarding chain, you the real API function that maps to the abstracted
operation is called. However, a handler can decide at any time to not forward calls which allows you to implement
emulation of access to selected files or I/O devices.
Modules that make use of this:
* iidxhook-util/d3d9
* ezusb-emu/device
* ezusb2-emu/device
* acioemu/emu
## Bemanitools's hook libraries, let's glue everything together
Bemanitools dlls to be injected into target game processes are refered to as "hook dlls" and come in different flavours
targetting different games and often different versions of the same game (series), for example:
* ddrhook: Hook dll for Dance Dance Revolution games
* iidxhook1-8: Hook dlls for Beatmania IIDX, we are currently at 8 different implementations due to the various
iterations the game went through, related to software and hardware.
* sdvxhook: Hook dll for SoundVoltex series
The following sub-sections will give you some brief insights on each hook implementation and what modules were used.
### bsthook
TODO
### ddrhook
TODO
### iidxhook
IIDX went through so many hard- and software iterations, it's actually amazing that the development team(s) refactored
and improved parts of the game and hardware with each iteration. However, when facing emulation and supporting
compatibility to legacy OS platforms, it can't get any worse. On the bright side, IIDX helped shaping Bemanitools a lot
and created a solid foundation other games can build on.
Because of that, we have 8 iidxhook implementations supporting sometimes different software features/fixes and
hardware. The following sub-sub-sections list the most relevant aspects and modules to point out common and different
higher level features.
Essentially, the main module file of each iidxhook implementation just glues the APIs of the modules it requires
together. An additional configuration layer allows users to tweak some of the features.
TODO go into some more detail about some differences in the hook modules, e.g. 18 to 19 look identical
-> but different AVS versions
#### iidxhook1 (9-12)
* Ezusb C02 I/O emulation
* Setupapi emulation
* Full security emulation with SRAM and round plugs
* Full serial emulation for magstripe card readers
* Full game essential I/O emulation
* d3d8 patching and extended features (superseded by d3d9 hook module + d3d8to9 wrapper)
* clock patching
* Font patching for Japanese chars
* Network related patches to enable eamuse to custom servers
* Filesystem patches to detour E and F backup drives for settings
#### iidxhook2 (13)
* Ezusb C02 I/O emulation
* Setupapi emulation
* Full security emulation with SRAM and round plugs
* Full game essential I/O emulation
* ACIO ICCA card reader emulation, slotted readers
* d3d8 patching and extended features (superseded by d3d9 hook module + d3d8to9 wrapper)
* clock patching
* Font patching for Japanese chars
* Network related patches to enable eamuse to custom servers
* Filesystem patches to detour E and F backup drives for settings
#### iidxhook3 (14-17)
* Ezusb IO2 I/O emulation
* Setupapi emulation
* Full security emulation with SRAM and round plugs
* Full game essential I/O emulation
* ACIO ICCA card reader emulation, slotted readers
* d3d9 patching and extended features
* Font patching for Japanese chars
* Network related patches to enable eamuse to custom servers
* Filesystem patches to detour E and F backup drives for settings
#### iidxhook4 (18)
* Ezusb IO2 I/O emulation
* Setupapi emulation
* Full game essential I/O emulation
* ACIO ICCA card reader emulation, slotted readers
* d3d9 patching and extended features
* Font patching for Japanese chars
* Filesystem patches to detour E and F backup drives for settings
#### iidxhook5 (19)
* Ezusb IO2 I/O emulation
* Setupapi emulation
* Full game essential I/O emulation
* ACIO ICCA card reader emulation, wave pass readers
* d3d9 patching and extended features
* Font patching for Japanese chars
* Filesystem patches to detour E and F backup drives for settings
#### iidxhook6 (20)
* Ezusb IO2 I/O emulation
* Setupapi emulation
* Full game essential I/O emulation
* ACIO ICCA card reader emulation, wave pass readers
* d3d9 patching and extended features
* Font patching for Japanese chars
#### iidxhook7 (21-24)
* Ezusb IO2 I/O emulation
* Setupapi emulation
* Full game essential I/O emulation
* ACIO ICCA card reader emulation, wave pass readers
* d3d9 patching and extended features
* Font patching for Japanese chars
#### iidxhook8 (25-26)
* ACIO BIO2 I/O emulation
* Setupapi emulation
* Full game essential I/O emulation
* ACIO ICCA card reader emulation, wave pass readers
* d3d9 patching and extended features
* Font patching for Japanese chars
### jbhook
TODO
### sdvxhook
TODO
## The ezusb (emulation) stack
TODO
## The ACIO (emulation) stack
TODO
## BT5 API
TODO
## AVS and launcher
TODO
## Inject
TODO

View File

@@ -0,0 +1,88 @@
# Notes outlining some aspects of the DirectX calls which were required to know to implement a up-/downscaling feature
As the title says, this outlines some aspects I needed to figure out in order to implement a up-/downscaling feature
within the d3d9 hook module that works on all currently available IIDX versions (9 to 26).
To analyze the rendering loops, I have used a tool called apitrace which traces the calls of many graphic APIs:
https://github.com/apitrace/apitrace
Defintely recommended to quickly figure out what is going on regarding rendering. It also allows you to let you render
parts of a scene after the application exited because it records all API calls and data passed to them.
Anyway, considering the various iterations in (GPU) hardware the game had to undergo combined with weird quirks and
"fixes" Bemanitools is undoing, I wouldn't have guessed that their rendering engine was nearly the same until IIDX 20.
That's when they introduced SD/HD mode.
In this case, that's great news because I had to craft a solution that allows up-/downscaling the final frame to
different resolutions (see the iidxhook-util/d3d9 module for more details about the feature).
But first, we need a breakdown of the render loop's most relevant parts for this:
## IIDX pre 20
Using apitrace, we can see the following outline of a frame (not counting the first one that does a lot of setup in
the beginning):
```
BeginScene
Clear
...
// Here are the main draw calls for the scene rendering to the back buffer
EndScene
Present
```
No render target switching, simply render everything to the back buffer...plain and simple.
Note: The viewport size is determined by the size returned by GetClientRect, wtf.
Welp, no official Konmai seal of approval without that. ¯\_(ツ)_/¯
## IIDX 20+
Using apitrace, we can see the following outline of a frame (not counting the first one that does a lot of setup in
the beginning):
```
BeginScene
// tex1 is a render target texture with size 1280x720 (also in SD mode)
// The game will render to this intermediate target and not directly to the fram ebuffer
SetRenderTarget(0, tex1)
...
Clear
BeginScene -> ErrInvalidCall return code
Clear
...
// Here are the main draw calls for the scene rendering to tex1
...
// Sets the render target to the original frame buffer. The size of the framebuffer is set to the output mode
// resolution, e.g. 1280x720 for HD mode and 640x480 for SD mode
SetRenderTarget(0, frame_buffer)
...
Clear
EndScene
...
// Render, texture and sampler state updates as well as a draw call that draws tex1 to a quad which fills the
// screen space.
...
EndScene -> ErrInvalidCall return code
Present
```
This is quite a different flow to implement HD and SD mode but the solution to solve that particular problem is straight
forward and easy to understand. This means that the game will always render in HD mode and only downscale the final
frame to SD resolution for 640x480 output.
Also, why the fuck do they call BeginScene and EndScene twice? Looks like they wanted to do this in two separate scenes
for some reason. Checking the return values would have revealed to them that something's not right...lucky them that
this code works nevertheless.
Another Konmai seal of approval, a job well done. ¯\_(ツ)_/¯
## iidxhook's up-/downscaling solution
The initial solution simply hooked into BeginScene and EndScene and let the game render to an intermediate render
target texture. The texture was scaled according to the actual target frame buffer size before getting presented. This
solution worked fine for pre IIDX 20 games but created a black screen on IIDX 20+.
In order to avoid two different scaling flows, the final solution that works for both does the following:
* Create a render target texture with native resolution and let the game render to it
* Set the render target to that intermediate render target texture on BeginScene
* Before Present
* Scale the intermediate render target texture to the back buffer
* Set the back buffer as the render target
* Present frame
Just an outline which follows the actual implementation that you can find in the iidxhook-util/d3d9.

View File

@@ -17,7 +17,7 @@ games:
* [iidxhook5](iidxhook5.md): Lincle
* [iidxhook6](iidxhook6.md): Tricoro
* [iidxhook7](iidxhook7.md): SPADA, PENDUAL, copula, SINOBUZ
* [iidxhook8](../iidxhook8/iidxhook8.md): CANNON BALLERS
* [iidxhook8](iidxhook8.md): CANNON BALLERS, Rootage
When building kactools, independent packages are created for each set of games
which are ready to be dropped on top of vanilla AC data dumps. We recommend

View File

@@ -24,6 +24,12 @@ integrated sound chip, you have to replace RtEffect.dll with a stubbed/patched
version (RtEffect_patched.dll). Otherwise, the game might crash instantly when
trying to start it.
In order to use the gfx feature patches, e.g. window mode, monitor check,
frame rate locking, framebuffer up/-downscaling etc. you have to use the
d3d8to9 wrapper library (get it from the bemanitools-supplement package).
Bemanitools removed the old d3d8 hooking module to provide native d3d8 hooks
due to compatibility and maintainability reasons.
Run the appropriate gamestart-XX.bat file as admin, where XX is either
09, 10, 11, 12.
@@ -211,6 +217,3 @@ If one or multiple of these issues apply, use the built in scaling options by se
to scale to. Usually, you want to set this to the monitor's native resolution, e.g.
1920x1080 for full HD. You can play around with a few different filters using
*gfx.scale_back_buffer_filter* which impacts image quality/blurriness on upscaling.
If you want to use this with old d3d8 games (IIDX 9-13), you have to use the d3d8to9
library from bemanitools-supplement because the d3d8 hook module cannot support this
upscaling feature. Make sure to set *misc.use_d3d9_hooks=true*.

View File

@@ -21,6 +21,12 @@ integrated sound chip, you have to replace RtEffect.dll with a stubbed/patched
version (RtEffect_patched.dll). Otherwise, the game might crash instantly when
trying to start it.
In order to use the gfx feature patches, e.g. window mode, monitor check,
frame rate locking, framebuffer up/-downscaling etc. you have to use the
d3d8to9 wrapper library (get it from the bemanitools-supplement package).
Bemanitools removed the old d3d8 hooking module to provide native d3d8 hooks
due to compatibility and maintainability reasons.
Run the gamestart-13.bat file as admin.
# Configuring iidxhook
@@ -176,6 +182,3 @@ If one or multiple of these issues apply, use the built in scaling options by se
to scale to. Usually, you want to set this to the monitor's native resolution, e.g.
1920x1080 for full HD. You can play around with a few different filters using
*gfx.scale_back_buffer_filter* which impacts image quality/blurriness on upscaling.
If you want to use this with old d3d8 games (IIDX 9-13), you have to use the d3d8to9
library from bemanitools-supplement because the d3d8 hook module cannot support this
upscaling feature. Make sure to set *misc.use_d3d9_hooks=true*.

View File

@@ -93,6 +93,22 @@ IIDX occasionally fails to boot with a "USBIO (FM-DL TIMEOUT)" error. If this
happens, run the game again.
# Troubleshooting and FAQ
## The game does not start at all
If you try to run iidx16 or iidx17 and you see one of the following outputs when
running the gamestart-XX.bat script:
```
Failed to launch hook EXE: 00000002
```
or
```
Injecting: iidxhook3.dll
Debug active process
Resuming remote process...
```
Make sure to check if you are using non htpac'd executables on iidx16 and iidx17
and also non htpac'd libraries/dll files on iidx17. These won't work with BT
and injecting the hook libraries.
## The game does not run "well" (frame drops, drifting offsync etc)
This can be related to various issues:

View File

@@ -2,8 +2,8 @@
#define AC_IO_KFCA_H
#define AC_IO_CMD_KFCA_POLL 0x0113
#define AC_IO_CMD_KFCA_UNK_0120 0x0120
#define AC_IO_CMD_KFCA_UNK_0128 0x0128
#define AC_IO_CMD_KFCA_WATCHDOG 0x0120
#define AC_IO_CMD_KFCA_AMP_CONTROL 0x0128
#define AC_IO_KFCA_IN_GPIO_SYS_COIN 0x04
/* ... AC_IO_KFCA_IN_GPIO_SYS_COIN2 0x08 (maybe?) */
@@ -14,6 +14,7 @@
#define AC_IO_KFCA_IN_GPIO_0_B 0x0002
#define AC_IO_KFCA_IN_GPIO_0_A 0x0004
#define AC_IO_KFCA_IN_GPIO_0_START 0x0008
#define AC_IO_KFCA_IN_GPIO_0_RECORDER 0x0010
#define AC_IO_KFCA_IN_GPIO_0_HEADPHONE 0x0020
#define AC_IO_KFCA_IN_GPIO_1_FX_R 0x0008
@@ -39,6 +40,7 @@ struct ac_io_kfca_poll_in {
struct ac_io_kfca_poll_out {
uint32_t gpio;
uint8_t pwm[18];
uint8_t unk[2];
};
#pragma pack(pop)

View File

@@ -5,5 +5,6 @@ libs_aciodrv := \
src_aciodrv := \
device.c \
icca.c \
kfca.c \
port.c \

100
src/main/aciodrv/kfca.c Normal file
View File

@@ -0,0 +1,100 @@
#define LOG_MODULE "aciodrv-kfca"
#include <string.h>
#include <stdio.h>
#include "aciodrv/device.h"
#include "util/log.h"
static bool aciodrv_kfca_watchdog_start(uint8_t node_id)
{
// exit early and don't actually call watchdog
// the watchdog call actually returns different sized packets depending on the state
// this results in an issue during packet processing (see: #68)
return true;
/*
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG);
msg.cmd.nbytes = 2;
msg.cmd.nbytes = 2;
// uint16_t: 6000
msg.cmd.raw[0] = 23;
msg.cmd.raw[1] = 112;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + 2)) {
log_warning("Starting watchdog failed");
return false;
}
log_warning("Started watchdog of node %d, status: %d",
node_id, msg.cmd.status);
return true;
*/
}
static bool aciodrv_kfca_amp(uint8_t node_id)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
msg.cmd.nbytes = 4;
// yes this sets the amp to 100% volume
// TODO: expose this to sdvxio instead at some point
msg.cmd.raw[0] = 0;
msg.cmd.raw[1] = 0;
msg.cmd.raw[2] = 0;
msg.cmd.raw[3] = 0;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}
log_warning("Started AMP node %d", node_id);
return true;
}
bool aciodrv_kfca_init(uint8_t node_id)
{
if (!aciodrv_kfca_watchdog_start(node_id)) {
return false;
}
if (!aciodrv_kfca_amp(node_id)) {
return false;
}
return true;
}
bool aciodrv_kfca_poll(uint8_t node_id, const struct ac_io_kfca_poll_out* pout, struct ac_io_kfca_poll_in* pin)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
msg.cmd.nbytes = sizeof(*pout);
/* buffer size of data we expect */
msg.cmd.kfca_poll_out = *pout;
if (!aciodrv_send_and_recv(&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}
if (pin != NULL) {
memcpy(pin, &msg.cmd.kfca_poll_in, sizeof(*pin));
}
return true;
}

30
src/main/aciodrv/kfca.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef ACIODRV_KFCA_H
#define ACIODRV_KFCA_H
#include "acio/kfca.h"
/**
* Initialize an KFCA node.
*
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_kfca_init(uint8_t node_id);
/**
* Poll the KFCA io board
*
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
* @return True on success, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool aciodrv_kfca_poll(uint8_t node_id, const struct ac_io_kfca_poll_out* pout, struct ac_io_kfca_poll_in* pin);
#endif

View File

@@ -6,4 +6,5 @@ libs_aciotest := \
src_aciotest := \
icca.c \
kfca.c \
main.c \

75
src/main/aciotest/kfca.c Normal file
View File

@@ -0,0 +1,75 @@
#include "aciotest/kfca.h"
#include "acio/acio.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "aciodrv/kfca.h"
bool aciotest_kfca_handler_init(uint8_t node_id, void** ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t*) *ctx) = 0;
return aciodrv_kfca_init(node_id);
}
bool aciotest_kfca_handler_update(uint8_t node_id, void* ctx)
{
struct ac_io_kfca_poll_in pin;
struct ac_io_kfca_poll_out pout;
static int gpio_test_pin = 0;
static int gpio_test_counter = 0;
memset(&pout, 0, sizeof(pout));
pout.gpio |= 1 << gpio_test_pin;
pout.gpio = ac_io_u32(pout.gpio);
if (!aciodrv_kfca_poll(node_id, &pout, &pin)) {
return false;
}
pin.adc[0] = ac_io_u16(pin.adc[0]);
pin.adc[1] = ac_io_u16(pin.adc[1]);
pin.gpio[0] = ac_io_u16(pin.gpio[0]);
pin.gpio[1] = ac_io_u16(pin.gpio[1]);
printf(">>> KFCA %d: GPIO ON %d\n"
"BTN A B C D: %d %d %d %d\n"
"FX-L R: %d %d\n"
"VOL L: %d\n"
"VOL R: %d\n"
"START COIN TEST SERV REC HP: %d %d %d %d %d %d\n",
node_id, gpio_test_pin,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_A,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_B,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_C,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_D,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_FX_L,
pin.gpio[1] & AC_IO_KFCA_IN_GPIO_1_FX_R,
(pin.adc[0] >> 6) & 0x3FF,
(pin.adc[1] >> 6) & 0x3FF,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_START,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_COIN,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_TEST,
(pin.gpio_sys) & AC_IO_KFCA_IN_GPIO_SYS_SERVICE,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_RECORDER,
pin.gpio[0] & AC_IO_KFCA_IN_GPIO_0_HEADPHONE
);
++gpio_test_counter;
if (gpio_test_counter >= 4) {
gpio_test_counter = 0;
++gpio_test_pin;
if (gpio_test_pin >= 16) {
gpio_test_pin = 0;
}
}
return true;
}

10
src/main/aciotest/kfca.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef ACIOTEST_KFCA_H
#define ACIOTEST_KFCA_H
#include <stdint.h>
#include <stdbool.h>
bool aciotest_kfca_handler_init(uint8_t node_id, void** ctx);
bool aciotest_kfca_handler_update(uint8_t node_id, void* ctx);
#endif

View File

@@ -8,6 +8,7 @@
#include "aciotest/handler.h"
#include "aciotest/icca.h"
#include "aciotest/kfca.h"
#include "util/log.h"
@@ -29,6 +30,13 @@ static bool aciotest_assign_handler(char product[4],
return true;
}
if (!memcmp(product, "KFCA", 4)){
handler->init = aciotest_kfca_handler_init;
handler->update = aciotest_kfca_handler_update;
return true;
}
return false;
}

View File

@@ -10,8 +10,8 @@
enum sdvx_io_in_gpio_sys_bit {
SDVX_IO_IN_GPIO_SYS_COIN = 2,
SDVX_IO_IN_GPIO_SYS_TEST = 4,
SDVX_IO_IN_GPIO_SYS_SERVICE = 5,
SDVX_IO_IN_GPIO_SYS_SERVICE = 4,
SDVX_IO_IN_GPIO_SYS_TEST = 5,
};
enum sdvx_io_in_gpio_0_bit {
@@ -19,7 +19,8 @@ enum sdvx_io_in_gpio_0_bit {
SDVX_IO_IN_GPIO_0_B = 1,
SDVX_IO_IN_GPIO_0_A = 2,
SDVX_IO_IN_GPIO_0_START = 3,
SDVX_IO_IN_GPIO_0_HEADPHONE = 4,
SDVX_IO_IN_GPIO_0_RECORDER = 4,
SDVX_IO_IN_GPIO_0_HEADPHONE = 5,
};
enum sdvx_io_in_gpio_1_bit {

View File

@@ -0,0 +1,8 @@
libs += bio2emu
libs_bio2emu := \
acioemu \
src_bio2emu := \
emu.c \
setupapi.c \

103
src/main/bio2emu/emu.c Normal file
View File

@@ -0,0 +1,103 @@
#include <windows.h>
#include <ntdef.h>
#include <devioctl.h>
#include <ntddser.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>
#include "acioemu/addr.h"
#include "acioemu/emu.h"
#include "hook/iohook.h"
#include "hooklib/rs232.h"
#include "bio2emu/emu.h"
#include "bio2emu/setupapi.h"
#include "imports/avs.h"
#include "util/defs.h"
#include "util/iobuf.h"
#include "util/log.h"
#include "util/str.h"
#include "util/array.h"
static struct array bio2_active_ports;
void bio2emu_init()
{
array_init(&bio2_active_ports);
bio2emu_setupapi_hook_init(&bio2_active_ports);
}
void bio2emu_port_init(struct bio2emu_port* bio2_emu)
{
// BIO2 seems like ACIO with just 1 device
ac_io_emu_init(&bio2_emu->acio, bio2_emu->wport);
rs232_hook_add_fd(bio2_emu->acio.fd);
*array_append(struct bio2emu_port*, &bio2_active_ports) = bio2_emu;
}
void bio2emu_port_fini(struct bio2emu_port* bio2_emu)
{
ac_io_emu_fini(&bio2_emu->acio);
}
HRESULT bio2emu_port_dispatch_irp(struct irp *irp)
{
const struct ac_io_message *msg;
HRESULT hr;
log_assert(irp != NULL);
struct bio2emu_port* check = NULL;
struct bio2emu_port* selected_emu = NULL;
for (size_t i = 0 ; i < bio2_active_ports.nitems ; i++) {
check = *array_item(struct bio2emu_port*, &bio2_active_ports, i);
if (ac_io_emu_match_irp(&check->acio, irp)) {
selected_emu = check;
}
}
if (!selected_emu) {
return irp_invoke_next(irp);
}
struct ac_io_emu* emu = &selected_emu->acio;
for (;;) {
hr = ac_io_emu_dispatch_irp(emu, irp);
if (hr != S_OK) {
return hr;
}
msg = ac_io_emu_request_peek(emu);
switch (msg->addr) {
case 0:
ac_io_emu_cmd_assign_addrs(emu, msg, 1);
break;
case 1:
selected_emu->dispatcher(selected_emu, msg);
break;
case AC_IO_BROADCAST:
log_warning("Broadcast(?) message on BIO2 bus?");
break;
default:
log_warning("BIO2 message on unhandled bus address: %d", msg->addr);
break;
}
ac_io_emu_request_pop(emu);
}
}

27
src/main/bio2emu/emu.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef BIO2EMU_EMU_H
#define BIO2EMU_EMU_H
#include "hook/iohook.h"
#include "acioemu/emu.h"
struct bio2emu_port;
struct ac_io_message;
typedef void (*bio2_bi2a_dispatcher)(struct bio2emu_port *emu, const struct ac_io_message *req);
struct bio2emu_port {
struct ac_io_emu acio;
const char* port;
const wchar_t* wport;
bio2_bi2a_dispatcher dispatcher;
};
void bio2emu_init();
void bio2emu_port_init(struct bio2emu_port* bio2emu_emu);
void bio2emu_port_fini(struct bio2emu_port* bio2emu_emu);
HRESULT bio2emu_port_dispatch_irp(struct irp *irp);
#endif

401
src/main/bio2emu/setupapi.c Normal file
View File

@@ -0,0 +1,401 @@
#define LOG_MODULE "setupapi-hook"
#include <windows.h>
#include <initguid.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include "hook/table.h"
#include "bio2emu/setupapi.h"
#include "bio2emu/emu.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/time.h"
static struct array* bio2_assigned_ports = NULL;
DEFINE_GUID(GUID_COM_BUS_ENUMERATOR,
0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);
#define MAX_INSTANCES_HOOKED 16
#define CUSTOM_DEVICE_INSTANCE 0x3113ca70
#define CUSTOM_DEVICE_INSTANCE_MASK 0xfffffff0
#define CUSTOM_DEVICE_INSTANCE_IDXMASK 0x0000000f
static void* CUSTOM_DEVICE_HANDLE;
static struct HKEY__ CUSTOM_REGISTRY_HANDLE[MAX_INSTANCES_HOOKED];
// end result should be like BIO2(VIDEO)(COM4)
static const char DEVICE_PROPERTY_VALUE[] = "BIO2(VIDEO)(";
static const size_t DEVICE_PROPERTY_LENGTH = 12;
static const char devpath[] = "USB\\VID_5730&PID_804C&MI_00\\000";
static const size_t devpathsize = 32;
// check if HKEY handle is one of ours
static BOOL check_if_match(HKEY ptr, HKEY base) {
return (ptr >= &base[0]) && (ptr <= &base[MAX_INSTANCES_HOOKED - 1]);
}
// turn HKEY handle back into idx
static size_t get_match_index(HKEY ptr, HKEY base) {
for (size_t i = 0; i < MAX_INSTANCES_HOOKED; ++i) {
if (ptr == &base[i]) {
return i;
}
}
return -1;
}
// check if devinst is on of ours (can't use pointer since this is a DWORD)
static BOOL check_instances_limit(DWORD devinst) {
if ((devinst & CUSTOM_DEVICE_INSTANCE_MASK) != CUSTOM_DEVICE_INSTANCE) {
return false;
}
size_t num = devinst & CUSTOM_DEVICE_INSTANCE_IDXMASK;
if (num >= MAX_INSTANCES_HOOKED) {
return false;
}
if (num >= bio2_assigned_ports->nitems) {
return false;
}
return true;
}
//
// hooked functions
//
static BOOL my_SetupDiDestroyDeviceInfoList(
HDEVINFO DeviceInfoSet
);
static BOOL (*real_SetupDiDestroyDeviceInfoList)(
HDEVINFO DeviceInfoSet
);
static BOOL my_SetupDiEnumDeviceInfo(
HDEVINFO DeviceInfoSet,
DWORD MemberIndex,
PSP_DEVINFO_DATA DeviceInfoData
);
static BOOL (*real_SetupDiEnumDeviceInfo)(
HDEVINFO DeviceInfoSet,
DWORD MemberIndex,
PSP_DEVINFO_DATA DeviceInfoData
);
static HKEY my_SetupDiOpenDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
REGSAM samDesired
);
static HKEY (*real_SetupDiOpenDevRegKey)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
REGSAM samDesired
);
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize
);
static BOOL (*real_SetupDiGetDeviceRegistryPropertyA)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize
);
static BOOL my_SetupDiGetDeviceInfoListDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
);
static BOOL (*real_SetupDiGetDeviceInfoListDetailA)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
);
static HDEVINFO my_SetupDiGetClassDevsA(
CONST GUID *ClassGuid,
PCSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
static HDEVINFO(*real_SetupDiGetClassDevsA)(
CONST GUID *ClassGuid,
PCSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
static CONFIGRET my_CM_Get_Device_IDA(
DEVINST dnDevInst,
PSTR Buffer,
ULONG BufferLen,
ULONG ulFlags
);
static CONFIGRET(*real_CM_Get_Device_IDA)(
DEVINST dnDevInst,
PSTR Buffer,
ULONG BufferLen,
ULONG ulFlags
);
static const struct hook_symbol bio2emu_setupapi_syms[] = {
{
.name = "SetupDiDestroyDeviceInfoList",
.patch = my_SetupDiDestroyDeviceInfoList,
.link = (void **) &real_SetupDiDestroyDeviceInfoList
},
{
.name = "SetupDiEnumDeviceInfo",
.patch = my_SetupDiEnumDeviceInfo,
.link = (void **) &real_SetupDiEnumDeviceInfo
},
{
.name = "SetupDiOpenDevRegKey",
.patch = my_SetupDiOpenDevRegKey,
.link = (void **) &real_SetupDiOpenDevRegKey
},
{
.name = "SetupDiGetDeviceRegistryPropertyA",
.patch = my_SetupDiGetDeviceRegistryPropertyA,
.link = (void **) &real_SetupDiGetDeviceRegistryPropertyA
},
{
.name = "SetupDiGetDeviceInfoListDetailA",
.patch = my_SetupDiGetDeviceInfoListDetailA,
.link = (void **) &real_SetupDiGetDeviceInfoListDetailA
},
{
.name = "SetupDiGetClassDevsA",
.patch = my_SetupDiGetClassDevsA,
.link = (void **) &real_SetupDiGetClassDevsA
},
{
.name = "CM_Get_Device_IDA",
.patch = my_CM_Get_Device_IDA,
.link = (void **) &real_CM_Get_Device_IDA
},
};
static LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
static LSTATUS (*real_RegQueryValueExA)(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
static const struct hook_symbol bio2emu_Advapi32_syms[] = {
{
.name = "RegQueryValueExA",
.patch = my_RegQueryValueExA,
.link = (void **) &real_RegQueryValueExA
},
};
static BOOL my_SetupDiDestroyDeviceInfoList(
HDEVINFO DeviceInfoSet
){
if (DeviceInfoSet == &CUSTOM_DEVICE_HANDLE){
log_info("Inside: %s", __FUNCTION__);
return true;
}
return real_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
}
static BOOL my_SetupDiEnumDeviceInfo(
HDEVINFO DeviceInfoSet,
DWORD MemberIndex,
PSP_DEVINFO_DATA DeviceInfoData
){
if (DeviceInfoSet == &CUSTOM_DEVICE_HANDLE){
log_info("%s: Loaded idx %ld", __FUNCTION__, MemberIndex);
if (MemberIndex < bio2_assigned_ports->nitems) {
DeviceInfoData->DevInst = CUSTOM_DEVICE_INSTANCE | MemberIndex;
return true;
}
return false;
}
return real_SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex, DeviceInfoData);
}
static HKEY my_SetupDiOpenDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
REGSAM samDesired
){
if (DeviceInfoSet == &CUSTOM_DEVICE_HANDLE){
if (check_instances_limit(DeviceInfoData->DevInst)){
log_info("%s: matched instance", __FUNCTION__);
return &CUSTOM_REGISTRY_HANDLE[DeviceInfoData->DevInst & CUSTOM_DEVICE_INSTANCE_IDXMASK];
}
}
return real_SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired);
}
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize
){
if (DeviceInfoSet == &CUSTOM_DEVICE_HANDLE){
if (check_instances_limit(DeviceInfoData->DevInst)){
struct bio2emu_port* selected_port = *array_item(struct bio2emu_port*, bio2_assigned_ports, DeviceInfoData->DevInst & CUSTOM_DEVICE_INSTANCE_IDXMASK);
size_t portname_len = strlen(selected_port->port);
size_t required_size = (DEVICE_PROPERTY_LENGTH + portname_len + 1 + 1); // + 1 for ')', + 1 for NULL
if (PropertyBuffer && (PropertyBufferSize >= required_size)){
char* PropBuffStr = (char*)PropertyBuffer;
strcpy(PropBuffStr, DEVICE_PROPERTY_VALUE);
strcpy(PropBuffStr + DEVICE_PROPERTY_LENGTH, selected_port->port);
strcpy(PropBuffStr + DEVICE_PROPERTY_LENGTH + portname_len, ")");
log_info("%s: Done copying property name [%s]", __FUNCTION__, PropBuffStr);
} else {
log_info("%s: Returning size", __FUNCTION__);
*RequiredSize = required_size;
}
}
log_info("%s: STUB RETURN", __FUNCTION__);
return true;
}
return real_SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
}
static BOOL my_SetupDiGetDeviceInfoListDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
){
if (DeviceInfoSet == &CUSTOM_DEVICE_HANDLE){
log_info("Inside: %s", __FUNCTION__);
return true;
}
return real_SetupDiGetDeviceInfoListDetailA(DeviceInfoSet, DeviceInfoSetDetailData);
}
static HDEVINFO my_SetupDiGetClassDevsA(
CONST GUID *ClassGuid,
PCSTR Enumerator,
HWND hwndParent,
DWORD Flags
){
if (ClassGuid) {
if (IsEqualGUID(ClassGuid, &GUID_COM_BUS_ENUMERATOR)){
log_info("Inside: %s", __FUNCTION__);
return &CUSTOM_DEVICE_HANDLE;
}
}
return real_SetupDiGetClassDevsA(ClassGuid, Enumerator, hwndParent, Flags);
}
static LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
){
if (check_if_match(hKey, CUSTOM_REGISTRY_HANDLE)){
if (strcmp(lpValueName, "PortName") == 0) {
if (lpData){
size_t portidx = get_match_index(hKey, CUSTOM_REGISTRY_HANDLE);
struct bio2emu_port* selected_port = *array_item(struct bio2emu_port*, bio2_assigned_ports, portidx);
strncpy((char*)lpData, selected_port->port, *lpcbData);
log_info("%s: Queried %s", __FUNCTION__, selected_port->port);
return ERROR_SUCCESS;
}
return ERROR_MORE_DATA;
}
}
return real_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
}
static CONFIGRET my_CM_Get_Device_IDA(
DEVINST dnDevInst,
PSTR Buffer,
ULONG BufferLen,
ULONG ulFlags
){
if (Buffer && BufferLen > devpathsize) {
if (check_instances_limit(dnDevInst)) {
log_info("%s: Injecting custom parent ID for BIO2", __FUNCTION__);
strcpy(Buffer, devpath);
Buffer[devpathsize - 1] = '\0' + (dnDevInst & CUSTOM_DEVICE_INSTANCE_IDXMASK);
log_info("%s: %s", __FUNCTION__, Buffer);
return CR_SUCCESS;
}
}
return real_CM_Get_Device_IDA(dnDevInst, Buffer, BufferLen, ulFlags);
}
void bio2emu_setupapi_hook_init(struct array* bio2_ports)
{
bio2_assigned_ports = bio2_ports;
hook_table_apply(
NULL,
"setupapi.dll",
bio2emu_setupapi_syms,
lengthof(bio2emu_setupapi_syms));
hook_table_apply(
NULL,
"Advapi32.dll",
bio2emu_Advapi32_syms,
lengthof(bio2emu_Advapi32_syms));
log_info("Inserted setupapi hooks");
}

View File

@@ -0,0 +1,8 @@
#ifndef BIO2EMU_SETUPAPI_H
#define BIO2EMU_SETUPAPI_H
#include "util/array.h"
void bio2emu_setupapi_hook_init(struct array* bio2_ports);
#endif

View File

@@ -47,14 +47,14 @@ void kfca_dispatch_request(const struct ac_io_message *req)
break;
case AC_IO_CMD_KFCA_UNK_0120:
log_misc("AC_IO_CMD_KFCA_UNK_%04X(%d)", cmd_code, req->addr);
case AC_IO_CMD_KFCA_WATCHDOG:
log_misc("AC_IO_CMD_KFCA_WATCHDOG(%d)", req->addr);
kfca_report_status(req, 0x00);
break;
case AC_IO_CMD_KFCA_UNK_0128:
log_misc("AC_IO_CMD_KFCA_UNK_%04X(%d)", cmd_code, req->addr);
case AC_IO_CMD_KFCA_AMP_CONTROL:
log_misc("AC_IO_CMD_KFCA_AMP_CONTROL(%d)", req->addr);
kfca_report_nil(req);
break;

View File

@@ -2,6 +2,7 @@ libs += hook
src_hook := \
com-proxy.c \
d3d9.c \
iohook.c \
pe.c \
peb.c \

654
src/main/hook/d3d9.c Normal file
View File

@@ -0,0 +1,654 @@
#define LOG_MODULE "hook-d3d9"
#include "hook/com-proxy.h"
#include "hook/d3d9.h"
#include "hook/table.h"
#include "util/log.h"
/* ------------------------------------------------------------------------------------------------------------------ */
static IDirect3D9* (STDCALL* real_Direct3DCreate9)(UINT sdk_ver);
static BOOL (STDCALL *real_EnumDisplayDevicesA)(
const char *dev_name, DWORD dev_num, DISPLAY_DEVICEA *info,
DWORD flags);
static HWND (STDCALL *real_CreateWindowExA)(
DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam);
static BOOL (STDCALL* real_GetClientRect)(HWND hWnd, LPRECT lpRect);
static HRESULT (STDCALL* real_CreateDevice)(IDirect3D9 *self, UINT adapter, D3DDEVTYPE type, HWND hwnd, DWORD flags,
D3DPRESENT_PARAMETERS *pp, IDirect3DDevice9 **pdev);
static HRESULT (STDCALL* real_CreateTexture)(IDirect3DDevice9* self, UINT width, UINT height, UINT levels, DWORD usage,
D3DFORMAT format, D3DPOOL pool, IDirect3DTexture9** texture, HANDLE* shared_handle);
static HRESULT (STDCALL* real_BeginScene)(IDirect3DDevice9* self);
static HRESULT (STDCALL* real_EndScene)(IDirect3DDevice9* self);
static HRESULT (STDCALL* real_Present)(IDirect3DDevice9* self,
CONST RECT *pSourceRect, CONST RECT *pDestRect,
HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion);
static HRESULT (STDCALL* real_SetRenderState)(IDirect3DDevice9* self,
D3DRENDERSTATETYPE State, DWORD Value);
static HRESULT (STDCALL *real_DrawPrimitiveUP)(
IDirect3DDevice9* self, D3DPRIMITIVETYPE primitive_type,
UINT primitive_count, const void *data, UINT stride);
/* ------------------------------------------------------------------------------------------------------------------ */
static IDirect3D9* STDCALL my_Direct3DCreate9(UINT sdk_ver);
static BOOL STDCALL my_EnumDisplayDevicesA(const char *dev_name, DWORD dev_num, DISPLAY_DEVICEA *info, DWORD flags);
static HWND STDCALL my_CreateWindowExA(
DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam);
static BOOL STDCALL my_GetClientRect(HWND hWnd, LPRECT lpRect);
static HRESULT STDCALL my_CreateDevice(IDirect3D9 *self, UINT adapter, D3DDEVTYPE type, HWND hwnd, DWORD flags,
D3DPRESENT_PARAMETERS *pp, IDirect3DDevice9 **pdev);
static HRESULT STDCALL my_CreateTexture(IDirect3DDevice9* self, UINT width, UINT height, UINT levels, DWORD usage,
D3DFORMAT format, D3DPOOL pool, IDirect3DTexture9** texture, HANDLE* shared_handle);
static HRESULT STDCALL my_BeginScene(IDirect3DDevice9* self);
static HRESULT STDCALL my_EndScene(IDirect3DDevice9* self);
static HRESULT STDCALL my_Present(IDirect3DDevice9* self,
CONST RECT *pSourceRect, CONST RECT *pDestRect,
HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion);
static HRESULT STDCALL my_SetRenderState(IDirect3DDevice9* self,
D3DRENDERSTATETYPE State, DWORD Value);
static HRESULT STDCALL my_DrawPrimitiveUP(
IDirect3DDevice9* self, D3DPRIMITIVETYPE primitive_type,
UINT primitive_count, const void *data, UINT stride);
/* ------------------------------------------------------------------------------------------------------------------ */
static const struct hook_symbol hook_d3d9_hook_syms[] = {
{
.name = "Direct3DCreate9",
.patch = my_Direct3DCreate9,
.link = (void **) &real_Direct3DCreate9
},
};
static const struct hook_symbol hook_d3d9_hook_user32_syms[] = {
{
.name = "EnumDisplayDevicesA",
.patch = my_EnumDisplayDevicesA,
.link = (void **) &real_EnumDisplayDevicesA
},
{
.name = "CreateWindowExA",
.patch = my_CreateWindowExA,
.link = (void **) &real_CreateWindowExA
},
{
.name = "GetClientRect",
.patch = my_GetClientRect,
.link = (void **) &real_GetClientRect
},
};
/* ------------------------------------------------------------------------------------------------------------------ */
static HRESULT hook_d3d9_irp_handler_real_invalid(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_ctx_create(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_enum_display_devices(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_create_window_ex(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_get_client_rect(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_dev_create_device(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_dev_create_texture(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_dev_begin_scene(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_dev_end_scene(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_dev_present(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_dev_set_render_state(struct hook_d3d9_irp* irp);
static HRESULT hook_d3d9_irp_handler_real_dev_draw_primitive_up(struct hook_d3d9_irp* irp);
/* ------------------------------------------------------------------------------------------------------------------ */
static const hook_d3d9_irp_handler_t hook_d3d9_irp_real_handlers[] = {
[HOOK_D3D9_IRP_OP_INVALID] = hook_d3d9_irp_handler_real_invalid,
[HOOK_D3D9_IRP_OP_CTX_CREATE] = hook_d3d9_irp_handler_real_ctx_create,
[HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES] = hook_d3d9_irp_handler_real_enum_display_devices,
[HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX] = hook_d3d9_irp_handler_real_create_window_ex,
[HOOK_D3D9_IRP_OP_GET_CLIENT_RECT] = hook_d3d9_irp_handler_real_get_client_rect,
[HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE] = hook_d3d9_irp_handler_real_dev_create_device,
[HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE] = hook_d3d9_irp_handler_real_dev_create_texture,
[HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE] = hook_d3d9_irp_handler_real_dev_begin_scene,
[HOOK_D3D9_IRP_OP_DEV_END_SCENE] = hook_d3d9_irp_handler_real_dev_end_scene,
[HOOK_D3D9_IRP_OP_DEV_PRESENT] = hook_d3d9_irp_handler_real_dev_present,
[HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE] = hook_d3d9_irp_handler_real_dev_set_render_state,
[HOOK_D3D9_IRP_OP_DEV_DRAW_PRIMITIVE_UP] = hook_d3d9_irp_handler_real_dev_draw_primitive_up,
};
static const hook_d3d9_irp_handler_t* hook_d3d9_handlers;
static size_t hook_d3d9_nhandlers;
/* ------------------------------------------------------------------------------------------------------------------ */
static IDirect3D9* STDCALL my_Direct3DCreate9(UINT sdk_ver)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_CTX_CREATE;
irp.args.ctx_create.sdk_ver = sdk_ver;
irp.args.ctx_create.ctx = NULL;
hr = hook_d3d9_irp_invoke_next(&irp);
if (hr == S_OK && irp.args.ctx_create.ctx) {
return irp.args.ctx_create.ctx;
} else {
return NULL;
}
}
static BOOL STDCALL my_EnumDisplayDevicesA(const char *dev_name, DWORD dev_num, DISPLAY_DEVICEA *info, DWORD flags)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES;
irp.args.enum_display_devices.dev_name = dev_name;
irp.args.enum_display_devices.dev_num = dev_num;
irp.args.enum_display_devices.info = info;
irp.args.enum_display_devices.flags = flags;
hr = hook_d3d9_irp_invoke_next(&irp);
if (hr == S_OK) {
return TRUE;
} else {
return FALSE;
}
}
static HWND STDCALL my_CreateWindowExA(
DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX;
irp.args.create_window_ex.ex_style = dwExStyle;
irp.args.create_window_ex.class_name = lpClassName;
irp.args.create_window_ex.window_name = lpWindowName;
irp.args.create_window_ex.style = dwStyle;
irp.args.create_window_ex.x = X;
irp.args.create_window_ex.y = Y;
irp.args.create_window_ex.width = nWidth;
irp.args.create_window_ex.height = nHeight;
irp.args.create_window_ex.wnd_parent = hWndParent;
irp.args.create_window_ex.menu = hMenu;
irp.args.create_window_ex.instance = hInstance;
irp.args.create_window_ex.param = lpParam;
irp.args.create_window_ex.result = NULL;
hr = hook_d3d9_irp_invoke_next(&irp);
if (hr == S_OK && irp.args.create_window_ex.result != NULL) {
return irp.args.create_window_ex.result;
} else {
return NULL;
}
}
static BOOL STDCALL my_GetClientRect(HWND hWnd, LPRECT lpRect)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_GET_CLIENT_RECT;
irp.args.get_client_rect.wnd = hWnd;
irp.args.get_client_rect.rect = lpRect;
hr = hook_d3d9_irp_invoke_next(&irp);
if (hr == S_OK) {
return TRUE;
} else {
return FALSE;
}
}
static HRESULT STDCALL my_CreateDevice(
IDirect3D9 *self, UINT adapter, D3DDEVTYPE type, HWND hwnd, DWORD flags,
D3DPRESENT_PARAMETERS *pp, IDirect3DDevice9 **pdev)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE;
irp.args.ctx_create_device.self = self;
irp.args.ctx_create_device.adapter = adapter;
irp.args.ctx_create_device.type = type;
irp.args.ctx_create_device.hwnd = hwnd;
irp.args.ctx_create_device.flags = flags;
irp.args.ctx_create_device.pp = pp;
irp.args.ctx_create_device.pdev = pdev;
hr = hook_d3d9_irp_invoke_next(&irp);
return hr;
}
static HRESULT STDCALL my_CreateTexture(IDirect3DDevice9* self, UINT width, UINT height, UINT levels, DWORD usage,
D3DFORMAT format, D3DPOOL pool, IDirect3DTexture9** texture, HANDLE* shared_handle)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE;
irp.args.dev_create_texture.self = self;
irp.args.dev_create_texture.width = width;
irp.args.dev_create_texture.height = height;
irp.args.dev_create_texture.levels = levels;
irp.args.dev_create_texture.usage = usage;
irp.args.dev_create_texture.format = format;
irp.args.dev_create_texture.pool = pool;
irp.args.dev_create_texture.texture = texture;
irp.args.dev_create_texture.shared_handle = shared_handle;
hr = hook_d3d9_irp_invoke_next(&irp);
return hr;
}
static HRESULT STDCALL my_BeginScene(IDirect3DDevice9* self)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE;
irp.args.dev_begin_scene.self = self;
hr = hook_d3d9_irp_invoke_next(&irp);
return hr;
}
static HRESULT STDCALL my_EndScene(IDirect3DDevice9* self)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_DEV_END_SCENE;
irp.args.dev_end_scene.self = self;
hr = hook_d3d9_irp_invoke_next(&irp);
return hr;
}
static HRESULT STDCALL my_Present(IDirect3DDevice9* self,
CONST RECT *pSourceRect, CONST RECT *pDestRect,
HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_DEV_PRESENT;
irp.args.dev_present.self = self;
irp.args.dev_present.source_rect = pSourceRect;
irp.args.dev_present.dest_rect = pDestRect;
irp.args.dev_present.dest_window_override = hDestWindowOverride;
irp.args.dev_present.dirty_region = pDirtyRegion;
hr = hook_d3d9_irp_invoke_next(&irp);
return hr;
}
static HRESULT STDCALL my_SetRenderState(IDirect3DDevice9* self,
D3DRENDERSTATETYPE State, DWORD Value)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE;
irp.args.dev_set_render_state.self = self;
irp.args.dev_set_render_state.state = State;
irp.args.dev_set_render_state.value = Value;
hr = hook_d3d9_irp_invoke_next(&irp);
return hr;
}
static HRESULT STDCALL my_DrawPrimitiveUP(
IDirect3DDevice9* self, D3DPRIMITIVETYPE primitive_type,
UINT primitive_count, const void *data, UINT stride)
{
struct hook_d3d9_irp irp;
HRESULT hr;
memset(&irp, 0, sizeof(irp));
irp.op = HOOK_D3D9_IRP_OP_DEV_DRAW_PRIMITIVE_UP;
irp.args.dev_draw_primitive_up.self = self;
irp.args.dev_draw_primitive_up.primitive_type = primitive_type;
irp.args.dev_draw_primitive_up.primitive_count = primitive_count;
irp.args.dev_draw_primitive_up.data = data;
irp.args.dev_draw_primitive_up.stride = stride;
hr = hook_d3d9_irp_invoke_next(&irp);
return hr;
}
/* ------------------------------------------------------------------------------------------------------------------ */
static HRESULT hook_d3d9_irp_handler_invoke_real(struct hook_d3d9_irp* irp)
{
hook_d3d9_irp_handler_t handler;
log_assert(irp != NULL);
log_assert(irp->op < lengthof(hook_d3d9_irp_real_handlers));
handler = hook_d3d9_irp_real_handlers[irp->op];
log_assert(handler != NULL);
return handler(irp);
}
static HRESULT hook_d3d9_irp_handler_real_invalid(struct hook_d3d9_irp* irp)
{
log_fatal("Called invalid handler");
return E_FAIL;
}
static HRESULT hook_d3d9_irp_handler_real_ctx_create(struct hook_d3d9_irp* irp)
{
IDirect3D9* api;
IDirect3D9Vtbl* api_vtbl;
struct com_proxy* api_proxy;
log_assert(irp);
api = real_Direct3DCreate9(irp->args.ctx_create.sdk_ver);
if (api == NULL) {
return E_FAIL;
}
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
api_vtbl = api_proxy->vptr;
real_CreateDevice = api_vtbl->CreateDevice;
api_vtbl->CreateDevice = my_CreateDevice;
irp->args.ctx_create.ctx = (IDirect3D9*) api_proxy;
return S_OK;
}
static HRESULT hook_d3d9_irp_handler_real_enum_display_devices(struct hook_d3d9_irp* irp)
{
BOOL res;
log_assert(irp);
res = real_EnumDisplayDevicesA(
irp->args.enum_display_devices.dev_name,
irp->args.enum_display_devices.dev_num,
irp->args.enum_display_devices.info,
irp->args.enum_display_devices.flags);
if (res == TRUE) {
return S_OK;
} else {
return E_FAIL;
}
}
static HRESULT hook_d3d9_irp_handler_real_create_window_ex(struct hook_d3d9_irp* irp)
{
log_assert(irp);
irp->args.create_window_ex.result = real_CreateWindowExA(
irp->args.create_window_ex.ex_style,
irp->args.create_window_ex.class_name,
irp->args.create_window_ex.window_name,
irp->args.create_window_ex.style,
irp->args.create_window_ex.x,
irp->args.create_window_ex.y,
irp->args.create_window_ex.width,
irp->args.create_window_ex.height,
irp->args.create_window_ex.wnd_parent,
irp->args.create_window_ex.menu,
irp->args.create_window_ex.instance,
irp->args.create_window_ex.param);
if (irp->args.create_window_ex.result) {
return S_OK;
} else {
return E_FAIL;
}
}
static HRESULT hook_d3d9_irp_handler_real_get_client_rect(struct hook_d3d9_irp* irp)
{
BOOL res;
log_assert(irp);
res = real_GetClientRect(
irp->args.get_client_rect.wnd,
irp->args.get_client_rect.rect);
if (res == TRUE) {
return S_OK;
} else {
return E_FAIL;
}
}
static HRESULT hook_d3d9_irp_handler_real_dev_create_device(struct hook_d3d9_irp* irp)
{
HRESULT hr;
IDirect3DDevice9* api;
IDirect3DDevice9Vtbl* api_vtbl;
struct com_proxy *api_proxy;
log_assert(irp);
hr = real_CreateDevice(
irp->args.ctx_create_device.self,
irp->args.ctx_create_device.adapter,
irp->args.ctx_create_device.type,
irp->args.ctx_create_device.hwnd,
irp->args.ctx_create_device.flags,
irp->args.ctx_create_device.pp,
irp->args.ctx_create_device.pdev);
if (hr != S_OK) {
return hr;
}
api = *irp->args.ctx_create_device.pdev;
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
api_vtbl = api_proxy->vptr;
real_CreateTexture = api_vtbl->CreateTexture;
api_vtbl->CreateTexture = my_CreateTexture;
real_BeginScene = api_vtbl->BeginScene;
api_vtbl->BeginScene = my_BeginScene;
real_EndScene = api_vtbl->EndScene;
api_vtbl->EndScene = my_EndScene;
real_Present = api_vtbl->Present;
api_vtbl->Present = my_Present;
real_SetRenderState = api_vtbl->SetRenderState;
api_vtbl->SetRenderState = my_SetRenderState;
real_DrawPrimitiveUP = api_vtbl->DrawPrimitiveUP;
api_vtbl->DrawPrimitiveUP = my_DrawPrimitiveUP;
*irp->args.ctx_create_device.pdev = (IDirect3DDevice9*) api_proxy;
return hr;
}
static HRESULT hook_d3d9_irp_handler_real_dev_create_texture(struct hook_d3d9_irp* irp)
{
log_assert(irp);
return real_CreateTexture(
irp->args.dev_create_texture.self,
irp->args.dev_create_texture.width,
irp->args.dev_create_texture.height,
irp->args.dev_create_texture.levels,
irp->args.dev_create_texture.usage,
irp->args.dev_create_texture.format,
irp->args.dev_create_texture.pool,
irp->args.dev_create_texture.texture,
irp->args.dev_create_texture.shared_handle);
}
static HRESULT hook_d3d9_irp_handler_real_dev_begin_scene(struct hook_d3d9_irp* irp)
{
log_assert(irp);
return real_BeginScene(irp->args.dev_begin_scene.self);
}
static HRESULT hook_d3d9_irp_handler_real_dev_end_scene(struct hook_d3d9_irp* irp)
{
log_assert(irp);
return real_EndScene(irp->args.dev_end_scene.self);
}
static HRESULT hook_d3d9_irp_handler_real_dev_present(struct hook_d3d9_irp* irp)
{
log_assert(irp);
return real_Present(
irp->args.dev_present.self,
irp->args.dev_present.source_rect,
irp->args.dev_present.dest_rect,
irp->args.dev_present.dest_window_override,
irp->args.dev_present.dirty_region);
}
static HRESULT hook_d3d9_irp_handler_real_dev_set_render_state(struct hook_d3d9_irp* irp)
{
log_assert(irp);
return real_SetRenderState(
irp->args.dev_set_render_state.self,
irp->args.dev_set_render_state.state,
irp->args.dev_set_render_state.value);
}
static HRESULT hook_d3d9_irp_handler_real_dev_draw_primitive_up(struct hook_d3d9_irp* irp)
{
log_assert(irp);
return real_DrawPrimitiveUP(
irp->args.dev_draw_primitive_up.self,
irp->args.dev_draw_primitive_up.primitive_type,
irp->args.dev_draw_primitive_up.primitive_count,
irp->args.dev_draw_primitive_up.data,
irp->args.dev_draw_primitive_up.stride);
}
/* ------------------------------------------------------------------------------------------------------------------ */
void hook_d3d9_init(const hook_d3d9_irp_handler_t *handlers, size_t nhandlers)
{
log_assert(handlers);
log_assert(nhandlers > 0);
hook_d3d9_handlers = handlers;
hook_d3d9_nhandlers = nhandlers;
hook_table_apply(
NULL,
"d3d9.dll",
hook_d3d9_hook_syms,
lengthof(hook_d3d9_hook_syms));
hook_table_apply(
NULL,
"user32.dll",
hook_d3d9_hook_user32_syms,
lengthof(hook_d3d9_hook_user32_syms));
}
HRESULT hook_d3d9_irp_invoke_next(struct hook_d3d9_irp* irp)
{
hook_d3d9_irp_handler_t handler;
HRESULT hr;
log_assert(irp != NULL);
log_assert(irp->next_handler <= hook_d3d9_nhandlers);
if (irp->next_handler < hook_d3d9_nhandlers) {
handler = hook_d3d9_handlers[irp->next_handler++];
hr = handler(irp);
if (FAILED(hr)) {
irp->next_handler = (size_t) -1;
}
} else {
irp->next_handler = (size_t) -1;
hr = hook_d3d9_irp_handler_invoke_real(irp);
}
return hr;
}

192
src/main/hook/d3d9.h Normal file
View File

@@ -0,0 +1,192 @@
#ifndef HOOK_D3D9_H
#define HOOK_D3D9_H
/**
* This module hooks the d3d9 API and abstracts it using IRPs (like iohook).
* It allows hiding the COM stuff which is required to be handled when interacting with d3d9.
* Furthermore, this module supports chaining of multiple handlers and more flexible and structured
* dispatching on the available operations (more can be added when required, obviously).
*
* @author icex2
*/
#include <d3d9.h>
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
/**
* D3D9 ops (currently) supported by this hook module.
*/
enum hook_d3d9_irp_op {
HOOK_D3D9_IRP_OP_INVALID = 0,
HOOK_D3D9_IRP_OP_CTX_CREATE = 1,
HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES = 2,
HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX = 3,
HOOK_D3D9_IRP_OP_GET_CLIENT_RECT = 4,
HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE = 5,
HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE = 6,
HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE = 7,
HOOK_D3D9_IRP_OP_DEV_END_SCENE = 8,
HOOK_D3D9_IRP_OP_DEV_PRESENT = 9,
HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE = 10,
HOOK_D3D9_IRP_OP_DEV_DRAW_PRIMITIVE_UP = 11,
};
/**
* Main irp structure which gets passed around as a parameter to chain multiple
* handler calls and avoiding one handler per request/function.
*/
struct hook_d3d9_irp {
enum hook_d3d9_irp_op op;
union {
/**
* Params of Direct3DCreate9.
*/
struct {
UINT sdk_ver;
// Return value of call
IDirect3D9* ctx;
} ctx_create;
/**
* Params of EnumDisplayDevicesA.
*/
struct {
const char* dev_name;
DWORD dev_num;
DISPLAY_DEVICEA* info;
DWORD flags;
} enum_display_devices;
/**
* Params of CreateWindowExA.
*/
struct {
DWORD ex_style;
LPCSTR class_name;
LPCSTR window_name;
DWORD style;
int x;
int y;
int width;
int height;
HWND wnd_parent;
HMENU menu;
HINSTANCE instance;
LPVOID param;
HWND result;
} create_window_ex;
/**
* Params of GetClientRect.
*/
struct {
HWND wnd;
LPRECT rect;
} get_client_rect;
/**
* Params of IDirect3D9_CreateDevice.
*/
struct {
IDirect3D9* self;
UINT adapter;
D3DDEVTYPE type;
HWND hwnd;
DWORD flags;
D3DPRESENT_PARAMETERS* pp;
IDirect3DDevice9** pdev;
} ctx_create_device;
/**
* Params of IDirect3DDevice9_CreateTexture.
*/
struct {
IDirect3DDevice9* self;
UINT width;
UINT height;
UINT levels;
DWORD usage;
D3DFORMAT format;
D3DPOOL pool;
IDirect3DTexture9** texture;
HANDLE* shared_handle;
} dev_create_texture;
/**
* Params of IDirect3DDevice9_BeginScene.
*/
struct {
IDirect3DDevice9* self;
} dev_begin_scene;
/**
* Params of IDirect3DDevice9_EndScene.
*/
struct {
IDirect3DDevice9* self;
} dev_end_scene;
/**
* Params of IDirect3DDevice9_Present.
*/
struct {
IDirect3DDevice9* self;
CONST RECT* source_rect;
CONST RECT* dest_rect;
HWND dest_window_override;
CONST RGNDATA* dirty_region;
} dev_present;
/**
* Params of IDirect3DDevice9_SetRenderState.
*/
struct {
IDirect3DDevice9* self;
D3DRENDERSTATETYPE state;
DWORD value;
} dev_set_render_state;
/**
* Params of IDirect3DDevice9_DrawPrimitiveUP.
*/
struct {
IDirect3DDevice9* self;
D3DPRIMITIVETYPE primitive_type;
UINT primitive_count;
const void *data;
UINT stride;
} dev_draw_primitive_up;
} args;
size_t next_handler;
};
/**
* D3D9 IRP handler function typedef.
*/
typedef HRESULT (*hook_d3d9_irp_handler_t)(struct hook_d3d9_irp* irp);
/**
* Initialize the d3d9 hook module.
*
* @param handlers The handlers to install which will be called once one of the hooked functions is called.
* @param nhandlers Number of handlers to install (length of provided array above).
*/
void hook_d3d9_init(const hook_d3d9_irp_handler_t *handlers, size_t nhandlers);
/**
* Main invoke next function.
*
* Call this from your handlers if you are done handling and to pass on the IRP to the further installed IRP handlers.
* At the end of the chain, calls the real function.
*
* @param irp Pointer to a valid IRP.
* @return S_OK on success, error otherwise (depending on the irp op).
*/
HRESULT hook_d3d9_irp_invoke_next(struct hook_d3d9_irp* irp);
#endif

View File

@@ -4,6 +4,7 @@
#include <devioctl.h>
#include <ntddser.h>
#include <stdbool.h>
#include <string.h>
#include "hook/iohook.h"
@@ -11,6 +12,7 @@
#include "util/hr.h"
#include "util/log.h"
#include "util/array.h"
/* RS232 API hooks */
@@ -29,55 +31,130 @@ static BOOL STDCALL my_SetupComm(HANDLE fd, uint32_t in_q, uint32_t out_q);
static BOOL STDCALL my_SetCommBreak(HANDLE fd);
static BOOL STDCALL my_ClearCommBreak(HANDLE fd);
static BOOL (STDCALL *real_ClearCommError)(
HANDLE fd,
uint32_t *errors,
COMSTAT *status);
static BOOL (STDCALL *real_EscapeCommFunction)(HANDLE fd, uint32_t func);
static BOOL (STDCALL *real_GetCommState)(HANDLE fd, DCB *dcb);
static BOOL (STDCALL *real_PurgeComm)(HANDLE fd, uint32_t flags);
static BOOL (STDCALL *real_SetCommMask)(HANDLE fd, uint32_t mask);
static BOOL (STDCALL *real_SetCommState)(HANDLE fd, const DCB *dcb);
static BOOL (STDCALL *real_SetCommTimeouts)(HANDLE fd, COMMTIMEOUTS *timeouts);
static BOOL (STDCALL *real_SetupComm)(HANDLE fd, uint32_t in_q, uint32_t out_q);
static BOOL (STDCALL *real_SetCommBreak)(HANDLE fd);
static BOOL (STDCALL *real_ClearCommBreak)(HANDLE fd);
static struct hook_symbol rs232_syms[] = {
{
.name = "ClearCommError",
.patch = my_ClearCommError,
.link = (void*) &real_ClearCommError,
},
{
.name = "EscapeCommFunction",
.patch = my_EscapeCommFunction,
.link = (void*) &real_EscapeCommFunction,
},
{
.name = "GetCommState",
.patch = my_GetCommState,
.link = (void*) &real_GetCommState,
},
{
.name = "PurgeComm",
.patch = my_PurgeComm,
.link = (void*) &real_PurgeComm,
},
{
.name = "SetCommMask",
.patch = my_SetCommMask,
.link = (void*) &real_SetCommMask,
},
{
.name = "SetCommState",
.patch = my_SetCommState,
.link = (void*) &real_SetCommState,
},
{
.name = "SetCommTimeouts",
.patch = my_SetCommTimeouts,
.link = (void*) &real_SetCommTimeouts,
},
{
.name = "SetupComm",
.patch = my_SetupComm,
.link = (void*) &real_SetupComm,
},
{
.name = "SetCommBreak",
.patch = my_SetCommBreak,
.link = (void*) &real_SetCommBreak,
},
{
.name = "ClearCommBreak",
.patch = my_ClearCommBreak,
.link = (void*) &real_ClearCommBreak,
},
};
static struct array hooked_port_fds;
static bool rs232_limit_hooks;
static CRITICAL_SECTION hooked_port_fds_cs;
/**
* Some notes:
*
* The point of this, is to allow rs232 hooks for only the descriptors that we hook.
* This is because the emulation here is incomplete.
* Although the IOCTL's do end up being passed to the real hardware, the game rejects some of the responses and hangs.
* By short circuiting out, and calling the real Comm functions instead, it works.
* And hence, card-reader passthrough works on IIDX25+/SDVX5+ finally without eamio-real
*
*/
void rs232_hook_init(void)
{
array_init(&hooked_port_fds);
InitializeCriticalSection(&hooked_port_fds_cs);
hook_table_apply(NULL, "kernel32.dll", rs232_syms, lengthof(rs232_syms));
log_info("IO Hook RS232 ioctl subsystem initialized");
}
void rs232_hook_limit_hooks(void)
{
rs232_limit_hooks = true;
}
static BOOL rs232_check_fd(HANDLE fd) {
HANDLE check;
if (rs232_limit_hooks){
EnterCriticalSection(&hooked_port_fds_cs);
for (size_t i = 0 ; i < hooked_port_fds.nitems ; i++) {
check = *array_item(HANDLE, &hooked_port_fds, i);
if (check == fd) {
LeaveCriticalSection(&hooked_port_fds_cs);
return TRUE;
}
}
LeaveCriticalSection(&hooked_port_fds_cs);
return FALSE;
}
return TRUE;
}
void rs232_hook_add_fd(HANDLE fd)
{
EnterCriticalSection(&hooked_port_fds_cs);
*array_append(HANDLE, &hooked_port_fds) = fd;
LeaveCriticalSection(&hooked_port_fds_cs);
}
static BOOL STDCALL my_ClearCommError(
HANDLE fd,
uint32_t *errors,
@@ -87,6 +164,10 @@ static BOOL STDCALL my_ClearCommError(
SERIAL_STATUS llstatus;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_ClearCommError(fd, errors, status);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@@ -180,6 +261,10 @@ static BOOL STDCALL my_EscapeCommFunction(HANDLE fd, uint32_t cmd)
uint32_t ioctl;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_EscapeCommFunction(fd, cmd);
}
switch (cmd) {
case CLRBREAK: ioctl = IOCTL_SERIAL_SET_BREAK_OFF; break;
case CLRDTR: ioctl = IOCTL_SERIAL_CLR_DTR; break;
@@ -221,6 +306,10 @@ static BOOL STDCALL my_GetCommState(HANDLE fd, DCB *dcb)
SERIAL_LINE_CONTROL line_control;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_GetCommState(fd, dcb);
}
/*
* Validate params
*/
@@ -393,6 +482,10 @@ static BOOL STDCALL my_PurgeComm(HANDLE fd, uint32_t flags)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_PurgeComm(fd, flags);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@@ -415,6 +508,10 @@ static BOOL STDCALL my_SetCommMask(HANDLE fd, uint32_t mask)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommMask(fd, mask);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@@ -440,6 +537,10 @@ static BOOL STDCALL my_SetCommState(HANDLE fd, const DCB *dcb)
SERIAL_LINE_CONTROL line_control;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommState(fd, dcb);
}
if (dcb == NULL) {
log_warning("%s: DCB pointer is NULL", __func__);
SetLastError(ERROR_INVALID_PARAMETER);
@@ -616,6 +717,10 @@ static BOOL STDCALL my_SetCommTimeouts(HANDLE fd, COMMTIMEOUTS *src)
SERIAL_TIMEOUTS dest;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommTimeouts(fd, src);
}
dest.ReadIntervalTimeout = src->ReadIntervalTimeout;
dest.ReadTotalTimeoutMultiplier = src->ReadTotalTimeoutMultiplier;
dest.ReadTotalTimeoutConstant = src->ReadTotalTimeoutConstant;
@@ -644,6 +749,10 @@ static BOOL STDCALL my_SetupComm(HANDLE fd, uint32_t in_q, uint32_t out_q)
SERIAL_QUEUE_SIZE qs;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetupComm(fd, in_q, out_q);
}
qs.InSize = in_q;
qs.OutSize = out_q;
@@ -668,6 +777,10 @@ static BOOL STDCALL my_SetCommBreak(HANDLE fd)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_SetCommBreak(fd);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;
@@ -687,6 +800,10 @@ static BOOL STDCALL my_ClearCommBreak(HANDLE fd)
struct irp irp;
HRESULT hr;
if (!rs232_check_fd(fd)) {
return real_ClearCommBreak(fd);
}
memset(&irp, 0, sizeof(irp));
irp.op = IRP_OP_IOCTL;
irp.fd = fd;

View File

@@ -1,6 +1,21 @@
#ifndef HOOKLIB_RS232_H
#define HOOKLIB_RS232_H
#include <windows.h>
void rs232_hook_init(void);
/**
* Allows limiting the rs232 to only the specified fd's
*/
void rs232_hook_limit_hooks(void);
/**
* Adds the specified fd to the list of descriptors to hook
*
* @param fd descriptor to hook
*/
void rs232_hook_add_fd(HANDLE fd);
#endif

View File

@@ -11,7 +11,6 @@ src_iidxhook-util := \
config-gfx.c \
config-misc.c \
config-sec.c \
d3d8.c \
d3d9.c \
eamuse.c \
effector.c \

View File

@@ -14,6 +14,7 @@
#include "acioemu/icca.h"
#include "hook/iohook.h"
#include "hooklib/rs232.h"
#include "iidxhook-util/acio.h"
@@ -41,6 +42,8 @@ void iidxhook_util_acio_init(bool legacy_mode)
ac_io_emu_icca_init(&iidxhook_util_acio_emu_icca[i],
&iidxhook_util_acio_emu, i);
}
rs232_hook_add_fd(iidxhook_util_acio_emu.fd);
}
void iidxhook_util_acio_fini(void)

View File

@@ -220,13 +220,13 @@ void iidxhook_config_gfx_get(struct iidxhook_config_gfx* config_gfx,
}
if (!strcmp(tmp, "none")) {
config_gfx->scale_back_buffer_filter = D3D9_BACK_BUFFER_SCALE_FILTER_NONE;
config_gfx->scale_back_buffer_filter = IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_NONE;
} else if (!strcmp(tmp, "linear")) {
config_gfx->scale_back_buffer_filter = D3D9_BACK_BUFFER_SCALE_FILTER_LINEAR;
config_gfx->scale_back_buffer_filter = IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_LINEAR;
} else if (!strcmp(tmp, "point")) {
config_gfx->scale_back_buffer_filter = D3D9_BACK_BUFFER_SCALE_FILTER_POINT;
config_gfx->scale_back_buffer_filter = IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_POINT;
} else {
config_gfx->scale_back_buffer_filter = D3D9_BACK_BUFFER_SCALE_FILTER_NONE;
config_gfx->scale_back_buffer_filter = IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_NONE;
log_warning("Invalid value for key '%s' specified, fallback "
"to default '%s'", IIDXHOOK_CONFIG_GFX_SCALE_BACK_BUFFER_FILTER_KEY,

View File

@@ -17,7 +17,7 @@ struct iidxhook_config_gfx {
int32_t window_height;
uint16_t scale_back_buffer_width;
uint16_t scale_back_buffer_height;
enum d3d9_back_buffer_scale_filter scale_back_buffer_filter;
enum iidxhook_util_d3d9_back_buffer_scale_filter scale_back_buffer_filter;
};
void iidxhook_config_gfx_init(struct cconfig* config);

View File

@@ -1,600 +0,0 @@
#define LOG_MODULE "d3d8-hook"
#include <windows.h>
#include <d3d8.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "iidxhook-util/d3d8.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/time.h"
/* ------------------------------------------------------------------------- */
struct d3d8_vertex {
float x;
float y;
float z;
uint32_t color;
uint32_t unknown;
float tu;
float tv;
};
/* ------------------------------------------------------------------------- */
static HWND STDCALL my_CreateWindowExA(
DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam);
static HRESULT STDCALL my_CreateDevice(
IDirect3D8 *self, UINT adapter, D3DDEVTYPE type, HWND hwnd,
DWORD flags, D3DPRESENT_PARAMETERS *pp, IDirect3DDevice8 **pdev);
static HRESULT STDCALL my_SetRenderState(IDirect3DDevice8* self,
D3DRENDERSTATETYPE State, DWORD Value);
static HRESULT STDCALL my_DrawPrimitiveUP(
IDirect3DDevice8* self, D3DPRIMITIVETYPE primitive_type,
UINT primitive_count, const void *data, UINT stride);
static HRESULT STDCALL my_Present(IDirect3DDevice8* self,
CONST RECT *pSourceRect, CONST RECT *pDestRect,
HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion);
static IDirect3D8* STDCALL my_Direct3DCreate8(UINT sdk_ver);
static void execute_monitor_check(IDirect3DDevice8Vtbl* api_vtbl,
IDirect3DDevice8* pdev);
static void calc_win_size_with_framed(HWND hwnd, DWORD x, DWORD y,
DWORD width, DWORD height, LPWINDOWPOS wp);
/* ------------------------------------------------------------------------- */
static bool gfx_windowed = false;
static int32_t gfx_window_width = -1;
static int32_t gfx_window_height = -1;
static bool gfx_window_framed = false;
static float gfx_frame_rate_limit = 0.0f;
static bool gfx_fix_stretched_bg_videos = false;
static bool gfx_fix_iidx_12_fog = false;
static bool gfx_fix_iidx_13_lighting = false;
static d3d8_monitor_check_result_callback_t gfx_monitor_check_cb = NULL;
/* ------------------------------------------------------------------------- */
static IDirect3D8* (STDCALL *real_Direct3DCreate8)(UINT sdk_ver);
static HWND (STDCALL *real_CreateWindowExA)(
DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam);
static HRESULT (STDCALL* real_SetRenderState)(IDirect3DDevice8* self,
D3DRENDERSTATETYPE State, DWORD Value);
static HRESULT (STDCALL *real_DrawPrimitiveUP)(
IDirect3DDevice8* self, D3DPRIMITIVETYPE primitive_type,
UINT primitive_count, const void *data, UINT stride);
static HRESULT (STDCALL* real_Present)(IDirect3DDevice8* self,
CONST RECT *pSourceRect, CONST RECT *pDestRect,
HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion);
static const struct hook_symbol d3d8_hook_syms[] = {
{
.name = "Direct3DCreate8",
.patch = my_Direct3DCreate8,
.link = (void **) &real_Direct3DCreate8,
},
};
static const struct hook_symbol d3d8_hook_user32_syms[] = {
{
.name = "CreateWindowExA",
.patch = my_CreateWindowExA,
.link = (void **) &real_CreateWindowExA,
},
};
/* ------------------------------------------------------------------------- */
static bool float_equal(float a, float b, float eps)
{
return fabs(a - b) < eps;
}
static HWND STDCALL my_CreateWindowExA(
DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle,
int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam)
{
if (gfx_windowed && gfx_window_framed) {
/* use a different style */
dwStyle |= WS_OVERLAPPEDWINDOW;
/* also show mouse cursor */
ShowCursor(TRUE);
}
if (gfx_window_width != -1 && gfx_window_height != -1) {
log_misc("Overriding window size from %dx%d with %dx%d", nWidth,
nHeight, gfx_window_width, gfx_window_height);
nWidth = gfx_window_width;
nHeight = gfx_window_height;
}
HWND hwnd = real_CreateWindowExA(dwExStyle, lpClassName, lpWindowName,
dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance,
lpParam);
if (hwnd == INVALID_HANDLE_VALUE) {
return hwnd;
}
if (gfx_windowed && gfx_window_framed) {
/* we have to adjust the window size, because the window needs to be a
slightly bigger than the rendering resolution (window caption and
stuff is included in the window size) */
WINDOWPOS wp;
calc_win_size_with_framed(hwnd, X, Y, nWidth, nHeight, &wp);
SetWindowPos(hwnd, 0, wp.x, wp.y, wp.cx, wp.cy, 0);
X = wp.x;
Y = wp.y;
nWidth = wp.cx;
nHeight = wp.cy;
}
return hwnd;
}
static HRESULT STDCALL my_CreateDevice(
IDirect3D8 *self, UINT adapter, D3DDEVTYPE type, HWND hwnd, DWORD flags,
D3DPRESENT_PARAMETERS *pp, IDirect3DDevice8 **pdev)
{
IDirect3D8 *real = COM_PROXY_UNWRAP(self);
HRESULT hr;
IDirect3DDevice8* api;
IDirect3DDevice8Vtbl *api_vtbl;
struct com_proxy *api_proxy;
char* error;
log_info("Direct3D8 CreateDevice hook hit");
/* Fix a long-standing bug in IIDX */
if (flags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) {
flags &= ~D3DCREATE_PUREDEVICE;
}
if (gfx_windowed) {
log_misc("Window mode");
pp->hDeviceWindow = 0;
pp->Windowed = TRUE;
pp->FullScreen_RefreshRateInHz = 0;
pp->FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
}
/* If we don't do this, the game will crash on some versions of windows
on either fullscreen or windowed or even both. Also, further reports
about textures with green glowing borders are gone as well when applying
this */
D3DDISPLAYMODE mode;
IDirect3D8_GetAdapterDisplayMode(real, adapter, &mode);
pp->BackBufferFormat = mode.Format;
hr = IDirect3D8_CreateDevice(real, adapter, type, hwnd, flags, pp, pdev);
if (hr != S_OK) {
switch (hr) {
case D3DERR_INVALIDCALL:
error = "invalid call";
break;
case D3DERR_NOTAVAILABLE:
error = "not available";
break;
case D3DERR_OUTOFVIDEOMEMORY:
error = "out of video memory";
break;
default:
error = "unknown";
break;
}
log_warning("Creating D3D8 device failed: %lX, %s", hr, error);
return hr;
}
api = *pdev;
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
api_vtbl = api_proxy->vptr;
real_DrawPrimitiveUP = api_vtbl->DrawPrimitiveUP;
api_vtbl->DrawPrimitiveUP = my_DrawPrimitiveUP;
real_SetRenderState = api_vtbl->SetRenderState;
api_vtbl->SetRenderState = my_SetRenderState;
real_Present = api_vtbl->Present;
api_vtbl->Present = my_Present;
*pdev = (IDirect3DDevice8*) api_proxy;
if (gfx_monitor_check_cb) {
execute_monitor_check(api_vtbl, *pdev);
}
return hr;
}
static IDirect3D8 *STDCALL my_Direct3DCreate8(UINT sdk_ver)
{
IDirect3D8 *api;
IDirect3D8Vtbl *api_vtbl;
struct com_proxy *api_proxy;
log_info("Direct3DCreate8 hook hit");
api = real_Direct3DCreate8(sdk_ver);
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
api_vtbl = api_proxy->vptr;
api_vtbl->CreateDevice = my_CreateDevice;
return (IDirect3D8 *) api_proxy;
}
static HRESULT STDCALL my_SetRenderState(IDirect3DDevice8* self,
D3DRENDERSTATETYPE State, DWORD Value)
{
if (gfx_fix_iidx_12_fog) {
if (State == D3DRS_FOGENABLE) {
Value = FALSE;
}
}
if (gfx_fix_iidx_13_lighting) {
if (State == D3DRS_LIGHTING) {
Value = FALSE;
}
}
return real_SetRenderState(self, State, Value);
}
static HRESULT STDCALL my_DrawPrimitiveUP(
IDirect3DDevice8* self, D3DPRIMITIVETYPE primitive_type,
UINT primitive_count, const void *data, UINT stride)
{
/* trap the background video texture to fix the UVs for newer hardware
background videos are rendered to a 512x512 texture, but the videos
are 312x416 in size (on IIDX RED)
the old hardware supported this to render correctly
(VMs might work as well) with the UVs set in the code but on newer
hardware, the video frame gets stretched to the full 512x512 texture
The tex UVs are only set to a subsection of that texture thus just a
subsection is rendered (video appears to be stretched)
to fix this, we simply set the UVs to apply to the full texture
Quad for BG Video (triangle fan!):
164/0 ------- 476/0
| |
| |
| |
| |
| |
| |
164/416 ------- 476/416
Original UVs for the quad
0/0,8125 ------- 0,609375/0,812500
| |
| |
| |
| |
| |
| |
0/0 ------- 0,609375/0
*/
if ( gfx_fix_stretched_bg_videos && primitive_type == 6 &&
primitive_count == 2 && stride == 28) {
struct d3d8_vertex* vertices = (struct d3d8_vertex*) data;
/*
log_info("Video Tex: %f/%f %f/%f %f/%f %f/%f",
vertices[0].x, vertices[0].y,
vertices[1].x, vertices[1].y,
vertices[2].x, vertices[2].y,
vertices[3].x, vertices[3].y);
*/
/* Fix full screen background videos (e.g. DistorteD intro sequence) */
if ( vertices[0].x >= 0.0f && vertices[0].x < 1.0f &&
vertices[0].y >= 0.0f && vertices[0].y < 1.0f &&
vertices[1].x > 639.0f && vertices[1].x < 641.0f &&
vertices[1].y >= 0.0f && vertices[1].y < 1.0f &&
vertices[2].x > 639.0f && vertices[2].x < 641.0f &&
vertices[2].y > 479.0f && vertices[2].y < 481.0f &&
vertices[3].x >= 0.0f && vertices[3].x < 1.0f &&
vertices[3].y > 479.0f && vertices[3].y < 481.0f) {
/* fix UVs
1.0f / 640 or 480 fixes the diagonal seam connecting the two
triangles which is visible on some GPUs (why? idk)
*/
vertices[0].tu = 0.0f + 1.0f / 640;
vertices[0].tv = 1.0f;
vertices[1].tu = 1.0f;
vertices[1].tv = 1.0f;
vertices[2].tu = 1.0f;
vertices[2].tv = 0.0f + 1.0f / 480;
vertices[3].tu = 0.0f + 1.0f / 640;
vertices[3].tv = 0.0f + 1.0f / 480;
} else
/* another identifier, because there are other textures with 512x512 size
make sure we got the bg video only to not mess up anything else */
/* different versions have different themes and position the bg video
on slightly different positions (good job...) */
if ( /* single */
((vertices[0].x >= 164.0f && vertices[0].x <= 168.0f &&
float_equal(vertices[0].y, 0.0f, 0.1f)) &&
(vertices[1].x >= 472.0f && vertices[1].x <= 476.0f &&
float_equal(vertices[1].y, 0.0f, 0.1f)) &&
(vertices[2].x >= 472.0f && vertices[2].x <= 476.0f &&
float_equal(vertices[2].y, 416.0f, 0.1f)) &&
(vertices[3].x >= 164.0f && vertices[3].x <= 168.0f &&
float_equal(vertices[3].y, 416.0f, 0.1f))) ||
/* double top left */
((float_equal(vertices[0].x, 6.0f, 0.1f) &&
vertices[0].y >= 24.0f && vertices[0].y <= 28.0f) &&
(float_equal(vertices[1].x, 147.0f, 0.1f) &&
vertices[1].y >= 24.0f && vertices[1].y <= 28.0f) &&
(float_equal(vertices[2].x, 147.0f, 0.1f) &&
vertices[2].y >= 212.0f && vertices[2].y <= 216.0f) &&
(float_equal(vertices[3].x, 6.0f, 0.1f) &&
vertices[3].y >= 212.0f && vertices[3].y <= 216.0f)) ||
/* double bottom left */
((float_equal(vertices[0].x, 6.0f, 0.1f) &&
vertices[0].y >= 216.0f && vertices[0].y <= 220.0f) &&
(float_equal(vertices[1].x, 147.0f, 0.1f) &&
vertices[1].y >= 216.0f && vertices[1].y <= 220.0f) &&
(float_equal(vertices[2].x, 147.0f, 0.1) &&
vertices[2].y >= 404.0f && vertices[2].y <= 408.0f) &&
(float_equal(vertices[3].x, 6.0f, 0.1f) &&
vertices[3].y >= 404.0f && vertices[3].y <= 408.0f)) ||
/* double top right */
((vertices[0].x >= 493.0f && vertices[0].x <= 494.0f &&
vertices[0].y >= 24.0f && vertices[0].y <= 28.0f) &&
(vertices[1].x >= 634.0f && vertices[1].x <= 635.0f &&
vertices[1].y >= 24.0f && vertices[1].y <= 28.0f) &&
(vertices[2].x >= 634.0f && vertices[2].x <= 635.0f &&
vertices[2].y >= 212.0f && vertices[2].y <= 216.0f) &&
(vertices[3].x >= 493.0f && vertices[3].x <= 494.0f &&
vertices[3].y >= 212.0f && vertices[3].y <= 216.0f)) ||
/* double bottom right */
((vertices[0].x >= 493.0f && vertices[0].x <= 494.0f &&
vertices[0].y >= 216.0f && vertices[0].y <= 220.0f) &&
(vertices[1].x >= 634.0f && vertices[1].x <= 635.0f &&
vertices[1].y >= 216.0f && vertices[1].y <= 220.0f) &&
(vertices[2].x >= 634.0f && vertices[2].x <= 635.0f &&
vertices[2].y >= 404.0f && vertices[2].y <= 408.0f) &&
(vertices[3].x >= 493.0f && vertices[3].x <= 494.0f &&
vertices[3].y >= 404.0f && vertices[3].y <= 408.0f)))
{
/* fix UVs
1.0f / 512 fixes the diagonal seam connecting the two triangles
which is visible on some GPUs (why? idk)
*/
vertices[0].tu = 0.0f + 1.0f / 512;
vertices[0].tv = 1.0f;
vertices[1].tu = 1.0f;
vertices[1].tv = 1.0f;
vertices[2].tu = 1.0f;
vertices[2].tv = 0.0f + 1.0f / 512;
vertices[3].tu = 0.0f + 1.0f / 512;
vertices[3].tv = 0.0f + 1.0f / 512;
}
}
return real_DrawPrimitiveUP(self, primitive_type, primitive_count,
data, stride);
}
static HRESULT STDCALL my_Present(IDirect3DDevice8* self,
CONST RECT *pSourceRect, CONST RECT *pDestRect,
HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion)
{
static uint64_t current_time = 0;
HRESULT hr = real_Present(self, pSourceRect, pDestRect, hDestWindowOverride,
pDirtyRegion);
if (gfx_frame_rate_limit > 0.0f) {
if (current_time == 0) {
current_time = time_get_counter();
} else {
uint64_t frame_time = 1000000 / gfx_frame_rate_limit;
uint64_t dt = time_get_elapsed_us(
time_get_counter() - current_time);
while (dt < frame_time) {
/* waste some cpu time by polling
because we can't sleep for X us */
dt = time_get_elapsed_us(time_get_counter() - current_time);
}
current_time = time_get_counter();
}
}
return hr;
}
/* ------------------------------------------------------------------------- */
void d3d8_hook_init(void)
{
hook_table_apply(
NULL,
"d3d8.dll",
d3d8_hook_syms,
lengthof(d3d8_hook_syms));
hook_table_apply(
NULL,
"user32.dll",
d3d8_hook_user32_syms,
lengthof(d3d8_hook_user32_syms));
log_info("Inserted d3d8 graphics hooks");
}
void d3d8_set_windowed(bool framed, int32_t width, int32_t height)
{
gfx_windowed = true;
gfx_window_framed = framed;
gfx_window_width = width;
gfx_window_height = height;
}
void d3d8_set_frame_rate_limit(float limit)
{
if (limit < 0.0f) {
limit = 0.0f;
}
log_info("Limiting rendering frame rate to %f frames", limit);
gfx_frame_rate_limit = limit;
}
void d3d8_enable_monitor_check(d3d8_monitor_check_result_callback_t cb)
{
log_assert(cb);
gfx_monitor_check_cb = cb;
log_info("Enabled monitor check");
}
void d3d8_iidx_fix_stretched_bg_videos(void)
{
gfx_fix_stretched_bg_videos = true;
log_info("Fixing UVs of stretched BG videos");
}
void d3d8_iidx_fix_12_song_select_bg(void)
{
gfx_fix_iidx_12_fog = true;
log_info("Fixing Happy Sky bugged music select 3D background");
}
void d3d8_iidx_fix_13_song_select_bg(void)
{
gfx_fix_iidx_13_lighting = true;
log_info("Fixing DistorteD music select 3D background");
}
/* ------------------------------------------------------------------------- */
static void execute_monitor_check(IDirect3DDevice8Vtbl* api_vtbl,
IDirect3DDevice8* pdev)
{
log_info("Running monitor check...");
/* d3d8 does not provide anything like d3d9 with DrawText */
const uint32_t max_iterations = 60 * 30;
const uint32_t skip_frames = 60 * 1;
uint64_t accu_us = 0;
double result = 0;
uint32_t iterations = 0;
while (iterations < max_iterations) {
iterations++;
uint64_t start = time_get_counter();
api_vtbl->Clear(pdev, 0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0xFF, 0xFF, 0xFF), 0.0f, 0);
api_vtbl->BeginScene(pdev);
api_vtbl->EndScene(pdev);
api_vtbl->Present(pdev, NULL, NULL, NULL, NULL);
/* Skip the first inaccurate values */
if (iterations > skip_frames) {
accu_us += time_get_elapsed_us(time_get_counter() - start);
result = ((double) (iterations - skip_frames)) /
(accu_us / 1000.0 / 1000.0);
}
}
log_info("Monitor check done (total iterations %d), refesh rate: %f hz",
iterations, result);
/* Sanity check to ensure people notice that their current refresh rate
is way off. */
if (result < 55 || result > 65) {
log_warning("Monitor check result (%f hz) is not even near the "
"intended refresh rate of 60 hz. Fix your setup to ensure a "
"constant and as close to as possible 60 hz refresh rate.", result);
}
log_assert(gfx_monitor_check_cb);
gfx_monitor_check_cb(result);
}
static void calc_win_size_with_framed(HWND hwnd, DWORD x, DWORD y, DWORD width,
DWORD height, LPWINDOWPOS wp)
{
/* taken from dxwnd */
RECT rect;
DWORD style;
int max_x, max_y;
HMENU menu;
rect.left = x;
rect.top = y;
max_x = width;
max_y = height;
rect.right = x + max_x;
rect.bottom = y + max_y;
style = GetWindowLong(hwnd, GWL_STYLE);
menu = GetMenu(hwnd);
AdjustWindowRect(&rect, style, (menu != NULL));
/* shift down-right so that the border is visible
and also update the iPosX,iPosY upper-left coordinates
of the client area */
if (rect.left < 0) {
rect.right -= rect.left;
rect.left = 0;
}
if (rect.top < 0) {
rect.bottom -= rect.top;
rect.top = 0;
}
wp->x = rect.left;
wp->y = rect.top;
wp->cx = rect.right - rect.left;
wp->cy = rect.bottom - rect.top;
}

View File

@@ -1,73 +0,0 @@
#ifndef IIDXHOOK_D3D8_H
#define IIDXHOOK_D3D8_H
#include <stdbool.h>
/**
* Callback function to receive resulting refresh rate of monitor check.
*/
typedef void (*d3d8_monitor_check_result_callback_t)(double refresh_rate);
/**
* Hook some d3d8 related functions to patch gfx related stuff
* like enabling window mode.
*
* Games using d3d8:
* - IIDX: 9th to DD
*/
void d3d8_hook_init(void);
/**
* Set the game to window mode.
*
* @param framed True to add a window frame and make the window
* movable, resizable, minizable. False for no frame.
* @param width Width of the window. -1 to keep original width.
* @param height Height of the window. -1 to keep original height.
*/
void d3d8_set_windowed(bool framed, int32_t width, int32_t height);
/**
* Set a framerate limit for the rendering loop.
*
* Use this if the game won't sync up properly with vsync enabled.
*
* @limit Number of frames to limit the rendering loop to
*/
void d3d8_set_frame_rate_limit(float limit);
/**
* Enable a software a "monitor check" which determines the (avg.) refresh rate
* of the game. Ensure that your GPU is outputting a stable refresh rate to
* your monitor. Otherwise, the resulting values fluctuate a lot
*
* @param cb Callback to a function that receives the result of the monitor
* check once it completed.
*/
void d3d8_enable_monitor_check(d3d8_monitor_check_result_callback_t cb);
/**
* Fixes UV coordinates for background videos on
* IIDX Red to DD. Use this if you experience the game
* stretching the background videos
* (see implementation for further details)
*/
void d3d8_iidx_fix_stretched_bg_videos(void);
/**
* Fixes the 3D background displayed during song select by disabling fog.
* On some machines/GPUs the background is rendered completely white which
* is caused by buggy fog rendering. Fog is used to hide the rings appearing
* but that's quite 'far away' so disabling fog doesn't look bad.
*/
void d3d8_iidx_fix_12_song_select_bg(void);
/**
* Fixes the 3D background displayed during song select by disabling lighting.
* On some machines/GPUs the background is rendered completely black which
* is caused by buggy lighting. Disabling (dynamic) lighting sets the whole
* scene to ambient lighting which displays everything properly.
*/
void d3d8_iidx_fix_13_song_select_bg(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,123 +1,180 @@
#ifndef IIDXHOOK_D3D9_H
#define IIDXHOOK_D3D9_H
/**
* This module hooks into various D3D9 calls implementing a large set of features for IIDX games such as:
* window mode, frame buffer up-/downscaling, software rate limiting, software monitor check,...
*
* @author icex2
*/
#include <stdbool.h>
#include <stdint.h>
#include "hook/d3d9.h"
/**
* Filter types for scaling back buffer, e.g. upscaling for higher resolution monitors.
*/
enum d3d9_back_buffer_scale_filter {
D3D9_BACK_BUFFER_SCALE_FILTER_NONE = 0,
D3D9_BACK_BUFFER_SCALE_FILTER_LINEAR = 1,
D3D9_BACK_BUFFER_SCALE_FILTER_POINT = 2,
enum iidxhook_util_d3d9_back_buffer_scale_filter {
IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_NONE = 0,
IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_LINEAR = 1,
IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_POINT = 2,
};
/**
* Callback function to receive resulting refresh rate of monitor check.
*/
typedef void (*d3d9_monitor_check_result_callback_t)(double refresh_rate);
typedef void (*iidxhook_util_d3d9_monitor_check_result_callback_t)(double refresh_rate);
/**
* Hook some d3d9 functions to patch gfx related stuff
* like enabling window mode.
*
* Games using d3d9:
* - IIDX: Gold to Copula
* Config structure for this module. Enable/disable supported features.
*/
void d3d9_hook_init(void);
struct iidxhook_util_d3d9_config {
/**
* Enable/disable window mode. Consider combining with framed.
*/
bool windowed;
/**
* Enable a window frame and make the window movable, resizable, minizable.
*/
bool framed;
/**
* Override the default window height which is determined by the frame buffer size.
* Set this to 0 to disable the override.
*/
uint16_t override_window_width;
/**
* Override the default window width which is determined by the frame buffer size.
* Set this to 0 to disable the override.
*/
uint16_t override_window_height;
/**
* Set a software driven framerate limit for the rendering loop and lock to the specified refresh rate, e.g. 59.94.
* Use this if the game won't sync up properly with vsync enabled.
*/
float framerate_limit;
/**
* Override the GPU vendor ID identifier on display device enumeration.
* Use this to disable locking to specific GPU cards.
* Combine with the pci_pid parameter.
*
* Vendor ATI: 1002
*/
uint16_t pci_vid;
/**
* Override the GPU product ID identifier on display device enumeration.
* Use this to disable locking to specific GPU cards.
* Combine with the pci_pid parameter.
*
* PIDs:
* 7146: RV515 [Radeon X1300]
* 95C5: RV620 LE [Radeon HD 3450]
*/
uint16_t pci_pid;
/**
* Enable a software "monitor check" which determines the (avg.) refresh rate
* of the game. Ensure that your GPU is outputting a stable refresh rate to
* your monitor. Otherwise, the resulting values fluctuate a lot.
*
* Callback to a function that receives the result of the monitor check once it completed.
*/
iidxhook_util_d3d9_monitor_check_result_callback_t iidx09_to_19_monitor_check_cb;
/**
* Ported from d3d8 module to enable this when using d3d8to9.
*
* Fixes UV coordinates for background videos on IIDX Red to DD and a quad seam issue for 14 to 17.
* Use this if you experience the game stretching the background videos or seeing a quad seam
* (see implementation for further details).
*/
bool iidx11_to_17_fix_uvs_bg_videos;
/**
* Ported from d3d8 module to enable this when using d3d8to9.
*
* Fixes the 3D background displayed during song select by disabling fog.
* On some machines/GPUs the background is rendered completely white which
* is caused by buggy fog rendering. Fog is used to hide the rings appearing
* but that's quite 'far away' so disabling fog doesn't look bad.
*/
bool iidx12_fix_song_select_bg;
/**
* Ported from d3d8 module to enable this when using d3d8to9.
*
* Fixes the 3D background displayed during song select by disabling lighting.
* On some machines/GPUs the background is rendered completely black which
* is caused by buggy lighting. Disabling (dynamic) lighting sets the whole
* scene to ambient lighting which displays everything properly.
*/
bool iidx13_fix_song_select_bg;
/**
* Fixes a parameter on CreateTexture calls causing the game to crash with
* NVIDIA cards (on GOLD and possible newer)
*/
bool iidx14_to_19_nvidia_fix;
/**
* Scale the back buffer after a frame got rendered. This allows you to up-/downscale the final frame to display
* arbitrary resolutions, e.g. 640x480 -> 1920x1080 to allow displaying the game in the monitor's native resolution.
* This avoids over-/underscan (yes, that's still a thing with todays TVs) or leaving the upscaling to monitors/TVs
* that are doing a terrible job regarding picture quality or latency wise.
*
* @param width Target width to scale the frame to. 0 disables scaling entirely.
* @param height Target height to scale the frame to. 0 disables scaling entirely.
* @param filter Filtering method to use for scaling. Depending on how you scale, this can have an impact on the
* final image quality.
*/
uint16_t scale_back_buffer_width;
/**
* Back buffer scale height, see parameter scale_back_buffer_width for full doc.
*/
uint16_t scale_back_buffer_height;
/**
* Back buffer scale filter to apply, see parameter scale_back_buffer_width for full doc.
*/
enum iidxhook_util_d3d9_back_buffer_scale_filter scale_back_buffer_filter;
};
/**
* Set the game to window mode.
*
* @param framed True to add a window frame and make the window
* movable, resizable, minizable. False for no frame.
* @param width Width of the window. -1 to keep original width.
* @param height Height of the window. -1 to keep original height.
*/
void d3d9_set_windowed(bool framed, int32_t width, int32_t height);
/**
* Patch the GPU device ID detection to allow running the game with
* other GPUs than the ones it is locked to.
*
* @param vid Vendor ID to patch.
* @param pid Product ID to patch.
*/
void d3d9_set_pci_id(uint16_t vid, uint16_t pid);
/**
* Set a framerate limit for the rendering loop.
*
* Use this if the game won't sync up properly with vsync enabled.
*
* @limit Number of frames to limit the rendering loop to
*/
void d3d9_set_frame_rate_limit(float limit);
/**
* Enable a software a "monitor check" which determines the (avg.) refresh rate
* of the game. Ensure that your GPU is outputting a stable refresh rate to
* your monitor. Otherwise, the resulting values fluctuate a lot
* Initialize this hook module. Must be called before any other function of this module.
*
* @param cb Callback to a function that receives the result of the monitor
* check once it completed.
* Games using d3d9: IIDX 14 (Gold) to IIDX 27 (Rootage)
* For d3d8 based games (IIDX 9 to 13): use d3d8to9 wrapper to allow usage of this module.
*/
void d3d9_enable_monitor_check(d3d9_monitor_check_result_callback_t cb);
void iidxhook_util_d3d9_hook_init(void);
/**
* Ported from d3d8 module to enable this when using d3d8to9.
* Initialize the provided config struct with default values.
*
* Fixes UV coordinates for background videos on
* IIDX Red to DD. Use this if you experience the game
* stretching the background videos
* (see implementation for further details)
* @param config Pointer to an initialized struct to write default values to.
*/
void d3d9_iidx_fix_stretched_bg_videos(void);
void iidxhook_util_d3d9_init_config(struct iidxhook_util_d3d9_config* config);
/**
* Ported from d3d8 module to enable this when using d3d8to9.
* Configure this module by applying the provided config.
*
* Fixes the 3D background displayed during song select by disabling fog.
* On some machines/GPUs the background is rendered completely white which
* is caused by buggy fog rendering. Fog is used to hide the rings appearing
* but that's quite 'far away' so disabling fog doesn't look bad.
* @param config Config to apply.
*/
void d3d9_iidx_fix_12_song_select_bg(void);
void iidxhook_util_d3d9_configure(const struct iidxhook_util_d3d9_config* config);
/**
* Ported from d3d8 module to enable this when using d3d8to9.
* Main IRP handler call for this module. Must be set up with the hook/d3d9 module to receive calls from d3d9.
*
* Fixes the 3D background displayed during song select by disabling lighting.
* On some machines/GPUs the background is rendered completely black which
* is caused by buggy lighting. Disabling (dynamic) lighting sets the whole
* scene to ambient lighting which displays everything properly.
* @param irp Pointer to a valid IRP.
* @return S_OK on success, error otherwise (depending on the irp op).
*/
void d3d9_iidx_fix_13_song_select_bg(void);
/**
* Fixes a parameter on CreateTexture calls causing the game to crash with
* NVIDIA cards (on GOLD and possible newer)
*/
void d3d9_enable_nvidia_fix(void);
/**
* Fixes UV coordinates for background videos on
* (similar to the d3d8 games). But, this fixes the quad seam issue on 14 to
* 17, only.
*/
void d3d9_bg_video_seams_fix(void);
/**
* Scale the back buffer after a frame got rendered. This allows you to up-/downscale the final frame to display
* arbitrary resolutions, e.g. 640x480 -> 1920x1080 to allow displaying the game in the monitor's native resolution.
* This avoids over-/underscan (yes, that's still a thing with todays TVs) or leaving the upscaling to monitors/TVs
* that are doing a terrible job regarding picture quality or latency wise.
*
* @param width Target width to scale the frame to. 0 disables scaling entirely.
* @param height Target height to scale the frame to. 0 disables scaling entirely.
* @param filter Filtering method to use for scaling. Depending on how you scale, this can have an impact on the final
* image quality.
*/
void d3d9_scale_back_buffer(uint16_t width, uint16_t height, enum d3d9_back_buffer_scale_filter filter);
HRESULT iidxhook_util_d3d9_irp_handler(struct hook_d3d9_irp* irp);
#endif

View File

@@ -5,10 +5,8 @@
#include "util/log.h"
#define IIDXHOOK_CONFIG_MISC_HAPPY_SKY_MS_BG_FIX_KEY "misc.happy_sky_ms_bg_fix"
#define IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY "misc.use_d3d9_hooks"
#define IIDXHOOK_CONFIG_MISC_DEFAULT_HAPPY_SKY_MS_BG_FIX_VALUE false
#define IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE false
void iidxhook_config_iidxhook1_init(struct cconfig* config)
{
@@ -17,12 +15,6 @@ void iidxhook_config_iidxhook1_init(struct cconfig* config)
IIDXHOOK_CONFIG_MISC_DEFAULT_HAPPY_SKY_MS_BG_FIX_VALUE,
"Fix broken 3D background on Happy Sky's music select (if appearing "
"completely white)");
cconfig_util_set_bool(config,
IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY,
IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE,
"Use d3d9 hooks instead of d3d8 to enable d3d9 hook features not available on d3d8 (e.g. upscaling). Requires "
" d3d8to9 wrapper library to be used with this game.");
}
void iidxhook_config_iidxhook1_get(
@@ -37,13 +29,4 @@ void iidxhook_config_iidxhook1_get(
"to default '%d'", IIDXHOOK_CONFIG_MISC_HAPPY_SKY_MS_BG_FIX_KEY,
IIDXHOOK_CONFIG_MISC_DEFAULT_HAPPY_SKY_MS_BG_FIX_VALUE);
}
if (!cconfig_util_get_bool(config,
IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY,
&config_iidxhook1->use_d3d9_hooks,
IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE)) {
log_warning("Invalid value for key '%s' specified, fallback "
"to default '%d'", IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY,
IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE);
}
}

View File

@@ -5,7 +5,6 @@
struct iidxhook_config_iidxhook1 {
bool happy_sky_ms_bg_fix;
bool use_d3d9_hooks;
};
void iidxhook_config_iidxhook1_init(struct cconfig* config);

View File

@@ -17,6 +17,7 @@
#include "ezusb-iidx-emu/node-serial.h"
#include "ezusb-iidx-emu/nodes.h"
#include "hook/d3d9.h"
#include "hook/iohook.h"
#include "hook/table.h"
@@ -30,7 +31,6 @@
#include "iidxhook-util/config-gfx.h"
#include "iidxhook-util/config-misc.h"
#include "iidxhook-util/config-sec.h"
#include "iidxhook-util/d3d8.h"
#include "iidxhook-util/d3d9.h"
#include "iidxhook-util/eamuse.h"
#include "iidxhook-util/effector.h"
@@ -55,6 +55,10 @@ static const irp_handler_t iidxhook_handlers[] = {
settings_hook_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static HANDLE STDCALL my_OpenProcess(DWORD, BOOL, DWORD);
static HANDLE (STDCALL *real_OpenProcess)(DWORD, BOOL, DWORD);
@@ -68,6 +72,43 @@ static const struct hook_symbol init_hook_syms[] = {
},
};
static void iidxhook1_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx,
const struct iidxhook_config_iidxhook1* config_iidxhook1)
{
struct iidxhook_util_d3d9_config d3d9_config;
log_warning("d3d8 hook module deprecated, using d3d9 hook modules requiring d3d8to9 to work!");
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.iidx12_fix_song_select_bg = config_iidxhook1->happy_sky_ms_bg_fix;
d3d9_config.iidx11_to_17_fix_uvs_bg_videos = config_gfx->bgvideo_uv_fix;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
if (config_gfx->monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_config.iidx09_to_19_monitor_check_cb = iidxhook_util_chart_patch_set_refresh_rate;
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
} else if (config_gfx->monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f", config_gfx->monitor_check);
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx->monitor_check);
}
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
/**
* This seems to be a good entry point to intercept
* before the game calls anything important
@@ -144,87 +185,7 @@ static HANDLE STDCALL my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle,
/* Direct3D and USER32 hooks */
/* There are a few features that cannot be implemented using d3d8,
e.g. GPU based upscaling with filtering. When using d3d8to9, allow
using the d3d9 hooks instead because the game is running on d3d9. */
if (config_iidxhook1.use_d3d9_hooks) {
log_warning("d3d9 hook modules enabled. Requires d3d8to9!");
d3d9_hook_init();
if (config_gfx.bgvideo_uv_fix) {
/* Red, HS, DistorteD, only */
d3d9_iidx_fix_stretched_bg_videos();
}
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_enable_monitor_check(iidxhook_util_chart_patch_set_refresh_rate);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
} else if (config_gfx.monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f",
config_gfx.monitor_check);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx.monitor_check);
}
/* Fix Happy Sky 3D background */
if (config_iidxhook1.happy_sky_ms_bg_fix) {
d3d9_iidx_fix_12_song_select_bg();
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
} else {
d3d8_hook_init();
if (config_gfx.bgvideo_uv_fix) {
/* Red, HS, DistorteD, only */
d3d8_iidx_fix_stretched_bg_videos();
}
if (config_gfx.windowed) {
d3d8_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.frame_rate_limit > 0) {
d3d8_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d8_enable_monitor_check(iidxhook_util_chart_patch_set_refresh_rate);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
} else if (config_gfx.monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f",
config_gfx.monitor_check);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx.monitor_check);
}
/* Fix Happy Sky 3D background */
if (config_iidxhook1.happy_sky_ms_bg_fix) {
d3d8_iidx_fix_12_song_select_bg();
}
}
iidxhook1_setup_d3d9_hooks(&config_gfx, &config_iidxhook1);
/* Disable operator menu clock setting system clock time */

View File

@@ -5,10 +5,8 @@
#include "util/log.h"
#define IIDXHOOK_CONFIG_MISC_DISTORTED_MS_BG_FIX_KEY "misc.distorted_ms_bg_fix"
#define IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY "misc.use_d3d9_hooks"
#define IIDXHOOK_CONFIG_MISC_DEFAULT_DISTORTED_MS_BG_FIX_VALUE false
#define IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE false
void iidxhook_config_iidxhook2_init(struct cconfig* config)
{
@@ -17,12 +15,6 @@ void iidxhook_config_iidxhook2_init(struct cconfig* config)
IIDXHOOK_CONFIG_MISC_DEFAULT_DISTORTED_MS_BG_FIX_VALUE,
"Fix broken 3D background on DistorteD's music select (if appearing "
"completely black)");
cconfig_util_set_bool(config,
IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY,
IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE,
"Use d3d9 hooks instead of d3d8 to enable d3d9 hook features not available on d3d8 (e.g. upscaling). Requires "
" d3d8to9 wrapper library to be used with this game.");
}
void iidxhook_config_iidxhook2_get(
@@ -37,13 +29,4 @@ void iidxhook_config_iidxhook2_get(
"to default '%d'", IIDXHOOK_CONFIG_MISC_DISTORTED_MS_BG_FIX_KEY,
IIDXHOOK_CONFIG_MISC_DEFAULT_DISTORTED_MS_BG_FIX_VALUE);
}
if (!cconfig_util_get_bool(config,
IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY,
&config_iidxhook2->use_d3d9_hooks,
IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE)) {
log_warning("Invalid value for key '%s' specified, fallback "
"to default '%d'", IIDXHOOK_CONFIG_MISC_USE_D3D9_HOOKS_KEY,
IIDXHOOK_CONFIG_MISC_DEFAULT_USE_D3D9_HOOKS_VALUE);
}
}

View File

@@ -5,7 +5,6 @@
struct iidxhook_config_iidxhook2 {
bool distorted_ms_bg_fix;
bool use_d3d9_hooks;
};
void iidxhook_config_iidxhook2_init(struct cconfig* config);

View File

@@ -17,6 +17,7 @@
#include "ezusb-iidx-emu/node-serial.h"
#include "ezusb-iidx-emu/nodes.h"
#include "hook/d3d9.h"
#include "hook/iohook.h"
#include "hook/table.h"
@@ -32,7 +33,7 @@
#include "iidxhook-util/config-gfx.h"
#include "iidxhook-util/config-misc.h"
#include "iidxhook-util/config-sec.h"
#include "iidxhook-util/d3d8.h"
#include "iidxhook-util/d3d9.h"
#include "iidxhook-util/eamuse.h"
#include "iidxhook-util/effector.h"
#include "iidxhook-util/settings.h"
@@ -55,8 +56,13 @@ static const irp_handler_t iidxhook_handlers[] = {
settings_hook_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static HANDLE STDCALL my_OpenProcess(DWORD, BOOL, DWORD);
static HANDLE (STDCALL *real_OpenProcess)(DWORD, BOOL, DWORD);
static bool iidxhook_init_check;
static const struct hook_symbol init_hook_syms[] = {
@@ -67,6 +73,43 @@ static const struct hook_symbol init_hook_syms[] = {
},
};
static void iidxhook2_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx,
const struct iidxhook_config_iidxhook2* config_iidxhook2)
{
struct iidxhook_util_d3d9_config d3d9_config;
log_warning("d3d8 hook module deprecated, using d3d9 hook modules requiring d3d8to9 to work!");
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.iidx13_fix_song_select_bg = config_iidxhook2->distorted_ms_bg_fix;
d3d9_config.iidx11_to_17_fix_uvs_bg_videos = config_gfx->bgvideo_uv_fix;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
if (config_gfx->monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_config.iidx09_to_19_monitor_check_cb = iidxhook_util_chart_patch_set_refresh_rate;
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
} else if (config_gfx->monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f", config_gfx->monitor_check);
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx->monitor_check);
}
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
/**
* This seems to be a good entry point to intercept
* before the game calls anything important
@@ -138,87 +181,7 @@ HANDLE STDCALL my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle,
/* Direct3D and USER32 hooks */
/* There are a few features that cannot be implemented using d3d8,
e.g. GPU based upscaling with filtering. When using d3d8to9, allow
using the d3d9 hooks instead because the game is running on d3d9. */
if (config_iidxhook2.use_d3d9_hooks) {
log_warning("d3d9 hook modules enabled. Requires d3d8to9!");
d3d9_hook_init();
if (config_gfx.bgvideo_uv_fix) {
/* Red, HS, DistorteD, only */
d3d9_iidx_fix_stretched_bg_videos();
}
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_enable_monitor_check(iidxhook_util_chart_patch_set_refresh_rate);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
} else if (config_gfx.monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f",
config_gfx.monitor_check);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx.monitor_check);
}
/* Fix DistorteD 3D background on music select screen */
if (config_iidxhook2.distorted_ms_bg_fix) {
d3d9_iidx_fix_13_song_select_bg();
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
} else {
d3d8_hook_init();
if (config_gfx.bgvideo_uv_fix) {
/* Red, HS, DistorteD, only */
d3d8_iidx_fix_stretched_bg_videos();
}
if (config_gfx.windowed) {
d3d8_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.frame_rate_limit > 0) {
d3d8_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d8_enable_monitor_check(iidxhook_util_chart_patch_set_refresh_rate);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
} else if (config_gfx.monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f",
config_gfx.monitor_check);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_9_TO_13);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx.monitor_check);
}
/* Fix DistorteD 3D background on music select screen */
if (config_iidxhook2.distorted_ms_bg_fix) {
d3d8_iidx_fix_13_song_select_bg();
}
}
iidxhook2_setup_d3d9_hooks(&config_gfx, &config_iidxhook2);
/* Disable operator menu clock setting system clock time */

View File

@@ -18,6 +18,7 @@
#include "ezusb2-iidx-emu/msg.h"
#include "hook/d3d9.h"
#include "hook/iohook.h"
#include "hook/table.h"
@@ -54,6 +55,10 @@ static const irp_handler_t iidxhook_handlers[] = {
settings_hook_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static HANDLE STDCALL my_OpenProcess(DWORD, BOOL, DWORD);
static HANDLE (STDCALL *real_OpenProcess)(DWORD, BOOL, DWORD);
static bool iidxhook_init_check;
@@ -66,6 +71,45 @@ static const struct hook_symbol init_hook_syms[] = {
},
};
static void iidxhook3_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx)
{
struct iidxhook_util_d3d9_config d3d9_config;
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.pci_vid = config_gfx->pci_id_vid;
d3d9_config.pci_pid = config_gfx->pci_id_pid;
/* Required for GOLD (and newer?) to not crash with NVIDIA cards */
d3d9_config.iidx11_to_17_fix_uvs_bg_videos = true;
d3d9_config.iidx14_to_19_nvidia_fix = true;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
if (config_gfx->monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_config.iidx09_to_19_monitor_check_cb = iidxhook_util_chart_patch_set_refresh_rate;
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
} else if (config_gfx->monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f", config_gfx->monitor_check);
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx->monitor_check);
}
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
/**
* This seems to be a good entry point to intercept
* before the game calls anything important
@@ -131,42 +175,7 @@ HANDLE STDCALL my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle,
/* Direct3D and USER32 hooks */
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
/* Empress onwards */
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_enable_monitor_check(iidxhook_util_chart_patch_set_refresh_rate);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
} else if (config_gfx.monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f",
config_gfx.monitor_check);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx.monitor_check);
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
/* Required for GOLD (and newer?) to not crash with NVIDIA cards */
d3d9_enable_nvidia_fix();
d3d9_bg_video_seams_fix();
iidxhook3_setup_d3d9_hooks(&config_gfx);
/* Disable operator menu clock setting system clock time */
@@ -240,7 +249,6 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
acp_hook_init();
adapter_hook_init();
d3d9_hook_init();
eamuse_hook_init();
settings_hook_init();

View File

@@ -17,6 +17,8 @@
#include "ezusb2-iidx-emu/msg.h"
#include "hook/d3d9.h"
#include "hooklib/acp.h"
#include "hooklib/adapter.h"
#include "hooklib/app.h"
@@ -49,6 +51,44 @@ static const irp_handler_t iidxhook_handlers[] = {
settings_hook_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static void iidxhook4_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx)
{
struct iidxhook_util_d3d9_config d3d9_config;
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.pci_vid = config_gfx->pci_id_vid;
d3d9_config.pci_pid = config_gfx->pci_id_pid;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
if (config_gfx->monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_config.iidx09_to_19_monitor_check_cb = iidxhook_util_chart_patch_set_refresh_rate;
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
} else if (config_gfx->monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f", config_gfx->monitor_check);
iidxhook_util_chart_patch_init(IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx->monitor_check);
}
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
{
struct cconfig* config;
@@ -77,36 +117,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
log_info(IIDXHOOK4_INFO_HEADER);
log_info("Initializing iidxhook...");
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.monitor_check == 0) {
log_info("Auto monitor check enabled");
d3d9_enable_monitor_check(iidxhook_util_chart_patch_set_refresh_rate);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
} else if (config_gfx.monitor_check > 0) {
log_info("Manual monitor check, resulting refresh rate: %f",
config_gfx.monitor_check);
iidxhook_util_chart_patch_init(
IIDXHOOK_UTIL_CHART_PATCH_TIMEBASE_14_TO_18_VGA);
iidxhook_util_chart_patch_set_refresh_rate(config_gfx.monitor_check);
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
iidxhook4_setup_d3d9_hooks(&config_gfx);
/* Start up IIDXIO.DLL */
log_info("Starting IIDX IO backend");
@@ -183,7 +194,6 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
acp_hook_init();
adapter_hook_init();
d3d9_hook_init();
settings_hook_init();
end:

View File

@@ -17,6 +17,8 @@
#include "ezusb2-iidx-emu/msg.h"
#include "hook/d3d9.h"
#include "hooklib/acp.h"
#include "hooklib/adapter.h"
#include "hooklib/app.h"
@@ -47,6 +49,32 @@ static const irp_handler_t iidxhook_handlers[] = {
settings_hook_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static void iidxhook5_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx)
{
struct iidxhook_util_d3d9_config d3d9_config;
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.pci_vid = config_gfx->pci_id_vid;
d3d9_config.pci_pid = config_gfx->pci_id_pid;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
{
struct cconfig* config;
@@ -75,23 +103,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
log_info(IIDXHOOK5_INFO_HEADER);
log_info("Initializing iidxhook...");
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
iidxhook5_setup_d3d9_hooks(&config_gfx);
/* Start up IIDXIO.DLL */
log_info("Starting IIDX IO backend");
@@ -167,7 +179,6 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
acp_hook_init();
adapter_hook_init();
d3d9_hook_init();
settings_hook_init();
end:

View File

@@ -17,6 +17,8 @@
#include "ezusb2-iidx-emu/msg.h"
#include "hook/d3d9.h"
#include "hooklib/acp.h"
#include "hooklib/adapter.h"
#include "hooklib/app.h"
@@ -45,6 +47,32 @@ static const irp_handler_t iidxhook_handlers[] = {
iidxhook_util_acio_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static void iidxhook6_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx)
{
struct iidxhook_util_d3d9_config d3d9_config;
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.pci_vid = config_gfx->pci_id_vid;
d3d9_config.pci_pid = config_gfx->pci_id_pid;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
{
struct cconfig* config;
@@ -73,23 +101,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
log_info(IIDXHOOK6_INFO_HEADER);
log_info("Initializing iidxhook...");
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
iidxhook6_setup_d3d9_hooks(&config_gfx);
/* Start up IIDXIO.DLL */
log_info("Starting IIDX IO backend");
@@ -165,7 +177,6 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
acp_hook_init();
adapter_hook_init();
d3d9_hook_init();
end:
return TRUE;

View File

@@ -17,6 +17,8 @@
#include "ezusb2-iidx-emu/msg.h"
#include "hook/d3d9.h"
#include "hooklib/acp.h"
#include "hooklib/adapter.h"
#include "hooklib/app.h"
@@ -45,6 +47,32 @@ static const irp_handler_t iidxhook_handlers[] = {
iidxhook_util_acio_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static void iidxhook7_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx)
{
struct iidxhook_util_d3d9_config d3d9_config;
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.pci_vid = config_gfx->pci_id_vid;
d3d9_config.pci_pid = config_gfx->pci_id_pid;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
{
struct cconfig* config;
@@ -73,23 +101,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
log_info(IIDXHOOK7_INFO_HEADER);
log_info("Initializing iidxhook...");
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
iidxhook7_setup_d3d9_hooks(&config_gfx);
/* Start up IIDXIO.DLL */
log_info("Starting IIDX IO backend");
@@ -165,7 +177,6 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
acp_hook_init();
adapter_hook_init();
d3d9_hook_init();
end:
return TRUE;

View File

@@ -14,6 +14,7 @@ deplibs_iidxhook8 := \
libs_iidxhook8 := \
iidxhook-util \
acioemu \
bio2emu \
iidxio \
hook \
hooklib \
@@ -23,9 +24,7 @@ libs_iidxhook8 := \
src_iidxhook8 := \
bi2a.c \
bio2.c \
cam.c \
config-cam.c \
config-io.c \
dllmain.c \
setupapi.c \

View File

@@ -1,6 +1,7 @@
#define LOG_MODULE "bio2emu-bi2a"
#include "iidxhook8/bi2a.h"
#include "bio2emu/emu.h"
#include <windows.h> /* for _BitScanForward */
@@ -13,12 +14,11 @@
#include "bemanitools/iidxio.h"
static int get_default_slider_valid(size_t idx);
static void bio2_emu_bi2a_cmd_send_version(const struct ac_io_message *req);
static void bio2_emu_bi2a_send_state(const struct ac_io_message *req);
static void bio2_emu_bi2a_send_empty(const struct ac_io_message *req);
static void bio2_emu_bi2a_send_status(const struct ac_io_message *req, uint8_t status);
static void bio2_emu_bi2a_cmd_send_version(struct ac_io_emu *emu, const struct ac_io_message *req);
static void bio2_emu_bi2a_send_state(struct ac_io_emu *emu, const struct ac_io_message *req);
static void bio2_emu_bi2a_send_empty(struct ac_io_emu *emu, const struct ac_io_message *req);
static void bio2_emu_bi2a_send_status(struct ac_io_emu *emu, const struct ac_io_message *req, uint8_t status);
static struct ac_io_emu *bi2a_bio2;
static int default_sliders[5];
static bool poll_delay;
@@ -30,10 +30,10 @@ int get_default_slider_valid(size_t idx) {
}
}
void bio2_emu_bi2a_init(struct ac_io_emu *bio2_emu, bool disable_poll_limiter)
void bio2_emu_bi2a_init(struct bio2emu_port *bio2_emu, bool disable_poll_limiter)
{
FILE* f;
bi2a_bio2 = bio2_emu;
bio2emu_port_init(bio2_emu);
poll_delay = !disable_poll_limiter;
if (!poll_delay) {
log_warning("bio2_emu_bi2a_init: poll_delay has been disabled");
@@ -43,7 +43,7 @@ void bio2_emu_bi2a_init(struct ac_io_emu *bio2_emu, bool disable_poll_limiter)
default_sliders[i] = -1;
}
f = fopen("vefx.txt", "r");
FILE* f = fopen("vefx.txt", "r");
if (f) {
fscanf(f, "%d %d %d %d %d", &default_sliders[0], &default_sliders[1], &default_sliders[2], &default_sliders[3], &default_sliders[4]);
fclose(f);
@@ -51,7 +51,7 @@ void bio2_emu_bi2a_init(struct ac_io_emu *bio2_emu, bool disable_poll_limiter)
}
void bio2_emu_bi2a_dispatch_request(const struct ac_io_message *req)
void bio2_emu_bi2a_dispatch_request(struct bio2emu_port *bio2port, const struct ac_io_message *req)
{
uint16_t cmd_code;
@@ -61,27 +61,27 @@ void bio2_emu_bi2a_dispatch_request(const struct ac_io_message *req)
case BIO2_BI2A_CMD_UNK_0100:
case BIO2_BI2A_CMD_UNK_0120:
log_misc("BIO2_BI2A_CMD_UNK_%04X(%d)", cmd_code, req->addr);
bio2_emu_bi2a_send_status(req, 0x00);
bio2_emu_bi2a_send_status(&bio2port->acio, req, 0x00);
break;
case BIO2_BI2A_CMD_POLL:
// log_misc("BIO2_BI2A_CMD_POLL");
bio2_emu_bi2a_send_state(req);
bio2_emu_bi2a_send_state(&bio2port->acio, req);
break;
case AC_IO_CMD_GET_VERSION:
log_misc("BIO2_CMD_GET_VERSION(%d)", req->addr);
bio2_emu_bi2a_cmd_send_version(req);
bio2_emu_bi2a_cmd_send_version(&bio2port->acio, req);
break;
case AC_IO_CMD_START_UP:
log_misc("BIO2_CMD_START_UP(%d)", req->addr);
bio2_emu_bi2a_send_status(req, 0x00);
bio2_emu_bi2a_send_status(&bio2port->acio, req, 0x00);
break;
case AC_IO_CMD_KEEPALIVE:
log_misc("BIO2_CMD_KEEPALIVE(%d)", req->addr);
bio2_emu_bi2a_send_empty(req);
bio2_emu_bi2a_send_empty(&bio2port->acio, req);
break;
default:
@@ -90,7 +90,7 @@ void bio2_emu_bi2a_dispatch_request(const struct ac_io_message *req)
}
}
static void bio2_emu_bi2a_cmd_send_version(const struct ac_io_message *req)
static void bio2_emu_bi2a_cmd_send_version(struct ac_io_emu *emu, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -108,10 +108,10 @@ static void bio2_emu_bi2a_cmd_send_version(const struct ac_io_message *req)
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
ac_io_emu_response_push(emu, &resp, 0);
}
static void bio2_emu_bi2a_send_empty(const struct ac_io_message *req)
static void bio2_emu_bi2a_send_empty(struct ac_io_emu *emu, const struct ac_io_message *req)
{
struct ac_io_message resp;
@@ -120,10 +120,10 @@ static void bio2_emu_bi2a_send_empty(const struct ac_io_message *req)
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = 0;
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
ac_io_emu_response_push(emu, &resp, 0);
}
static void bio2_emu_bi2a_send_status(const struct ac_io_message *req, uint8_t status)
static void bio2_emu_bi2a_send_status(struct ac_io_emu *emu, const struct ac_io_message *req, uint8_t status)
{
struct ac_io_message resp;
@@ -133,15 +133,15 @@ static void bio2_emu_bi2a_send_status(const struct ac_io_message *req, uint8_t s
resp.cmd.nbytes = sizeof(resp.cmd.status);
resp.cmd.status = status;
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
ac_io_emu_response_push(emu, &resp, 0);
}
static void bio2_emu_bi2a_send_state(const struct ac_io_message *req)
static void bio2_emu_bi2a_send_state(struct ac_io_emu *emu, const struct ac_io_message *req)
{
struct ac_io_message resp;
struct bio2_bi2a_state *body;
struct bio2_bi2a_state_in *req_bi2a;
struct bi2a_iidx_state_out *body;
struct bi2a_iidx_state_in *req_bi2a;
uint8_t input_sys = 0;
uint8_t input_panel = 0;
@@ -156,8 +156,8 @@ static void bio2_emu_bi2a_send_state(const struct ac_io_message *req)
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = sizeof(struct bio2_bi2a_state);
req_bi2a = (struct bio2_bi2a_state_in*)req->cmd.raw;
resp.cmd.nbytes = sizeof(struct bi2a_iidx_state_out);
req_bi2a = (struct bi2a_iidx_state_in*)req->cmd.raw;
packed_lights.panel_lights = 0;
for (size_t i = 0; i < 4; ++i) {
@@ -190,16 +190,16 @@ static void bio2_emu_bi2a_send_state(const struct ac_io_message *req)
if (!iidx_io_ep1_send()) {
log_warning("BIO2: iidx_io_ep1_send error");
return bio2_emu_bi2a_send_status(req, 0);
return bio2_emu_bi2a_send_status(emu, req, 0);
}
if (!iidx_io_ep3_write_16seg((const char*) req_bi2a->SEG16)) {
log_warning("BIO2: iidx_io_ep3_write_16seg error");
return bio2_emu_bi2a_send_status(req, 0);
return bio2_emu_bi2a_send_status(emu, req, 0);
}
body = (struct bio2_bi2a_state *)&resp.cmd.raw;
memset(body, 0, sizeof(struct bio2_bi2a_state));
memset(body, 0, sizeof(struct bi2a_iidx_state_out));
// IIDX25 polls really really fast, this limits it to 1000Hz
if (poll_delay) {
@@ -208,7 +208,7 @@ static void bio2_emu_bi2a_send_state(const struct ac_io_message *req)
if (!iidx_io_ep2_recv()) {
log_warning("BIO2: iidx_io_ep2_recv error");
return bio2_emu_bi2a_send_status(req, 0);
return bio2_emu_bi2a_send_status(emu, req, 0);
}
body->TURNTABLE1 = iidx_io_ep2_get_turntable(0);
@@ -247,5 +247,5 @@ static void bio2_emu_bi2a_send_state(const struct ac_io_message *req)
body->SYSTEM.v_service = (input_sys >> IIDX_IO_SYS_SERVICE) & 1;
body->SYSTEM.v_coin = (input_sys >> IIDX_IO_SYS_COIN) & 1;
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
ac_io_emu_response_push(emu, &resp, 0);
}

View File

@@ -5,9 +5,9 @@
#include <stdint.h>
#include <stddef.h>
#include "acioemu/emu.h"
#include "bio2emu/emu.h"
enum bio2_bi2a_cmd {
enum bio2_iidx_cmd {
// Custom Stuff
BIO2_BI2A_CMD_UNK_0100 = 0x0100,
BIO2_BI2A_CMD_UNK_0120 = 0x0120,
@@ -15,12 +15,12 @@ enum bio2_bi2a_cmd {
};
#pragma pack(push, 1)
struct _slider {
struct bi2a_iidx_slider {
uint8_t s_unk : 4;
uint8_t s_val : 4;
};
struct _system {
struct bi2a_iidx_system {
uint8_t v_unk1 : 1;
uint8_t v_coin : 1;
uint8_t v_service : 1;
@@ -28,12 +28,12 @@ struct _system {
uint8_t v_unk2 : 4;
};
struct _button {
struct bi2a_iidx_button {
uint8_t b_unk : 7;
uint8_t b_val : 1;
};
struct _panel {
struct bi2a_iidx_panel {
uint8_t y_unk : 4;
uint8_t y_effect : 1;
uint8_t y_vefx : 1;
@@ -41,17 +41,17 @@ struct _panel {
uint8_t y_start1 : 1;
};
struct bio2_bi2a_state {
struct _slider SLIDER1;
struct _system SYSTEM;
struct _slider SLIDER2;
struct bi2a_iidx_state_out {
struct bi2a_iidx_slider SLIDER1;
struct bi2a_iidx_system SYSTEM;
struct bi2a_iidx_slider SLIDER2;
uint8_t UNK1;
struct _slider SLIDER3;
struct bi2a_iidx_slider SLIDER3;
uint8_t UNK2;
struct _slider SLIDER4;
struct _slider SLIDER5;
struct bi2a_iidx_slider SLIDER4;
struct bi2a_iidx_slider SLIDER5;
uint8_t UNK3; // coin mech?
struct _panel PANEL;
struct bi2a_iidx_panel PANEL;
uint8_t UNK4;
uint8_t UNK5;
uint8_t UNK6;
@@ -60,56 +60,57 @@ struct bio2_bi2a_state {
uint8_t UNK9;
uint8_t TURNTABLE1;
uint8_t TURNTABLE2;
struct _button P1SW1;
struct bi2a_iidx_button P1SW1;
uint8_t UNK11;
struct _button P1SW2;
struct bi2a_iidx_button P1SW2;
uint8_t UNK12;
struct _button P1SW3;
struct bi2a_iidx_button P1SW3;
uint8_t UNK13;
struct _button P1SW4;
struct bi2a_iidx_button P1SW4;
uint8_t UNK14;
struct _button P1SW5;
struct bi2a_iidx_button P1SW5;
uint8_t UNK15;
struct _button P1SW6;
struct bi2a_iidx_button P1SW6;
uint8_t UNK16;
struct _button P1SW7;
struct bi2a_iidx_button P1SW7;
uint8_t UNK17;
struct _button P2SW1;
struct bi2a_iidx_button P2SW1;
uint8_t UNK21;
struct _button P2SW2;
struct bi2a_iidx_button P2SW2;
uint8_t UNK22;
struct _button P2SW3;
struct bi2a_iidx_button P2SW3;
uint8_t UNK23;
struct _button P2SW4;
struct bi2a_iidx_button P2SW4;
uint8_t UNK24;
struct _button P2SW5;
struct bi2a_iidx_button P2SW5;
uint8_t UNK25;
struct _button P2SW6;
struct bi2a_iidx_button P2SW6;
uint8_t UNK26;
struct _button P2SW7;
struct bi2a_iidx_button P2SW7;
uint8_t UNK27;
};
struct _light {
struct bi2a_iidx_light {
uint8_t l_unk : 7;
uint8_t l_state : 1;
};
struct bio2_bi2a_state_in {
struct _light UNK1[3];
struct _light PANEL[4];
struct _light DECKSW[14];
struct bi2a_iidx_state_in {
struct bi2a_iidx_light UNK1[3];
struct bi2a_iidx_light PANEL[4];
struct bi2a_iidx_light DECKSW[14];
uint8_t UNK2[2];
uint8_t SEG16[9];
struct _light SPOTLIGHT1[4];
struct _light NEONLAMP;
struct _light SPOTLIGHT2[4];
struct bi2a_iidx_light SPOTLIGHT1[4];
struct bi2a_iidx_light NEONLAMP;
struct bi2a_iidx_light SPOTLIGHT2[4];
uint8_t UNK3[7];
};
_Static_assert(sizeof(struct bio2_bi2a_state_in) == 48, "bio2_bi2a_state_in is the wrong size");
_Static_assert(sizeof(struct bi2a_iidx_state_in) == 48, "bio2_bi2a_state_in is the wrong size");
_Static_assert(sizeof(struct bi2a_iidx_state_out) == 46, "bio2_bi2a_state_out is the wrong size");
#pragma pack(pop)
void bio2_emu_bi2a_init(struct ac_io_emu *in, bool disable_poll_limiter);
void bio2_emu_bi2a_dispatch_request(const struct ac_io_message *req);
void bio2_emu_bi2a_init(struct bio2emu_port *in, bool disable_poll_limiter);
void bio2_emu_bi2a_dispatch_request(struct bio2emu_port *bio2port, const struct ac_io_message *req);
#endif

View File

@@ -1,81 +0,0 @@
#include <windows.h>
#include <ntdef.h>
#include <devioctl.h>
#include <ntddser.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>
#include "acioemu/addr.h"
#include "acioemu/emu.h"
#include "hook/iohook.h"
#include "iidxhook8/bi2a.h"
#include "imports/avs.h"
#include "util/defs.h"
#include "util/iobuf.h"
#include "util/log.h"
#include "util/str.h"
static struct ac_io_emu bio2_emu;
void bio2_port_init(bool disable_poll_limiter)
{
// yes I'm using acio
// they use the same framing
ac_io_emu_init(&bio2_emu, L"COM4");
bio2_emu_bi2a_init(&bio2_emu, disable_poll_limiter);
}
void bio2_port_fini(void)
{
ac_io_emu_fini(&bio2_emu);
}
HRESULT bio2_port_dispatch_irp(struct irp *irp)
{
const struct ac_io_message *msg;
HRESULT hr;
log_assert(irp != NULL);
if (!ac_io_emu_match_irp(&bio2_emu, irp)) {
return irp_invoke_next(irp);
}
for (;;) {
hr = ac_io_emu_dispatch_irp(&bio2_emu, irp);
if (hr != S_OK) {
return hr;
}
msg = ac_io_emu_request_peek(&bio2_emu);
switch (msg->addr) {
case 0:
ac_io_emu_cmd_assign_addrs(&bio2_emu, msg, 1);
break;
case 1:
bio2_emu_bi2a_dispatch_request(msg);
break;
case AC_IO_BROADCAST:
log_warning("Broadcast(?) message on IIDX BIO2 bus?");
break;
default:
log_warning("BIO2 message on unhandled bus address: %d", msg->addr);
break;
}
ac_io_emu_request_pop(&bio2_emu);
}
}

View File

@@ -1,14 +0,0 @@
#ifndef IIDXHOOK_BIO2_H
#define IIDXHOOK_BIO2_H
#include <windows.h>
#include <stdbool.h>
#include "hook/iohook.h"
void bio2_port_init(bool disable_poll_limiter);
void bio2_port_fini(void);
HRESULT bio2_port_dispatch_irp(struct irp *irp);
#endif

View File

@@ -10,6 +10,8 @@
#include "cconfig/cconfig-hook.h"
#include "hook/d3d9.h"
#include "hooklib/acp.h"
#include "hooklib/adapter.h"
#include "hooklib/app.h"
@@ -21,11 +23,12 @@
#include "iidxhook-util/d3d9.h"
#include "iidxhook-util/log-server.h"
#include "iidxhook8/bio2.h"
#include "bio2emu/emu.h"
#include "iidxhook8/bi2a.h"
#include "iidxhook8/cam.h"
#include "iidxhook8/config-cam.h"
#include "iidxhook8/config-io.h"
#include "iidxhook8/setupapi.h"
#include "iidxhook8/cam.h"
#include "imports/avs.h"
@@ -42,11 +45,43 @@
static const irp_handler_t iidxhook_handlers[] = {
iidxhook_util_acio_dispatch_irp,
bio2_port_dispatch_irp,
bio2emu_port_dispatch_irp,
};
static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = {
iidxhook_util_d3d9_irp_handler,
};
static void iidxhook8_setup_d3d9_hooks(const struct iidxhook_config_gfx* config_gfx)
{
struct iidxhook_util_d3d9_config d3d9_config;
iidxhook_util_d3d9_init_config(&d3d9_config);
d3d9_config.windowed = config_gfx->windowed;
d3d9_config.framed = config_gfx->framed;
d3d9_config.override_window_width = config_gfx->window_width;
d3d9_config.override_window_height = config_gfx->window_height;
d3d9_config.framerate_limit = config_gfx->frame_rate_limit;
d3d9_config.pci_vid = config_gfx->pci_id_vid;
d3d9_config.pci_pid = config_gfx->pci_id_pid;
d3d9_config.scale_back_buffer_width = config_gfx->scale_back_buffer_width;
d3d9_config.scale_back_buffer_height = config_gfx->scale_back_buffer_height;
d3d9_config.scale_back_buffer_filter = config_gfx->scale_back_buffer_filter;
iidxhook_util_d3d9_configure(&d3d9_config);
hook_d3d9_init(iidxhook_d3d9_handlers, lengthof(iidxhook_d3d9_handlers));
}
struct iidxhook8_config_io iidxhook8_config_io;
static struct bio2emu_port bio2_emu = {
.port = "COM4",
.wport = L"COM4",
.dispatcher = bio2_emu_bi2a_dispatch_request,
};
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
{
struct cconfig* config;
@@ -54,7 +89,8 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
struct iidxhook_config_gfx config_gfx;
struct iidxhook8_config_cam config_cam;
// log_server_init is not required anymore
// log_server_init is required due to IO occuring in a non avs_thread
log_server_init();
log_info("-------------------------------------------------------------");
log_info("--------------- Begin iidxhook dll_entry_init ---------------");
@@ -81,23 +117,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
log_info(IIDXHOOK8_INFO_HEADER);
log_info("Initializing iidxhook...");
if (config_gfx.windowed) {
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
}
if (config_gfx.frame_rate_limit > 0) {
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
}
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
config_gfx.scale_back_buffer_filter);
}
iidxhook8_setup_d3d9_hooks(&config_gfx);
/* Start up IIDXIO.DLL */
if (!iidxhook8_config_io.disable_bio2_emu) {
@@ -126,10 +146,11 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param)
API implementations with real IO devices */
iohook_init(iidxhook_handlers, lengthof(iidxhook_handlers));
rs232_hook_init();
rs232_hook_limit_hooks();
if (!iidxhook8_config_io.disable_bio2_emu) {
bio2_port_init(iidxhook8_config_io.disable_poll_limiter);
setupapi_hook_init();
bio2emu_init();
bio2_emu_bi2a_init(&bio2_emu, iidxhook8_config_io.disable_poll_limiter);
}
if (!iidxhook8_config_io.disable_card_reader_emu) {
@@ -164,6 +185,8 @@ static bool my_dll_entry_main(void)
iidx_io_fini();
}
log_server_fini();
return result;
}
@@ -186,7 +209,6 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
acp_hook_init();
adapter_hook_init();
d3d9_hook_init();
end:
return TRUE;

View File

@@ -1,287 +0,0 @@
#define LOG_MODULE "setupapi-hook"
#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include "hook/table.h"
#include "iidxhook8/setupapi.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/time.h"
static BOOL my_SetupDiDestroyDeviceInfoList(
HDEVINFO DeviceInfoSet
);
static BOOL (*real_SetupDiDestroyDeviceInfoList)(
HDEVINFO DeviceInfoSet
);
static BOOL my_SetupDiEnumDeviceInfo(
HDEVINFO DeviceInfoSet,
DWORD MemberIndex,
PSP_DEVINFO_DATA DeviceInfoData
);
static BOOL (*real_SetupDiEnumDeviceInfo)(
HDEVINFO DeviceInfoSet,
DWORD MemberIndex,
PSP_DEVINFO_DATA DeviceInfoData
);
static HKEY my_SetupDiOpenDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
REGSAM samDesired
);
static HKEY (*real_SetupDiOpenDevRegKey)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
REGSAM samDesired
);
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize
);
static BOOL (*real_SetupDiGetDeviceRegistryPropertyA)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize
);
static BOOL my_SetupDiGetDeviceInfoListDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
);
static BOOL (*real_SetupDiGetDeviceInfoListDetailA)(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
);
static HDEVINFO my_SetupDiGetClassDevsA(
CONST GUID *ClassGuid,
PCSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
static HDEVINFO(*real_SetupDiGetClassDevsA)(
CONST GUID *ClassGuid,
PCSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
static const struct hook_symbol iidxhook5_setupapi_syms[] = {
{
.name = "SetupDiDestroyDeviceInfoList",
.patch = my_SetupDiDestroyDeviceInfoList,
.link = (void **) &real_SetupDiDestroyDeviceInfoList
},
{
.name = "SetupDiEnumDeviceInfo",
.patch = my_SetupDiEnumDeviceInfo,
.link = (void **) &real_SetupDiEnumDeviceInfo
},
{
.name = "SetupDiOpenDevRegKey",
.patch = my_SetupDiOpenDevRegKey,
.link = (void **) &real_SetupDiOpenDevRegKey
},
{
.name = "SetupDiGetDeviceRegistryPropertyA",
.patch = my_SetupDiGetDeviceRegistryPropertyA,
.link = (void **) &real_SetupDiGetDeviceRegistryPropertyA
},
{
.name = "SetupDiGetDeviceInfoListDetailA",
.patch = my_SetupDiGetDeviceInfoListDetailA,
.link = (void **) &real_SetupDiGetDeviceInfoListDetailA
},
{
.name = "SetupDiGetClassDevsA",
.patch = my_SetupDiGetClassDevsA,
.link = (void **) &real_SetupDiGetClassDevsA
},
};
static LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
static LSTATUS (*real_RegQueryValueExA)(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
static const struct hook_symbol iidxhook5_Advapi32_syms[] = {
{
.name = "RegQueryValueExA",
.patch = my_RegQueryValueExA,
.link = (void **) &real_RegQueryValueExA
},
};
#define CUSTOM_DEVICE_HANDLE (void*)0x12341230
#define CUSTOM_REGISTRY_HANDLE (void*)0x4242ccc0
static BOOL my_SetupDiDestroyDeviceInfoList(
HDEVINFO DeviceInfoSet
){
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
log_info("Inside: %s", __FUNCTION__);
return true;
}
return real_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
}
static BOOL my_SetupDiEnumDeviceInfo(
HDEVINFO DeviceInfoSet,
DWORD MemberIndex,
PSP_DEVINFO_DATA DeviceInfoData
){
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
log_info("Inside: %s", __FUNCTION__);
return true;
}
return real_SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex, DeviceInfoData);
}
static HKEY my_SetupDiOpenDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
REGSAM samDesired
){
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
log_info("Inside: %s", __FUNCTION__);
return CUSTOM_REGISTRY_HANDLE;
}
return real_SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired);
}
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize
){
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
log_info("Inside: %s", __FUNCTION__);
log_info("%s: Found CUSTOM HANDLE", __FUNCTION__);
if (PropertyBuffer && (PropertyBufferSize >= 12)){
log_info("%s: Copying property name (%ld)", __FUNCTION__, PropertyBufferSize);
strncpy((char*)PropertyBuffer, "BIO2(VIDEO)", PropertyBufferSize);
log_info("%s: Done copying property name", __FUNCTION__);
// Sleep(500);
} else {
log_info("%s: Returning size", __FUNCTION__);
*RequiredSize = 12;
}
log_info("%s: STUB RETURN", __FUNCTION__);
return true;
}
return real_SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
}
static BOOL my_SetupDiGetDeviceInfoListDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
){
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
log_info("Inside: %s", __FUNCTION__);
return true;
}
return real_SetupDiGetDeviceInfoListDetailA(DeviceInfoSet, DeviceInfoSetDetailData);
}
DEFINE_GUID(GUID_COM_BUS_ENUMERATOR,
0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);
static HDEVINFO my_SetupDiGetClassDevsA(
CONST GUID *ClassGuid,
PCSTR Enumerator,
HWND hwndParent,
DWORD Flags
){
if (ClassGuid) {
if (IsEqualGUID(ClassGuid, &GUID_COM_BUS_ENUMERATOR)){
log_info("Inside: %s", __FUNCTION__);
return CUSTOM_DEVICE_HANDLE;
}
}
return real_SetupDiGetClassDevsA(ClassGuid, Enumerator, hwndParent, Flags);
}
static LSTATUS my_RegQueryValueExA(
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
){
if (hKey == CUSTOM_REGISTRY_HANDLE){
if (strcmp(lpValueName, "PortName") == 0) {
log_info("Inside: %s", __FUNCTION__);
if (lpData){
strncpy((char*)lpData, "COM4", *lpcbData);
return ERROR_SUCCESS;
}
return ERROR_MORE_DATA;
}
}
return real_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
}
void setupapi_hook_init(void)
{
hook_table_apply(
NULL,
"setupapi.dll",
iidxhook5_setupapi_syms,
lengthof(iidxhook5_setupapi_syms));
hook_table_apply(
NULL,
"Advapi32.dll",
iidxhook5_Advapi32_syms,
lengthof(iidxhook5_Advapi32_syms));
log_info("Inserted setupapi hooks");
}

View File

@@ -1,6 +0,0 @@
#ifndef IIDXHOOK_SETUPAPI_H
#define IIDXHOOK_SETUPAPI_H
void setupapi_hook_init(void);
#endif

View File

@@ -52,14 +52,14 @@ void kfca_dispatch_request(const struct ac_io_message *req)
break;
case AC_IO_CMD_KFCA_UNK_0120:
log_misc("AC_IO_CMD_KFCA_UNK_%04X(%d)", cmd_code, req->addr);
case AC_IO_CMD_KFCA_WATCHDOG:
log_misc("AC_IO_CMD_KFCA_WATCHDOG(%d)", req->addr);
kfca_report_status(req, 0x00);
break;
case AC_IO_CMD_KFCA_UNK_0128:
log_misc("AC_IO_CMD_KFCA_UNK_0128(%d)", req->addr);
case AC_IO_CMD_KFCA_AMP_CONTROL:
log_misc("AC_IO_CMD_KFCA_AMP_CONTROL(%d)", req->addr);
kfca_report_0128(req);
break;

View File

@@ -0,0 +1,10 @@
dlls += sdvxio-kfca
libs_sdvxio-kfca := \
geninput \
aciodrv \
util \
src_sdvxio-kfca := \
sdvxio.c \

View File

@@ -0,0 +1,13 @@
LIBRARY sdvxio
EXPORTS
sdvx_io_fini
sdvx_io_get_input_gpio
sdvx_io_get_input_gpio_sys
sdvx_io_get_spinner_pos
sdvx_io_init
sdvx_io_read_input
sdvx_io_set_gpio_lights
sdvx_io_set_loggers
sdvx_io_set_pwm_light
sdvx_io_write_output

View File

@@ -0,0 +1,146 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "bemanitools/glue.h"
#include "bemanitools/sdvxio.h"
#include "aciodrv/device.h"
#include "aciodrv/kfca.h"
#define LOG_MODULE "sdvxio-kfca"
#define log_misc(...) sdvx_io_log_misc(LOG_MODULE, __VA_ARGS__)
#define log_info(...) sdvx_io_log_info(LOG_MODULE, __VA_ARGS__)
#define log_warning(...) sdvx_io_log_warning(LOG_MODULE, __VA_ARGS__)
#define log_fatal(...) sdvx_io_log_fatal(LOG_MODULE, __VA_ARGS__)
static log_formatter_t sdvx_io_log_misc;
static log_formatter_t sdvx_io_log_info;
static log_formatter_t sdvx_io_log_warning;
static log_formatter_t sdvx_io_log_fatal;
static uint16_t sdvx_io_gpio[2];
static uint8_t sdvx_io_gpio_sys;
static uint16_t sdvx_io_analog[2];
static bool running;
static bool processing_io;
struct ac_io_kfca_poll_out pout_staging;
struct ac_io_kfca_poll_out pout_ready;
void sdvx_io_set_loggers(log_formatter_t misc, log_formatter_t info,
log_formatter_t warning, log_formatter_t fatal)
{
sdvx_io_log_misc = misc;
sdvx_io_log_info = info;
sdvx_io_log_warning = warning;
sdvx_io_log_fatal = fatal;
}
bool sdvx_io_init(thread_create_t thread_create, thread_join_t thread_join,
thread_destroy_t thread_destroy)
{
if (!aciodrv_device_open("COM3", 57600)) {
log_info("Opening acio device failed\n");
return -1;
}
log_info("Opening acio device successful\n");
uint8_t node_count = aciodrv_device_get_node_count();
log_info("Enumerated %d nodes\n", node_count);
aciodrv_kfca_init(0);
running = true;
return true;
}
void sdvx_io_fini(void)
{
running = false;
while(processing_io) {
}
}
void sdvx_io_set_gpio_lights(uint32_t gpio_lights)
{
pout_staging.gpio = gpio_lights;
pout_staging.gpio |= 1 << 0x16;
pout_staging.gpio = ac_io_u32(pout_staging.gpio);
}
void sdvx_io_set_pwm_light(uint8_t light_no, uint8_t intensity)
{
pout_staging.pwm[light_no] = intensity;
}
bool sdvx_io_write_output(void)
{
memcpy(&pout_ready, &pout_staging, sizeof(struct ac_io_kfca_poll_out));
return true;
}
bool sdvx_io_read_input(void)
{
struct ac_io_kfca_poll_in pin;
if (!running) {
return false;
}
processing_io = true;
if (!aciodrv_kfca_poll(0, &pout_ready, &pin)) {
return false;
}
processing_io = false;
pin.adc[0] = ac_io_u16(pin.adc[0]);
pin.adc[1] = ac_io_u16(pin.adc[1]);
pin.gpio[0] = ac_io_u16(pin.gpio[0]);
pin.gpio[1] = ac_io_u16(pin.gpio[1]);
sdvx_io_gpio_sys = pin.gpio_sys;
sdvx_io_analog[0] = (pin.adc[0] >> 6) & 0x3FF;
sdvx_io_analog[1] = (pin.adc[1] >> 6) & 0x3FF;
sdvx_io_gpio[0] = pin.gpio[0];
sdvx_io_gpio[1] = pin.gpio[1];
return true;
}
uint8_t sdvx_io_get_input_gpio_sys(void)
{
return sdvx_io_gpio_sys;
}
uint16_t sdvx_io_get_input_gpio(uint8_t gpio_bank)
{
if (gpio_bank > 1) {
return 0;
}
return sdvx_io_gpio[gpio_bank];
}
uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no)
{
if (spinner_no >= 2) {
return 0;
}
return sdvx_io_analog[spinner_no];
}

View File

@@ -0,0 +1,32 @@
testdlls += d3d9hook
srcdir_d3d9hook := src/test/d3d9hook
ldflags_d3d9hook := \
libs_d3d9hook := \
hook \
test \
util \
src_d3d9hook := \
dllmain.c \
################################################################################
testexes += d3d9hook-test
srcdir_d3d9hook-test := src/test/d3d9hook
ldflags_d3d9hook-test := \
-ld3d9
libs_d3d9hook-test := \
hook \
test \
util \
src_d3d9hook-test := \
main.c \
################################################################################

View File

@@ -0,0 +1,5 @@
LIBRARY d3d9hook
EXPORTS
DllMain@12 @1 NONAME

289
src/test/d3d9hook/dllmain.c Normal file
View File

@@ -0,0 +1,289 @@
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "hook/d3d9.h"
#include "test/check.h"
#include "util/log.h"
#define debug_print(...) fprintf(stderr, __VA_ARGS__)
static HRESULT my_d3d9_handler(struct hook_d3d9_irp* irp);
static const hook_d3d9_irp_handler_t d3d9_handlers[] = {
my_d3d9_handler
};
static HRESULT my_d3d9_handler(struct hook_d3d9_irp* irp)
{
HRESULT hr;
enum hook_d3d9_irp_op pre_op;
debug_print("my_d3d9_handler dispatch: %d\n", irp->op);
// Important: All parameter checks must align with the parameters from the test executable
// Pre-real invoke checks
switch (irp->op) {
case HOOK_D3D9_IRP_OP_INVALID:
exit(EXIT_FAILURE);
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE:
debug_print("Pre HOOK_D3D9_IRP_OP_CTX_CREATE\n");
check_int_eq(irp->args.ctx_create.sdk_ver, D3D_SDK_VERSION);
check_null(irp->args.ctx_create.ctx);
break;
case HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES:
debug_print("Pre HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES\n");
check_null(irp->args.enum_display_devices.dev_name);
check_int_eq(irp->args.enum_display_devices.dev_num, 0);
check_non_null(irp->args.enum_display_devices.info);
check_int_eq(irp->args.enum_display_devices.flags, EDD_GET_DEVICE_INTERFACE_NAME);
break;
case HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX:
debug_print("Pre HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX\n");
// Cannot test because wine is also using this call causing the tests to fail
// check_int_eq(irp->args.create_window_ex.ex_style, 0);
// check_str_eq(irp->args.create_window_ex.class_name, "d3d9hook");
// check_str_eq(irp->args.create_window_ex.window_name, "d3d9hook test");
// check_int_eq(irp->args.create_window_ex.style, WS_OVERLAPPEDWINDOW);
// check_int_eq(irp->args.create_window_ex.x, 0);
// check_int_eq(irp->args.create_window_ex.y, 0);
// check_int_eq(irp->args.create_window_ex.width, 640);
// check_int_eq(irp->args.create_window_ex.height, 480);
// check_null(irp->args.create_window_ex.wnd_parent);
// check_null(irp->args.create_window_ex.menu);
// check_null(irp->args.create_window_ex.instance);
// check_null(irp->args.create_window_ex.param);
// check_null(irp->args.create_window_ex.result);
break;
case HOOK_D3D9_IRP_OP_GET_CLIENT_RECT:
debug_print("Pre HOOK_D3D9_IRP_OP_GET_CLIENT_RECT\n");
// Cannot test because wine is also using this call causing the tests to fail
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE:
debug_print("Pre HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE\n");
check_non_null(irp->args.ctx_create_device.self);
check_int_eq(irp->args.ctx_create_device.adapter, D3DADAPTER_DEFAULT);
check_int_eq(irp->args.ctx_create_device.type, D3DDEVTYPE_HAL);
check_non_null(irp->args.ctx_create_device.hwnd);
check_int_eq(irp->args.ctx_create_device.flags, D3DCREATE_HARDWARE_VERTEXPROCESSING);
check_non_null(irp->args.ctx_create_device.pp);
check_non_null(irp->args.ctx_create_device.pdev);
break;
case HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE\n");
check_non_null(irp->args.dev_create_texture.self);
check_int_eq(irp->args.dev_create_texture.width, 320);
check_int_eq(irp->args.dev_create_texture.height, 240);
check_int_eq(irp->args.dev_create_texture.levels, 0);
check_int_eq(irp->args.dev_create_texture.usage, 0);
check_int_eq(irp->args.dev_create_texture.format, D3DFMT_A8R8G8B8);
check_int_eq(irp->args.dev_create_texture.pool, D3DPOOL_DEFAULT);
check_non_null(irp->args.dev_create_texture.texture);
check_null(irp->args.dev_create_texture.shared_handle);
break;
case HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE\n");
check_non_null(irp->args.dev_begin_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_END_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_END_SCENE\n");
check_non_null(irp->args.dev_end_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_PRESENT:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_PRESENT\n");
check_non_null(irp->args.dev_present.self);
check_null(irp->args.dev_present.source_rect);
check_null(irp->args.dev_present.dest_rect);
check_null(irp->args.dev_present.dest_window_override);
check_null(irp->args.dev_present.dirty_region);
break;
case HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE\n");
check_non_null(irp->args.dev_set_render_state.self);
check_int_eq(irp->args.dev_set_render_state.state, D3DRS_FILLMODE);
check_int_eq(irp->args.dev_set_render_state.value, D3DFILL_POINT);
break;
default:
debug_print("Unhandled op code: %d\n", irp->op);
check_fail_msg("Unhandled op code.");
break;
}
pre_op = irp->op;
hr = hook_d3d9_irp_invoke_next(irp);
if (hr != S_OK) {
debug_print("HRESULT of op %d: %lX\n", irp->op, hr);
} else {
check_int_eq(irp->op, pre_op);
// Post real invoke checks
switch (irp->op) {
case HOOK_D3D9_IRP_OP_INVALID:
exit(EXIT_FAILURE);
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE:
debug_print("Post HOOK_D3D9_IRP_OP_CTX_CREATE\n");
check_int_eq(irp->args.ctx_create.sdk_ver, D3D_SDK_VERSION);
check_non_null(irp->args.ctx_create.ctx);
break;
case HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES:
debug_print("Post HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES\n");
check_null(irp->args.enum_display_devices.dev_name);
check_int_eq(irp->args.enum_display_devices.dev_num, 0);
check_non_null(irp->args.enum_display_devices.info);
check_int_eq(irp->args.enum_display_devices.flags, EDD_GET_DEVICE_INTERFACE_NAME);
break;
case HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX:
debug_print("Post HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX\n");
// Cannot test because wine is also using this call causing the tests to fail
// check_int_eq(irp->args.create_window_ex.ex_style, 0);
// check_str_eq(irp->args.create_window_ex.class_name, "d3d9hook");
// check_str_eq(irp->args.create_window_ex.window_name, "d3d9hook test");
// check_int_eq(irp->args.create_window_ex.style, WS_OVERLAPPEDWINDOW);
// check_int_eq(irp->args.create_window_ex.x, 0);
// check_int_eq(irp->args.create_window_ex.y, 0);
// check_int_eq(irp->args.create_window_ex.width, 640);
// check_int_eq(irp->args.create_window_ex.height, 480);
// check_null(irp->args.create_window_ex.wnd_parent);
// check_null(irp->args.create_window_ex.menu);
// check_null(irp->args.create_window_ex.instance);
// check_null(irp->args.create_window_ex.param);
// check_non_null(irp->args.create_window_ex.result);
break;
case HOOK_D3D9_IRP_OP_GET_CLIENT_RECT:
debug_print("Post HOOK_D3D9_IRP_OP_GET_CLIENT_RECT\n");
// Cannot test because wine is also using this call causing the tests to fail
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE:
debug_print("Post HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE\n");
check_non_null(irp->args.ctx_create_device.self);
check_int_eq(irp->args.ctx_create_device.adapter, D3DADAPTER_DEFAULT);
check_int_eq(irp->args.ctx_create_device.type, D3DDEVTYPE_HAL);
check_non_null(irp->args.ctx_create_device.hwnd);
check_int_eq(irp->args.ctx_create_device.flags, D3DCREATE_HARDWARE_VERTEXPROCESSING);
check_non_null(irp->args.ctx_create_device.pp);
check_non_null(irp->args.ctx_create_device.pdev);
break;
case HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE:
debug_print("Post HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE\n");
check_non_null(irp->args.dev_create_texture.self);
check_int_eq(irp->args.dev_create_texture.width, 320);
check_int_eq(irp->args.dev_create_texture.height, 240);
check_int_eq(irp->args.dev_create_texture.levels, 0);
check_int_eq(irp->args.dev_create_texture.usage, 0);
check_int_eq(irp->args.dev_create_texture.format, D3DFMT_A8R8G8B8);
check_int_eq(irp->args.dev_create_texture.pool, D3DPOOL_DEFAULT);
check_non_null(irp->args.dev_create_texture.texture);
check_null(irp->args.dev_create_texture.shared_handle);
break;
case HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE\n");
check_non_null(irp->args.dev_begin_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_END_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_END_SCENE\n");
check_non_null(irp->args.dev_end_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_PRESENT:
debug_print("Post HOOK_D3D9_IRP_OP_DEV_PRESENT\n");
check_non_null(irp->args.dev_present.self);
check_null(irp->args.dev_present.source_rect);
check_null(irp->args.dev_present.dest_rect);
check_null(irp->args.dev_present.dest_window_override);
check_null(irp->args.dev_present.dirty_region);
break;
case HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE:
debug_print("Post HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE\n");
check_non_null(irp->args.dev_set_render_state.self);
check_int_eq(irp->args.dev_set_render_state.state, D3DRS_FILLMODE);
check_int_eq(irp->args.dev_set_render_state.value, D3DFILL_POINT);
break;
default:
debug_print("Unhandled op code: %d\n", irp->op);
check_fail_msg("Unhandled op code.");
break;
}
}
return hr;
}
BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
{
if (reason == DLL_PROCESS_ATTACH) {
log_to_writer(log_writer_stderr, NULL);
debug_print("Initializing d3d9 hook module...\n");
hook_d3d9_init(d3d9_handlers, lengthof(d3d9_handlers));
}
return TRUE;
}

167
src/test/d3d9hook/main.c Normal file
View File

@@ -0,0 +1,167 @@
#include <d3d9.h>
#include <stdio.h>
#include <windows.h>
#include <winuser.h>
#include "test/check.h"
#define debug_print(...) fprintf(stderr, __VA_ARGS__)
static const int render_loop_iterations = 100;
static LRESULT CALLBACK wnd_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param);
static HWND create_window()
{
WNDCLASS wc;
HRESULT hr;
memset(&wc, 0, sizeof(WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hbrBackground = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpfnWndProc = (WNDPROC) wnd_proc;
wc.hInstance = NULL;
wc.lpszClassName = "d3d9hook";
hr = RegisterClass(&wc);
check_int_neq(hr, 0);
return CreateWindow("d3d9hook", "d3d9hook test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, NULL, NULL, NULL, 0);
}
static D3DPRESENT_PARAMETERS create_presenter_params(HWND window)
{
D3DPRESENT_PARAMETERS pp;
memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
pp.BackBufferWidth = 640;
pp.BackBufferHeight = 480;
pp.BackBufferFormat = D3DFMT_A8R8G8B8;
pp.BackBufferCount = 1;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.MultiSampleQuality = 0;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = window;
pp.Windowed = TRUE;
pp.EnableAutoDepthStencil = TRUE;
pp.AutoDepthStencilFormat = D3DFMT_D24S8;
pp.Flags = 0;
pp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
return pp;
}
static IDirect3DTexture9* create_texture(IDirect3DDevice9* dev)
{
HRESULT hr;
IDirect3DTexture9* texture;
hr = IDirect3DDevice9_CreateTexture(dev, 320, 240, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, NULL);
check_int_eq(hr, S_OK);
return texture;
}
int main(int argc, char** argv)
{
DISPLAY_DEVICEA display_device;
BOOL res;
HWND window;
RECT rect;
MSG msg;
IDirect3D9* d3d9;
HRESULT hr;
D3DPRESENT_PARAMETERS pp;
IDirect3DDevice9* dev;
int loop_count;
IDirect3DTexture9* texture;
res = EnumDisplayDevicesA(NULL, 0, &display_device, EDD_GET_DEVICE_INTERFACE_NAME);
check_int_eq(res, TRUE);
window = create_window();
check_non_null(window);
res = GetClientRect(window, &rect);
check_int_eq(res, TRUE);
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
check_non_null(d3d9);
pp = create_presenter_params(window);
hr = IDirect3D9_CreateDevice(
d3d9,
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
window,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&pp,
&dev);
check_int_eq(hr, S_OK);
IDirect3DDevice9_Release(d3d9);
d3d9 = NULL;
texture = create_texture(dev);
ShowWindow(window, SW_SHOW);
UpdateWindow(window);
memset(&msg, 0, sizeof(MSG));
loop_count = 0;
// TODO create vertex buffer, upload and render
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
hr = IDirect3DDevice9_Clear(dev, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff0000ff, 1.0f, 0);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_SetRenderState(dev, D3DRS_FILLMODE, D3DFILL_POINT);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_BeginScene(dev);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_EndScene(dev);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_Present(dev, NULL, NULL, NULL, NULL);
check_int_eq(hr, S_OK);
loop_count++;
if (loop_count > render_loop_iterations) {
PostQuitMessage(0);
}
}
}
IDirect3DTexture9_Release(texture);
IDirect3DDevice9_Release(dev);
return 0;
}
LRESULT CALLBACK wnd_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
switch(msg) {
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(wnd, msg, w_param, l_param);
}

View File

@@ -27,7 +27,7 @@ static void test_config_gfx_defaults()
check_bool_false(config_gfx.windowed);
check_int_eq(config_gfx.scale_back_buffer_width, 0);
check_int_eq(config_gfx.scale_back_buffer_height, 0);
check_int_eq(config_gfx.scale_back_buffer_width, D3D9_BACK_BUFFER_SCALE_FILTER_NONE);
check_int_eq(config_gfx.scale_back_buffer_width, IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_NONE);
}
static void test_config_gfx()
@@ -62,7 +62,7 @@ static void test_config_gfx()
check_bool_true(config_gfx.windowed);
check_int_eq(config_gfx.scale_back_buffer_width, 1920);
check_int_eq(config_gfx.scale_back_buffer_height, 1080);
check_int_eq(config_gfx.scale_back_buffer_filter, D3D9_BACK_BUFFER_SCALE_FILTER_LINEAR);
check_int_eq(config_gfx.scale_back_buffer_filter, IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_LINEAR);
}
static void test_config_gfx_invalid_values()
@@ -97,7 +97,7 @@ static void test_config_gfx_invalid_values()
check_bool_false(config_gfx.windowed);
check_int_eq(config_gfx.scale_back_buffer_width, 0);
check_int_eq(config_gfx.scale_back_buffer_height, 0);
check_int_eq(config_gfx.scale_back_buffer_width, D3D9_BACK_BUFFER_SCALE_FILTER_NONE);
check_int_eq(config_gfx.scale_back_buffer_width, IIDXHOOK_UTIL_D3D9_BACK_BUFFER_SCALE_FILTER_NONE);
}
TEST_MODULE_BEGIN("iidxhook-config-gfx")

View File

@@ -18,7 +18,6 @@ static void test_config_iidxhook1_defaults()
cconfig_finit(config);
check_bool_false(config_iidxhook1.happy_sky_ms_bg_fix);
check_bool_false(config_iidxhook1.use_d3d9_hooks);
}
static void test_config_iidxhook1()
@@ -31,14 +30,12 @@ static void test_config_iidxhook1()
iidxhook_config_iidxhook1_init(config);
cconfig_set2(config, "misc.happy_sky_ms_bg_fix", "true");
cconfig_set2(config, "misc.use_d3d9_hooks", "true");
iidxhook_config_iidxhook1_get(&config_iidxhook1, config);
cconfig_finit(config);
check_bool_true(config_iidxhook1.happy_sky_ms_bg_fix);
check_bool_true(config_iidxhook1.use_d3d9_hooks);
}
static void test_config_iidxhook1_invalid_values()
@@ -51,14 +48,12 @@ static void test_config_iidxhook1_invalid_values()
iidxhook_config_iidxhook1_init(config);
cconfig_set2(config, "misc.happy_sky_ms_bg_fix", "123");
cconfig_set2(config, "misc.use_d3d9_hooks", "sss");
iidxhook_config_iidxhook1_get(&config_iidxhook1, config);
cconfig_finit(config);
check_bool_false(config_iidxhook1.happy_sky_ms_bg_fix);
check_bool_false(config_iidxhook1.use_d3d9_hooks);
}
TEST_MODULE_BEGIN("iidxhook-config-iidxhook1")

View File

@@ -18,7 +18,6 @@ static void test_config_iidxhook2_defaults()
cconfig_finit(config);
check_bool_false(config_iidxhook2.distorted_ms_bg_fix);
check_bool_false(config_iidxhook2.use_d3d9_hooks);
}
static void test_config_iidxhook2()
@@ -31,14 +30,12 @@ static void test_config_iidxhook2()
iidxhook_config_iidxhook2_init(config);
cconfig_set2(config, "misc.distorted_ms_bg_fix", "true");
cconfig_set2(config, "misc.use_d3d9_hooks", "true");
iidxhook_config_iidxhook2_get(&config_iidxhook2, config);
cconfig_finit(config);
check_bool_true(config_iidxhook2.distorted_ms_bg_fix);
check_bool_true(config_iidxhook2.use_d3d9_hooks);
}
static void test_config_iidxhook2_invalid_values()
@@ -51,14 +48,12 @@ static void test_config_iidxhook2_invalid_values()
iidxhook_config_iidxhook2_init(config);
cconfig_set2(config, "misc.distorted_ms_bg_fix", "123");
cconfig_set2(config, "misc.use_d3d9_hooks", "sss");
iidxhook_config_iidxhook2_get(&config_iidxhook2, config);
cconfig_finit(config);
check_bool_false(config_iidxhook2.distorted_ms_bg_fix);
check_bool_false(config_iidxhook2.use_d3d9_hooks);
}
TEST_MODULE_BEGIN("iidxhook-config-iidxhook2")

View File

@@ -139,4 +139,10 @@ void _Noreturn check_null_failed(const char *file, int line, const char *func,
"\tValue is not null: %s\n"
"\tExpected null value\n\n",
expr);
}
void _Noreturn check_failed(const char *file, int line,
const char *func, char *expr)
{
fail(file, line, func, "\t%s\n", expr);
}

View File

@@ -109,6 +109,16 @@
} \
} \
#define check_fail() \
{ \
check_failed(__FILE__, __LINE__, __func__, ""); \
} \
#define check_fail_msg(expr) \
{ \
check_failed(__FILE__, __LINE__, __func__, expr); \
} \
void _Noreturn check_char_eq_failed(const char *file, int line,
const char *func, char *expr, char result, char expected);
void _Noreturn check_char_neq_failed(const char *file, int line,
@@ -132,5 +142,7 @@ void _Noreturn check_non_null_failed(const char *file, int line, const char *fun
char *expr);
void _Noreturn check_null_failed(const char *file, int line, const char *func,
char *expr);
void _Noreturn check_failed(const char *file, int line,
const char *func, char *expr);
#endif