mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 205cf29aff | |||
| bf9074a76e | |||
| 44e1edb50c | |||
| 41d0dce6e9 | |||
| 598422b701 | |||
| b58a1ccfcc | |||
| 60efd643d1 | |||
| 0596eeb6fe | |||
| 3d5c64feb7 | |||
| 610984f40e | |||
| 1e271b7352 | |||
| 07c78caf01 | |||
| d153209d8a | |||
| 48186245fe | |||
| f7c274591a | |||
| d1a20e58b6 | |||
| 1e02c31524 | |||
| 66fab48a5b | |||
| ae06652148 | |||
| bd6c8d3f3c | |||
| e88abec2a6 | |||
| 6de8b529d2 | |||
| 7301cdaa6c | |||
| 6969dfcdd1 | |||
| edaf5a386f | |||
| 302f08dd57 | |||
| 68f5a614ef | |||
| 5db43031f2 | |||
| 873ade757a | |||
| 3c8dc9de32 | |||
| 4694b59cec | |||
| 4f1ada7a2f | |||
| 104a9cbffd | |||
| 45a52cff90 | |||
| bf79b5d2aa | |||
| e74c60f61d | |||
| 89921e5ec2 | |||
| 1b7ebd6fc2 |
@@ -0,0 +1,32 @@
|
|||||||
|
on: [push, pull_request]
|
||||||
|
name: Continuous Integration
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
fw-ci:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./src/spice2x
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set ccache environment variables
|
||||||
|
run: |
|
||||||
|
echo "CCACHE_DIR=${{ github.workspace }}/src/spice2x/.ccache" >> $GITHUB_ENV
|
||||||
|
- name: Install ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2
|
||||||
|
- name: Calculate commit SHA
|
||||||
|
id: vars
|
||||||
|
run: |
|
||||||
|
calculatedSha=$(git rev-parse --short ${{ github.sha }})
|
||||||
|
echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
|
||||||
|
- name: Compile
|
||||||
|
run: ./build_docker.sh
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: spice2x-ci-${{ env.COMMIT_SHORT_SHA }}
|
||||||
|
path: src/spice2x/bin
|
||||||
|
if-no-files-found: error
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
.vscode/*
|
||||||
|
|
||||||
|
# JetBrains IDEs
|
||||||
|
.idea
|
||||||
|
.idea_modules
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build*
|
||||||
|
|
||||||
|
# user config
|
||||||
|
build_all.local.sh
|
||||||
|
build_docker.local.sh
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
> * Please do note that this is a GPL v3.0 open source project.
|
> * Please do note that this is a GPL v3.0 open source project.
|
||||||
> * Please read the [CONTRIBUTING](https://github.com/spice2x/spice2x.github.io/blob/main/CONTRIBUTING.md) guide.
|
> * Please read the [CONTRIBUTING](https://github.com/spice2x/spice2x.github.io/blob/main/CONTRIBUTING.md) guide.
|
||||||
> * Maintainers reserve the right to reject or modify your submission without reason.
|
> * Maintainers reserve the right to reject or modify your submission without reason.
|
||||||
|
> * No new compiler warnings must be introduced. Check the CI build results.
|
||||||
>
|
>
|
||||||
> Feel free to remove this section after you have read it.
|
> Feel free to remove this section after you have read it.
|
||||||
|
|
||||||
@@ -12,8 +13,5 @@
|
|||||||
## Description of change
|
## Description of change
|
||||||
*what does this code do?*
|
*what does this code do?*
|
||||||
|
|
||||||
## Compiling
|
|
||||||
*you must be able to compile with the included Docker script with zero compiler warnings*
|
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
*how was the code tested?*
|
*how was the code tested?*
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ bin/**
|
|||||||
dist/**
|
dist/**
|
||||||
docker/**
|
docker/**
|
||||||
cmake-build*
|
cmake-build*
|
||||||
|
.ccache/**
|
||||||
@@ -16,4 +16,6 @@ build_docker.local.sh
|
|||||||
bin/*
|
bin/*
|
||||||
dist/*
|
dist/*
|
||||||
|
|
||||||
external/cv2pdb/*
|
external/cv2pdb/*
|
||||||
|
|
||||||
|
.ccache/*
|
||||||
@@ -211,14 +211,12 @@ add_compile_definitions(
|
|||||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DACIOEMU_LOG")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DACIOEMU_LOG")
|
||||||
|
|
||||||
# add project directory to include path so we can comfortably import
|
# add project directory to include path so we can comfortably import
|
||||||
include_directories(${spicetools_SOURCE_DIR})
|
include_directories(${spicetools_SOURCE_DIR} ${spicetools_SOURCE_DIR}/external/imgui)
|
||||||
|
|
||||||
# add external libraries
|
# add external libraries
|
||||||
add_subdirectory(external/fmt EXCLUDE_FROM_ALL)
|
add_subdirectory(external/fmt EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(external/discord-rpc EXCLUDE_FROM_ALL)
|
add_subdirectory(external/discord-rpc EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(external/hash-library EXCLUDE_FROM_ALL)
|
add_subdirectory(external/hash-library EXCLUDE_FROM_ALL)
|
||||||
add_compile_definitions(IMGUI_DISABLE_DEMO_WINDOWS)
|
|
||||||
add_compile_definitions(IMGUI_DISABLE_DEBUG_TOOLS)
|
|
||||||
add_subdirectory(external/imgui EXCLUDE_FROM_ALL)
|
add_subdirectory(external/imgui EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(external/minhook EXCLUDE_FROM_ALL)
|
add_subdirectory(external/minhook EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(external/cpu_features EXCLUDE_FROM_ALL)
|
add_subdirectory(external/cpu_features EXCLUDE_FROM_ALL)
|
||||||
@@ -442,6 +440,9 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/qks/qks.cpp
|
games/qks/qks.cpp
|
||||||
games/qks/io.cpp
|
games/qks/io.cpp
|
||||||
games/qks/bi2x_hook.cpp
|
games/qks/bi2x_hook.cpp
|
||||||
|
games/mfg/mfg.cpp
|
||||||
|
games/mfg/io.cpp
|
||||||
|
games/mfg/bi2a_hook.cpp
|
||||||
|
|
||||||
# hooks
|
# hooks
|
||||||
hooks/audio/audio.cpp
|
hooks/audio/audio.cpp
|
||||||
@@ -513,7 +514,6 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
overlay/overlay.cpp
|
overlay/overlay.cpp
|
||||||
overlay/window.cpp
|
overlay/window.cpp
|
||||||
overlay/imgui/extensions.cpp
|
overlay/imgui/extensions.cpp
|
||||||
overlay/imgui/impl_dx9.cpp
|
|
||||||
overlay/imgui/impl_spice.cpp
|
overlay/imgui/impl_spice.cpp
|
||||||
overlay/imgui/impl_sw.cpp
|
overlay/imgui/impl_sw.cpp
|
||||||
overlay/windows/acio_status_buffers.cpp
|
overlay/windows/acio_status_buffers.cpp
|
||||||
@@ -587,6 +587,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
util/sysutils.cpp
|
util/sysutils.cpp
|
||||||
util/lz77.cpp
|
util/lz77.cpp
|
||||||
util/tapeled.cpp
|
util/tapeled.cpp
|
||||||
|
util/execexe.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES})
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES})
|
||||||
@@ -606,6 +607,22 @@ IF(NOT MSVC)
|
|||||||
set_target_properties(spicetools_spice PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
set_target_properties(spicetools_spice PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# spice_laa.exe
|
||||||
|
###########
|
||||||
|
|
||||||
|
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
|
||||||
|
add_executable(spicetools_spice_laa ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||||
|
target_link_libraries(spicetools_spice_laa
|
||||||
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp
|
||||||
|
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||||
|
set_target_properties(spicetools_spice_laa PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_spice_laa PROPERTIES OUTPUT_NAME "spice_laa")
|
||||||
|
target_compile_definitions(spicetools_spice_laa PRIVATE SPICE32_LARGE_ADDRESS_AWARE=1)
|
||||||
|
|
||||||
|
IF(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_spice_laa PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -Wl,--large-address-aware")
|
||||||
|
endif()
|
||||||
|
|
||||||
# spice64.exe
|
# spice64.exe
|
||||||
#############
|
#############
|
||||||
|
|
||||||
@@ -625,7 +642,6 @@ IF(NOT MSVC)
|
|||||||
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# spicecfg.exe
|
# spicecfg.exe
|
||||||
##############
|
##############
|
||||||
|
|
||||||
@@ -731,7 +747,7 @@ set_target_properties(spicetools_cfg
|
|||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
||||||
|
|
||||||
# output 32bit
|
# output 32bit
|
||||||
set_target_properties(spicetools_spice spicetools_stubs_kbt spicetools_stubs_kld
|
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_stubs_kbt spicetools_stubs_kld
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
FROM spicetools/deps
|
FROM spicetools/deps
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
RUN chown user:user /src
|
|
||||||
USER user
|
COPY --from=gitroot . /src/.git
|
||||||
COPY --chown=user:user --from=gitroot . /src/.git
|
COPY . /src/src/spice2x
|
||||||
COPY --chown=user:user . /src/src/spice2x
|
|
||||||
WORKDIR /src/src/spice2x
|
WORKDIR /src/src/spice2x
|
||||||
CMD ["./build_all.sh"]
|
ENTRYPOINT ["./build_all.sh"]
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ static int __cdecl ac_io_bmpu_control_1p_start_led_off() {
|
|||||||
if (avs::game::is_model("KDM")) {
|
if (avs::game::is_model("KDM")) {
|
||||||
auto &lights = games::dea::get_lights();
|
auto &lights = games::dea::get_lights();
|
||||||
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P1Start), 0.f);
|
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P1Start), 0.f);
|
||||||
|
|
||||||
|
// MUSECA
|
||||||
|
} else if (avs::game::is_model("PIX")) {
|
||||||
|
auto &lights = games::museca::get_lights();
|
||||||
|
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Start), 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -44,6 +49,11 @@ static int __cdecl ac_io_bmpu_control_1p_start_led_on() {
|
|||||||
if (avs::game::is_model("KDM")) {
|
if (avs::game::is_model("KDM")) {
|
||||||
auto &lights = games::dea::get_lights();
|
auto &lights = games::dea::get_lights();
|
||||||
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P1Start), 1.f);
|
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P1Start), 1.f);
|
||||||
|
|
||||||
|
// MUSECA
|
||||||
|
} else if (avs::game::is_model("PIX")) {
|
||||||
|
auto &lights = games::museca::get_lights();
|
||||||
|
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Start), 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -55,6 +65,11 @@ static int __cdecl ac_io_bmpu_control_2p_start_led_off() {
|
|||||||
if (avs::game::is_model("KDM")) {
|
if (avs::game::is_model("KDM")) {
|
||||||
auto &lights = games::dea::get_lights();
|
auto &lights = games::dea::get_lights();
|
||||||
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P2Start), 0.f);
|
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P2Start), 0.f);
|
||||||
|
|
||||||
|
// MUSECA
|
||||||
|
} else if (avs::game::is_model("PIX")) {
|
||||||
|
auto &lights = games::museca::get_lights();
|
||||||
|
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Keypad), 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -66,6 +81,11 @@ static int __cdecl ac_io_bmpu_control_2p_start_led_on() {
|
|||||||
if (avs::game::is_model("KDM")) {
|
if (avs::game::is_model("KDM")) {
|
||||||
auto &lights = games::dea::get_lights();
|
auto &lights = games::dea::get_lights();
|
||||||
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P2Start), 1.f);
|
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P2Start), 1.f);
|
||||||
|
|
||||||
|
// MUSECA
|
||||||
|
} else if (avs::game::is_model("PIX")) {
|
||||||
|
auto &lights = games::museca::get_lights();
|
||||||
|
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Keypad), 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
acioemu::ACIOHandle::ACIOHandle(LPCWSTR lpCOMPort) {
|
acioemu::ACIOHandle::ACIOHandle(LPCWSTR lpCOMPort, uint8_t iccaNodeCount) {
|
||||||
this->com_port = lpCOMPort;
|
this->com_port = lpCOMPort;
|
||||||
|
this->icca_node_count = iccaNodeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool acioemu::ACIOHandle::open(LPCWSTR lpFileName) {
|
bool acioemu::ACIOHandle::open(LPCWSTR lpFileName) {
|
||||||
@@ -16,7 +17,7 @@ bool acioemu::ACIOHandle::open(LPCWSTR lpFileName) {
|
|||||||
log_info("acioemu", "Opened {} (ACIO)", ws2s(com_port));
|
log_info("acioemu", "Opened {} (ACIO)", ws2s(com_port));
|
||||||
|
|
||||||
// ACIO device
|
// ACIO device
|
||||||
acio_emu.add_device(new acioemu::ICCADevice(false, true, 2));
|
acio_emu.add_device(new acioemu::ICCADevice(false, true, icca_node_count));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ namespace acioemu {
|
|||||||
private:
|
private:
|
||||||
LPCWSTR com_port;
|
LPCWSTR com_port;
|
||||||
|
|
||||||
|
uint8_t icca_node_count;
|
||||||
|
|
||||||
acioemu::ACIOEmu acio_emu;
|
acioemu::ACIOEmu acio_emu;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ACIOHandle(LPCWSTR lpCOMPort);
|
ACIOHandle(LPCWSTR lpCOMPort, uint8_t iccaNodeCount = 2);
|
||||||
|
|
||||||
bool open(LPCWSTR lpFileName) override;
|
bool open(LPCWSTR lpFileName) override;
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,8 @@ bool ICCADevice::parse_msg(MessageData *msg_in,
|
|||||||
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
||||||
) {
|
) {
|
||||||
this->set_version(msg, 0x3, 0, 1, 7, 0, "ICCA");
|
this->set_version(msg, 0x3, 0, 1, 7, 0, "ICCA");
|
||||||
|
} else if (avs::game::is_model({"VFG"})) {
|
||||||
|
this->set_version(msg, 0x3, 0, 1, 7, 0, "ICCB");
|
||||||
} else {
|
} else {
|
||||||
this->set_version(msg, 0x3, 0, 1, 6, 0, "ICCA");
|
this->set_version(msg, 0x3, 0, 1, 6, 0, "ICCA");
|
||||||
}
|
}
|
||||||
@@ -333,6 +335,7 @@ bool ICCADevice::parse_msg(MessageData *msg_in,
|
|||||||
case ACIO_CMD_CLEAR:
|
case ACIO_CMD_CLEAR:
|
||||||
case 0x30: // GetBoardProductNumber
|
case 0x30: // GetBoardProductNumber
|
||||||
case 0x31: // GetMicomInfo
|
case 0x31: // GetMicomInfo
|
||||||
|
case 0x3A: // ???
|
||||||
case 0x0116: // ???
|
case 0x0116: // ???
|
||||||
case 0x0120: // ???
|
case 0x0120: // ???
|
||||||
case 0xFF: // BROADCAST
|
case 0xFF: // BROADCAST
|
||||||
|
|||||||
@@ -76,18 +76,23 @@ namespace avs {
|
|||||||
const auto dll_path_s = dll_path.string();
|
const auto dll_path_s = dll_path.string();
|
||||||
log_info("avs-game", "DLL path: {}", dll_path_s.c_str());
|
log_info("avs-game", "DLL path: {}", dll_path_s.c_str());
|
||||||
|
|
||||||
if (MAX_PATH <= (dll_path_s.length() + 64)) {
|
// MAX_PATH is 260
|
||||||
|
if (130 <= dll_path_s.length()) {
|
||||||
log_warning(
|
log_warning(
|
||||||
"avs-game",
|
"avs-game",
|
||||||
"PATH TOO LONG WARNING\n\n\n"
|
"PATH TOO LONG WARNING\n\n\n"
|
||||||
"-------------------------------------------------------------------\n"
|
"-------------------------------------------------------------------\n"
|
||||||
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||||
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||||
|
" PATH TOO LONG \n"
|
||||||
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||||
"'{}' has a length of {}\n"
|
"The path '{}'\n"
|
||||||
"Most of these games will behave unexpectedly when the path is too long,\n"
|
" has a length of {}\n"
|
||||||
"often resulting in random crashes. Move the game contents to a directory\n"
|
"Most of these games may behave unexpectedly when the path is too\n"
|
||||||
"with shorter path.\n"
|
"long, often resulting in random crashes. Move the game contents to\n"
|
||||||
"-------------------------------------------------------------------\n\n\n",
|
"a directory with shorter path.\n"
|
||||||
|
"-------------------------------------------------------------------\n\n",
|
||||||
dll_path_s, dll_path_s.length());
|
dll_path_s, dll_path_s.length());
|
||||||
}
|
}
|
||||||
if (!fileutils::file_exists(dll_path)) {
|
if (!fileutils::file_exists(dll_path)) {
|
||||||
|
|||||||
Regular → Executable
+58
-26
@@ -19,6 +19,25 @@ function trap_error_exit {
|
|||||||
trap trap_error_dbg DEBUG
|
trap trap_error_dbg DEBUG
|
||||||
trap trap_error_exit EXIT
|
trap trap_error_exit EXIT
|
||||||
|
|
||||||
|
IGNORE_CACHE=0
|
||||||
|
|
||||||
|
# Parse options
|
||||||
|
while getopts "ih" opt; do
|
||||||
|
case $opt in
|
||||||
|
i) IGNORE_CACHE=1 ;;
|
||||||
|
h)
|
||||||
|
echo "Usage: $0 [-i]"
|
||||||
|
echo " -i: Ignore build cache"
|
||||||
|
echo " -h: Show this help"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Invalid option: -$OPTARG" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# settings
|
# settings
|
||||||
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "none")
|
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "none")
|
||||||
GIT_HEAD=$(git rev-parse HEAD || echo "none")
|
GIT_HEAD=$(git rev-parse HEAD || echo "none")
|
||||||
@@ -41,7 +60,7 @@ DIST_ENABLE=1
|
|||||||
DIST_FOLDER="./dist"
|
DIST_FOLDER="./dist"
|
||||||
DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip"
|
DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip"
|
||||||
DIST_COMMENT=${DIST_NAME}$'\n'"$GIT_BRANCH - $GIT_HEAD"$'\nThank you for playing.'
|
DIST_COMMENT=${DIST_NAME}$'\n'"$GIT_BRANCH - $GIT_HEAD"$'\nThank you for playing.'
|
||||||
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_spice"
|
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_spice spicetools_spice_laa"
|
||||||
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64"
|
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64"
|
||||||
|
|
||||||
# determine build type
|
# determine build type
|
||||||
@@ -57,7 +76,7 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# determine number of cores
|
# determine number of cores
|
||||||
CORES=$(awk '/^processor\t/ {cores[$NF]++} END {print length(cores)}' /proc/cpuinfo)
|
CORES=$(nproc)
|
||||||
|
|
||||||
# print information
|
# print information
|
||||||
echo ""
|
echo ""
|
||||||
@@ -74,34 +93,45 @@ echo "Build Type: $BUILD_TYPE"
|
|||||||
echo "Cores: $CORES"
|
echo "Cores: $CORES"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 32 bit
|
if ((IGNORE_CACHE > 0))
|
||||||
echo "Building 32bit targets..."
|
|
||||||
echo "========================="
|
|
||||||
if ((CLEAN_BUILD > 0))
|
|
||||||
then
|
then
|
||||||
rm -rf ${BUILDDIR_32}
|
echo "Ignoring build cache..."
|
||||||
|
else
|
||||||
|
export CCACHE_DIR="$(pwd)/.ccache"
|
||||||
|
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
export CMAKE_C_COMPILER_LAUNCHER=ccache
|
||||||
fi
|
fi
|
||||||
mkdir -p ${BUILDDIR_32}
|
|
||||||
pushd ${BUILDDIR_32} > /dev/null
|
|
||||||
cmake -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_32} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} $OLDPWD && make -j ${CORES} ${TARGETS_32}
|
|
||||||
popd > /dev/null
|
|
||||||
|
|
||||||
# 64 bit
|
time (
|
||||||
echo ""
|
# 32 bit
|
||||||
echo "Building 64bit targets..."
|
echo "Building 32bit targets..."
|
||||||
echo "========================="
|
echo "========================="
|
||||||
if ((CLEAN_BUILD > 0))
|
if ((CLEAN_BUILD > 0))
|
||||||
then
|
then
|
||||||
rm -rf ${BUILDDIR_64}
|
rm -rf ${BUILDDIR_32}
|
||||||
fi
|
fi
|
||||||
mkdir -p ${BUILDDIR_64}
|
mkdir -p ${BUILDDIR_32}
|
||||||
pushd ${BUILDDIR_64} > /dev/null
|
pushd ${BUILDDIR_32} > /dev/null
|
||||||
cmake -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_64} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} $OLDPWD && make -j ${CORES} ${TARGETS_64}
|
cmake -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_32} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} $OLDPWD && ninja ${TARGETS_32}
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
|
|
||||||
echo ""
|
# 64 bit
|
||||||
echo "Compilation process done :)"
|
echo ""
|
||||||
echo "==========================="
|
echo "Building 64bit targets..."
|
||||||
|
echo "========================="
|
||||||
|
if ((CLEAN_BUILD > 0))
|
||||||
|
then
|
||||||
|
rm -rf ${BUILDDIR_64}
|
||||||
|
fi
|
||||||
|
mkdir -p ${BUILDDIR_64}
|
||||||
|
pushd ${BUILDDIR_64} > /dev/null
|
||||||
|
cmake -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_64} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} $OLDPWD && ninja ${TARGETS_64}
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Compilation process done :)"
|
||||||
|
echo "==========================="
|
||||||
|
)
|
||||||
|
|
||||||
# generate PDBs
|
# generate PDBs
|
||||||
if false # ((DEBUG > 0))
|
if false # ((DEBUG > 0))
|
||||||
@@ -153,6 +183,7 @@ rm -rf ${OUTDIR}
|
|||||||
mkdir -p ${OUTDIR}
|
mkdir -p ${OUTDIR}
|
||||||
#mkdir -p ${OUTDIR}/stubs/32
|
#mkdir -p ${OUTDIR}/stubs/32
|
||||||
mkdir -p ${OUTDIR}/stubs/64
|
mkdir -p ${OUTDIR}/stubs/64
|
||||||
|
mkdir -p ${OUTDIR}/extras/largeaddressaware
|
||||||
if false # ((DEBUG > 0))
|
if false # ((DEBUG > 0))
|
||||||
then
|
then
|
||||||
# debug files
|
# debug files
|
||||||
@@ -173,6 +204,7 @@ else
|
|||||||
# release files
|
# release files
|
||||||
cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null
|
||||||
cp ${BUILDDIR_32}/spicetools/32/spice.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/32/spice.exe ${OUTDIR} 2>/dev/null
|
||||||
|
cp ${BUILDDIR_32}/spicetools/32/spice_laa.exe ${OUTDIR}/extras/largeaddressaware/spice.exe 2>/dev/null
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/kbt.dll ${OUTDIR}/stubs/32 2>/dev/null
|
#cp ${BUILDDIR_32}/spicetools/32/kbt.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/kld.dll ${OUTDIR}/stubs/32 2>/dev/null
|
#cp ${BUILDDIR_32}/spicetools/32/kld.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/spice64.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/spice64.exe ${OUTDIR} 2>/dev/null
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
docker build --pull external/docker -t spicetools/deps
|
docker build --pull external/docker -t spicetools/deps
|
||||||
docker build --build-context gitroot=%cd%/../../.git . -t spicetools/spice --no-cache
|
docker build --build-context gitroot=%cd%/../../.git . -t spicetools/spice
|
||||||
docker run --rm -it -v %cd%/dist:/src/src/spice2x/dist -v %cd%/bin:/src/src/spice2x/bin spicetools/spice
|
docker run --rm -it -v %cd%/dist:/src/src/spice2x/dist -v %cd%/bin:/src/src/spice2x/bin -v %cd%/.ccache:/src/src/spice2x/.ccache spicetools/spice %*
|
||||||
@REM to generate PDBs, set DEBUG to 1 in build_all.sh, place cv2pdb in external\cv2pdb, and run below
|
@REM to generate PDBs, set DEBUG to 1 in build_all.sh, place cv2pdb in external\cv2pdb, and run below
|
||||||
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spicecfg.exe bin\spice2x\spicecfg-pdb.exe bin\spice2x\spicecfg-pdb.pdb
|
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spicecfg.exe bin\spice2x\spicecfg-pdb.exe bin\spice2x\spicecfg-pdb.pdb
|
||||||
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spice.exe bin\spice2x\spice-pdb.exe bin\spice2x\spice-pdb.pdb
|
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spice.exe bin\spice2x\spice-pdb.exe bin\spice2x\spice-pdb.pdb
|
||||||
|
|||||||
Regular → Executable
+2
-4
@@ -1,6 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
export DOCKER_BUILDKIT=0
|
|
||||||
|
|
||||||
docker build --pull $PWD/external/docker -t spicetools/deps --platform linux/x86_64
|
docker build --pull $PWD/external/docker -t spicetools/deps --platform linux/x86_64
|
||||||
docker build --build-context gitroot=$PWD/../../.git . -t spicetools/spice:latest --no-cache
|
docker build --build-context gitroot=$PWD/../../.git . -t spicetools/spice:latest
|
||||||
docker run --rm -it -v $PWD/dist:/src/src/spice2x/dist -v $PWD/bin:/src/src/spice2x/bin spicetools/spice
|
docker run --rm -v $PWD/dist:/src/src/spice2x/dist -v $PWD/bin:/src/src/spice2x/bin -v $PWD/.ccache:/src/src/spice2x/.ccache spicetools/spice "$@"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
del /s /q .ccache
|
||||||
|
call build_docker.bat
|
||||||
@@ -15,12 +15,18 @@ namespace cfg {
|
|||||||
std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
||||||
|
|
||||||
ScreenResize::ScreenResize() {
|
ScreenResize::ScreenResize() {
|
||||||
|
bool file_exists = false;
|
||||||
if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) {
|
if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) {
|
||||||
this->config_path = SCREEN_RESIZE_CFG_PATH_OVERRIDE.value();
|
this->config_path = SCREEN_RESIZE_CFG_PATH_OVERRIDE.value();
|
||||||
|
if (fileutils::file_exists(this->config_path)) {
|
||||||
|
log_info("ScreenResize", "loading config from: {}", this->config_path.string());
|
||||||
|
file_exists = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_screen_resize.json";
|
this->config_path =
|
||||||
|
fileutils::get_config_file_path("ScreenResize", "spicetools_screen_resize.json", &file_exists);
|
||||||
}
|
}
|
||||||
if (fileutils::file_exists(this->config_path)) {
|
if (file_exists) {
|
||||||
this->config_load();
|
this->config_load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,12 +35,6 @@ namespace cfg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenResize::config_load() {
|
void ScreenResize::config_load() {
|
||||||
if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) {
|
|
||||||
log_info("ScreenResize", "loading custom config: {}", this->config_path.string());
|
|
||||||
} else {
|
|
||||||
log_info("ScreenResize", "loading global config from APPDATA");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string config = fileutils::text_read(this->config_path);
|
std::string config = fileutils::text_read(this->config_path);
|
||||||
if (config.empty()) {
|
if (config.empty()) {
|
||||||
log_info("ScreenResize", "config is empty");
|
log_info("ScreenResize", "config is empty");
|
||||||
@@ -81,16 +81,12 @@ namespace cfg {
|
|||||||
load_bool_value(doc, root + "enable_linear_filter", this->enable_linear_filter);
|
load_bool_value(doc, root + "enable_linear_filter", this->enable_linear_filter);
|
||||||
for (size_t i = 0; i < std::size(this->scene_settings); i++) {
|
for (size_t i = 0; i < std::size(this->scene_settings); i++) {
|
||||||
auto& scene = this->scene_settings[i];
|
auto& scene = this->scene_settings[i];
|
||||||
std::string prefix = "";
|
const std::string prefix = fmt::format("scenes/{}/", i);
|
||||||
if (0 < i) {
|
|
||||||
prefix += fmt::format("scenes/{}/", i-1);
|
|
||||||
}
|
|
||||||
load_int_value(doc, root + prefix + "offset_x", scene.offset_x);
|
load_int_value(doc, root + prefix + "offset_x", scene.offset_x);
|
||||||
load_int_value(doc, root + prefix + "offset_y", scene.offset_y);
|
load_int_value(doc, root + prefix + "offset_y", scene.offset_y);
|
||||||
load_float_value(doc, root + prefix + "scale_x", scene.scale_x);
|
load_float_value(doc, root + prefix + "scale_x", scene.scale_x);
|
||||||
load_float_value(doc, root + prefix + "scale_y", scene.scale_y);
|
load_float_value(doc, root + prefix + "scale_y", scene.scale_y);
|
||||||
load_bool_value(doc, root + prefix + "keep_aspect_ratio", scene.keep_aspect_ratio);
|
load_bool_value(doc, root + prefix + "keep_aspect_ratio", scene.keep_aspect_ratio);
|
||||||
load_bool_value(doc, root + prefix + "centered", scene.centered);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// windowed settings are always under game settings
|
// windowed settings are always under game settings
|
||||||
@@ -174,8 +170,6 @@ namespace cfg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenResize::config_save() {
|
void ScreenResize::config_save() {
|
||||||
log_info("ScreenResize", "saving config: {}", this->config_path.string());
|
|
||||||
|
|
||||||
rapidjson::Document doc;
|
rapidjson::Document doc;
|
||||||
std::string config = fileutils::text_read(this->config_path);
|
std::string config = fileutils::text_read(this->config_path);
|
||||||
if (!config.empty()) {
|
if (!config.empty()) {
|
||||||
@@ -201,16 +195,12 @@ namespace cfg {
|
|||||||
rapidjson::Pointer(root + "enable_linear_filter").Set(doc, this->enable_linear_filter);
|
rapidjson::Pointer(root + "enable_linear_filter").Set(doc, this->enable_linear_filter);
|
||||||
for (size_t i = 0; i < std::size(this->scene_settings); i++) {
|
for (size_t i = 0; i < std::size(this->scene_settings); i++) {
|
||||||
auto& scene = this->scene_settings[i];
|
auto& scene = this->scene_settings[i];
|
||||||
std::string prefix = "";
|
const std::string prefix = fmt::format("scenes/{}/", i);
|
||||||
if (0 < i) {
|
|
||||||
prefix += fmt::format("scenes/{}/", i-1);
|
|
||||||
}
|
|
||||||
rapidjson::Pointer(root + prefix + "offset_x").Set(doc, scene.offset_x);
|
rapidjson::Pointer(root + prefix + "offset_x").Set(doc, scene.offset_x);
|
||||||
rapidjson::Pointer(root + prefix + "offset_y").Set(doc, scene.offset_y);
|
rapidjson::Pointer(root + prefix + "offset_y").Set(doc, scene.offset_y);
|
||||||
rapidjson::Pointer(root + prefix + "scale_x").Set(doc, scene.scale_x);
|
rapidjson::Pointer(root + prefix + "scale_x").Set(doc, scene.scale_x);
|
||||||
rapidjson::Pointer(root + prefix + "scale_y").Set(doc, scene.scale_y);
|
rapidjson::Pointer(root + prefix + "scale_y").Set(doc, scene.scale_y);
|
||||||
rapidjson::Pointer(root + prefix + "keep_aspect_ratio").Set(doc, scene.keep_aspect_ratio);
|
rapidjson::Pointer(root + prefix + "keep_aspect_ratio").Set(doc, scene.keep_aspect_ratio);
|
||||||
rapidjson::Pointer(root + prefix + "centered").Set(doc, scene.centered);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// windowed mode settings
|
// windowed mode settings
|
||||||
@@ -229,10 +219,10 @@ namespace cfg {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(this->config_path, buffer.GetString())) {
|
if (fileutils::write_config_file("ScreenResize", this->config_path, buffer.GetString())) {
|
||||||
// this->config_dirty = false;
|
// this->config_dirty = false;
|
||||||
} else {
|
} else {
|
||||||
log_warning("ScreenResize", "unable to save config file to {}", this->config_path.string());
|
log_warning("ScreenResize", "unable to save config file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ namespace cfg {
|
|||||||
float scale_x = 1.0;
|
float scale_x = 1.0;
|
||||||
float scale_y = 1.0;
|
float scale_y = 1.0;
|
||||||
bool keep_aspect_ratio = true;
|
bool keep_aspect_ratio = true;
|
||||||
bool centered = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
||||||
|
|||||||
@@ -1,3 +1,22 @@
|
|||||||
|
04/25/2025 [spice2x]
|
||||||
|
LargeAddressAware variant of spice.exe for Metal Gear
|
||||||
|
Save new JSON config files to %appdata%/spice2x
|
||||||
|
Various bug fixes
|
||||||
|
|
||||||
|
04/08/2025 [spice2x]
|
||||||
|
Ensure rawinput touch is default for all games (-wintouch to override)
|
||||||
|
Various overlay UI fixes and improvements, update ImGui library
|
||||||
|
Add missing lights in Museca
|
||||||
|
|
||||||
|
03/29/2025 [spice2x]
|
||||||
|
Add SDVX landscape mode, -forceresswap option
|
||||||
|
Fix bugs in image scaler
|
||||||
|
Configurator UI tweaks
|
||||||
|
|
||||||
|
03/25/2025 [spice2x]
|
||||||
|
Add Mahjong Fight Girl support
|
||||||
|
Add option for custom full screen resolution (-forceres)
|
||||||
|
|
||||||
03/24/2025 [spice2x]
|
03/24/2025 [spice2x]
|
||||||
Auto PIN entry
|
Auto PIN entry
|
||||||
Multiple scenes for image resize
|
Multiple scenes for image resize
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required (VERSION 3.2.0)
|
cmake_minimum_required (VERSION 3.12)
|
||||||
project (DiscordRPC)
|
project (DiscordRPC)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|||||||
+6
-14
@@ -1,25 +1,17 @@
|
|||||||
FROM archlinux:base
|
FROM ghcr.io/archlinux/archlinux:base-devel
|
||||||
|
|
||||||
RUN pacman --noconfirm -Syu gettext \
|
RUN pacman --noconfirm -Syu git \
|
||||||
base-devel \
|
|
||||||
git \
|
|
||||||
bash \
|
bash \
|
||||||
zip \
|
zip \
|
||||||
upx \
|
upx \
|
||||||
sudo \
|
ninja \
|
||||||
binutils \
|
|
||||||
file \
|
|
||||||
make \
|
|
||||||
gcc \
|
|
||||||
fakeroot \
|
|
||||||
diffutils \
|
|
||||||
cmake \
|
cmake \
|
||||||
awk \
|
|
||||||
unzip \
|
unzip \
|
||||||
mingw-w64-crt \
|
mingw-w64-crt \
|
||||||
mingw-w64-winpthreads \
|
mingw-w64-winpthreads \
|
||||||
mingw-w64-gcc \
|
mingw-w64-gcc \
|
||||||
mingw-w64-headers \
|
mingw-w64-headers \
|
||||||
mingw-w64-binutils
|
mingw-w64-binutils \
|
||||||
|
ccache
|
||||||
RUN useradd user -m && echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
RUN useradd user -m && echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||||
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay.git --depth=1 && cd yay && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
|
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay-bin.git --depth=1 && cd yay-bin && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
project(imgui CXX)
|
project(imgui CXX)
|
||||||
|
|
||||||
set(HASH_LIBRARY_HEADERS
|
set(HASH_LIBRARY_HEADERS
|
||||||
|
|||||||
+5
-3
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
project(imgui CXX)
|
project(imgui CXX)
|
||||||
|
|
||||||
# dear imgui uses the C++ virtual interfaces for DirectX
|
# dear imgui uses the C++ virtual interfaces for DirectX
|
||||||
@@ -8,7 +8,8 @@ set(IMGUI_HEADERS
|
|||||||
imconfig.h
|
imconfig.h
|
||||||
imgui.h
|
imgui.h
|
||||||
imgui_internal.h
|
imgui_internal.h
|
||||||
imgui_stdlib.h
|
backends/imgui_impl_dx9.h
|
||||||
|
misc/cpp/imgui_stdlib.h
|
||||||
)
|
)
|
||||||
set(IMGUI_SOURCES
|
set(IMGUI_SOURCES
|
||||||
imgui.cpp
|
imgui.cpp
|
||||||
@@ -16,7 +17,8 @@ set(IMGUI_SOURCES
|
|||||||
imgui_tables.cpp
|
imgui_tables.cpp
|
||||||
imgui_widgets.cpp
|
imgui_widgets.cpp
|
||||||
imgui_demo.cpp
|
imgui_demo.cpp
|
||||||
imgui_stdlib.cpp
|
backends/imgui_impl_dx9.cpp
|
||||||
|
misc/cpp/imgui_stdlib.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(imgui STATIC ${IMGUI_HEADERS} ${IMGUI_SOURCES})
|
add_library(imgui STATIC ${IMGUI_HEADERS} ${IMGUI_SOURCES})
|
||||||
|
|||||||
Vendored
+3
-3
@@ -22,14 +22,14 @@
|
|||||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
|
||||||
#include "impl_dx9.h"
|
#include "imgui_impl_dx9.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
// DirectX
|
// DirectX
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
|
|
||||||
#include "external/imgui/imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
// allow std::min use
|
// allow std::min use
|
||||||
#ifdef min
|
#ifdef min
|
||||||
@@ -327,7 +327,7 @@ void ImGui_ImplDX9_InvalidateDeviceObjects() {
|
|||||||
if (g_FontTexture) {
|
if (g_FontTexture) {
|
||||||
g_FontTexture->Release();
|
g_FontTexture->Release();
|
||||||
g_FontTexture = NULL;
|
g_FontTexture = NULL;
|
||||||
ImGui::GetIO().Fonts->TexID = NULL;
|
ImGui::GetIO().Fonts->TexID = 0;
|
||||||
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||||
}
|
}
|
||||||
|
|
||||||
Vendored
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "external/imgui/imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
struct IDirect3DDevice9;
|
struct IDirect3DDevice9;
|
||||||
|
|
||||||
+33
-16
@@ -1,5 +1,5 @@
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -21,27 +21,29 @@
|
|||||||
|
|
||||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||||
//#define IMGUI_API __declspec( dllexport )
|
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
|
||||||
//#define IMGUI_API __declspec( dllimport )
|
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
|
||||||
|
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
|
||||||
|
|
||||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
|
||||||
|
|
||||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||||
|
|
||||||
//---- Don't implement some functions to reduce linkage requirements.
|
//---- Don't implement some functions to reduce linkage requirements.
|
||||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||||
#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
|
||||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||||
@@ -49,8 +51,13 @@
|
|||||||
#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||||
|
|
||||||
|
//---- Enable Test Engine / Automation features.
|
||||||
|
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
|
||||||
|
|
||||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||||
|
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
|
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||||
|
|
||||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||||
#define IMGUI_USE_BGRA_PACKED_COLOR
|
#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
@@ -58,16 +65,17 @@
|
|||||||
//---- Performance optimization for DX9
|
//---- Performance optimization for DX9
|
||||||
#define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
#define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||||
|
|
||||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||||
//#define IMGUI_USE_WCHAR32
|
//#define IMGUI_USE_WCHAR32
|
||||||
|
|
||||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
|
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||||
|
|
||||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||||
@@ -78,6 +86,15 @@
|
|||||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||||
//#define IMGUI_ENABLE_FREETYPE
|
//#define IMGUI_ENABLE_FREETYPE
|
||||||
|
|
||||||
|
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||||
|
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||||
|
// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg.
|
||||||
|
// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions.
|
||||||
|
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||||
|
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||||
|
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||||
|
|
||||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||||
@@ -108,7 +125,7 @@
|
|||||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||||
//#define ImDrawCallback MyImDrawCallback
|
//#define ImDrawCallback MyImDrawCallback
|
||||||
|
|
||||||
//---- Debug Tools: Macro to break in Debugger
|
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||||
//#define IM_DEBUG_BREAK __debugbreak()
|
//#define IM_DEBUG_BREAK __debugbreak()
|
||||||
@@ -116,10 +133,10 @@
|
|||||||
//---- Debug Tools: Enable slower asserts
|
//---- Debug Tools: Enable slower asserts
|
||||||
//#define IMGUI_DEBUG_PARANOID
|
//#define IMGUI_DEBUG_PARANOID
|
||||||
|
|
||||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||||
/*
|
/*
|
||||||
namespace ImGui
|
namespace ImGui
|
||||||
{
|
{
|
||||||
void MyFunction(const char* name, const MyMatrix44& v);
|
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|||||||
Vendored
+4651
-2301
File diff suppressed because it is too large
Load Diff
Vendored
+1497
-902
File diff suppressed because it is too large
Load Diff
+3015
-663
File diff suppressed because it is too large
Load Diff
+621
-129
File diff suppressed because it is too large
Load Diff
+938
-658
File diff suppressed because it is too large
Load Diff
+584
-235
File diff suppressed because it is too large
Load Diff
+2536
-870
File diff suppressed because it is too large
Load Diff
+139
-107
@@ -2,8 +2,11 @@
|
|||||||
// This is a slightly modified version of stb_textedit.h 1.14.
|
// This is a slightly modified version of stb_textedit.h 1.14.
|
||||||
// Those changes would need to be pushed into nothings/stb:
|
// Those changes would need to be pushed into nothings/stb:
|
||||||
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
||||||
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000)
|
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
|
||||||
|
// - Added name to struct or it may be forward declared in our code.
|
||||||
|
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
|
||||||
// Grep for [DEAR IMGUI] to find the changes.
|
// Grep for [DEAR IMGUI] to find the changes.
|
||||||
|
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
|
||||||
|
|
||||||
// stb_textedit.h - v1.14 - public domain - Sean Barrett
|
// stb_textedit.h - v1.14 - public domain - Sean Barrett
|
||||||
// Development of this library was sponsored by RAD Game Tools
|
// Development of this library was sponsored by RAD Game Tools
|
||||||
@@ -30,7 +33,7 @@
|
|||||||
// DEPENDENCIES
|
// DEPENDENCIES
|
||||||
//
|
//
|
||||||
// Uses the C runtime function 'memmove', which you can override
|
// Uses the C runtime function 'memmove', which you can override
|
||||||
// by defining STB_TEXTEDIT_memmove before the implementation.
|
// by defining IMSTB_TEXTEDIT_memmove before the implementation.
|
||||||
// Uses no other functions. Performs no runtime allocations.
|
// Uses no other functions. Performs no runtime allocations.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@@ -40,7 +43,7 @@
|
|||||||
// 1.13 (2019-02-07) fix bug in undo size management
|
// 1.13 (2019-02-07) fix bug in undo size management
|
||||||
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
|
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
|
||||||
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
|
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
|
||||||
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
|
// 1.10 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
|
||||||
// 1.9 (2016-08-27) customizable move-by-word
|
// 1.9 (2016-08-27) customizable move-by-word
|
||||||
// 1.8 (2016-04-02) better keyboard handling when mouse button is down
|
// 1.8 (2016-04-02) better keyboard handling when mouse button is down
|
||||||
// 1.7 (2015-09-13) change y range handling in case baseline is non-0
|
// 1.7 (2015-09-13) change y range handling in case baseline is non-0
|
||||||
@@ -208,6 +211,7 @@
|
|||||||
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||||
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
||||||
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
|
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
|
||||||
|
// void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len)
|
||||||
//
|
//
|
||||||
// Each of these functions potentially updates the string and updates the
|
// Each of these functions potentially updates the string and updates the
|
||||||
// state.
|
// state.
|
||||||
@@ -242,7 +246,12 @@
|
|||||||
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
|
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
|
||||||
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
|
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
|
||||||
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
|
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
|
||||||
// anything other type you wante before including.
|
// anything other type you want before including.
|
||||||
|
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
|
||||||
|
// transformed into text and stb_textedit_text() is automatically called.
|
||||||
|
//
|
||||||
|
// text: [DEAR IMGUI] added 2024-09
|
||||||
|
// call this to text inputs sent to the textfield.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// When rendering, you can read the cursor position and selection state from
|
// When rendering, you can read the cursor position and selection state from
|
||||||
@@ -274,8 +283,8 @@
|
|||||||
////
|
////
|
||||||
////
|
////
|
||||||
|
|
||||||
#ifndef INCLUDE_STB_TEXTEDIT_H
|
#ifndef INCLUDE_IMSTB_TEXTEDIT_H
|
||||||
#define INCLUDE_STB_TEXTEDIT_H
|
#define INCLUDE_IMSTB_TEXTEDIT_H
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -286,38 +295,38 @@
|
|||||||
// and undo state.
|
// and undo state.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef STB_TEXTEDIT_UNDOSTATECOUNT
|
#ifndef IMSTB_TEXTEDIT_UNDOSTATECOUNT
|
||||||
#define STB_TEXTEDIT_UNDOSTATECOUNT 99
|
#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
|
||||||
#endif
|
#endif
|
||||||
#ifndef STB_TEXTEDIT_UNDOCHARCOUNT
|
#ifndef IMSTB_TEXTEDIT_UNDOCHARCOUNT
|
||||||
#define STB_TEXTEDIT_UNDOCHARCOUNT 999
|
#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
|
||||||
#endif
|
#endif
|
||||||
#ifndef STB_TEXTEDIT_CHARTYPE
|
#ifndef IMSTB_TEXTEDIT_CHARTYPE
|
||||||
#define STB_TEXTEDIT_CHARTYPE int
|
#define IMSTB_TEXTEDIT_CHARTYPE int
|
||||||
#endif
|
#endif
|
||||||
#ifndef STB_TEXTEDIT_POSITIONTYPE
|
#ifndef IMSTB_TEXTEDIT_POSITIONTYPE
|
||||||
#define STB_TEXTEDIT_POSITIONTYPE int
|
#define IMSTB_TEXTEDIT_POSITIONTYPE int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
// private data
|
// private data
|
||||||
STB_TEXTEDIT_POSITIONTYPE where;
|
IMSTB_TEXTEDIT_POSITIONTYPE where;
|
||||||
STB_TEXTEDIT_POSITIONTYPE insert_length;
|
IMSTB_TEXTEDIT_POSITIONTYPE insert_length;
|
||||||
STB_TEXTEDIT_POSITIONTYPE delete_length;
|
IMSTB_TEXTEDIT_POSITIONTYPE delete_length;
|
||||||
int char_storage;
|
int char_storage;
|
||||||
} StbUndoRecord;
|
} StbUndoRecord;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
// private data
|
// private data
|
||||||
StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];
|
StbUndoRecord undo_rec [IMSTB_TEXTEDIT_UNDOSTATECOUNT];
|
||||||
STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
|
IMSTB_TEXTEDIT_CHARTYPE undo_char[IMSTB_TEXTEDIT_UNDOCHARCOUNT];
|
||||||
short undo_point, redo_point;
|
short undo_point, redo_point;
|
||||||
int undo_char_point, redo_char_point;
|
int undo_char_point, redo_char_point;
|
||||||
} StbUndoState;
|
} StbUndoState;
|
||||||
|
|
||||||
typedef struct
|
typedef struct STB_TexteditState
|
||||||
{
|
{
|
||||||
/////////////////////
|
/////////////////////
|
||||||
//
|
//
|
||||||
@@ -371,7 +380,7 @@ typedef struct
|
|||||||
float ymin,ymax; // height of row above and below baseline
|
float ymin,ymax; // height of row above and below baseline
|
||||||
int num_chars;
|
int num_chars;
|
||||||
} StbTexteditRow;
|
} StbTexteditRow;
|
||||||
#endif //INCLUDE_STB_TEXTEDIT_H
|
#endif //INCLUDE_IMSTB_TEXTEDIT_H
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -384,11 +393,11 @@ typedef struct
|
|||||||
|
|
||||||
// implementation isn't include-guarded, since it might have indirectly
|
// implementation isn't include-guarded, since it might have indirectly
|
||||||
// included just the "header" portion
|
// included just the "header" portion
|
||||||
#ifdef STB_TEXTEDIT_IMPLEMENTATION
|
#ifdef IMSTB_TEXTEDIT_IMPLEMENTATION
|
||||||
|
|
||||||
#ifndef STB_TEXTEDIT_memmove
|
#ifndef IMSTB_TEXTEDIT_memmove
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#define STB_TEXTEDIT_memmove memmove
|
#define IMSTB_TEXTEDIT_memmove memmove
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -398,7 +407,7 @@ typedef struct
|
|||||||
//
|
//
|
||||||
|
|
||||||
// traverse the layout to locate the nearest character to a display position
|
// traverse the layout to locate the nearest character to a display position
|
||||||
static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
||||||
{
|
{
|
||||||
StbTexteditRow r;
|
StbTexteditRow r;
|
||||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
@@ -437,13 +446,13 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
|||||||
if (x < r.x1) {
|
if (x < r.x1) {
|
||||||
// search characters in row for one that straddles 'x'
|
// search characters in row for one that straddles 'x'
|
||||||
prev_x = r.x0;
|
prev_x = r.x0;
|
||||||
for (k=0; k < r.num_chars; ++k) {
|
for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
|
||||||
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
|
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
|
||||||
if (x < prev_x+w) {
|
if (x < prev_x+w) {
|
||||||
if (x < prev_x+w/2)
|
if (x < prev_x+w/2)
|
||||||
return k+i;
|
return k+i;
|
||||||
else
|
else
|
||||||
return k+i+1;
|
return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
|
||||||
}
|
}
|
||||||
prev_x += w;
|
prev_x += w;
|
||||||
}
|
}
|
||||||
@@ -458,7 +467,7 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API click: on mouse down, move the cursor to the clicked location, and reset the selection
|
// API click: on mouse down, move the cursor to the clicked location, and reset the selection
|
||||||
static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||||
{
|
{
|
||||||
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
||||||
// goes off the top or bottom of the text
|
// goes off the top or bottom of the text
|
||||||
@@ -476,7 +485,7 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
|
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
|
||||||
static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||||
{
|
{
|
||||||
int p = 0;
|
int p = 0;
|
||||||
|
|
||||||
@@ -502,11 +511,11 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
|
|||||||
//
|
//
|
||||||
|
|
||||||
// forward declarations
|
// forward declarations
|
||||||
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||||
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||||
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
||||||
static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length);
|
static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length);
|
||||||
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
|
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -518,7 +527,7 @@ typedef struct
|
|||||||
|
|
||||||
// find the x/y location of a character, and remember info about the previous row in
|
// find the x/y location of a character, and remember info about the previous row in
|
||||||
// case we get a move-up event (for page up, we'll have to rescan)
|
// case we get a move-up event (for page up, we'll have to rescan)
|
||||||
static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line)
|
static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING *str, int n, int single_line)
|
||||||
{
|
{
|
||||||
StbTexteditRow r;
|
StbTexteditRow r;
|
||||||
int prev_start = 0;
|
int prev_start = 0;
|
||||||
@@ -549,7 +558,10 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
|
|||||||
i += r.num_chars;
|
i += r.num_chars;
|
||||||
find->y += r.baseline_y_delta;
|
find->y += r.baseline_y_delta;
|
||||||
if (i == z) // [DEAR IMGUI]
|
if (i == z) // [DEAR IMGUI]
|
||||||
|
{
|
||||||
|
r.num_chars = 0; // [DEAR IMGUI]
|
||||||
break; // [DEAR IMGUI]
|
break; // [DEAR IMGUI]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
find->first_char = first = i;
|
find->first_char = first = i;
|
||||||
@@ -559,14 +571,14 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
|
|||||||
|
|
||||||
// now scan to find xpos
|
// now scan to find xpos
|
||||||
find->x = r.x0;
|
find->x = r.x0;
|
||||||
for (i=0; first+i < n; ++i)
|
for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
|
||||||
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
|
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
|
#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
|
||||||
|
|
||||||
// make the selection/cursor state valid if client altered the string
|
// make the selection/cursor state valid if client altered the string
|
||||||
static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
static void stb_textedit_clamp(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||||
{
|
{
|
||||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||||
@@ -580,7 +592,7 @@ static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete characters while updating undo
|
// delete characters while updating undo
|
||||||
static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
|
static void stb_textedit_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
|
||||||
{
|
{
|
||||||
stb_text_makeundo_delete(str, state, where, len);
|
stb_text_makeundo_delete(str, state, where, len);
|
||||||
STB_TEXTEDIT_DELETECHARS(str, where, len);
|
STB_TEXTEDIT_DELETECHARS(str, where, len);
|
||||||
@@ -588,7 +600,7 @@ static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete the section
|
// delete the section
|
||||||
static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
static void stb_textedit_delete_selection(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||||
{
|
{
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||||
@@ -625,7 +637,7 @@ static void stb_textedit_move_to_first(STB_TexteditState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// move cursor to last character of selection
|
// move cursor to last character of selection
|
||||||
static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||||
{
|
{
|
||||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||||
stb_textedit_sortselection(state);
|
stb_textedit_sortselection(state);
|
||||||
@@ -636,14 +648,25 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [DEAR IMGUI]
|
||||||
|
// Functions must be implemented for UTF8 support
|
||||||
|
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
|
||||||
|
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
|
||||||
|
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
|
||||||
|
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1)
|
||||||
|
#endif
|
||||||
|
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
|
||||||
|
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef STB_TEXTEDIT_IS_SPACE
|
#ifdef STB_TEXTEDIT_IS_SPACE
|
||||||
static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
|
static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
||||||
{
|
{
|
||||||
return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
|
return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
||||||
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
|
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||||
{
|
{
|
||||||
--c; // always move at least one character
|
--c; // always move at least one character
|
||||||
while( c >= 0 && !is_word_boundary( str, c ) )
|
while( c >= 0 && !is_word_boundary( str, c ) )
|
||||||
@@ -658,7 +681,7 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
|
#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
|
||||||
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
|
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||||
{
|
{
|
||||||
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
++c; // always move at least one character
|
++c; // always move at least one character
|
||||||
@@ -685,7 +708,7 @@ static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API cut: delete selection
|
// API cut: delete selection
|
||||||
static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
static int stb_textedit_cut(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||||
{
|
{
|
||||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||||
stb_textedit_delete_selection(str,state); // implicitly clamps
|
stb_textedit_delete_selection(str,state); // implicitly clamps
|
||||||
@@ -696,7 +719,7 @@ static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API paste: replace existing selection with passed-in text
|
// API paste: replace existing selection with passed-in text
|
||||||
static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE *text, int len)
|
||||||
{
|
{
|
||||||
// if there's a selection, the paste should delete it
|
// if there's a selection, the paste should delete it
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
@@ -716,36 +739,44 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
|
|||||||
#define STB_TEXTEDIT_KEYTYPE int
|
#define STB_TEXTEDIT_KEYTYPE int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
|
||||||
|
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
|
||||||
|
{
|
||||||
|
// can't add newline in single-line mode
|
||||||
|
if (text[0] == '\n' && state->single_line)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
||||||
|
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
||||||
|
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
||||||
|
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
||||||
|
state->cursor += text_len;
|
||||||
|
state->has_preferred_x = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stb_textedit_delete_selection(str, state); // implicitly clamps
|
||||||
|
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
||||||
|
stb_text_makeundo_insert(state, state->cursor, text_len);
|
||||||
|
state->cursor += text_len;
|
||||||
|
state->has_preferred_x = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// API key: process a keyboard input
|
// API key: process a keyboard input
|
||||||
static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
|
static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
|
||||||
{
|
{
|
||||||
retry:
|
retry:
|
||||||
switch (key) {
|
switch (key) {
|
||||||
default: {
|
default: {
|
||||||
|
#ifdef STB_TEXTEDIT_KEYTOTEXT
|
||||||
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c;
|
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
|
||||||
|
stb_textedit_text(str, state, &ch, 1);
|
||||||
// can't add newline in single-line mode
|
|
||||||
if (c == '\n' && state->single_line)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
|
||||||
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
|
||||||
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
|
||||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
|
|
||||||
++state->cursor;
|
|
||||||
state->has_preferred_x = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stb_textedit_delete_selection(str,state); // implicitly clamps
|
|
||||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
|
|
||||||
stb_text_makeundo_insert(state, state->cursor, 1);
|
|
||||||
++state->cursor;
|
|
||||||
state->has_preferred_x = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,7 +802,7 @@ retry:
|
|||||||
stb_textedit_move_to_first(state);
|
stb_textedit_move_to_first(state);
|
||||||
else
|
else
|
||||||
if (state->cursor > 0)
|
if (state->cursor > 0)
|
||||||
--state->cursor;
|
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -780,7 +811,7 @@ retry:
|
|||||||
if (STB_TEXT_HAS_SELECTION(state))
|
if (STB_TEXT_HAS_SELECTION(state))
|
||||||
stb_textedit_move_to_last(str, state);
|
stb_textedit_move_to_last(str, state);
|
||||||
else
|
else
|
||||||
++state->cursor;
|
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
@@ -790,7 +821,7 @@ retry:
|
|||||||
stb_textedit_prep_selection_at_cursor(state);
|
stb_textedit_prep_selection_at_cursor(state);
|
||||||
// move selection left
|
// move selection left
|
||||||
if (state->select_end > 0)
|
if (state->select_end > 0)
|
||||||
--state->select_end;
|
state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
|
||||||
state->cursor = state->select_end;
|
state->cursor = state->select_end;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
@@ -840,7 +871,7 @@ retry:
|
|||||||
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
|
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
|
||||||
stb_textedit_prep_selection_at_cursor(state);
|
stb_textedit_prep_selection_at_cursor(state);
|
||||||
// move selection right
|
// move selection right
|
||||||
++state->select_end;
|
state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
state->cursor = state->select_end;
|
state->cursor = state->select_end;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
@@ -889,14 +920,14 @@ retry:
|
|||||||
x = row.x0;
|
x = row.x0;
|
||||||
for (i=0; i < row.num_chars; ++i) {
|
for (i=0; i < row.num_chars; ++i) {
|
||||||
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
||||||
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||||
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
x += dx;
|
x += dx;
|
||||||
if (x > goal_x)
|
if (x > goal_x)
|
||||||
break;
|
break;
|
||||||
++state->cursor;
|
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||||
}
|
}
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
|
|
||||||
@@ -951,14 +982,14 @@ retry:
|
|||||||
x = row.x0;
|
x = row.x0;
|
||||||
for (i=0; i < row.num_chars; ++i) {
|
for (i=0; i < row.num_chars; ++i) {
|
||||||
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
||||||
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||||
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
x += dx;
|
x += dx;
|
||||||
if (x > goal_x)
|
if (x > goal_x)
|
||||||
break;
|
break;
|
||||||
++state->cursor;
|
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||||
}
|
}
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
|
|
||||||
@@ -986,7 +1017,7 @@ retry:
|
|||||||
else {
|
else {
|
||||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
if (state->cursor < n)
|
if (state->cursor < n)
|
||||||
stb_textedit_delete(str, state, state->cursor, 1);
|
stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
|
||||||
}
|
}
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
@@ -998,8 +1029,9 @@ retry:
|
|||||||
else {
|
else {
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
if (state->cursor > 0) {
|
if (state->cursor > 0) {
|
||||||
stb_textedit_delete(str, state, state->cursor-1, 1);
|
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||||
--state->cursor;
|
stb_textedit_delete(str, state, prev, state->cursor - prev);
|
||||||
|
state->cursor = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
@@ -1109,8 +1141,8 @@ retry:
|
|||||||
|
|
||||||
static void stb_textedit_flush_redo(StbUndoState *state)
|
static void stb_textedit_flush_redo(StbUndoState *state)
|
||||||
{
|
{
|
||||||
state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
|
state->redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
|
||||||
state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
|
state->redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// discard the oldest entry in the undo list
|
// discard the oldest entry in the undo list
|
||||||
@@ -1122,13 +1154,13 @@ static void stb_textedit_discard_undo(StbUndoState *state)
|
|||||||
int n = state->undo_rec[0].insert_length, i;
|
int n = state->undo_rec[0].insert_length, i;
|
||||||
// delete n characters from all other records
|
// delete n characters from all other records
|
||||||
state->undo_char_point -= n;
|
state->undo_char_point -= n;
|
||||||
STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
IMSTB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
|
||||||
for (i=0; i < state->undo_point; ++i)
|
for (i=0; i < state->undo_point; ++i)
|
||||||
if (state->undo_rec[i].char_storage >= 0)
|
if (state->undo_rec[i].char_storage >= 0)
|
||||||
state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it
|
state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it
|
||||||
}
|
}
|
||||||
--state->undo_point;
|
--state->undo_point;
|
||||||
STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
|
IMSTB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1138,7 +1170,7 @@ static void stb_textedit_discard_undo(StbUndoState *state)
|
|||||||
// fill up even though the undo buffer didn't
|
// fill up even though the undo buffer didn't
|
||||||
static void stb_textedit_discard_redo(StbUndoState *state)
|
static void stb_textedit_discard_redo(StbUndoState *state)
|
||||||
{
|
{
|
||||||
int k = STB_TEXTEDIT_UNDOSTATECOUNT-1;
|
int k = IMSTB_TEXTEDIT_UNDOSTATECOUNT-1;
|
||||||
|
|
||||||
if (state->redo_point <= k) {
|
if (state->redo_point <= k) {
|
||||||
// if the k'th undo state has characters, clean those up
|
// if the k'th undo state has characters, clean those up
|
||||||
@@ -1146,7 +1178,7 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
|||||||
int n = state->undo_rec[k].insert_length, i;
|
int n = state->undo_rec[k].insert_length, i;
|
||||||
// move the remaining redo character data to the end of the buffer
|
// move the remaining redo character data to the end of the buffer
|
||||||
state->redo_char_point += n;
|
state->redo_char_point += n;
|
||||||
STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
IMSTB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((IMSTB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
|
||||||
// adjust the position of all the other records to account for above memmove
|
// adjust the position of all the other records to account for above memmove
|
||||||
for (i=state->redo_point; i < k; ++i)
|
for (i=state->redo_point; i < k; ++i)
|
||||||
if (state->undo_rec[i].char_storage >= 0)
|
if (state->undo_rec[i].char_storage >= 0)
|
||||||
@@ -1154,12 +1186,12 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
|||||||
}
|
}
|
||||||
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
|
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
|
||||||
// [DEAR IMGUI]
|
// [DEAR IMGUI]
|
||||||
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
|
size_t move_size = (size_t)((IMSTB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
|
||||||
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
|
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
|
||||||
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
|
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
|
||||||
IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
|
IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
|
||||||
IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
|
IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
|
||||||
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
|
IMSTB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
|
||||||
|
|
||||||
// now move redo_point to point to the new one
|
// now move redo_point to point to the new one
|
||||||
++state->redo_point;
|
++state->redo_point;
|
||||||
@@ -1173,32 +1205,32 @@ static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numch
|
|||||||
|
|
||||||
// if we have no free records, we have to make room, by sliding the
|
// if we have no free records, we have to make room, by sliding the
|
||||||
// existing records down
|
// existing records down
|
||||||
if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
if (state->undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||||
stb_textedit_discard_undo(state);
|
stb_textedit_discard_undo(state);
|
||||||
|
|
||||||
// if the characters to store won't possibly fit in the buffer, we can't undo
|
// if the characters to store won't possibly fit in the buffer, we can't undo
|
||||||
if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
|
if (numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||||
state->undo_point = 0;
|
state->undo_point = 0;
|
||||||
state->undo_char_point = 0;
|
state->undo_char_point = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we don't have enough free characters in the buffer, we have to make room
|
// if we don't have enough free characters in the buffer, we have to make room
|
||||||
while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
|
while (state->undo_char_point + numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT)
|
||||||
stb_textedit_discard_undo(state);
|
stb_textedit_discard_undo(state);
|
||||||
|
|
||||||
return &state->undo_rec[state->undo_point++];
|
return &state->undo_rec[state->undo_point++];
|
||||||
}
|
}
|
||||||
|
|
||||||
static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
|
static IMSTB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
|
||||||
{
|
{
|
||||||
StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
|
StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
|
||||||
if (r == NULL)
|
if (r == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
r->where = pos;
|
r->where = pos;
|
||||||
r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len;
|
r->insert_length = (IMSTB_TEXTEDIT_POSITIONTYPE) insert_len;
|
||||||
r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len;
|
r->delete_length = (IMSTB_TEXTEDIT_POSITIONTYPE) delete_len;
|
||||||
|
|
||||||
if (insert_len == 0) {
|
if (insert_len == 0) {
|
||||||
r->char_storage = -1;
|
r->char_storage = -1;
|
||||||
@@ -1210,7 +1242,7 @@ static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||||
{
|
{
|
||||||
StbUndoState *s = &state->undostate;
|
StbUndoState *s = &state->undostate;
|
||||||
StbUndoRecord u, *r;
|
StbUndoRecord u, *r;
|
||||||
@@ -1237,7 +1269,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
|||||||
// characters stored for *undoing* don't leave room for redo
|
// characters stored for *undoing* don't leave room for redo
|
||||||
// if the last is true, we have to bail
|
// if the last is true, we have to bail
|
||||||
|
|
||||||
if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
|
if (s->undo_char_point + u.delete_length >= IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||||
// the undo records take up too much character space; there's no space to store the redo characters
|
// the undo records take up too much character space; there's no space to store the redo characters
|
||||||
r->insert_length = 0;
|
r->insert_length = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -1246,7 +1278,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
|||||||
// there's definitely room to store the characters eventually
|
// there's definitely room to store the characters eventually
|
||||||
while (s->undo_char_point + u.delete_length > s->redo_char_point) {
|
while (s->undo_char_point + u.delete_length > s->redo_char_point) {
|
||||||
// should never happen:
|
// should never happen:
|
||||||
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||||
return;
|
return;
|
||||||
// there's currently not enough room, so discard a redo record
|
// there's currently not enough room, so discard a redo record
|
||||||
stb_textedit_discard_redo(s);
|
stb_textedit_discard_redo(s);
|
||||||
@@ -1278,11 +1310,11 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
|||||||
s->redo_point--;
|
s->redo_point--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||||
{
|
{
|
||||||
StbUndoState *s = &state->undostate;
|
StbUndoState *s = &state->undostate;
|
||||||
StbUndoRecord *u, r;
|
StbUndoRecord *u, r;
|
||||||
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// we need to do two things: apply the redo record, and create an undo record
|
// we need to do two things: apply the redo record, and create an undo record
|
||||||
@@ -1334,20 +1366,20 @@ static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int le
|
|||||||
stb_text_createundo(&state->undostate, where, 0, length);
|
stb_text_createundo(&state->undostate, where, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
|
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
|
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
|
||||||
if (p) {
|
if (p) {
|
||||||
for (i=0; i < length; ++i)
|
for (i=0; i < length; ++i)
|
||||||
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
|
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
|
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
|
||||||
if (p) {
|
if (p) {
|
||||||
for (i=0; i < old_length; ++i)
|
for (i=0; i < old_length; ++i)
|
||||||
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
||||||
@@ -1359,8 +1391,8 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin
|
|||||||
{
|
{
|
||||||
state->undostate.undo_point = 0;
|
state->undostate.undo_point = 0;
|
||||||
state->undostate.undo_char_point = 0;
|
state->undostate.undo_char_point = 0;
|
||||||
state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
|
state->undostate.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
|
||||||
state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
|
state->undostate.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
|
||||||
state->select_end = state->select_start = 0;
|
state->select_end = state->select_start = 0;
|
||||||
state->cursor = 0;
|
state->cursor = 0;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
@@ -1383,16 +1415,16 @@ static void stb_textedit_initialize_state(STB_TexteditState *state, int is_singl
|
|||||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
static int stb_textedit_paste(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
||||||
{
|
{
|
||||||
return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
|
return stb_textedit_paste_internal(str, state, (IMSTB_TEXTEDIT_CHARTYPE *) ctext, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif//STB_TEXTEDIT_IMPLEMENTATION
|
#endif//IMSTB_TEXTEDIT_IMPLEMENTATION
|
||||||
|
|
||||||
/*
|
/*
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|||||||
+1
-1
@@ -656,7 +656,7 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
|
|||||||
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
|
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
|
||||||
// If skip != 0, this tells stb_truetype to skip any codepoints for which
|
// If skip != 0, this tells stb_truetype to skip any codepoints for which
|
||||||
// there is no corresponding glyph. If skip=0, which is the default, then
|
// there is no corresponding glyph. If skip=0, which is the default, then
|
||||||
// codepoints without a glyph recived the font's "missing character" glyph,
|
// codepoints without a glyph received the font's "missing character" glyph,
|
||||||
// typically an empty box by convention.
|
// typically an empty box by convention.
|
||||||
|
|
||||||
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
|
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
|
||||||
|
|||||||
Vendored
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
cmake_policy(SET CMP0069 NEW)
|
cmake_policy(SET CMP0069 NEW)
|
||||||
project(minhook)
|
project(minhook)
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace games::iidx {
|
|||||||
static IIDXLocalCamera *front_camera = nullptr; // camera id #1
|
static IIDXLocalCamera *front_camera = nullptr; // camera id #1
|
||||||
std::vector<IIDXLocalCamera*> LOCAL_CAMERA_LIST = {};
|
std::vector<IIDXLocalCamera*> LOCAL_CAMERA_LIST = {};
|
||||||
static IDirect3DDeviceManager9 *s_pD3DManager = nullptr;
|
static IDirect3DDeviceManager9 *s_pD3DManager = nullptr;
|
||||||
std::filesystem::path CAMERA_CONFIG_PATH = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_camera_control.json";
|
std::filesystem::path CAMERA_CONFIG_PATH;
|
||||||
bool CAMERA_READY = false;
|
bool CAMERA_READY = false;
|
||||||
|
|
||||||
bool parse_cmd_params() {
|
bool parse_cmd_params() {
|
||||||
@@ -493,7 +493,8 @@ namespace games::iidx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool camera_config_load() {
|
bool camera_config_load() {
|
||||||
log_info("iidx:camhook", "loading config");
|
CAMERA_CONFIG_PATH =
|
||||||
|
fileutils::get_config_file_path("iidx::camhook", "spicetools_camera_control.json");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// read config file
|
// read config file
|
||||||
@@ -651,9 +652,9 @@ namespace games::iidx {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(CAMERA_CONFIG_PATH, buffer.GetString())) {
|
if (fileutils::write_config_file("iidx::camhook", CAMERA_CONFIG_PATH, buffer.GetString())) {
|
||||||
} else {
|
} else {
|
||||||
log_warning("iidx:camhook", "unable to save config file to {}", CAMERA_CONFIG_PATH.string());
|
log_warning("iidx:camhook", "unable to save config file");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "bc/io.h"
|
#include "bc/io.h"
|
||||||
#include "ccj/io.h"
|
#include "ccj/io.h"
|
||||||
#include "qks/io.h"
|
#include "qks/io.h"
|
||||||
|
#include "mfg/io.h"
|
||||||
|
|
||||||
namespace games {
|
namespace games {
|
||||||
|
|
||||||
@@ -305,6 +306,13 @@ namespace games {
|
|||||||
buttons.insert({ qks, qks::get_buttons() });
|
buttons.insert({ qks, qks::get_buttons() });
|
||||||
buttons_help.insert({ qks, qks::get_buttons_help() });
|
buttons_help.insert({ qks, qks::get_buttons_help() });
|
||||||
file_hints[qks].emplace_back("game/uks.exe");
|
file_hints[qks].emplace_back("game/uks.exe");
|
||||||
|
|
||||||
|
// Mahjong Fight Girl
|
||||||
|
const std::string mfg("Mahjong Fight Girl");
|
||||||
|
games.push_back(mfg);
|
||||||
|
buttons.insert({ mfg, mfg::get_buttons() });
|
||||||
|
buttons_help.insert({ mfg, mfg::get_buttons_help() });
|
||||||
|
file_hints[mfg].emplace_back("game/MFGClient_Data");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &get_games() {
|
const std::vector<std::string> &get_games() {
|
||||||
@@ -453,18 +461,6 @@ namespace games {
|
|||||||
vkey_defaults.push_back(0xFF);
|
vkey_defaults.push_back(0xFF);
|
||||||
names.emplace_back("Force Exit Game");
|
names.emplace_back("Force Exit Game");
|
||||||
vkey_defaults.push_back(0xFF);
|
vkey_defaults.push_back(0xFF);
|
||||||
names.emplace_back("Navigator Activate");
|
|
||||||
vkey_defaults.push_back(0xFF);
|
|
||||||
names.emplace_back("Navigator Cancel");
|
|
||||||
vkey_defaults.push_back(0xFF);
|
|
||||||
names.emplace_back("Navigator Up");
|
|
||||||
vkey_defaults.push_back(0xFF);
|
|
||||||
names.emplace_back("Navigator Down");
|
|
||||||
vkey_defaults.push_back(0xFF);
|
|
||||||
names.emplace_back("Navigator Left");
|
|
||||||
vkey_defaults.push_back(0xFF);
|
|
||||||
names.emplace_back("Navigator Right");
|
|
||||||
vkey_defaults.push_back(0xFF);
|
|
||||||
names.emplace_back("Hotkey Enable 1");
|
names.emplace_back("Hotkey Enable 1");
|
||||||
vkey_defaults.push_back(0xFF);
|
vkey_defaults.push_back(0xFF);
|
||||||
names.emplace_back("Hotkey Enable 2");
|
names.emplace_back("Hotkey Enable 2");
|
||||||
|
|||||||
@@ -30,12 +30,6 @@ namespace games {
|
|||||||
ScreenResizeScene3,
|
ScreenResizeScene3,
|
||||||
ScreenResizeScene4,
|
ScreenResizeScene4,
|
||||||
SuperExit,
|
SuperExit,
|
||||||
NavigatorActivate,
|
|
||||||
NavigatorCancel,
|
|
||||||
NavigatorUp,
|
|
||||||
NavigatorDown,
|
|
||||||
NavigatorLeft,
|
|
||||||
NavigatorRight,
|
|
||||||
HotkeyEnable1,
|
HotkeyEnable1,
|
||||||
HotkeyEnable2,
|
HotkeyEnable2,
|
||||||
HotkeyToggle,
|
HotkeyToggle,
|
||||||
|
|||||||
@@ -0,0 +1,385 @@
|
|||||||
|
#include "bi2a_hook.h"
|
||||||
|
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "rawinput/rawinput.h"
|
||||||
|
#include "misc/eamuse.h"
|
||||||
|
#include "games/io.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "util/tapeled.h"
|
||||||
|
|
||||||
|
namespace games::mfg {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* class definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct AIO_SCI_COMM {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_NMGR_IOB {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB_BI2A_VFG {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB_BI2A_VFG__INPUTDATA {
|
||||||
|
uint8_t data[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB_BI2A_VFG__OUTPUTDATA {
|
||||||
|
uint8_t data[40];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB_BI2A_VFG__INPUT
|
||||||
|
{
|
||||||
|
uint8_t bPcPowerCheck;
|
||||||
|
uint8_t CoinCount;
|
||||||
|
uint8_t bTest;
|
||||||
|
uint8_t bService;
|
||||||
|
uint8_t bCoinSw;
|
||||||
|
uint8_t bCoinJam;
|
||||||
|
uint8_t bCabinet;
|
||||||
|
uint8_t bHPDetect;
|
||||||
|
uint8_t bRecDetect;
|
||||||
|
uint8_t bStart;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB_BI2A_VFG__DEVSTATUS
|
||||||
|
{
|
||||||
|
uint8_t MechType;
|
||||||
|
uint8_t bIsBi2a;
|
||||||
|
uint8_t IoCounter;
|
||||||
|
AIO_IOB_BI2A_VFG__INPUT Input;
|
||||||
|
AIO_IOB_BI2A_VFG__INPUTDATA InputData;
|
||||||
|
AIO_IOB_BI2A_VFG__OUTPUTDATA OutputData;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob_video.dll
|
||||||
|
typedef AIO_SCI_COMM* (__fastcall *aioIobBi2a_OpenSciUsbCdc_t)(uint32_t i_SerialNumber);
|
||||||
|
typedef AIO_IOB_BI2A_VFG* (__fastcall *aioIobBi2aVFG_Create_t)(AIO_NMGR_IOB *i_pNodeMgr, uint32_t i_DevId);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_SetMechType_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl, uint32_t i_MechType);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_GetDeviceStatus_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl,
|
||||||
|
AIO_IOB_BI2A_VFG__DEVSTATUS *o_pDevStatus,
|
||||||
|
uint32_t i_cbDevStatus);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_SetWatchDogTimer_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint16_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_ControlCoinBlocker_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Slot,
|
||||||
|
bool i_bOpen);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_AddCounter_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Counter,
|
||||||
|
uint32_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_SetAmpVolume_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Amp,
|
||||||
|
uint32_t i_Volume);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_EnableUsbCharger_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, bool i_bEnable);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_SetLamp_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Lamp, uint8_t i_Bright);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_SetIccrLed_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_RGB);
|
||||||
|
typedef void (__fastcall *aioIobBi2aVFG_SetLedData_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint8_t *i_pData,
|
||||||
|
uint32_t i_cbData);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
typedef AIO_NMGR_IOB* (__fastcall *aioNMgrIob_Create_t)(AIO_SCI_COMM* i_pSci, uint32_t i_bfMode);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
typedef void (__fastcall *aioNodeMgr_Destroy_t)(AIO_NMGR_IOB *i_pNodeMgr);
|
||||||
|
typedef int32_t (__fastcall *aioNodeMgr_GetState_t)(AIO_NMGR_IOB *i_pNodeMgr);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsReady_t)(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsError_t)(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef void (__fastcall *aioNodeCtl_Destroy_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl);
|
||||||
|
typedef int32_t (__fastcall *aioNodeCtl_GetState_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsReady_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsError_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function pointers
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob_video.dll
|
||||||
|
static aioIobBi2a_OpenSciUsbCdc_t aioIobBi2a_OpenSciUsbCdc_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_Create_t aioIobBi2aVFG_Create_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_SetMechType_t aioIobBi2aVFG_SetMechType_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_GetDeviceStatus_t aioIobBi2aVFG_GetDeviceStatus_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_SetWatchDogTimer_t aioIobBi2aVFG_SetWatchDogTimer_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_ControlCoinBlocker_t aioIobBi2aVFG_ControlCoinBlocker_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_AddCounter_t aioIobBi2aVFG_AddCounter_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_SetAmpVolume_t aioIobBi2aVFG_SetAmpVolume_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_EnableUsbCharger_t aioIobBi2aVFG_EnableUsbCharger_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_SetLamp_t aioIobBi2aVFG_SetLamp_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_SetIccrLed_t aioIobBi2aVFG_SetIccrLed_orig = nullptr;
|
||||||
|
static aioIobBi2aVFG_SetLedData_t aioIobBi2aVFG_SetLedData_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
static aioNMgrIob_Create_t aioNMgrIob_Create_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
static aioNodeMgr_Destroy_t aioNodeMgr_Destroy_orig = nullptr;
|
||||||
|
static aioNodeMgr_GetState_t aioNodeMgr_GetState_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsReady_t aioNodeMgr_IsReady_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsError_t aioNodeMgr_IsError_orig = nullptr;
|
||||||
|
static aioNodeCtl_Destroy_t aioNodeCtl_Destroy_orig = nullptr;
|
||||||
|
static aioNodeCtl_GetState_t aioNodeCtl_GetState_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsReady_t aioNodeCtl_IsReady_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsError_t aioNodeCtl_IsError_orig = nullptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
static AIO_SCI_COMM *aioSciComm;
|
||||||
|
static AIO_NMGR_IOB *aioNmgrIob;
|
||||||
|
static AIO_IOB_BI2A_VFG *aioIobBi2aVfg;
|
||||||
|
static uint8_t mechType = 0;
|
||||||
|
static uint8_t count = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
static AIO_SCI_COMM* __fastcall aioIob2Bi2a_OpenSciUsbCdc(uint32_t i_SerialNumber) {
|
||||||
|
log_info("bi2a_hook", "aioIob2Bi2a_OpenSciUsbCdc hook hit");
|
||||||
|
aioSciComm = new AIO_SCI_COMM;
|
||||||
|
return aioSciComm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_IOB_BI2A_VFG* __fastcall aioIobBi2aVFG_Create(AIO_NMGR_IOB *i_pNodeMgr, uint32_t i_DevId) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob) {
|
||||||
|
log_info("bi2a_hook", "node created");
|
||||||
|
aioIobBi2aVfg = new AIO_IOB_BI2A_VFG;
|
||||||
|
return aioIobBi2aVfg;
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_Create_orig(i_pNodeMgr, i_DevId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_SetMechType(AIO_IOB_BI2A_VFG *i_pNodeCtl, uint32_t i_MechType) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
mechType = i_MechType;
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_SetMechType_orig(i_pNodeCtl, i_MechType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_GetDeviceStatus(AIO_IOB_BI2A_VFG* i_pNodeCtl,
|
||||||
|
AIO_IOB_BI2A_VFG__DEVSTATUS *o_pDevStatus,
|
||||||
|
uint32_t i_cbDevStatus) {
|
||||||
|
|
||||||
|
RI_MGR->devices_flush_output();
|
||||||
|
|
||||||
|
if (i_pNodeCtl != aioIobBi2aVfg) {
|
||||||
|
return aioIobBi2aVFG_GetDeviceStatus_orig(i_pNodeCtl, o_pDevStatus, i_cbDevStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(o_pDevStatus, 0x00, sizeof(AIO_IOB_BI2A_VFG__DEVSTATUS));
|
||||||
|
|
||||||
|
o_pDevStatus->MechType = mechType;
|
||||||
|
o_pDevStatus->bIsBi2a = 1;
|
||||||
|
o_pDevStatus->IoCounter = count++;
|
||||||
|
|
||||||
|
auto &buttons = get_buttons();
|
||||||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Test]))
|
||||||
|
o_pDevStatus->Input.bTest = 1;
|
||||||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Service]))
|
||||||
|
o_pDevStatus->Input.bService = 1;
|
||||||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::CoinMech]))
|
||||||
|
o_pDevStatus->Input.bCoinSw = 1;
|
||||||
|
|
||||||
|
o_pDevStatus->Input.CoinCount = eamuse_coin_get_stock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_SetWatchDogTimer(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint16_t i_Count) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_SetWatchDogTimer_orig(i_pNodeCtl, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_ControlCoinBlocker(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Slot, bool i_bOpen) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_ControlCoinBlocker_orig(i_pNodeCtl, i_Slot, i_bOpen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_AddCounter(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Counter, uint32_t i_Count) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_AddCounter_orig(i_pNodeCtl, i_Counter, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_SetAmpVolume(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Amp, uint32_t i_Volume) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_SetAmpVolume_orig(i_pNodeCtl, i_Amp, i_Volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_EnableUsbCharger(AIO_IOB_BI2A_VFG* i_pNodeCtl, bool i_bEnable) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_EnableUsbCharger_orig(i_pNodeCtl, i_bEnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_SetLamp(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Lamp, uint8_t i_Bright) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_SetLamp_orig(i_pNodeCtl, i_Lamp, i_Bright);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_SetIccrLed(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_RGB) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_SetIccrLed_orig(i_pNodeCtl, i_RGB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIobBi2aVFG_SetLedData(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint8_t *i_pData, uint32_t i_cbData) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
} else {
|
||||||
|
return aioIobBi2aVFG_SetLedData_orig(i_pNodeCtl, i_pData, i_cbData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_NMGR_IOB* __fastcall aioNMgrIob_Create(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode) {
|
||||||
|
if (i_pSci == aioSciComm) {
|
||||||
|
aioNmgrIob = new AIO_NMGR_IOB;
|
||||||
|
return aioNmgrIob;
|
||||||
|
} else {
|
||||||
|
return aioNMgrIob_Create_orig(i_pSci, i_bfMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeMgr_Destroy(AIO_NMGR_IOB *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob) {
|
||||||
|
delete aioNmgrIob;
|
||||||
|
aioNmgrIob = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_Destroy_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeMgr_GetState(AIO_NMGR_IOB *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_GetState_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsReady(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsReady_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsError(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsError_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeCtl_Destroy(AIO_IOB_BI2A_VFG *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
delete aioIobBi2aVfg;
|
||||||
|
aioIobBi2aVfg = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_Destroy_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeCtl_GetState(AIO_IOB_BI2A_VFG *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_GetState_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsReady(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsReady_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsError(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIobBi2aVfg) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsError_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bi2a_hook_init() {
|
||||||
|
// avoid double init
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// announce
|
||||||
|
log_info("bi2a_hook", "init");
|
||||||
|
|
||||||
|
// libaio-iob_video.dll
|
||||||
|
const auto libaioIobVideoDll = "libaio-iob_video.dll";
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2a_OpenSciUsbCdc",
|
||||||
|
aioIob2Bi2a_OpenSciUsbCdc, &aioIobBi2a_OpenSciUsbCdc_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_Create",
|
||||||
|
aioIobBi2aVFG_Create, &aioIobBi2aVFG_Create_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetMechType",
|
||||||
|
aioIobBi2aVFG_SetMechType, &aioIobBi2aVFG_SetMechType_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_GetDeviceStatus",
|
||||||
|
aioIobBi2aVFG_GetDeviceStatus, &aioIobBi2aVFG_GetDeviceStatus_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetWatchDogTimer",
|
||||||
|
aioIobBi2aVFG_SetWatchDogTimer, &aioIobBi2aVFG_SetWatchDogTimer_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_ControlCoinBlocker",
|
||||||
|
aioIobBi2aVFG_ControlCoinBlocker, &aioIobBi2aVFG_ControlCoinBlocker_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_AddCounter",
|
||||||
|
aioIobBi2aVFG_AddCounter, &aioIobBi2aVFG_AddCounter_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetAmpVolume",
|
||||||
|
aioIobBi2aVFG_SetAmpVolume, &aioIobBi2aVFG_SetAmpVolume_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_EnableUsbCharger",
|
||||||
|
aioIobBi2aVFG_EnableUsbCharger, &aioIobBi2aVFG_EnableUsbCharger_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetLamp",
|
||||||
|
aioIobBi2aVFG_SetLamp, &aioIobBi2aVFG_SetLamp_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetIccrLed",
|
||||||
|
aioIobBi2aVFG_SetIccrLed, &aioIobBi2aVFG_SetIccrLed_orig);
|
||||||
|
execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetLedData",
|
||||||
|
aioIobBi2aVFG_SetLedData, &aioIobBi2aVFG_SetLedData_orig);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
const auto libaioIobDll = "libaio-iob.dll";
|
||||||
|
execexe::trampoline_try(libaioIobDll, "aioNMgrIob_Create",
|
||||||
|
aioNMgrIob_Create, &aioNMgrIob_Create_orig);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
const auto libaioDll = "libaio.dll";
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_Destroy",
|
||||||
|
aioNodeMgr_Destroy, &aioNodeMgr_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_GetState",
|
||||||
|
aioNodeMgr_GetState, &aioNodeMgr_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsReady",
|
||||||
|
aioNodeMgr_IsReady, &aioNodeMgr_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsError",
|
||||||
|
aioNodeMgr_IsError, &aioNodeMgr_IsError_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_Destroy",
|
||||||
|
aioNodeCtl_Destroy, &aioNodeCtl_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_GetState",
|
||||||
|
aioNodeCtl_GetState, &aioNodeCtl_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsReady",
|
||||||
|
aioNodeCtl_IsReady, &aioNodeCtl_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
||||||
|
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace games::mfg {
|
||||||
|
void bi2a_hook_init();
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
std::vector<Button> &games::mfg::get_buttons() {
|
||||||
|
static std::vector<Button> buttons;
|
||||||
|
|
||||||
|
if (buttons.empty()) {
|
||||||
|
buttons = GameAPI::Buttons::getButtons("Mahjong Fight Girl");
|
||||||
|
|
||||||
|
GameAPI::Buttons::sortButtons(
|
||||||
|
&buttons,
|
||||||
|
"Service",
|
||||||
|
"Test",
|
||||||
|
"Coin Mech"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string games::mfg::get_buttons_help() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "cfg/api.h"
|
||||||
|
|
||||||
|
namespace games::mfg {
|
||||||
|
namespace Buttons {
|
||||||
|
enum {
|
||||||
|
Service,
|
||||||
|
Test,
|
||||||
|
CoinMech
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// getters
|
||||||
|
std::vector<Button> &get_buttons();
|
||||||
|
std::string get_buttons_help();
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#include "mfg.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include "util/fileutils.h"
|
||||||
|
#include "util/unity_player.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "acioemu/handle.h"
|
||||||
|
#include "misc/wintouchemu.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
|
#include "bi2a_hook.h"
|
||||||
|
|
||||||
|
namespace games::mfg {
|
||||||
|
std::string MFG_INJECT_ARGS = "";
|
||||||
|
std::string MFG_CABINET_TYPE = "HG";
|
||||||
|
bool MFG_NO_IO = false;
|
||||||
|
|
||||||
|
static acioemu::ACIOHandle *acioHandle = nullptr;
|
||||||
|
static std::wstring portName;
|
||||||
|
|
||||||
|
void MFGGame::attach() {
|
||||||
|
Game::attach();
|
||||||
|
|
||||||
|
// create required files
|
||||||
|
fileutils::dir_create_recursive("dev/raw/log");
|
||||||
|
fileutils::bin_write("dev/raw/log/output_log.txt", nullptr, 0);
|
||||||
|
|
||||||
|
SetEnvironmentVariableA("VFG_CABINET_TYPE", MFG_CABINET_TYPE.c_str());
|
||||||
|
|
||||||
|
// add card reader
|
||||||
|
portName = MFG_CABINET_TYPE == "UKS" ? L"\\\\.\\COM1" : L"\\\\.\\COM3";
|
||||||
|
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
||||||
|
devicehook_init_trampoline();
|
||||||
|
devicehook_add(acioHandle);
|
||||||
|
|
||||||
|
execexe::init();
|
||||||
|
execexe::init_port_hook(portName, acioHandle);
|
||||||
|
|
||||||
|
if (GRAPHICS_SHOW_CURSOR) {
|
||||||
|
unity_utils::force_show_cursor(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unity_utils::set_args(
|
||||||
|
std::format("{} {}{}",
|
||||||
|
GetCommandLineA(),
|
||||||
|
MFG_INJECT_ARGS,
|
||||||
|
unity_utils::get_unity_player_args()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MFGGame::post_attach() {
|
||||||
|
Game::post_attach();
|
||||||
|
|
||||||
|
execexe::load_library("libaio.dll");
|
||||||
|
execexe::load_library("libaio-iob.dll");
|
||||||
|
execexe::load_library("libaio-iob_video.dll");
|
||||||
|
execexe::load_library("libaio-iob2_video.dll");
|
||||||
|
execexe::load_library("win10actlog.dll");
|
||||||
|
|
||||||
|
if (!MFG_NO_IO) {
|
||||||
|
// insert BI2* hooks
|
||||||
|
if (MFG_CABINET_TYPE == "UKS") {
|
||||||
|
log_fatal("mfg", "UKS io is not supported");
|
||||||
|
} else {
|
||||||
|
bi2a_hook_init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MFGGame::detach() {
|
||||||
|
Game::detach();
|
||||||
|
|
||||||
|
devicehook_dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "games/game.h"
|
||||||
|
|
||||||
|
namespace games::mfg {
|
||||||
|
extern std::string MFG_INJECT_ARGS;
|
||||||
|
extern std::string MFG_CABINET_TYPE;
|
||||||
|
extern bool MFG_NO_IO;
|
||||||
|
|
||||||
|
class MFGGame : public games::Game {
|
||||||
|
public:
|
||||||
|
MFGGame() : Game("Mahjong Fight Girl") {}
|
||||||
|
|
||||||
|
virtual void attach() override;
|
||||||
|
virtual void post_attach() override;
|
||||||
|
virtual void detach() override;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -71,6 +71,8 @@ std::vector<Light> &games::museca::get_lights() {
|
|||||||
|
|
||||||
GameAPI::Lights::sortLights(
|
GameAPI::Lights::sortLights(
|
||||||
&lights,
|
&lights,
|
||||||
|
"Start",
|
||||||
|
"Keypad",
|
||||||
"Title R",
|
"Title R",
|
||||||
"Title G",
|
"Title G",
|
||||||
"Title B",
|
"Title B",
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ namespace games::museca {
|
|||||||
// all lights in correct order
|
// all lights in correct order
|
||||||
namespace Lights {
|
namespace Lights {
|
||||||
enum {
|
enum {
|
||||||
|
Start,
|
||||||
|
Keypad,
|
||||||
TitleR,
|
TitleR,
|
||||||
TitleG,
|
TitleG,
|
||||||
TitleB,
|
TitleB,
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace games::qma {
|
|||||||
touch_attach_dx_hook();
|
touch_attach_dx_hook();
|
||||||
|
|
||||||
// cursor
|
// cursor
|
||||||
if (!is_touch_available()) {
|
if (!is_touch_available("QMATouchDevice::open")) {
|
||||||
ShowCursor(true);
|
ShowCursor(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ bool games::rb::ReflecBeatTouchDeviceHandle::open(LPCWSTR lpFileName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// show cursor on window if mouse is used
|
// show cursor on window if mouse is used
|
||||||
if (!is_touch_available()) {
|
if (!is_touch_available("ReflecBeatTouchDeviceHandle::open")) {
|
||||||
ShowCursor(TRUE);
|
ShowCursor(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public:
|
|||||||
touch_attach_dx_hook();
|
touch_attach_dx_hook();
|
||||||
|
|
||||||
// cursor
|
// cursor
|
||||||
if (!is_touch_available()) {
|
if (!is_touch_available("TwTouchDevice::open")) {
|
||||||
ShowCursor(true);
|
ShowCursor(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ namespace games::sdvx {
|
|||||||
enum SdvxOverlayPosition {
|
enum SdvxOverlayPosition {
|
||||||
SDVX_OVERLAY_TOP,
|
SDVX_OVERLAY_TOP,
|
||||||
SDVX_OVERLAY_MIDDLE,
|
SDVX_OVERLAY_MIDDLE,
|
||||||
SDVX_OVERLAY_BOTTOM
|
SDVX_OVERLAY_BOTTOM,
|
||||||
|
SDVX_OVERLAY_BOTTOM_LEFT,
|
||||||
|
SDVX_OVERLAY_BOTTOM_RIGHT
|
||||||
};
|
};
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
|
|||||||
@@ -680,7 +680,29 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDevice(
|
|||||||
|
|
||||||
// dump presentation parameters
|
// dump presentation parameters
|
||||||
for (size_t i = 0; i < num_adapters; i++) {
|
for (size_t i = 0; i < num_adapters; i++) {
|
||||||
const auto *params = &pPresentationParameters[i];
|
auto *params = &pPresentationParameters[i];
|
||||||
|
if (!GRAPHICS_WINDOWED && i == 0) {
|
||||||
|
GRAPHICS_FS_ORIGINAL_WIDTH = params->BackBufferWidth;
|
||||||
|
GRAPHICS_FS_ORIGINAL_HEIGHT = params->BackBufferHeight;
|
||||||
|
log_misc("graphics::d3d9", "original resolution: {}x{}", GRAPHICS_FS_ORIGINAL_WIDTH, GRAPHICS_FS_ORIGINAL_HEIGHT);
|
||||||
|
if (GRAPHICS_FS_CUSTOM_RESOLUTION.has_value()) {
|
||||||
|
log_misc(
|
||||||
|
"graphics::d3d9",
|
||||||
|
"use custom resolution {}x{} => {}x{}",
|
||||||
|
params->BackBufferWidth, params->BackBufferHeight,
|
||||||
|
GRAPHICS_FS_CUSTOM_RESOLUTION.value().first,
|
||||||
|
GRAPHICS_FS_CUSTOM_RESOLUTION.value().second);
|
||||||
|
params->BackBufferWidth = GRAPHICS_FS_CUSTOM_RESOLUTION.value().first;
|
||||||
|
params->BackBufferHeight = GRAPHICS_FS_CUSTOM_RESOLUTION.value().second;
|
||||||
|
} else if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
|
log_misc(
|
||||||
|
"graphics::d3d9",
|
||||||
|
"swap full orientation {}x{} => {}x{}",
|
||||||
|
params->BackBufferWidth, params->BackBufferHeight,
|
||||||
|
params->BackBufferHeight, params->BackBufferWidth);
|
||||||
|
std::swap(params->BackBufferWidth, params->BackBufferHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log_info("graphics::d3d9",
|
log_info("graphics::d3d9",
|
||||||
"D3D9 presentation parameters for adapter {}: BackBufferWidth: {}, BackBufferHeight: {}, "
|
"D3D9 presentation parameters for adapter {}: BackBufferWidth: {}, BackBufferHeight: {}, "
|
||||||
@@ -846,7 +868,29 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDeviceEx(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < num_adapters; i++) {
|
for (size_t i = 0; i < num_adapters; i++) {
|
||||||
const auto *params = &pPresentationParameters[i];
|
auto *params = &pPresentationParameters[i];
|
||||||
|
if (!GRAPHICS_WINDOWED && i == 0) {
|
||||||
|
GRAPHICS_FS_ORIGINAL_WIDTH = params->BackBufferWidth;
|
||||||
|
GRAPHICS_FS_ORIGINAL_HEIGHT = params->BackBufferHeight;
|
||||||
|
log_misc("graphics::d3d9", "original resolution: {}x{}", GRAPHICS_FS_ORIGINAL_WIDTH, GRAPHICS_FS_ORIGINAL_HEIGHT);
|
||||||
|
if (GRAPHICS_FS_CUSTOM_RESOLUTION.has_value()) {
|
||||||
|
log_misc(
|
||||||
|
"graphics::d3d9",
|
||||||
|
"use custom resolution {}x{} => {}x{}",
|
||||||
|
params->BackBufferWidth, params->BackBufferHeight,
|
||||||
|
GRAPHICS_FS_CUSTOM_RESOLUTION.value().first,
|
||||||
|
GRAPHICS_FS_CUSTOM_RESOLUTION.value().second);
|
||||||
|
params->BackBufferWidth = GRAPHICS_FS_CUSTOM_RESOLUTION.value().first;
|
||||||
|
params->BackBufferHeight = GRAPHICS_FS_CUSTOM_RESOLUTION.value().second;
|
||||||
|
} else if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
|
log_misc(
|
||||||
|
"graphics::d3d9",
|
||||||
|
"swap full orientation {}x{} => {}x{}",
|
||||||
|
params->BackBufferWidth, params->BackBufferHeight,
|
||||||
|
params->BackBufferHeight, params->BackBufferWidth);
|
||||||
|
std::swap(params->BackBufferWidth, params->BackBufferHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log_info("graphics::d3d9",
|
log_info("graphics::d3d9",
|
||||||
"D3D9Ex presentation parameters for adapter {}: BackBufferWidth: {}, BackBufferHeight: {}, "
|
"D3D9Ex presentation parameters for adapter {}: BackBufferWidth: {}, BackBufferHeight: {}, "
|
||||||
@@ -870,7 +914,16 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDeviceEx(
|
|||||||
}
|
}
|
||||||
if (pFullscreenDisplayMode) {
|
if (pFullscreenDisplayMode) {
|
||||||
for (size_t i = 0; i < num_adapters; i++) {
|
for (size_t i = 0; i < num_adapters; i++) {
|
||||||
const auto *fullscreen_display_mode = &pFullscreenDisplayMode[i];
|
auto *fullscreen_display_mode = &pFullscreenDisplayMode[i];
|
||||||
|
|
||||||
|
if (!GRAPHICS_WINDOWED && i == 0) {
|
||||||
|
if (GRAPHICS_FS_CUSTOM_RESOLUTION.has_value()) {
|
||||||
|
fullscreen_display_mode->Width = GRAPHICS_FS_CUSTOM_RESOLUTION.value().first;
|
||||||
|
fullscreen_display_mode->Height = GRAPHICS_FS_CUSTOM_RESOLUTION.value().second;
|
||||||
|
} else if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
|
std::swap(fullscreen_display_mode->Width, fullscreen_display_mode->Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log_info("graphics::d3d9",
|
log_info("graphics::d3d9",
|
||||||
"D3D9Ex fullscreen display mode for adapter {}: Width: {}, Height: {}, RefreshRate: {}, "
|
"D3D9Ex fullscreen display mode for adapter {}: Width: {}, Height: {}, RefreshRate: {}, "
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
#include "util/flags_helper.h"
|
#include "util/flags_helper.h"
|
||||||
|
#include "util/utils.h"
|
||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
|
|
||||||
#include "d3d9_backend.h"
|
#include "d3d9_backend.h"
|
||||||
@@ -692,89 +693,181 @@ static IDirect3DSurface9 *backbuffer = nullptr;
|
|||||||
static LPDIRECT3DSWAPCHAIN9 mSwapChain = nullptr;
|
static LPDIRECT3DSWAPCHAIN9 mSwapChain = nullptr;
|
||||||
static IDirect3DTexture9* tex;
|
static IDirect3DTexture9* tex;
|
||||||
|
|
||||||
|
static UINT topSurface_width = 0;
|
||||||
|
static UINT topSurface_height = 0;
|
||||||
|
static float topSurface_aspect_ratio = 1.f;
|
||||||
|
|
||||||
void SurfaceHook(IDirect3DDevice9 *pReal) {
|
void SurfaceHook(IDirect3DDevice9 *pReal) {
|
||||||
// log_misc("graphics::d3d9", "SurfaceHook called");
|
|
||||||
D3DPRESENT_PARAMETERS param {};
|
D3DPRESENT_PARAMETERS param {};
|
||||||
|
|
||||||
pReal->GetSwapChain(0, &mSwapChain);
|
pReal->GetSwapChain(0, &mSwapChain);
|
||||||
mSwapChain->GetPresentParameters(¶m);
|
mSwapChain->GetPresentParameters(¶m);
|
||||||
|
|
||||||
|
// phase 0 - create a surface that has the same aspect ratio as the original back buffer
|
||||||
|
// but larger in size. this is needed to ensure that when the user zooms out, we have
|
||||||
|
// sufficient buffer space (black border) around the original image
|
||||||
|
//
|
||||||
|
// (only done once)
|
||||||
if (!topSurface) {
|
if (!topSurface) {
|
||||||
if (pReal->CreateTexture(4096, 4096, 1,
|
topSurface_width = param.BackBufferWidth * 3;
|
||||||
|
topSurface_height = param.BackBufferHeight * 3;
|
||||||
|
topSurface_aspect_ratio = (float)topSurface_width / (float)topSurface_height;
|
||||||
|
if (pReal->CreateTexture(topSurface_width, topSurface_height, 1,
|
||||||
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
||||||
D3DPOOL_DEFAULT, &tex, NULL) != D3D_OK) {
|
D3DPOOL_DEFAULT, &tex, NULL) != D3D_OK) {
|
||||||
log_misc("graphics::d3d9", "create texture failed");
|
log_warning("graphics::d3d9", "SurfaceHook - create texture failed");
|
||||||
|
|
||||||
}
|
}
|
||||||
log_misc("graphics::d3d9", "Backbuffer: {} {} {}",
|
|
||||||
param.BackBufferWidth, param.BackBufferHeight, param.BackBufferCount);
|
|
||||||
tex->GetSurfaceLevel(0, &topSurface);
|
|
||||||
|
|
||||||
|
log_misc(
|
||||||
|
"graphics::d3d9", "SurfaceHook - Backbuffer: {} {} {}",
|
||||||
|
param.BackBufferWidth, param.BackBufferHeight, param.BackBufferCount);
|
||||||
|
|
||||||
|
tex->GetSurfaceLevel(0, &topSurface);
|
||||||
if (mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer) != D3D_OK) {
|
if (mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer) != D3D_OK) {
|
||||||
log_misc("graphics::d3d9", "GetBackBuffer failed");
|
log_warning("graphics::d3d9", "SurfaceHook - GetBackBuffer failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int rectLeft = 1024;
|
// pre-calculate dimensions used for phase 1
|
||||||
const int rectTop = 576;
|
const int rectLeft = param.BackBufferWidth;
|
||||||
|
const int rectTop = param.BackBufferHeight;
|
||||||
const int w = param.BackBufferWidth;
|
const int w = param.BackBufferWidth;
|
||||||
const int h = param.BackBufferHeight;
|
const int h = param.BackBufferHeight;
|
||||||
|
|
||||||
D3DLOCKED_RECT rect;
|
D3DLOCKED_RECT rect;
|
||||||
|
HRESULT hr;
|
||||||
|
topSurface->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
|
||||||
|
|
||||||
|
// phase 1 - copy the original back buffer onto the new surface.
|
||||||
|
// we draw it 1:1 in the center of the surface.
|
||||||
|
// if orientation is swapped, fix up the rect and draw it in the center.
|
||||||
|
//
|
||||||
|
// for this phase we always render with the same rect so that it's always overwritten
|
||||||
|
// by a new frame on the same spot.
|
||||||
|
RECT originRect {
|
||||||
|
rectLeft,
|
||||||
|
rectTop,
|
||||||
|
(LONG)(rectLeft + w),
|
||||||
|
(LONG)(rectTop + h),
|
||||||
|
};
|
||||||
|
if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
|
originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2);
|
||||||
|
originRect.top = (topSurface_height / 2) - (GRAPHICS_FS_ORIGINAL_HEIGHT / 2);
|
||||||
|
originRect.right = originRect.left + GRAPHICS_FS_ORIGINAL_WIDTH;
|
||||||
|
originRect.bottom = originRect.top + GRAPHICS_FS_ORIGINAL_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// log_misc(
|
||||||
|
// "graphics::d3d9", "originRect: {} {} {} {}",
|
||||||
|
// originRect.left, originRect.top, originRect.right, originRect.bottom);
|
||||||
|
|
||||||
|
hr = pReal->StretchRect(
|
||||||
|
backbuffer, nullptr,
|
||||||
|
topSurface, &originRect,
|
||||||
|
D3DTEXF_LINEAR);
|
||||||
|
if (hr != D3D_OK) {
|
||||||
|
log_warning(
|
||||||
|
"graphics::d3d9",
|
||||||
|
"SurfaceHook - StretchRect backbuffer failed, rect: {} {} {} {}",
|
||||||
|
originRect.left, originRect.top, originRect.right, originRect.bottom);
|
||||||
|
}
|
||||||
|
topSurface->UnlockRect();
|
||||||
|
|
||||||
|
// phase 2 - viewport calculation - do the actual zoom / offset math
|
||||||
|
// figure out what region of the surface to copy back to the back buffer.
|
||||||
RECT targetRect {
|
RECT targetRect {
|
||||||
rectLeft,
|
rectLeft,
|
||||||
rectTop,
|
rectTop,
|
||||||
(LONG)(rectLeft + w),
|
(LONG)(rectLeft + w),
|
||||||
(LONG)(rectTop + h),
|
(LONG)(rectTop + h),
|
||||||
};
|
};
|
||||||
|
if (cfg::SCREENRESIZE->enable_screen_resize) {
|
||||||
|
auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene];
|
||||||
|
auto w_new = w / scene.scale_x;
|
||||||
|
auto h_new = h / scene.scale_y;
|
||||||
|
|
||||||
// stretch to add top/left offset to avoid going negative
|
// make sure the scaling is within bounds
|
||||||
topSurface->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
|
if (cfg::SCREENRESIZE->client_keep_aspect_ratio) {
|
||||||
auto hr = pReal->StretchRect(
|
if (w_new > topSurface_width || h_new > topSurface_height) {
|
||||||
backbuffer, nullptr,
|
w_new = topSurface_width;
|
||||||
topSurface, &targetRect,
|
h_new = topSurface_height;
|
||||||
D3DTEXF_LINEAR);
|
}
|
||||||
|
} else {
|
||||||
|
w_new = MIN(w_new, topSurface_width);
|
||||||
|
h_new = MIN(h_new, topSurface_height);
|
||||||
|
}
|
||||||
|
|
||||||
if (hr != D3D_OK) {
|
targetRect.left = (topSurface_width / 2) - (w_new / 2) - scene.offset_x;
|
||||||
log_misc("graphics::d3d9", "StretchRect backbuffer failed");
|
targetRect.top = (topSurface_height / 2) - (h_new / 2) - scene.offset_y;
|
||||||
}
|
targetRect.right = targetRect.left + w_new;
|
||||||
topSurface->UnlockRect();
|
targetRect.bottom = targetRect.top + h_new;
|
||||||
|
|
||||||
// do the actual zoom / offset math
|
// boundary check to prevent StretchRect failures
|
||||||
auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene];
|
if (targetRect.left < 0) {
|
||||||
if (scene.centered) {
|
targetRect.left = 0;
|
||||||
targetRect.right = (w + rectLeft) / scene.scale_x;
|
targetRect.right = w_new;
|
||||||
targetRect.bottom = (h + rectTop) / scene.scale_y;
|
} else if (targetRect.right > (LONG)topSurface_width) {
|
||||||
const LONG deltaH = ((targetRect.bottom - targetRect.top) - h) / 2;
|
targetRect.left = topSurface_width - w_new;
|
||||||
const LONG deltaW = ((targetRect.right - targetRect.left) - w) / 2;
|
targetRect.right = topSurface_width;
|
||||||
targetRect.top -= deltaH;
|
}
|
||||||
targetRect.bottom -= deltaH;
|
if (targetRect.top < 0) {
|
||||||
targetRect.left -= deltaW;
|
targetRect.top = 0;
|
||||||
targetRect.right -= deltaW;
|
targetRect.bottom = h_new;
|
||||||
} else {
|
} else if (targetRect.bottom > (LONG)topSurface_height) {
|
||||||
targetRect.left -= scene.offset_x;
|
targetRect.top = topSurface_height - h_new;
|
||||||
targetRect.top += scene.offset_y;
|
targetRect.bottom = topSurface_height;
|
||||||
targetRect.right = -scene.offset_x;
|
}
|
||||||
targetRect.right += (w + rectLeft) / scene.scale_x;
|
|
||||||
targetRect.bottom = scene.offset_y;
|
} else if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
targetRect.bottom += (h + rectTop) / scene.scale_y;
|
// increase the viewport to fit the image on screen (effectively, zoom out a little)
|
||||||
|
if (GRAPHICS_FS_ORIGINAL_WIDTH < GRAPHICS_FS_ORIGINAL_HEIGHT) {
|
||||||
|
// portrait game on landscape display
|
||||||
|
// height should match the original image
|
||||||
|
targetRect.top = originRect.top;
|
||||||
|
targetRect.bottom = originRect.bottom;
|
||||||
|
|
||||||
|
// width of viewport should be wider, effectively shrinking the image on x-axis when rendered
|
||||||
|
const auto w_new = GRAPHICS_FS_ORIGINAL_HEIGHT * topSurface_aspect_ratio;
|
||||||
|
targetRect.left = (topSurface_width / 2) - (w_new / 2);
|
||||||
|
targetRect.right = targetRect.left + w_new;
|
||||||
|
} else {
|
||||||
|
// landscape game on portrait display
|
||||||
|
targetRect.left = originRect.left;
|
||||||
|
targetRect.right = originRect.right;
|
||||||
|
|
||||||
|
// height of viewport should be taller, effectively shrinking the image on y-axis when rendered
|
||||||
|
const auto h_new = GRAPHICS_FS_ORIGINAL_WIDTH / topSurface_aspect_ratio;
|
||||||
|
targetRect.top = (topSurface_height / 2) - (h_new / 2);
|
||||||
|
targetRect.bottom = targetRect.top + h_new;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw to back buffer
|
// log_misc("graphics::d3d9", "targetRect: {} {} {} {}",
|
||||||
|
// targetRect.left, targetRect.top, targetRect.right, targetRect.bottom);
|
||||||
|
|
||||||
|
// phase 3 - draw the surface to back buffer
|
||||||
backbuffer->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
|
backbuffer->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
|
||||||
|
bool use_linear_filter = true;
|
||||||
|
if (cfg::SCREENRESIZE->enable_screen_resize) {
|
||||||
|
use_linear_filter = cfg::SCREENRESIZE->enable_linear_filter;
|
||||||
|
}
|
||||||
hr = pReal->StretchRect(
|
hr = pReal->StretchRect(
|
||||||
topSurface, &targetRect,
|
topSurface, &targetRect,
|
||||||
backbuffer, nullptr,
|
backbuffer, nullptr,
|
||||||
cfg::SCREENRESIZE->enable_linear_filter ? D3DTEXF_LINEAR : D3DTEXF_NONE);
|
use_linear_filter ? D3DTEXF_LINEAR : D3DTEXF_NONE);
|
||||||
backbuffer->UnlockRect();
|
backbuffer->UnlockRect();
|
||||||
if (hr != D3D_OK) {
|
if (hr != D3D_OK) {
|
||||||
log_misc("graphics::d3d9", "StretchRect targetRect failed");
|
log_warning(
|
||||||
|
"graphics::d3d9",
|
||||||
|
"SurfaceHook - StretchRect targetRect failed, you must reset image scaling to default values! rect: {} {} {} {}",
|
||||||
|
targetRect.left, targetRect.top, targetRect.right, targetRect.bottom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::EndScene() {
|
HRESULT STDMETHODCALLTYPE WrappedIDirect3DDevice9::EndScene() {
|
||||||
WRAP_DEBUG;
|
WRAP_DEBUG;
|
||||||
|
|
||||||
if (cfg::SCREENRESIZE->enable_screen_resize) {
|
if (cfg::SCREENRESIZE->enable_screen_resize || GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
SurfaceHook(pReal);
|
SurfaceHook(pReal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ graphics_dx9on12_state GRAPHICS_9_ON_12_STATE = DX9ON12_AUTO;
|
|||||||
bool GRAPHICS_9_ON_12_REQUESTED_BY_GAME = false;
|
bool GRAPHICS_9_ON_12_REQUESTED_BY_GAME = false;
|
||||||
bool SUBSCREEN_FORCE_REDRAW = false;
|
bool SUBSCREEN_FORCE_REDRAW = false;
|
||||||
bool D3D9_DEVICE_HOOK_DISABLE = false;
|
bool D3D9_DEVICE_HOOK_DISABLE = false;
|
||||||
|
std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_FS_CUSTOM_RESOLUTION;
|
||||||
|
bool GRAPHICS_FS_ORIENTATION_SWAP = false;
|
||||||
|
uint32_t GRAPHICS_FS_ORIGINAL_WIDTH = 0;
|
||||||
|
uint32_t GRAPHICS_FS_ORIGINAL_HEIGHT = 0;
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
std::string GRAPHICS_DEVICEID = "PCI\\VEN_1002&DEV_7146";
|
std::string GRAPHICS_DEVICEID = "PCI\\VEN_1002&DEV_7146";
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ extern UINT GRAPHICS_FORCE_REFRESH;
|
|||||||
extern std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
extern std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
||||||
extern bool GRAPHICS_FORCE_SINGLE_ADAPTER;
|
extern bool GRAPHICS_FORCE_SINGLE_ADAPTER;
|
||||||
extern bool GRAPHICS_PREVENT_SECONDARY_WINDOW;
|
extern bool GRAPHICS_PREVENT_SECONDARY_WINDOW;
|
||||||
|
extern std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_FS_CUSTOM_RESOLUTION;
|
||||||
|
extern bool GRAPHICS_FS_ORIENTATION_SWAP;
|
||||||
|
extern uint32_t GRAPHICS_FS_ORIGINAL_WIDTH;
|
||||||
|
extern uint32_t GRAPHICS_FS_ORIGINAL_HEIGHT;
|
||||||
|
|
||||||
extern graphics_dx9on12_state GRAPHICS_9_ON_12_STATE;
|
extern graphics_dx9on12_state GRAPHICS_9_ON_12_STATE;
|
||||||
extern bool GRAPHICS_9_ON_12_REQUESTED_BY_GAME;
|
extern bool GRAPHICS_9_ON_12_REQUESTED_BY_GAME;
|
||||||
|
|||||||
@@ -123,10 +123,6 @@ void graphics_load_windowed_parameters() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_debug("graphics-windowed", "graphics_load_windowed_parameters called");
|
log_debug("graphics-windowed", "graphics_load_windowed_parameters called");
|
||||||
const auto remove_spaces = [](const char& c) {
|
|
||||||
return c == ' ';
|
|
||||||
};
|
|
||||||
|
|
||||||
if (GRAPHICS_WINDOW_STYLE.has_value()) {
|
if (GRAPHICS_WINDOW_STYLE.has_value()) {
|
||||||
log_debug(
|
log_debug(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
@@ -148,13 +144,11 @@ void graphics_load_windowed_parameters() {
|
|||||||
log_debug(
|
log_debug(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_POS");
|
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_POS");
|
||||||
int32_t x, y;
|
std::pair<uint32_t, uint32_t> result;
|
||||||
auto s = GRAPHICS_WINDOW_POS.value();
|
if (parse_width_height(GRAPHICS_WINDOW_POS.value(), result)) {
|
||||||
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
|
|
||||||
if (sscanf(s.c_str(), "%d,%d", &x, &y) == 2) {
|
|
||||||
cfg::SCREENRESIZE->enable_window_resize = true;
|
cfg::SCREENRESIZE->enable_window_resize = true;
|
||||||
cfg::SCREENRESIZE->window_offset_x = x;
|
cfg::SCREENRESIZE->window_offset_x = result.first;
|
||||||
cfg::SCREENRESIZE->window_offset_y = y;
|
cfg::SCREENRESIZE->window_offset_y = result.second;
|
||||||
} else {
|
} else {
|
||||||
log_warning("graphics-windowed", "failed to parse -windowpos");
|
log_warning("graphics-windowed", "failed to parse -windowpos");
|
||||||
}
|
}
|
||||||
@@ -174,20 +168,16 @@ void graphics_load_windowed_subscreen_parameters() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_debug("graphics-windowed", "graphics_load_windowed_subscreen_parameters called");
|
log_debug("graphics-windowed", "graphics_load_windowed_subscreen_parameters called");
|
||||||
const auto remove_spaces = [](const char& c) {
|
|
||||||
return c == ' ';
|
|
||||||
};
|
|
||||||
|
|
||||||
if (GRAPHICS_IIDX_WSUB_SIZE.has_value()) {
|
if (GRAPHICS_IIDX_WSUB_SIZE.has_value()) {
|
||||||
log_debug(
|
log_debug(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_SIZE");
|
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_SIZE");
|
||||||
uint32_t w, h;
|
|
||||||
auto s = GRAPHICS_IIDX_WSUB_SIZE.value();
|
std::pair<uint32_t, uint32_t> result;
|
||||||
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
|
if (parse_width_height(GRAPHICS_IIDX_WSUB_SIZE.value(), result)) {
|
||||||
if (sscanf(s.c_str(), "%u,%u", &w, &h) == 2) {
|
GRAPHICS_IIDX_WSUB_WIDTH = result.first;
|
||||||
GRAPHICS_IIDX_WSUB_WIDTH = w;
|
GRAPHICS_IIDX_WSUB_HEIGHT = result.second;
|
||||||
GRAPHICS_IIDX_WSUB_HEIGHT = h;
|
|
||||||
} else {
|
} else {
|
||||||
log_warning("graphics-windowed", "failed to parse -wsubsize");
|
log_warning("graphics-windowed", "failed to parse -wsubsize");
|
||||||
}
|
}
|
||||||
@@ -197,12 +187,11 @@ void graphics_load_windowed_subscreen_parameters() {
|
|||||||
log_debug(
|
log_debug(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_POS");
|
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_POS");
|
||||||
int32_t x, y;
|
|
||||||
auto s = GRAPHICS_IIDX_WSUB_POS.value();
|
std::pair<uint32_t, uint32_t> result;
|
||||||
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
|
if (parse_width_height(GRAPHICS_IIDX_WSUB_POS.value(), result)) {
|
||||||
if (sscanf(s.c_str(), "%d,%d", &x, &y) == 2) {
|
GRAPHICS_IIDX_WSUB_X = result.first;
|
||||||
GRAPHICS_IIDX_WSUB_X = x;
|
GRAPHICS_IIDX_WSUB_Y = result.second;
|
||||||
GRAPHICS_IIDX_WSUB_Y = y;
|
|
||||||
} else {
|
} else {
|
||||||
log_warning("graphics-windowed", "failed to parse -wsubpos");
|
log_warning("graphics-windowed", "failed to parse -wsubpos");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
#include "games/ccj/ccj.h"
|
#include "games/ccj/ccj.h"
|
||||||
#include "games/ccj/trackball.h"
|
#include "games/ccj/trackball.h"
|
||||||
#include "games/qks/qks.h"
|
#include "games/qks/qks.h"
|
||||||
|
#include "games/mfg/mfg.h"
|
||||||
#include "games/museca/museca.h"
|
#include "games/museca/museca.h"
|
||||||
#include "hooks/avshook.h"
|
#include "hooks/avshook.h"
|
||||||
#include "hooks/audio/audio.h"
|
#include "hooks/audio/audio.h"
|
||||||
@@ -101,6 +102,7 @@
|
|||||||
#include "util/sysutils.h"
|
#include "util/sysutils.h"
|
||||||
#include "util/tapeled.h"
|
#include "util/tapeled.h"
|
||||||
#include "util/time.h"
|
#include "util/time.h"
|
||||||
|
#include "util/utils.h"
|
||||||
#include "avs/ssl.h"
|
#include "avs/ssl.h"
|
||||||
#include "nvapi/nvapi.h"
|
#include "nvapi/nvapi.h"
|
||||||
#include "hooks/graphics/nvapi_hook.h"
|
#include "hooks/graphics/nvapi_hook.h"
|
||||||
@@ -122,6 +124,8 @@ std::string LOG_FILE_PATH = "";
|
|||||||
int LAUNCHER_ARGC = 0;
|
int LAUNCHER_ARGC = 0;
|
||||||
char **LAUNCHER_ARGV = nullptr;
|
char **LAUNCHER_ARGV = nullptr;
|
||||||
std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
||||||
|
|
||||||
|
std::mutex CARD_OVERRIDES_LOCK;
|
||||||
std::string CARD_OVERRIDES[2];
|
std::string CARD_OVERRIDES[2];
|
||||||
|
|
||||||
// sub-systems
|
// sub-systems
|
||||||
@@ -213,7 +217,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
bool attach_bc = false;
|
bool attach_bc = false;
|
||||||
bool attach_ccj = false;
|
bool attach_ccj = false;
|
||||||
bool attach_qks = false;
|
bool attach_qks = false;
|
||||||
|
bool attach_mfg = false;
|
||||||
bool attach_museca = false;
|
bool attach_museca = false;
|
||||||
|
bool show_cursor_if_no_touch = false;
|
||||||
|
|
||||||
// misc settings
|
// misc settings
|
||||||
size_t user_heap_size = 0;
|
size_t user_heap_size = 0;
|
||||||
@@ -436,7 +442,12 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_TOP;
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_TOP;
|
||||||
} else if (txt == "center") {
|
} else if (txt == "center") {
|
||||||
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_MIDDLE;
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_MIDDLE;
|
||||||
|
} else if (txt == "bottomleft") {
|
||||||
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_BOTTOM_LEFT;
|
||||||
|
} else if (txt == "bottomright") {
|
||||||
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_BOTTOM_RIGHT;
|
||||||
}
|
}
|
||||||
|
// else - bottom
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::spice2x_SDVXSubRedraw].value_bool()) {
|
if (options[launcher::Options::spice2x_SDVXSubRedraw].value_bool()) {
|
||||||
SUBSCREEN_FORCE_REDRAW = true;
|
SUBSCREEN_FORCE_REDRAW = true;
|
||||||
@@ -602,6 +613,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::LoadQKSModule].value_bool()) {
|
if (options[launcher::Options::LoadQKSModule].value_bool()) {
|
||||||
attach_qks = true;
|
attach_qks = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
||||||
|
attach_mfg = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
||||||
attach_museca = true;
|
attach_museca = true;
|
||||||
}
|
}
|
||||||
@@ -732,9 +746,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
SetDllDirectoryW(MODULE_PATH.c_str());
|
SetDllDirectoryW(MODULE_PATH.c_str());
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::Player1Card].is_active()) {
|
if (options[launcher::Options::Player1Card].is_active()) {
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
CARD_OVERRIDES[0] = options[launcher::Options::Player1Card].value_text();
|
CARD_OVERRIDES[0] = options[launcher::Options::Player1Card].value_text();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::Player2Card].is_active()) {
|
if (options[launcher::Options::Player2Card].is_active()) {
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
CARD_OVERRIDES[1] = options[launcher::Options::Player2Card].value_text();
|
CARD_OVERRIDES[1] = options[launcher::Options::Player2Card].value_text();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::Player1PinMacro].is_active()) {
|
if (options[launcher::Options::Player1PinMacro].is_active()) {
|
||||||
@@ -947,12 +963,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
GRAPHICS_WINDOW_STYLE = options[launcher::Options::spice2x_WindowBorder].value_uint32();
|
GRAPHICS_WINDOW_STYLE = options[launcher::Options::spice2x_WindowBorder].value_uint32();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::spice2x_WindowSize].is_active()) {
|
if (options[launcher::Options::spice2x_WindowSize].is_active()) {
|
||||||
auto s = options[launcher::Options::spice2x_WindowSize].value_text();
|
std::pair<uint32_t, uint32_t> result;
|
||||||
uint32_t w, h;
|
if (parse_width_height(options[launcher::Options::spice2x_WindowSize].value_text(), result)) {
|
||||||
const auto remove_spaces = [](const char& c) { return c == ' '; };
|
GRAPHICS_WINDOW_SIZE = result;
|
||||||
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
|
|
||||||
if (sscanf(s.c_str(), "%u,%u", &w, &h) == 2) {
|
|
||||||
GRAPHICS_WINDOW_SIZE = std::pair(w, h);
|
|
||||||
} else {
|
} else {
|
||||||
log_warning("launcher", "failed to parse -windowsize");
|
log_warning("launcher", "failed to parse -windowsize");
|
||||||
}
|
}
|
||||||
@@ -1028,6 +1041,15 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::QKSArgs].is_active()) {
|
if (options[launcher::Options::QKSArgs].is_active()) {
|
||||||
games::qks::QKS_INJECT_ARGS = options[launcher::Options::QKSArgs].value_text();
|
games::qks::QKS_INJECT_ARGS = options[launcher::Options::QKSArgs].value_text();
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::MFGArgs].is_active()) {
|
||||||
|
games::mfg::MFG_INJECT_ARGS = options[launcher::Options::MFGArgs].value_text();
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::MFGCabType].is_active()) {
|
||||||
|
games::mfg::MFG_CABINET_TYPE = options[launcher::Options::MFGCabType].value_text();
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::MFGNoIO].is_active()) {
|
||||||
|
games::mfg::MFG_NO_IO = options[launcher::Options::MFGNoIO].value_bool();
|
||||||
|
}
|
||||||
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
|
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
|
||||||
rawinput::ENABLE_SMX_STAGE = true;
|
rawinput::ENABLE_SMX_STAGE = true;
|
||||||
}
|
}
|
||||||
@@ -1096,6 +1118,8 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// log
|
// log
|
||||||
#ifdef SPICE64
|
#ifdef SPICE64
|
||||||
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
||||||
|
#elif SPICE32_LARGE_ADDRESS_AWARE
|
||||||
|
log_info("launcher", "SpiceTools Bootstrap (x32) (Large Address Aware) (spice2x)");
|
||||||
#else
|
#else
|
||||||
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
||||||
#endif
|
#endif
|
||||||
@@ -1139,6 +1163,30 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
log_info("launcher", "arguments:\n{}", arguments.str());
|
log_info("launcher", "arguments:\n{}", arguments.str());
|
||||||
|
|
||||||
|
if (options[launcher::Options::FullscreenResolution].is_active()) {
|
||||||
|
std::pair<uint32_t, uint32_t> result;
|
||||||
|
if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) {
|
||||||
|
GRAPHICS_FS_CUSTOM_RESOLUTION = result;
|
||||||
|
} else {
|
||||||
|
log_warning("launcher", "failed to parse -forceres");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // SDVXFullscreenLandscape disabled due to it messing with in-game camera angle
|
||||||
|
// // FullscreenOrientationFlip continues to live on, however.
|
||||||
|
//
|
||||||
|
// if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
|
||||||
|
// #if SPICE64
|
||||||
|
// GRAPHICS_FS_ORIENTATION_SWAP = true;
|
||||||
|
// #else
|
||||||
|
// log_warning("launcher", "-sdvxlandscape is not supported in 32-bit SDVX, ignoring...");
|
||||||
|
// #endif
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (options[launcher::Options::FullscreenOrientationFlip].value_bool() && !GRAPHICS_WINDOWED) {
|
||||||
|
GRAPHICS_FS_ORIENTATION_SWAP = true;
|
||||||
|
}
|
||||||
|
|
||||||
// deleted options
|
// deleted options
|
||||||
if (options[launcher::Options::OpenKFControl].value_bool()) {
|
if (options[launcher::Options::OpenKFControl].value_bool()) {
|
||||||
log_fatal("launcher", "KFControl has been removed from spice2x; please use an older version.");
|
log_fatal("launcher", "KFControl has been removed from spice2x; please use an older version.");
|
||||||
@@ -1254,11 +1302,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::game::DLL_NAME = "system.dll";
|
avs::game::DLL_NAME = "system.dll";
|
||||||
attach_io = true;
|
attach_io = true;
|
||||||
attach_shogikai = true;
|
attach_shogikai = true;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
// automatically show cursor when no touchscreen is available
|
|
||||||
if (!is_touch_available()) {
|
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1301,12 +1345,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// game crash fix
|
// game crash fix
|
||||||
easrv_maint = false;
|
easrv_maint = false;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
// automatically show cursor when no touchscreen is available
|
|
||||||
if (!is_touch_available()) {
|
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1421,12 +1460,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::game::DLL_NAME = "nostalgia.dll";
|
avs::game::DLL_NAME = "nostalgia.dll";
|
||||||
attach_io = true;
|
attach_io = true;
|
||||||
attach_nostalgia = true;
|
attach_nostalgia = true;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
// automatically show cursor when no touchscreen is available
|
|
||||||
if (!is_touch_available()) {
|
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1532,12 +1566,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::game::DLL_NAME = "arknck.dll";
|
avs::game::DLL_NAME = "arknck.dll";
|
||||||
attach_io = true;
|
attach_io = true;
|
||||||
attach_we = true;
|
attach_we = true;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
// automatically show cursor when no touchscreen is available
|
|
||||||
if (!is_touch_available()) {
|
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1570,10 +1599,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::game::DLL_NAME = "kamunity.dll";
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
attach_io = true;
|
attach_io = true;
|
||||||
attach_ccj = true;
|
attach_ccj = true;
|
||||||
// automatically show cursor when no touchscreen is available
|
show_cursor_if_no_touch = true;
|
||||||
if (!is_touch_available()) {
|
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1582,10 +1608,17 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::game::DLL_NAME = "kamunity.dll";
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
attach_io = true;
|
attach_io = true;
|
||||||
attach_qks = true;
|
attach_qks = true;
|
||||||
// automatically show cursor when no touchscreen is available
|
show_cursor_if_no_touch = true;
|
||||||
if (!is_touch_available()) {
|
break;
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
}
|
||||||
}
|
|
||||||
|
// Mahjong Fight Girl
|
||||||
|
if (check_dll("kamunity.dll") && fileutils::dir_exists("game/MFGClient_Data")) {
|
||||||
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
|
attach_io = true;
|
||||||
|
attach_mfg = true;
|
||||||
|
launcher::signal::USE_VEH_WORKAROUND = true;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1594,10 +1627,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::game::DLL_NAME = "kamunity.dll";
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
attach_io = true;
|
attach_io = true;
|
||||||
attach_bc = true;
|
attach_bc = true;
|
||||||
// automatically show cursor when no touchscreen is available
|
show_cursor_if_no_touch = true;
|
||||||
if (!is_touch_available()) {
|
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1740,6 +1770,10 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::core::set_default_heap_size("kamunity.dll");
|
avs::core::set_default_heap_size("kamunity.dll");
|
||||||
games.push_back(new games::qks::QKSGame());
|
games.push_back(new games::qks::QKSGame());
|
||||||
}
|
}
|
||||||
|
if (attach_mfg) {
|
||||||
|
avs::core::set_default_heap_size("kamunity.dll");
|
||||||
|
games.push_back(new games::mfg::MFGGame());
|
||||||
|
}
|
||||||
|
|
||||||
// apply user heap size, if defined
|
// apply user heap size, if defined
|
||||||
if (user_heap_size > 0) {
|
if (user_heap_size > 0) {
|
||||||
@@ -1772,6 +1806,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
exit(spicecfg_run(sextet_devices));
|
exit(spicecfg_run(sextet_devices));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// complain loudly & early about dll load ordering issue
|
||||||
|
libutils::check_duplicate_dlls();
|
||||||
|
|
||||||
// print cpu features
|
// print cpu features
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && dump_sysinfo) {
|
if (!cfg::CONFIGURATOR_STANDALONE && dump_sysinfo) {
|
||||||
cpuutils::print_cpu_features();
|
cpuutils::print_cpu_features();
|
||||||
@@ -1789,6 +1826,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// print devices
|
// print devices
|
||||||
RI_MGR->devices_print();
|
RI_MGR->devices_print();
|
||||||
|
|
||||||
|
// for certain games, show cursor if no touch is available (must be called after RI_MGR is available)
|
||||||
|
if (show_cursor_if_no_touch && !is_touch_available("launcher::main_implementation")) {
|
||||||
|
GRAPHICS_SHOW_CURSOR = true;
|
||||||
|
}
|
||||||
|
|
||||||
// cardio
|
// cardio
|
||||||
if (cardio_enabled) {
|
if (cardio_enabled) {
|
||||||
cardio_runner_start(true);
|
cardio_runner_start(true);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
|
|||||||
"Network",
|
"Network",
|
||||||
"Overlay",
|
"Overlay",
|
||||||
"Graphics (Common)",
|
"Graphics (Common)",
|
||||||
|
"Graphics (Full Screen)",
|
||||||
"Graphics (Windowed)",
|
"Graphics (Windowed)",
|
||||||
"Audio",
|
"Audio",
|
||||||
};
|
};
|
||||||
@@ -185,9 +186,20 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
{
|
{
|
||||||
.title = "Monitor",
|
.title = "Monitor",
|
||||||
.name = "monitor",
|
.name = "monitor",
|
||||||
.desc = "Sets the display that the game will be opened in, for multiple monitors",
|
.desc = "Sets the display that the game will be opened in, for multiple monitors.\n\n"
|
||||||
|
"0 is the primary monitor, 1 is the second monitor, and so on.\n\n"
|
||||||
|
"Not all games will respect this. Does not work at all with multi-monitor games like TDJ/UFC. "
|
||||||
|
"Disable Full Screen Optimizations for best results",
|
||||||
.type = OptionType::Integer,
|
.type = OptionType::Integer,
|
||||||
.category = "Graphics (Common)",
|
.category = "Graphics (Full Screen)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.title = "Only Use One Monitor",
|
||||||
|
.name = "graphics-force-single-adapter",
|
||||||
|
.desc = "Force the graphics device to be opened utilizing only one adapter in multi-monitor systems.\n\n"
|
||||||
|
"May cause unstable framerate and desyncs, especially if monitors have different refresh rates!",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.category = "Graphics (Full Screen)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Force Refresh Rate",
|
.title = "Force Refresh Rate",
|
||||||
@@ -197,12 +209,29 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Graphics (Common)",
|
.category = "Graphics (Common)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Only Use One Monitor",
|
// FullscreenResolution
|
||||||
.name = "graphics-force-single-adapter",
|
.title = "Force Full Screen Resolution",
|
||||||
.desc = "Force the graphics device to be opened utilizing only one adapter in multi-monitor systems.\n\n"
|
.name = "forceres",
|
||||||
"May cause unstable framerate and desyncs, especially if monitors have different refresh rates!",
|
.desc =
|
||||||
|
"For full screen mode, forcibly set a custom resolution.\n\n"
|
||||||
|
"Works great for some games, but can COMPLETELY BREAK other games - YMMV!\n\n"
|
||||||
|
"If you are using -forceresswap/-sdvxlandscape, put the TARGET monitor resolution in this field.\n\n"
|
||||||
|
"This should only be used as last resort if your GPU/monitor can't display the resolution required by the game",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "1280,720",
|
||||||
|
.category = "Graphics (Full Screen)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// FullscreenOrientationFlip
|
||||||
|
.title = "Full Screen Orientation Swap",
|
||||||
|
.name = "forceresswap",
|
||||||
|
.desc =
|
||||||
|
"Allows you to play portrait games in in landscape (and vice versa) by transposing resolution and applying image scaling.\n\n"
|
||||||
|
"Works great for some games, but can COMPLETELY BREAK other games - YMMV!\n\n"
|
||||||
|
"Strongly consider combining this with -forceres option to render at monitor native resolution\n\n"
|
||||||
|
"WARNING: for SDVX, this messes with camera angle for note lanes, causing it to be zoomed out!",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Graphics (Common)",
|
.category = "Graphics (Full Screen)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Graphics9On12
|
// Graphics9On12
|
||||||
@@ -733,7 +762,13 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.game_name = "Sound Voltex",
|
.game_name = "Sound Voltex",
|
||||||
.category = "Overlay",
|
.category = "Overlay",
|
||||||
.elements = {{"top", ""}, {"center", ""}, {"bottom", ""}},
|
.elements = {
|
||||||
|
{"top", ""},
|
||||||
|
{"center", ""},
|
||||||
|
{"bottom", ""},
|
||||||
|
{"bottomleft", "for landscape"},
|
||||||
|
{"bottomright", "for landscape"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// spice2x_SDVXSubRedraw
|
// spice2x_SDVXSubRedraw
|
||||||
@@ -1006,6 +1041,15 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "QuizKnock STADIUM",
|
.game_name = "QuizKnock STADIUM",
|
||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// LoadMFGModule
|
||||||
|
.title = "Force Load Mahjong Fight Girl",
|
||||||
|
.name = "mfg",
|
||||||
|
.desc = "manually enable Mahjong Fight Girl module",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Mahjong Fight Girl",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// LoadMusecaModule
|
// LoadMusecaModule
|
||||||
.title = "Force Load Museca",
|
.title = "Force Load Museca",
|
||||||
@@ -1044,7 +1088,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.title = "Screen Resize Config Path",
|
.title = "Screen Resize Config Path",
|
||||||
.name = "resizecfgpath",
|
.name = "resizecfgpath",
|
||||||
.desc = "Sets a custom file path for screen resize config file. "
|
.desc = "Sets a custom file path for screen resize config file. "
|
||||||
"If left empty, %appdata%\\spicetools_screen_resize.json will be used",
|
"If left empty, %appdata%\\spice2x\\spicetools_screen_resize.json will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Paths",
|
||||||
},
|
},
|
||||||
@@ -1053,7 +1097,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.title = "Patch Manager Config Path",
|
.title = "Patch Manager Config Path",
|
||||||
.name = "patchcfgpath",
|
.name = "patchcfgpath",
|
||||||
.desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. "
|
.desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. "
|
||||||
"If left empty, %appdata%\\spicetools_patch_manager.json will be used",
|
"If left empty, %appdata%\\spice2x\\spicetools_patch_manager.json will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Paths",
|
||||||
},
|
},
|
||||||
@@ -1671,6 +1715,39 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Chase Chase Jokers",
|
.game_name = "Chase Chase Jokers",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.title = "MFG Arguments Override",
|
||||||
|
.name = "mfgargs",
|
||||||
|
.desc = "Command line arguments passed to the game.",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Mahjong Fight Girl",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.title = "MFG Cabinet Type",
|
||||||
|
.name = "mfgcabtype",
|
||||||
|
.desc = "MFG Cabinet Type. Default is HG.",
|
||||||
|
.type = OptionType::Enum,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Mahjong Fight Girl",
|
||||||
|
.category = "Game Options",
|
||||||
|
.elements = {
|
||||||
|
{"HG", "HG"},
|
||||||
|
{"B", "B"},
|
||||||
|
{"C", "C"},
|
||||||
|
{"UKS", "UKS"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.title = "MFG Disable IO Emulation",
|
||||||
|
.name = "mfgnoio",
|
||||||
|
.desc = "Disables BI2X hooks for MFG",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Mahjong Fight Girl",
|
||||||
|
.category = "Game Options (Advanced)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// spice2x_LightsOverallBrightness
|
// spice2x_LightsOverallBrightness
|
||||||
.title = "Lights Brightness Adjustment",
|
.title = "Lights Brightness Adjustment",
|
||||||
@@ -1741,7 +1818,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.title = "Window Forced Render Scaling",
|
.title = "Window Forced Render Scaling",
|
||||||
.name = "windowscale",
|
.name = "windowscale",
|
||||||
.desc = "For windowed mode: forcibly set DX9 back buffer dimensions to match window size. "
|
.desc = "For windowed mode: forcibly set DX9 back buffer dimensions to match window size. "
|
||||||
"Reduces pixelated scaling artifacts. Works great on some games, but completely broken on others",
|
"Reduces pixelated scaling artifacts. Works great for some games, but can COMPLETELY BREAK other games - YMMV!",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Graphics (Windowed)",
|
.category = "Graphics (Windowed)",
|
||||||
},
|
},
|
||||||
@@ -1971,6 +2048,20 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Sound Voltex",
|
.game_name = "Sound Voltex",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// SDVXFullscreenLandscape
|
||||||
|
.title = "(DISABLED) SDVX Landscape Mode (SDVX5+)",
|
||||||
|
.name = "sdvxlandscape",
|
||||||
|
.desc =
|
||||||
|
"Option HIDDEN and DISABLED due to it affecting in-game camera angle for displaying lanes.\n\n"
|
||||||
|
"Allows you to play in landscape by transposing resolution and applying image scaling.\n\n"
|
||||||
|
"Works only for SDVX5 and above! This is identical to -forceresswap.\n\n"
|
||||||
|
"Will launch at 1080p by default; strongly consider combining this with -forceres option to render at monitor native resolution",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.hidden = true,
|
||||||
|
.game_name = "Sound Voltex",
|
||||||
|
.category = "Game Options",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// spice2x_EnableSMXStage
|
// spice2x_EnableSMXStage
|
||||||
.title = "StepManiaX Stage Lighting Support",
|
.title = "StepManiaX Stage Lighting Support",
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ namespace launcher {
|
|||||||
CaptureCursor,
|
CaptureCursor,
|
||||||
ShowCursor,
|
ShowCursor,
|
||||||
DisplayAdapter,
|
DisplayAdapter,
|
||||||
GraphicsForceRefresh,
|
|
||||||
GraphicsForceSingleAdapter,
|
GraphicsForceSingleAdapter,
|
||||||
|
GraphicsForceRefresh,
|
||||||
|
FullscreenResolution,
|
||||||
|
FullscreenOrientationFlip,
|
||||||
Graphics9On12,
|
Graphics9On12,
|
||||||
spice2x_Dx9On12,
|
spice2x_Dx9On12,
|
||||||
NoLegacy,
|
NoLegacy,
|
||||||
@@ -114,6 +116,7 @@ namespace launcher {
|
|||||||
LoadBusouShinkiModule,
|
LoadBusouShinkiModule,
|
||||||
LoadCCJModule,
|
LoadCCJModule,
|
||||||
LoadQKSModule,
|
LoadQKSModule,
|
||||||
|
LoadMFGModule,
|
||||||
LoadMusecaModule,
|
LoadMusecaModule,
|
||||||
PathToModules,
|
PathToModules,
|
||||||
ScreenshotFolder,
|
ScreenshotFolder,
|
||||||
@@ -193,6 +196,9 @@ namespace launcher {
|
|||||||
CCJMouseTrackball,
|
CCJMouseTrackball,
|
||||||
CCJMouseTrackballWithToggle,
|
CCJMouseTrackballWithToggle,
|
||||||
CCJTrackballSensitivity,
|
CCJTrackballSensitivity,
|
||||||
|
MFGArgs,
|
||||||
|
MFGCabType,
|
||||||
|
MFGNoIO,
|
||||||
spice2x_LightsOverallBrightness,
|
spice2x_LightsOverallBrightness,
|
||||||
spice2x_WindowBorder,
|
spice2x_WindowBorder,
|
||||||
spice2x_WindowSize,
|
spice2x_WindowSize,
|
||||||
@@ -217,6 +223,7 @@ namespace launcher {
|
|||||||
spice2x_NoNVAPI,
|
spice2x_NoNVAPI,
|
||||||
spice2x_NoD3D9DeviceHook,
|
spice2x_NoD3D9DeviceHook,
|
||||||
spice2x_SDVXNoSub,
|
spice2x_SDVXNoSub,
|
||||||
|
SDVXFullscreenLandscape,
|
||||||
spice2x_EnableSMXStage,
|
spice2x_EnableSMXStage,
|
||||||
spice2x_EnableSMXDedicab,
|
spice2x_EnableSMXDedicab,
|
||||||
IIDXRecQuality,
|
IIDXRecQuality,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace launcher::signal {
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
bool DISABLE = false;
|
bool DISABLE = false;
|
||||||
|
bool USE_VEH_WORKAROUND = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define V(variant) case variant: return #variant
|
#define V(variant) case variant: return #variant
|
||||||
@@ -167,7 +168,7 @@ static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter_hook(
|
|||||||
static PVOID WINAPI AddVectoredExceptionHandler_hook(ULONG First, PVECTORED_EXCEPTION_HANDLER Handler) {
|
static PVOID WINAPI AddVectoredExceptionHandler_hook(ULONG First, PVECTORED_EXCEPTION_HANDLER Handler) {
|
||||||
log_info("signal", "AddVectoredExceptionHandler hook hit");
|
log_info("signal", "AddVectoredExceptionHandler hook hit");
|
||||||
|
|
||||||
return nullptr;
|
return launcher::signal::USE_VEH_WORKAROUND ? INVALID_HANDLE_VALUE : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void launcher::signal::attach() {
|
void launcher::signal::attach() {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace launcher::signal {
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
extern bool DISABLE;
|
extern bool DISABLE;
|
||||||
|
extern bool USE_VEH_WORKAROUND;
|
||||||
|
|
||||||
//void print_stacktrace();
|
//void print_stacktrace();
|
||||||
void attach();
|
void attach();
|
||||||
|
|||||||
+19
-13
@@ -66,7 +66,7 @@ bool eamuse_get_card(int active_count, int unit_id, uint8_t *card) {
|
|||||||
if (CARD_INSERT_UID_ENABLE[index]) {
|
if (CARD_INSERT_UID_ENABLE[index]) {
|
||||||
CARD_INSERT_UID_ENABLE[index] = false;
|
CARD_INSERT_UID_ENABLE[index] = false;
|
||||||
memcpy(card, CARD_INSERT_UID[index], 8);
|
memcpy(card, CARD_INSERT_UID[index], 8);
|
||||||
log_info("eamuse", "Inserted card from reader {}: {}", index, bin2hex(card, 8));
|
log_info("eamuse", "[P{}] Inserted card from reader: {}", index+1, bin2hex(card, 8));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,35 +83,40 @@ bool eamuse_get_card(int active_count, int unit_id, uint8_t *card) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool eamuse_get_card(const std::filesystem::path &path, uint8_t *card, int index) {
|
bool eamuse_get_card(const std::filesystem::path &path, uint8_t *card, int index) {
|
||||||
|
// do a quick copy under lock
|
||||||
|
std::unique_lock<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
|
const auto card_override = CARD_OVERRIDES[index];
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
// Check if card overrides are present
|
// Check if card overrides are present
|
||||||
if (!CARD_OVERRIDES[index].empty()) {
|
if (!card_override.empty()) {
|
||||||
|
|
||||||
// Override is present
|
// Override is present
|
||||||
for (int n = 0; n < 16; n++) {
|
for (int n = 0; n < 16; n++) {
|
||||||
char c = CARD_OVERRIDES[index].c_str()[n];
|
char c = card_override.c_str()[n];
|
||||||
bool digit = c >= '0' && c <= '9';
|
bool digit = c >= '0' && c <= '9';
|
||||||
bool character_big = c >= 'A' && c <= 'F';
|
bool character_big = c >= 'A' && c <= 'F';
|
||||||
bool character_small = c >= 'a' && c <= 'f';
|
bool character_small = c >= 'a' && c <= 'f';
|
||||||
if (!digit && !character_big && !character_small) {
|
if (!digit && !character_big && !character_small) {
|
||||||
log_warning("eamuse",
|
log_warning("eamuse",
|
||||||
"{} card override contains an invalid character sequence at byte {} (16 characters, 0-9/A-F only)",
|
"{} card override contains an invalid character sequence at byte {} (16 characters, 0-9/A-F only)",
|
||||||
CARD_OVERRIDES[index], n);
|
card_override, n);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Log info
|
// Log info
|
||||||
log_info("eamuse", "Inserted card override: {}", CARD_OVERRIDES[index]);
|
log_info("eamuse", "[P{}] Inserted card override: {}", index+1, card_override);
|
||||||
|
|
||||||
// Card is valid, convert and set it.
|
// Card is valid, convert and set it.
|
||||||
hex2bin(CARD_OVERRIDES[index].c_str(), card);
|
hex2bin(card_override.c_str(), card);
|
||||||
|
|
||||||
// cache it for auto-insert
|
// cache it for auto-insert
|
||||||
if (AUTO_INSERT_CARD[index] && !AUTO_INSERT_CARD_CACHED[index]) {
|
// always overwrite from overrides since override may have changed by user in card manager
|
||||||
|
if (AUTO_INSERT_CARD[index]) {
|
||||||
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
||||||
AUTO_INSERT_CARD_CACHED[index] = true;
|
AUTO_INSERT_CARD_CACHED[index] = true;
|
||||||
log_info("eamuse", "Auto card insert - caching this card in memory: {}", CARD_OVERRIDES[index]);
|
log_info("eamuse", "[P{}] Auto card insert - caching this card override in memory: {}", index+1, card_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
// success
|
// success
|
||||||
@@ -162,7 +167,7 @@ bool eamuse_get_card_from_file(const std::filesystem::path &path, uint8_t *card,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// info
|
// info
|
||||||
log_info("eamuse", "Inserted {}: {}", path.string(), buffer);
|
log_info("eamuse", "[P{}] Inserted {}: {}", index+1, path.string(), buffer);
|
||||||
|
|
||||||
// convert hex to bytes
|
// convert hex to bytes
|
||||||
hex2bin(buffer, card);
|
hex2bin(buffer, card);
|
||||||
@@ -171,7 +176,7 @@ bool eamuse_get_card_from_file(const std::filesystem::path &path, uint8_t *card,
|
|||||||
if (AUTO_INSERT_CARD[index] && !AUTO_INSERT_CARD_CACHED[index]) {
|
if (AUTO_INSERT_CARD[index] && !AUTO_INSERT_CARD_CACHED[index]) {
|
||||||
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
||||||
AUTO_INSERT_CARD_CACHED[index] = true;
|
AUTO_INSERT_CARD_CACHED[index] = true;
|
||||||
log_info("eamuse", "Auto card insert - caching this card in memory: {}", buffer);
|
log_info("eamuse", "[P{}] Auto card insert - caching this card from file in memory: {}", index+1, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// success
|
// success
|
||||||
@@ -211,7 +216,6 @@ bool eamuse_card_insert_consume(int active_count, int unit_id) {
|
|||||||
if (!CARD_INSERT[index]) {
|
if (!CARD_INSERT[index]) {
|
||||||
eamuse_card_insert(index);
|
eamuse_card_insert(index);
|
||||||
// not logging anything here to prevent spam
|
// not logging anything here to prevent spam
|
||||||
// log_info("eamuse", "Automatic card insert on {}/{} (-autocard)", unit_id + 1, active_count);
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -223,7 +227,7 @@ bool eamuse_card_insert_consume(int active_count, int unit_id) {
|
|||||||
auto offset = unit_id * games::KeypadButtons::Size;
|
auto offset = unit_id * games::KeypadButtons::Size;
|
||||||
if ((CARD_INSERT[index] && fabs(get_performance_seconds() - CARD_INSERT_TIME[index]) < CARD_INSERT_TIMEOUT)
|
if ((CARD_INSERT[index] && fabs(get_performance_seconds() - CARD_INSERT_TIME[index]) < CARD_INSERT_TIMEOUT)
|
||||||
|| GameAPI::Buttons::getState(RI_MGR, keypad_buttons->at(games::KeypadButtons::InsertCard + offset))) {
|
|| GameAPI::Buttons::getState(RI_MGR, keypad_buttons->at(games::KeypadButtons::InsertCard + offset))) {
|
||||||
log_info("eamuse", "Card insert on {}/{}", unit_id + 1, active_count);
|
log_info("eamuse", "[P{}] Card insert on reader (total active count: {})", unit_id+1, active_count);
|
||||||
CARD_INSERT[index] = false;
|
CARD_INSERT[index] = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -653,6 +657,8 @@ void eamuse_autodetect_game() {
|
|||||||
eamuse_set_game("Chase Chase Jokers");
|
eamuse_set_game("Chase Chase Jokers");
|
||||||
else if (avs::game::is_model("UKS"))
|
else if (avs::game::is_model("UKS"))
|
||||||
eamuse_set_game("QuizKnock STADIUM");
|
eamuse_set_game("QuizKnock STADIUM");
|
||||||
|
else if (avs::game::is_model("VFG"))
|
||||||
|
eamuse_set_game("Mahjong Fight Girl");
|
||||||
else {
|
else {
|
||||||
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
||||||
eamuse_set_game("unknown");
|
eamuse_set_game("unknown");
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "external/scard/scard.h"
|
#include "external/scard/scard.h"
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ enum eam_io_keypad_scan_code {
|
|||||||
EAM_IO_INSERT = 13, /* SpiceTools Extension */
|
EAM_IO_INSERT = 13, /* SpiceTools Extension */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern std::mutex CARD_OVERRIDES_LOCK;
|
||||||
extern std::string CARD_OVERRIDES[2];
|
extern std::string CARD_OVERRIDES[2];
|
||||||
extern bool AUTO_INSERT_CARD[2];
|
extern bool AUTO_INSERT_CARD[2];
|
||||||
extern float AUTO_INSERT_CARD_COOLDOWN;
|
extern float AUTO_INSERT_CARD_COOLDOWN;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace wintouchemu {
|
|||||||
bool LOG_FPS = false;
|
bool LOG_FPS = false;
|
||||||
|
|
||||||
static inline bool is_emu_enabled() {
|
static inline bool is_emu_enabled() {
|
||||||
return FORCE || !is_touch_available() || GRAPHICS_SHOW_CURSOR;
|
return FORCE || !is_touch_available("wintouchemu::is_emu_enabled") || GRAPHICS_SHOW_CURSOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static decltype(GetSystemMetrics) *GetSystemMetrics_orig = nullptr;
|
static decltype(GetSystemMetrics) *GetSystemMetrics_orig = nullptr;
|
||||||
|
|||||||
@@ -6,36 +6,61 @@
|
|||||||
|
|
||||||
namespace ImGui {
|
namespace ImGui {
|
||||||
|
|
||||||
|
const auto fg = ImVec4(0.910f, 0.914f, 0.922f, 1.0f);
|
||||||
|
const auto bg = ImVec4(0.192f, 0.212f, 0.220f, 1.0f);
|
||||||
|
|
||||||
|
void HelpTooltip(const char* desc) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_BorderShadow, bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, fg);
|
||||||
|
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
ImGui::TextUnformatted(desc);
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
}
|
||||||
|
|
||||||
void HelpMarker(const char* desc) {
|
void HelpMarker(const char* desc) {
|
||||||
ImGui::TextDisabled("(?)");
|
ImGui::TextDisabled("(?)");
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::BeginTooltip();
|
HelpTooltip(desc);
|
||||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
|
||||||
ImGui::TextUnformatted(desc);
|
|
||||||
ImGui::PopTextWrapPos();
|
|
||||||
ImGui::EndTooltip();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WarnTooltip(const char* desc, const char* warn) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_BorderShadow, bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, bg);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, fg);
|
||||||
|
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
if (desc && desc[0]) {
|
||||||
|
ImGui::TextUnformatted(desc);
|
||||||
|
ImGui::TextUnformatted("");
|
||||||
|
}
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 0.f, 1.f));
|
||||||
|
if (warn && warn[0]) {
|
||||||
|
ImGui::TextUnformatted("WARNING:");
|
||||||
|
ImGui::TextUnformatted(warn);
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
}
|
||||||
|
|
||||||
void WarnMarker(const char* desc, const char* warn) {
|
void WarnMarker(const char* desc, const char* warn) {
|
||||||
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImVec4(1.f, 1.f, 0.f, 1.f));
|
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImVec4(1.f, 1.f, 0.f, 1.f));
|
||||||
ImGui::TextDisabled("(!)");
|
ImGui::TextDisabled("(!)");
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::BeginTooltip();
|
WarnTooltip(desc, warn);
|
||||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
|
||||||
if (desc) {
|
|
||||||
ImGui::TextUnformatted(desc);
|
|
||||||
ImGui::TextUnformatted("");
|
|
||||||
}
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 0.f, 1.f));
|
|
||||||
if (warn) {
|
|
||||||
ImGui::TextUnformatted("WARNING:");
|
|
||||||
ImGui::TextUnformatted(warn);
|
|
||||||
}
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::PopTextWrapPos();
|
|
||||||
ImGui::EndTooltip();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace ImGui {
|
namespace ImGui {
|
||||||
|
|
||||||
|
void HelpTooltip(const char* desc);
|
||||||
void HelpMarker(const char* desc);
|
void HelpMarker(const char* desc);
|
||||||
|
void WarnTooltip(const char* desc, const char* warn);
|
||||||
void WarnMarker(const char* desc, const char* warn);
|
void WarnMarker(const char* desc, const char* warn);
|
||||||
void DummyMarker();
|
void DummyMarker();
|
||||||
void Knob(float fraction, float size, float thickness = 2.f,
|
void Knob(float fraction, float size, float thickness = 2.f,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "cfg/configurator.h"
|
||||||
#include "games/io.h"
|
#include "games/io.h"
|
||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "launcher/superexit.h"
|
#include "launcher/superexit.h"
|
||||||
@@ -12,6 +13,16 @@
|
|||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
|
#if !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) || \
|
||||||
|
!defined(IMGUI_DISABLE_DEFAULT_ALLOCATORS) || \
|
||||||
|
!defined(IMGUI_USE_BGRA_PACKED_COLOR) || \
|
||||||
|
!defined(IMGUI_HAS_VIEWPORT) || \
|
||||||
|
!defined(IMGUI_HAS_DOCK) || \
|
||||||
|
!defined(IMGUI_DISABLE_DEMO_WINDOWS) || \
|
||||||
|
defined(IMGUI_DISABLE_DEBUG_TOOLS)
|
||||||
|
#error "fix imconfig.h after updating imgui version"
|
||||||
|
#endif
|
||||||
|
|
||||||
// state
|
// state
|
||||||
static HWND g_hWnd = nullptr;
|
static HWND g_hWnd = nullptr;
|
||||||
static INT64 g_Time = 0;
|
static INT64 g_Time = 0;
|
||||||
@@ -42,6 +53,7 @@ bool ImGui_ImplSpice_Init(HWND hWnd) {
|
|||||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
|
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
|
||||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
|
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
|
||||||
io.BackendPlatformName = "imgui_impl_spice";
|
io.BackendPlatformName = "imgui_impl_spice";
|
||||||
|
io.ConfigErrorRecoveryEnableTooltip = true;
|
||||||
|
|
||||||
// keyboard mapping
|
// keyboard mapping
|
||||||
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
|
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
|
||||||
@@ -59,7 +71,7 @@ bool ImGui_ImplSpice_Init(HWND hWnd) {
|
|||||||
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
|
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
|
||||||
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
|
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
|
||||||
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
|
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
|
||||||
io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN;
|
io.KeyMap[ImGuiKey_KeypadEnter] = VK_RETURN;
|
||||||
io.KeyMap[ImGuiKey_A] = 'A';
|
io.KeyMap[ImGuiKey_A] = 'A';
|
||||||
io.KeyMap[ImGuiKey_C] = 'C';
|
io.KeyMap[ImGuiKey_C] = 'C';
|
||||||
io.KeyMap[ImGuiKey_V] = 'V';
|
io.KeyMap[ImGuiKey_V] = 'V';
|
||||||
@@ -349,27 +361,6 @@ void ImGui_ImplSpice_NewFrame() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// navigator input
|
|
||||||
auto buttons = games::get_buttons_overlay(eamuse_get_game());
|
|
||||||
if (buttons && (!overlay::OVERLAY || overlay::OVERLAY->hotkeys_triggered())) {
|
|
||||||
struct {
|
|
||||||
size_t index;
|
|
||||||
Button &btn;
|
|
||||||
} NAV_MAPPING[] = {
|
|
||||||
{ ImGuiNavInput_Activate, buttons->at(games::OverlayButtons::NavigatorActivate )},
|
|
||||||
{ ImGuiNavInput_Cancel, buttons->at(games::OverlayButtons::NavigatorCancel) },
|
|
||||||
{ ImGuiNavInput_DpadUp, buttons->at(games::OverlayButtons::NavigatorUp) },
|
|
||||||
{ ImGuiNavInput_DpadDown, buttons->at(games::OverlayButtons::NavigatorDown) },
|
|
||||||
{ ImGuiNavInput_DpadLeft, buttons->at(games::OverlayButtons::NavigatorLeft) },
|
|
||||||
{ ImGuiNavInput_DpadRight, buttons->at(games::OverlayButtons::NavigatorRight) },
|
|
||||||
};
|
|
||||||
for (auto mapping : NAV_MAPPING) {
|
|
||||||
if (GameAPI::Buttons::getState(RI_MGR, mapping.btn)) {
|
|
||||||
io.NavInputs[mapping.index] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set mouse wheel
|
// set mouse wheel
|
||||||
auto mouse_diff = mouse_wheel - mouse_wheel_last;
|
auto mouse_diff = mouse_wheel - mouse_wheel_last;
|
||||||
mouse_wheel_last = mouse_wheel;
|
mouse_wheel_last = mouse_wheel;
|
||||||
@@ -378,10 +369,27 @@ void ImGui_ImplSpice_NewFrame() {
|
|||||||
// update OS mouse position
|
// update OS mouse position
|
||||||
ImGui_ImplSpice_UpdateMousePos();
|
ImGui_ImplSpice_UpdateMousePos();
|
||||||
|
|
||||||
// update OS mouse cursor with the cursor requested by imgui
|
if (cfg::CONFIGURATOR_STANDALONE) {
|
||||||
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
// if cursor is inside the client area, always set the OS cursor to what ImGui wants
|
||||||
if (g_LastMouseCursor != mouse_cursor) {
|
// this is to deal with cases where mouse cursor changes outside the client rect and comes
|
||||||
g_LastMouseCursor = mouse_cursor;
|
// back into the window
|
||||||
ImGui_ImplSpice_UpdateMouseCursor();
|
// i'm sure there might be better ways to deal with this but this works so whatever, right?
|
||||||
|
RECT client_rect;
|
||||||
|
if (GetClientRect(g_hWnd, &client_rect)) {
|
||||||
|
POINT cursor;
|
||||||
|
if (GetCursorPos(&cursor) && ScreenToClient(g_hWnd, &cursor)) {
|
||||||
|
if (client_rect.left < cursor.x && cursor.x < client_rect.right &&
|
||||||
|
client_rect.top < cursor.y && cursor.y < client_rect.bottom) {
|
||||||
|
ImGui_ImplSpice_UpdateMouseCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// update OS mouse cursor with the cursor requested by imgui
|
||||||
|
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
||||||
|
if (g_LastMouseCursor != mouse_cursor) {
|
||||||
|
g_LastMouseCursor = mouse_cursor;
|
||||||
|
ImGui_ImplSpice_UpdateMouseCursor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -678,7 +678,7 @@ void bind_imgui_painting()
|
|||||||
int font_width, font_height;
|
int font_width, font_height;
|
||||||
io.Fonts->GetTexDataAsAlpha8(&tex_data, &font_width, &font_height);
|
io.Fonts->GetTexDataAsAlpha8(&tex_data, &font_width, &font_height);
|
||||||
const auto texture = new Texture{tex_data, font_width, font_height};
|
const auto texture = new Texture{tex_data, font_width, font_height};
|
||||||
io.Fonts->TexID = texture;
|
io.Fonts->TexID = reinterpret_cast<ImTextureID>(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Stats s_stats; // TODO: pass as an argument?
|
static Stats s_stats; // TODO: pass as an argument?
|
||||||
|
|||||||
@@ -7,14 +7,12 @@
|
|||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "touch/touch.h"
|
#include "touch/touch.h"
|
||||||
|
#include "util/fileutils.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/resutils.h"
|
#include "util/resutils.h"
|
||||||
#include "build/resource.h"
|
#include "build/resource.h"
|
||||||
|
|
||||||
#include "imgui/impl_dx9.h"
|
#include "external/imgui/backends/imgui_impl_dx9.h"
|
||||||
#include "imgui/impl_spice.h"
|
|
||||||
#include "imgui/impl_sw.h"
|
|
||||||
#include "overlay/imgui/impl_dx9.h"
|
|
||||||
#include "overlay/imgui/impl_spice.h"
|
#include "overlay/imgui/impl_spice.h"
|
||||||
#include "overlay/imgui/impl_sw.h"
|
#include "overlay/imgui/impl_sw.h"
|
||||||
|
|
||||||
@@ -62,6 +60,7 @@ namespace overlay {
|
|||||||
std::mutex OVERLAY_MUTEX;
|
std::mutex OVERLAY_MUTEX;
|
||||||
std::unique_ptr<overlay::SpiceOverlay> OVERLAY = nullptr;
|
std::unique_ptr<overlay::SpiceOverlay> OVERLAY = nullptr;
|
||||||
ImFont* DSEG_FONT = nullptr;
|
ImFont* DSEG_FONT = nullptr;
|
||||||
|
bool SHOW_DEBUG_LOG_WINDOW = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *ImGui_Alloc(size_t sz, void *user_data) {
|
static void *ImGui_Alloc(size_t sz, void *user_data) {
|
||||||
@@ -242,13 +241,20 @@ void overlay::SpiceOverlay::init() {
|
|||||||
io.UserData = this;
|
io.UserData = this;
|
||||||
io.ConfigFlags = ImGuiConfigFlags_NavEnableKeyboard
|
io.ConfigFlags = ImGuiConfigFlags_NavEnableKeyboard
|
||||||
| ImGuiConfigFlags_NavEnableGamepad
|
| ImGuiConfigFlags_NavEnableGamepad
|
||||||
| ImGuiConfigFlags_NavEnableSetMousePos
|
| ImGuiConfigFlags_NavEnableSetMousePos;
|
||||||
| ImGuiConfigFlags_DockingEnable
|
|
||||||
| ImGuiConfigFlags_ViewportsEnable;
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||||
if (is_touch_available()) {
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||||
|
}
|
||||||
|
if (is_touch_available("SpiceOverlay::init")) {
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_IsTouchScreen;
|
io.ConfigFlags |= ImGuiConfigFlags_IsTouchScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// temporarily turn this off as it can cause crashes during font load failures
|
||||||
|
// turns back on in ImGui_ImplSpice_Init
|
||||||
|
io.ConfigErrorRecoveryEnableTooltip = false;
|
||||||
|
|
||||||
io.MouseDrawCursor = !GRAPHICS_SHOW_CURSOR;
|
io.MouseDrawCursor = !GRAPHICS_SHOW_CURSOR;
|
||||||
|
|
||||||
// disable config
|
// disable config
|
||||||
@@ -263,20 +269,14 @@ void overlay::SpiceOverlay::init() {
|
|||||||
// add fallback fonts for missing glyph ranges
|
// add fallback fonts for missing glyph ranges
|
||||||
ImFontConfig config {};
|
ImFontConfig config {};
|
||||||
config.MergeMode = true;
|
config.MergeMode = true;
|
||||||
io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\simsun.ttc)",
|
|
||||||
13.0f, &config, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
add_font("simsun.ttc", &config, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||||
io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\arial.ttf)",
|
add_font("arial.ttc", &config, io.Fonts->GetGlyphRangesCyrillic());
|
||||||
13.0f, &config, io.Fonts->GetGlyphRangesCyrillic());
|
add_font("meiryu.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
||||||
io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\meiryu.ttc)",
|
add_font("meiryo.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
||||||
13.0f, &config, io.Fonts->GetGlyphRangesJapanese());
|
add_font("gulim.ttc", &config, io.Fonts->GetGlyphRangesKorean());
|
||||||
io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\meiryo.ttc)",
|
add_font("cordia.ttc", &config, io.Fonts->GetGlyphRangesThai());
|
||||||
13.0f, &config, io.Fonts->GetGlyphRangesJapanese());
|
add_font("arial.ttc", &config, io.Fonts->GetGlyphRangesVietnamese());
|
||||||
io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\gulim.ttc)",
|
|
||||||
13.0f, &config, io.Fonts->GetGlyphRangesKorean());
|
|
||||||
io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\cordia.ttf)",
|
|
||||||
13.0f, &config, io.Fonts->GetGlyphRangesThai());
|
|
||||||
io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\arial.ttf)",
|
|
||||||
13.0f, &config, io.Fonts->GetGlyphRangesVietnamese());
|
|
||||||
|
|
||||||
// add special font
|
// add special font
|
||||||
if (avs::game::is_model("LDJ")) {
|
if (avs::game::is_model("LDJ")) {
|
||||||
@@ -458,6 +458,10 @@ void overlay::SpiceOverlay::new_frame() {
|
|||||||
window->build();
|
window->build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SHOW_DEBUG_LOG_WINDOW) {
|
||||||
|
ImGui::ShowDebugLogWindow(&SHOW_DEBUG_LOG_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
// end frame
|
// end frame
|
||||||
ImGui::EndFrame();
|
ImGui::EndFrame();
|
||||||
}
|
}
|
||||||
@@ -693,3 +697,21 @@ uint32_t *overlay::SpiceOverlay::sw_get_pixel_data(int *width, int *height) {
|
|||||||
*height = this->pixel_data_height;
|
*height = this->pixel_data_height;
|
||||||
return &this->pixel_data[0];
|
return &this->pixel_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void overlay::SpiceOverlay::add_font(const char* font, ImFontConfig* config, const ImWchar* glyphs) {
|
||||||
|
CHAR fonts_dir[MAX_PATH];
|
||||||
|
ExpandEnvironmentStringsA(R"(%SYSTEMROOT%\Fonts\)", fonts_dir, MAX_PATH);
|
||||||
|
std::filesystem::path full_path = fonts_dir;
|
||||||
|
full_path += font;
|
||||||
|
|
||||||
|
if (fileutils::file_exists(full_path)) {
|
||||||
|
log_misc("overlay", "loading font: {}", full_path.string());
|
||||||
|
ImGui::GetIO().Fonts->AddFontFromFileTTF(
|
||||||
|
full_path.string().c_str(),
|
||||||
|
13.0f,
|
||||||
|
config,
|
||||||
|
glyphs);
|
||||||
|
} else {
|
||||||
|
log_misc("overlay", "font not found: {}", full_path.string());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ namespace overlay {
|
|||||||
extern bool AUTO_SHOW_KEYPAD_P2;
|
extern bool AUTO_SHOW_KEYPAD_P2;
|
||||||
extern bool USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT;
|
extern bool USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT;
|
||||||
extern bool FPS_SHOULD_FLIP;
|
extern bool FPS_SHOULD_FLIP;
|
||||||
|
extern bool SHOW_DEBUG_LOG_WINDOW;
|
||||||
|
|
||||||
class SpiceOverlay {
|
class SpiceOverlay {
|
||||||
public:
|
public:
|
||||||
@@ -128,6 +129,7 @@ namespace overlay {
|
|||||||
bool hotkey_toggle_last = false;
|
bool hotkey_toggle_last = false;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
void add_font(const char* font, ImFontConfig* config, const ImWchar* glyphs);
|
||||||
};
|
};
|
||||||
|
|
||||||
// global
|
// global
|
||||||
|
|||||||
@@ -99,10 +99,9 @@ void overlay::Window::build() {
|
|||||||
for (auto &child : this->children) {
|
for (auto &child : this->children) {
|
||||||
child->build();
|
child->build();
|
||||||
}
|
}
|
||||||
|
|
||||||
// end window
|
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
// end window
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
if (this->remove_window_padding) {
|
if (this->remove_window_padding) {
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "external/imgui/imgui.h"
|
#include "external/imgui/imgui.h"
|
||||||
#include "external/imgui/imgui_stdlib.h"
|
#include "external/imgui/misc/cpp/imgui_stdlib.h"
|
||||||
#include "overlay.h"
|
#include "overlay.h"
|
||||||
|
|
||||||
namespace overlay {
|
namespace overlay {
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
#include "external/rapidjson/document.h"
|
#include "external/rapidjson/document.h"
|
||||||
#include "external/rapidjson/prettywriter.h"
|
#include "external/rapidjson/prettywriter.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
|
#include "misc/clipboard.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
#include "util/fileutils.h"
|
#include "util/fileutils.h"
|
||||||
#include "cfg/configurator.h"
|
#include "cfg/configurator.h"
|
||||||
|
#include "overlay/imgui/extensions.h"
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
@@ -27,19 +29,76 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->toggle_button = games::OverlayButtons::ToggleCardManager;
|
this->toggle_button = games::OverlayButtons::ToggleCardManager;
|
||||||
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_card_manager.json";
|
|
||||||
if (fileutils::file_exists(this->config_path)) {
|
bool file_exists = false;
|
||||||
|
this->config_path =
|
||||||
|
fileutils::get_config_file_path("cardmanager", "spicetools_card_manager.json", &file_exists);
|
||||||
|
if (file_exists) {
|
||||||
this->config_load();
|
this->config_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load -card0 / -card1
|
||||||
|
// -card0 / -card1 override
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
|
if (!CARD_OVERRIDES[0].empty()) {
|
||||||
|
const CardEntry card0 = {
|
||||||
|
.name = "P1 Default (-card0)",
|
||||||
|
.id = CARD_OVERRIDES[0],
|
||||||
|
.search_string = "p1 default (-card0)",
|
||||||
|
.read_only = true,
|
||||||
|
.color = {0.9f, 0.9f, 0.9f}
|
||||||
|
};
|
||||||
|
card_cmd_overrides[0].emplace(card0);
|
||||||
|
this->loaded_card[0] = card0;
|
||||||
|
}
|
||||||
|
if (eamuse_get_game_keypads() > 1 && !CARD_OVERRIDES[1].empty()) {
|
||||||
|
const CardEntry card1 = {
|
||||||
|
.name = "P2 Default (-card1)",
|
||||||
|
.id = CARD_OVERRIDES[1],
|
||||||
|
.search_string = "p2 default (-card1)",
|
||||||
|
.read_only = true,
|
||||||
|
.color = {0.9f, 0.9f, 0.9f}
|
||||||
|
};
|
||||||
|
card_cmd_overrides[1].emplace(card1);
|
||||||
|
this->loaded_card[1] = card1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CardManager::~CardManager() {
|
CardManager::~CardManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::build_content() {
|
void CardManager::build_content() {
|
||||||
ImGui::SeparatorText("Selected card");
|
ImGui::TextColored(ImVec4(1, 0.7f, 0, 1), "Active card overrides");
|
||||||
build_card();
|
ImGui::SameLine();
|
||||||
ImGui::SeparatorText("Available cards");
|
ImGui::HelpMarker(
|
||||||
|
"Click to insert card now, or press Insert Card key. Auto Card Insert will also use these cards.\n\n"
|
||||||
|
"If no override is set, pressing Insert Card will read from card0.txt / card1.txt.");
|
||||||
|
if (ImGui::BeginTable("CardSetTable", eamuse_get_game_keypads() > 1 ? 2 : 1, ImGuiTableFlags_SizingFixedFit)) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted("Player 1");
|
||||||
|
if (eamuse_get_game_keypads() > 1) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted("Player 2");
|
||||||
|
}
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
if (eamuse_get_game_keypads() > (int)i) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (build_card(i) && this->loaded_card[i].has_value()) {
|
||||||
|
insert_card_over_api(i, this->loaded_card[i].value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::TextColored(ImVec4(1, 0.7f, 0, 1), "Available cards");
|
||||||
build_card_list();
|
build_card_list();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
@@ -48,44 +107,13 @@ namespace overlay::windows {
|
|||||||
build_card_editor();
|
build_card_editor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::build_card() {
|
bool CardManager::build_card(int reader) {
|
||||||
ImGui::BeginDisabled(this->current_card == nullptr);
|
ImGui::PushID(reader);
|
||||||
// insert P1 button
|
bool clicked = false;
|
||||||
if (ImGui::Button("Insert P1")) {
|
if (this->loaded_card[reader].has_value()) {
|
||||||
const auto card = this->current_card;
|
const auto &card = this->loaded_card[reader].value();
|
||||||
uint8_t card_bin[8];
|
const ImVec4 color(card.color[0], card.color[1], card.color[2], 1.f);
|
||||||
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
|
float bg_luminance = (0.299f * card.color[0] + 0.587 * card.color[1] + 0.114 * card.color[2]);
|
||||||
eamuse_card_insert(0, card_bin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert P2 button
|
|
||||||
if (eamuse_get_game_keypads() > 1) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Insert P2")) {
|
|
||||||
const auto card = this->current_card;
|
|
||||||
uint8_t card_bin[8];
|
|
||||||
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
|
|
||||||
eamuse_card_insert(1, card_bin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// edit selected card
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Edit Card")) {
|
|
||||||
open_card_editor();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
// card ui
|
|
||||||
if (this->current_card) {
|
|
||||||
const auto card = this->current_card;
|
|
||||||
const ImVec4 color(card->color[0], card->color[1], card->color[2], 1.f);
|
|
||||||
float bg_luminance = (0.299f * card->color[0] + 0.587 * card->color[1] + 0.114 * card->color[2]);
|
|
||||||
|
|
||||||
// text color
|
// text color
|
||||||
ImVec4 text_color;
|
ImVec4 text_color;
|
||||||
@@ -101,22 +129,25 @@ namespace overlay::windows {
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Text, text_color);
|
ImGui::PushStyleColor(ImGuiCol_Text, text_color);
|
||||||
if (ImGui::Button(fmt::format(
|
if (ImGui::Button(fmt::format(
|
||||||
" {} \n {} {} {} {} ",
|
" {} \n {} {} {} {} ",
|
||||||
card->name.empty() ? "<blank>" : card->name.substr(0, 19),
|
card.name.empty() ? "<blank>" : card.name.substr(0, 19),
|
||||||
card->id.substr(0, 4).c_str(),
|
card.id.substr(0, 4).c_str(),
|
||||||
card->id.substr(4, 4).c_str(),
|
card.id.substr(4, 4).c_str(),
|
||||||
card->id.substr(8, 4).c_str(),
|
card.id.substr(8, 4).c_str(),
|
||||||
card->id.substr(12, 4).c_str()
|
card.id.substr(12, 4).c_str()
|
||||||
).c_str())) {
|
).c_str())) {
|
||||||
|
|
||||||
open_card_editor();
|
clicked = true;
|
||||||
}
|
}
|
||||||
ImGui::PopStyleColor(4);
|
ImGui::PopStyleColor(4);
|
||||||
} else {
|
} else {
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
ImGui::Button(" <No card> \n xxxx xxxx xxxx xxxx ");
|
ImGui::Button(" (No override set) \n"
|
||||||
|
" xxxx xxxx xxxx xxxx ");
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
ImGui::PopStyleColor(4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
return clicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::open_card_editor() {
|
void CardManager::open_card_editor() {
|
||||||
@@ -140,13 +171,18 @@ namespace overlay::windows {
|
|||||||
this->card_buffer,
|
this->card_buffer,
|
||||||
std::size(this->card_buffer),
|
std::size(this->card_buffer),
|
||||||
ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
|
ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
|
||||||
|
ImGui::EndDisabled();
|
||||||
if (this->current_card == nullptr) {
|
if (this->current_card == nullptr) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Generate")) {
|
if (ImGui::Button("Generate")) {
|
||||||
generate_ea_card(this->card_buffer);
|
generate_ea_card(this->card_buffer);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Copy")) {
|
||||||
|
clipboard::copy_text(this->current_card->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
|
||||||
|
|
||||||
// name field
|
// name field
|
||||||
ImGui::InputTextWithHint("Card Name", "Main Card",
|
ImGui::InputTextWithHint("Card Name", "Main Card",
|
||||||
@@ -171,6 +207,18 @@ namespace overlay::windows {
|
|||||||
this->current_card->color[1] = this->color_buffer[1];
|
this->current_card->color[1] = this->color_buffer[1];
|
||||||
this->current_card->color[2] = this->color_buffer[2];
|
this->current_card->color[2] = this->color_buffer[2];
|
||||||
generate_search_string(this->current_card);
|
generate_search_string(this->current_card);
|
||||||
|
|
||||||
|
// ensure loaded cards are kept up to date
|
||||||
|
// note: does not handle cases where multiple cards have the same ID
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
if (this->loaded_card[i].has_value() &&
|
||||||
|
!this->loaded_card[i].value().read_only &&
|
||||||
|
this->loaded_card[i].value().id == this->current_card->id) {
|
||||||
|
this->loaded_card[i] = *this->current_card;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// create a new card
|
// create a new card
|
||||||
CardEntry card {
|
CardEntry card {
|
||||||
@@ -211,14 +259,54 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardManager::build_card_selectable(CardEntry &card) {
|
||||||
|
// generate card name
|
||||||
|
std::string card_name = "";
|
||||||
|
if (card.id.length() == 16) {
|
||||||
|
card_name += card.id.substr(0, 4);
|
||||||
|
card_name += " ";
|
||||||
|
card_name += card.id.substr(4, 4);
|
||||||
|
card_name += " ";
|
||||||
|
card_name += card.id.substr(8, 4);
|
||||||
|
card_name += " ";
|
||||||
|
card_name += card.id.substr(12, 4);
|
||||||
|
} else {
|
||||||
|
card_name += card.id;
|
||||||
|
}
|
||||||
|
if (!card.name.empty()) {
|
||||||
|
card_name += " - ";
|
||||||
|
card_name += card.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushID(&card);
|
||||||
|
|
||||||
|
// color button
|
||||||
|
ImVec4 color(card.color[0], card.color[1], card.color[2], 1.f);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color);
|
||||||
|
ImGui::SmallButton(" ");
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
// selectable item
|
||||||
|
if (ImGui::Selectable(card_name.c_str(), this->current_card == &card)) {
|
||||||
|
this->current_card = &card;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
void CardManager::build_card_list() {
|
void CardManager::build_card_list() {
|
||||||
|
|
||||||
// search for card
|
// search for card
|
||||||
//
|
//
|
||||||
// setting ImGuiInputTextFlags_CallbackCharFilter and pressing escape doesn't cause below
|
// setting ImGuiInputTextFlags_CallbackCharFilter and pressing escape doesn't cause below
|
||||||
// to return true, making it necessary to provide a callback...
|
// to return true, making it necessary to provide a callback...
|
||||||
ImGui::SetNextItemWidth(220);
|
ImGui::SetNextItemWidth(240);
|
||||||
if (ImGui::InputTextWithHint("", "Type here to search..", &this->search_filter)) {
|
if (ImGui::InputTextWithHint("", "Type here to search..", &this->search_filter)) {
|
||||||
|
this->current_card = nullptr;
|
||||||
this->search_filter_in_lower_case = strtolower(this->search_filter);
|
this->search_filter_in_lower_case = strtolower(this->search_filter);
|
||||||
}
|
}
|
||||||
if (!this->search_filter.empty()) {
|
if (!this->search_filter.empty()) {
|
||||||
@@ -227,11 +315,49 @@ namespace overlay::windows {
|
|||||||
this->search_filter.clear();
|
this->search_filter.clear();
|
||||||
this->search_filter_in_lower_case.clear();
|
this->search_filter_in_lower_case.clear();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
ImGui::SameLine();
|
|
||||||
|
// toolbar
|
||||||
// move selected up/down the list
|
|
||||||
ImGui::BeginDisabled(this->current_card == nullptr);
|
// set card as p1/p2
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
if (eamuse_get_game_keypads() > (int)i) {
|
||||||
|
if (i != 0) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
ImGui::PushID(i);
|
||||||
|
ImGui::BeginDisabled(this->current_card == nullptr);
|
||||||
|
if (ImGui::Button(i == 0 ? "Load P1" : "Load P2") && this->current_card) {
|
||||||
|
this->loaded_card[i] = *this->current_card;
|
||||||
|
log_info(
|
||||||
|
"cardmanager",
|
||||||
|
"[P{}] update override and insert card: {} ({})",
|
||||||
|
i+1,
|
||||||
|
this->current_card->id,
|
||||||
|
this->current_card->name
|
||||||
|
);
|
||||||
|
|
||||||
|
// update override
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
|
CARD_OVERRIDES[i] = this->current_card->id;
|
||||||
|
|
||||||
|
// insert card over api
|
||||||
|
insert_card_over_api(i, this->loaded_card[i].value());
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// edit selected card
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginDisabled(this->current_card == nullptr || this->current_card->read_only);
|
||||||
|
if (ImGui::Button("Edit")) {
|
||||||
|
open_card_editor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// move selected up/down the list
|
||||||
|
if (this->search_filter.empty()) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Move Up")) {
|
if (ImGui::Button("Move Up")) {
|
||||||
for (auto it = this->cards.begin(); it != this->cards.end(); ++it) {
|
for (auto it = this->cards.begin(); it != this->cards.end(); ++it) {
|
||||||
@@ -254,60 +380,37 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
|
||||||
}
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
// cards list
|
// cards list
|
||||||
// use all available vertical space, minus height of buttons, minus separator
|
// use all available vertical space, minus height footer (a row of buttons and separator)
|
||||||
if (ImGui::BeginChild(
|
if (ImGui::BeginChild(
|
||||||
"cards",
|
"cards",
|
||||||
ImVec2(0, ImGui::GetContentRegionAvail().y - ImGui::GetFrameHeightWithSpacing() - 8.f))) {
|
ImVec2(0, ImGui::GetContentRegionAvail().y - ImGui::GetFrameHeightWithSpacing() - 8.f))) {
|
||||||
|
|
||||||
|
// -card0 / -card1 override
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
if (card_cmd_overrides[i].has_value()) {
|
||||||
|
build_card_selectable(card_cmd_overrides[i].value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cards from card manager JSON
|
||||||
for (auto &card : this->cards) {
|
for (auto &card : this->cards) {
|
||||||
|
|
||||||
// get card name
|
|
||||||
std::string card_name = "";
|
|
||||||
if (card.id.length() == 16) {
|
|
||||||
card_name += card.id.substr(0, 4);
|
|
||||||
card_name += " ";
|
|
||||||
card_name += card.id.substr(4, 4);
|
|
||||||
card_name += " ";
|
|
||||||
card_name += card.id.substr(8, 4);
|
|
||||||
card_name += " ";
|
|
||||||
card_name += card.id.substr(12, 4);
|
|
||||||
} else {
|
|
||||||
card_name += card.id;
|
|
||||||
}
|
|
||||||
if (!card.name.empty()) {
|
|
||||||
card_name += " - ";
|
|
||||||
card_name += card.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->search_filter_in_lower_case.empty() && !card.search_string.empty()) {
|
if (!this->search_filter_in_lower_case.empty() && !card.search_string.empty()) {
|
||||||
const bool matched =
|
const bool matched =
|
||||||
card.search_string.find(this->search_filter_in_lower_case) != std::string::npos;
|
card.search_string.find(this->search_filter_in_lower_case) != std::string::npos;
|
||||||
|
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw entry
|
build_card_selectable(card);
|
||||||
ImGui::PushID(&card);
|
|
||||||
|
|
||||||
ImVec4 color(card.color[0], card.color[1], card.color[2], 1.f);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color);
|
|
||||||
ImGui::SmallButton(" ");
|
|
||||||
ImGui::PopStyleColor(3);
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Selectable(card_name.c_str(), this->current_card == &card)) {
|
|
||||||
this->current_card = &card;
|
|
||||||
}
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
@@ -334,8 +437,6 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::config_load() {
|
void CardManager::config_load() {
|
||||||
log_info("cardmanager", "loading config");
|
|
||||||
|
|
||||||
// clear cards
|
// clear cards
|
||||||
this->cards.clear();
|
this->cards.clear();
|
||||||
|
|
||||||
@@ -466,10 +567,10 @@ namespace overlay::windows {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(this->config_path, buffer.GetString())) {
|
if (fileutils::write_config_file("cardmanager", this->config_path, buffer.GetString())) {
|
||||||
this->config_dirty = false;
|
this->config_dirty = false;
|
||||||
} else {
|
} else {
|
||||||
log_warning("cardmanager", "unable to save config file to {}", this->config_path.string());
|
log_warning("cardmanager", "unable to save config file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,4 +605,11 @@ namespace overlay::windows {
|
|||||||
this->color_buffer[1] = g / 255.f;
|
this->color_buffer[1] = g / 255.f;
|
||||||
this->color_buffer[2] = b / 255.f;
|
this->color_buffer[2] = b / 255.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardManager::insert_card_over_api(int reader, CardEntry &card) {
|
||||||
|
uint8_t card_bin[8];
|
||||||
|
if (card.id.length() == 16 && hex2bin(card.id.c_str(), card_bin)) {
|
||||||
|
eamuse_card_insert(reader, card_bin);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "overlay/window.h"
|
#include "overlay/window.h"
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ namespace overlay::windows {
|
|||||||
std::string name = "unnamed";
|
std::string name = "unnamed";
|
||||||
std::string id = "E004010000000000";
|
std::string id = "E004010000000000";
|
||||||
std::string search_string = "";
|
std::string search_string = "";
|
||||||
|
bool read_only = false;
|
||||||
float color[3] {};
|
float color[3] {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,7 +31,10 @@ namespace overlay::windows {
|
|||||||
char name_buffer[65] {};
|
char name_buffer[65] {};
|
||||||
char card_buffer[17] {};
|
char card_buffer[17] {};
|
||||||
float color_buffer[3] {};
|
float color_buffer[3] {};
|
||||||
|
|
||||||
|
std::optional<CardEntry> card_cmd_overrides[2];
|
||||||
|
|
||||||
|
std::optional<CardEntry> loaded_card[2];
|
||||||
CardEntry *current_card = nullptr;
|
CardEntry *current_card = nullptr;
|
||||||
|
|
||||||
std::string search_filter = "";
|
std::string search_filter = "";
|
||||||
@@ -41,10 +46,13 @@ namespace overlay::windows {
|
|||||||
void generate_search_string(CardEntry *card);
|
void generate_search_string(CardEntry *card);
|
||||||
void generate_random_color();
|
void generate_random_color();
|
||||||
|
|
||||||
void build_card();
|
bool build_card(int reader);
|
||||||
void open_card_editor();
|
void open_card_editor();
|
||||||
void build_card_editor();
|
void build_card_editor();
|
||||||
void build_card_list();
|
void build_card_list();
|
||||||
|
void build_card_selectable(CardEntry &card);
|
||||||
void build_footer();
|
void build_footer();
|
||||||
|
|
||||||
|
void insert_card_over_api(int reader, CardEntry &card);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+1872
-1787
File diff suppressed because it is too large
Load Diff
@@ -178,9 +178,11 @@ namespace overlay::windows {
|
|||||||
static_cast<int>(ImGui::GetIO().DisplaySize.x),
|
static_cast<int>(ImGui::GetIO().DisplaySize.x),
|
||||||
static_cast<int>(ImGui::GetIO().DisplaySize.y));
|
static_cast<int>(ImGui::GetIO().DisplaySize.y));
|
||||||
|
|
||||||
// removed for size (along with setting IMGUI_DISABLE_DEMO_WINDOWS
|
if (ImGui::Button("ImGui Debug Log")) {
|
||||||
// and IMGUI_DISABLE_DEBUG_TOOLS) - saves about 300kb in each
|
overlay::SHOW_DEBUG_LOG_WINDOW = !overlay::SHOW_DEBUG_LOG_WINDOW;
|
||||||
// binary
|
}
|
||||||
|
|
||||||
|
// removed for size (IMGUI_DISABLE_DEMO_WINDOWS)
|
||||||
|
|
||||||
// metrics button
|
// metrics button
|
||||||
// this->metrics_open |= ImGui::Button("Metrics Window");
|
// this->metrics_open |= ImGui::Button("Metrics Window");
|
||||||
@@ -749,7 +751,7 @@ namespace overlay::windows {
|
|||||||
if (ImGui::CollapsingHeader("Touch")) {
|
if (ImGui::CollapsingHeader("Touch")) {
|
||||||
|
|
||||||
// status
|
// status
|
||||||
ImGui::Text("Status: %s", is_touch_available() ? "available" : "unavailable");
|
ImGui::Text("Status: %s", is_touch_available("Control::touch_view") ? "available" : "unavailable");
|
||||||
|
|
||||||
// touch points
|
// touch points
|
||||||
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ namespace overlay::windows {
|
|||||||
bottom_right.x += overlay_content_top_left.x;
|
bottom_right.x += overlay_content_top_left.x;
|
||||||
bottom_right.y += overlay_content_top_left.y;
|
bottom_right.y += overlay_content_top_left.y;
|
||||||
ImGui::GetBackgroundDrawList()->AddImage(
|
ImGui::GetBackgroundDrawList()->AddImage(
|
||||||
reinterpret_cast<void *>(this->texture),
|
reinterpret_cast<ImTextureID>(this->texture),
|
||||||
overlay_content_top_left,
|
overlay_content_top_left,
|
||||||
bottom_right);
|
bottom_right);
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ namespace overlay::windows {
|
|||||||
url_fetch_errors += fmt::format("WinHttpSendRequest failed: {}\n", gle);
|
url_fetch_errors += fmt::format("WinHttpSendRequest failed: {}\n", gle);
|
||||||
if (gle == 12175) {
|
if (gle == 12175) {
|
||||||
url_fetch_errors += "\nThis is ERROR_WINHTTP_SECURE_FAILURE - most likely TLS 1.1 / TLS 1.2 error on old OS versions.\n\n";
|
url_fetch_errors += "\nThis is ERROR_WINHTTP_SECURE_FAILURE - most likely TLS 1.1 / TLS 1.2 error on old OS versions.\n\n";
|
||||||
url_fetch_errors += "Look up MSDN article on 'Update to enable TLS 1.1 and TLS 1.2 as default secure protocols in WinHTTP in Windows' for a fix.";
|
url_fetch_errors += "Look up MSDN article on 'Update to enable TLS 1.1 and TLS 1.2 as default secure protocols in WinHTTP in Windows' for a fix.\n";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ namespace overlay::windows {
|
|||||||
statusCode,
|
statusCode,
|
||||||
netutils::http_status_reason_phrase(statusCode));
|
netutils::http_status_reason_phrase(statusCode));
|
||||||
if (statusCode == 404) {
|
if (statusCode == 404) {
|
||||||
url_fetch_errors += "(Patch server did not find any patches for this game version)";
|
url_fetch_errors += "(Patch server did not find any patches for this game version)\n";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,8 @@ namespace overlay::windows {
|
|||||||
this->config_path = PATCH_MANAGER_CFG_PATH_OVERRIDE.value();
|
this->config_path = PATCH_MANAGER_CFG_PATH_OVERRIDE.value();
|
||||||
log_info("patchmanager", "using custom config file path: {}", this->config_path.string().c_str());
|
log_info("patchmanager", "using custom config file path: {}", this->config_path.string().c_str());
|
||||||
} else {
|
} else {
|
||||||
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_patch_manager.json";
|
this->config_path =
|
||||||
|
fileutils::get_config_file_path("patchmanager", "spicetools_patch_manager.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ldr_registered) {
|
if (!ldr_registered) {
|
||||||
@@ -550,7 +551,7 @@ namespace overlay::windows {
|
|||||||
ImGui::Text("Failed to import patches from URL.");
|
ImGui::Text("Failed to import patches from URL.");
|
||||||
if (!url_fetch_errors.empty()) {
|
if (!url_fetch_errors.empty()) {
|
||||||
ImGui::TextUnformatted("");
|
ImGui::TextUnformatted("");
|
||||||
ImGui::PushTextWrapPos(ImGui::GetIO().DisplaySize.x * 0.5);
|
ImGui::PushTextWrapPos(ImGui::GetIO().DisplaySize.x * 0.7);
|
||||||
ImGui::TextUnformatted(url_fetch_errors.c_str());
|
ImGui::TextUnformatted(url_fetch_errors.c_str());
|
||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
}
|
}
|
||||||
@@ -558,6 +559,12 @@ namespace overlay::windows {
|
|||||||
if (ImGui::Button("OK")) {
|
if (ImGui::Button("OK")) {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
if (!url_fetch_errors.empty()) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Copy Error")) {
|
||||||
|
clipboard::copy_text(url_fetch_errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,17 +656,9 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
// first column, part 1: help / caution marker
|
// first column, part 1: help / caution marker
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
const std::string description = patch.description;
|
if (!patch.caution.empty()) {
|
||||||
const std::string caution = patch.caution;
|
|
||||||
if (!description.empty() && !caution.empty()) {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::WarnMarker(description.c_str(), caution.c_str());
|
ImGui::WarnMarker(patch.description.c_str(), patch.caution.c_str());
|
||||||
} else if (!description.empty()) {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
ImGui::HelpMarker(description.c_str());
|
|
||||||
} else if (!caution.empty()) {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
ImGui::WarnMarker(nullptr, caution.c_str());
|
|
||||||
} else {
|
} else {
|
||||||
ImGui::DummyMarker();
|
ImGui::DummyMarker();
|
||||||
}
|
}
|
||||||
@@ -705,6 +704,11 @@ namespace overlay::windows {
|
|||||||
if (style_color_pushed) {
|
if (style_color_pushed) {
|
||||||
ImGui::PopStyleColor(style_color_pushed);
|
ImGui::PopStyleColor(style_color_pushed);
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
show_patch_tooltip(patch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// show range after label for integer patches
|
||||||
if (patch.type == PatchType::Integer) {
|
if (patch.type == PatchType::Integer) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
auto& numpatch = patch.patch_number;
|
auto& numpatch = patch.patch_number;
|
||||||
@@ -741,6 +745,9 @@ namespace overlay::windows {
|
|||||||
patch.last_status = is_patch_active(patch);
|
patch.last_status = is_patch_active(patch);
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
show_patch_tooltip(patch);
|
||||||
|
}
|
||||||
|
|
||||||
// second column, part 2: additional options UI (dropdown, text input)
|
// second column, part 2: additional options UI (dropdown, text input)
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@@ -767,6 +774,9 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
show_patch_tooltip(patch);
|
||||||
|
}
|
||||||
} else if (patch.type == PatchType::Integer) {
|
} else if (patch.type == PatchType::Integer) {
|
||||||
ImGui::SetNextItemWidth(200.0f);
|
ImGui::SetNextItemWidth(200.0f);
|
||||||
auto& numpatch = patch.patch_number;
|
auto& numpatch = patch.patch_number;
|
||||||
@@ -780,6 +790,9 @@ namespace overlay::windows {
|
|||||||
apply_patch(patch, true);
|
apply_patch(patch, true);
|
||||||
config_dirty = true;
|
config_dirty = true;
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
show_patch_tooltip(patch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (patch_status == PatchStatus::Disabled) {
|
} else if (patch_status == PatchStatus::Disabled) {
|
||||||
ImGui::SetNextItemWidth(200.0f);
|
ImGui::SetNextItemWidth(200.0f);
|
||||||
@@ -794,6 +807,9 @@ namespace overlay::windows {
|
|||||||
ImGui::InputInt("##dummy_int_input", &patch.patch_number.value);
|
ImGui::InputInt("##dummy_int_input", &patch.patch_number.value);
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
show_patch_tooltip(patch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
@@ -822,6 +838,14 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PatchManager::show_patch_tooltip(const PatchData& patch) {
|
||||||
|
if (!patch.caution.empty()) {
|
||||||
|
ImGui::WarnTooltip(patch.description.c_str(), patch.caution.c_str());
|
||||||
|
} else if (!patch.description.empty()) {
|
||||||
|
ImGui::HelpTooltip(patch.description.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PatchManager::hard_apply_patches() {
|
void PatchManager::hard_apply_patches() {
|
||||||
std::vector<std::string> written_list;
|
std::vector<std::string> written_list;
|
||||||
for (auto& patch : patches) {
|
for (auto& patch : patches) {
|
||||||
@@ -1104,7 +1128,7 @@ namespace overlay::windows {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(config_path, buffer.GetString())) {
|
if (fileutils::write_config_file("patchmanager", config_path, buffer.GetString())) {
|
||||||
config_dirty = false;
|
config_dirty = false;
|
||||||
} else {
|
} else {
|
||||||
log_warning("patchmanager", "unable to save config file");
|
log_warning("patchmanager", "unable to save config file");
|
||||||
@@ -1500,16 +1524,44 @@ namespace overlay::windows {
|
|||||||
try {
|
try {
|
||||||
auto patches_json = getFromUrl(dll_name, json_path);
|
auto patches_json = getFromUrl(dll_name, json_path);
|
||||||
if (!patches_json.empty()) {
|
if (!patches_json.empty()) {
|
||||||
if (!fileutils::dir_exists(LOCAL_PATCHES_PATH))
|
|
||||||
|
// see if this is valid JSON
|
||||||
|
Document doc_temp;
|
||||||
|
doc_temp.Parse(patches_json.c_str());
|
||||||
|
const auto error = doc_temp.GetParseError();
|
||||||
|
if (error) {
|
||||||
|
log_warning(
|
||||||
|
"patchmanager",
|
||||||
|
"remotely fetched JSON file parse error: {}",
|
||||||
|
rapidjson::GetParseError_En(error));
|
||||||
|
url_fetch_errors += fmt::format(
|
||||||
|
"Invalid JSON received from remote URL.\n"
|
||||||
|
"Your DLL version might not be supported.\n"
|
||||||
|
"URL: {}\n"
|
||||||
|
"JSON Parse Error: {}\n",
|
||||||
|
json_path,
|
||||||
|
rapidjson::GetParseError_En(error));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
log_info("patchmanager", "remotely fetched JSON was successfully parsed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create patches dir
|
||||||
|
if (!fileutils::dir_exists(LOCAL_PATCHES_PATH)) {
|
||||||
fileutils::dir_create(LOCAL_PATCHES_PATH);
|
fileutils::dir_create(LOCAL_PATCHES_PATH);
|
||||||
|
}
|
||||||
|
// save to file
|
||||||
std::filesystem::path save_path = LOCAL_PATCHES_PATH / (identifier + ".json");
|
std::filesystem::path save_path = LOCAL_PATCHES_PATH / (identifier + ".json");
|
||||||
fileutils::text_write(save_path, patches_json);
|
fileutils::text_write(save_path, patches_json);
|
||||||
|
log_info("patchmanager", "remotely fetched JSON saved to: {}", save_path.string());
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
log_warning("patchmanager", "failed to fetch patches JSON for {}", dll_name);
|
log_warning("patchmanager", "failed to fetch patches JSON for {}", dll_name);
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
log_warning("patchmanager", "exception occurred while loading remote patches JSON for {}: {}", dll_name, e.what());
|
log_warning("patchmanager", "exception occurred while loading remote patches JSON for {}: {}", dll_name, e.what());
|
||||||
|
url_fetch_errors += fmt::format(
|
||||||
|
"Exception while loading remote patches for {}: {}\n", dll_name, e.what());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ namespace overlay::windows {
|
|||||||
std::function<bool(const PatchData&)> filter = std::function<bool(const PatchData&)>(),
|
std::function<bool(const PatchData&)> filter = std::function<bool(const PatchData&)>(),
|
||||||
std::string pe_identifier_for_patch = "");
|
std::string pe_identifier_for_patch = "");
|
||||||
|
|
||||||
|
void show_patch_tooltip(const PatchData& patch);
|
||||||
};
|
};
|
||||||
|
|
||||||
PatchStatus is_patch_active(PatchData &patch);
|
PatchStatus is_patch_active(PatchData &patch);
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ namespace overlay::windows {
|
|||||||
for (size_t i = 0; i < std::size(cfg::SCREENRESIZE->scene_settings); i++) {
|
for (size_t i = 0; i < std::size(cfg::SCREENRESIZE->scene_settings); i++) {
|
||||||
auto& scene = cfg::SCREENRESIZE->scene_settings[i];
|
auto& scene = cfg::SCREENRESIZE->scene_settings[i];
|
||||||
scene.keep_aspect_ratio = true;
|
scene.keep_aspect_ratio = true;
|
||||||
scene.centered = true;
|
|
||||||
scene.offset_x = 0;
|
scene.offset_x = 0;
|
||||||
scene.offset_y = 0;
|
scene.offset_y = 0;
|
||||||
scene.scale_x = 1.f;
|
scene.scale_x = 1.f;
|
||||||
@@ -126,21 +125,28 @@ namespace overlay::windows {
|
|||||||
auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene];
|
auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene];
|
||||||
|
|
||||||
// general settings
|
// general settings
|
||||||
ImGui::Checkbox("Centered", &scene.centered);
|
ImGui::InputInt("X Offset", &scene.offset_x);
|
||||||
if (!scene.centered) {
|
ImGui::SameLine();
|
||||||
ImGui::InputInt("X Offset", &scene.offset_x);
|
ImGui::HelpMarker("Hint: ctrl + click on +/- buttons to move quickly.");
|
||||||
ImGui::InputInt("Y Offset", &scene.offset_y);
|
ImGui::InputInt("Y Offset", &scene.offset_y);
|
||||||
}
|
ImGui::SameLine();
|
||||||
|
ImGui::HelpMarker("Hint: ctrl + click on +/- buttons to move quickly.");
|
||||||
|
|
||||||
// aspect ratio
|
// aspect ratio
|
||||||
ImGui::Checkbox("Keep Aspect Ratio", &scene.keep_aspect_ratio);
|
ImGui::Checkbox("Keep Aspect Ratio", &scene.keep_aspect_ratio);
|
||||||
if (scene.keep_aspect_ratio) {
|
if (scene.keep_aspect_ratio) {
|
||||||
if (ImGui::SliderFloat("Scale", &scene.scale_x, 0.65f, 2.0f)) {
|
if (ImGui::SliderFloat("Scale", &scene.scale_x, 0.5f, 2.5f)) {
|
||||||
scene.scale_y = scene.scale_x;
|
scene.scale_y = scene.scale_x;
|
||||||
}
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
||||||
} else {
|
} else {
|
||||||
ImGui::SliderFloat("Width Scale", &scene.scale_x, 0.65f, 2.0f);
|
ImGui::SliderFloat("Width Scale", &scene.scale_x, 0.5f, 2.5f);
|
||||||
ImGui::SliderFloat("Height Scale", &scene.scale_y, 0.65f, 2.0f);
|
ImGui::SameLine();
|
||||||
|
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
||||||
|
ImGui::SliderFloat("Height Scale", &scene.scale_y, 0.5f, 2.5f);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|||||||
@@ -23,11 +23,35 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
const auto padding = ImGui::GetFrameHeight() / 2;
|
const auto padding = ImGui::GetFrameHeight() / 2;
|
||||||
|
|
||||||
this->init_size = ImVec2(ImGui::GetIO().DisplaySize.x - (padding * 2), 0.f);
|
switch (games::sdvx::OVERLAY_POS) {
|
||||||
this->init_size.y = (this->init_size.x * 9 / 16) + ImGui::GetFrameHeight();
|
case games::sdvx::SDVX_OVERLAY_BOTTOM_LEFT:
|
||||||
|
case games::sdvx::SDVX_OVERLAY_BOTTOM_RIGHT:
|
||||||
|
this->init_size.x = (ImGui::GetIO().DisplaySize.x - (ImGui::GetIO().DisplaySize.y * 9 / 16)) / 2 - padding;
|
||||||
|
this->init_size.y = (this->init_size.x * 9 / 16) + ImGui::GetFrameHeight();
|
||||||
|
break;
|
||||||
|
case games::sdvx::SDVX_OVERLAY_TOP:
|
||||||
|
case games::sdvx::SDVX_OVERLAY_BOTTOM:
|
||||||
|
case games::sdvx::SDVX_OVERLAY_MIDDLE:
|
||||||
|
default:
|
||||||
|
this->init_size = ImVec2(ImGui::GetIO().DisplaySize.x - (padding * 2), 0.f);
|
||||||
|
this->init_size.y = (this->init_size.x * 9 / 16) + ImGui::GetFrameHeight();
|
||||||
|
if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
|
this->init_size.x /= 2;
|
||||||
|
this->init_size.y /= 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
this->init_pos = ImVec2(ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2, 0);
|
this->init_pos = ImVec2(ImGui::GetIO().DisplaySize.x / 2 - this->init_size.x / 2, 0);
|
||||||
switch (games::sdvx::OVERLAY_POS) {
|
switch (games::sdvx::OVERLAY_POS) {
|
||||||
|
case games::sdvx::SDVX_OVERLAY_BOTTOM_LEFT:
|
||||||
|
this->init_pos.x = 0;
|
||||||
|
this->init_pos.y = ImGui::GetIO().DisplaySize.y - this->init_size.y;
|
||||||
|
break;
|
||||||
|
case games::sdvx::SDVX_OVERLAY_BOTTOM_RIGHT:
|
||||||
|
this->init_pos.x = ImGui::GetIO().DisplaySize.x - this->init_size.x;
|
||||||
|
this->init_pos.y = ImGui::GetIO().DisplaySize.y - this->init_size.y;
|
||||||
|
break;
|
||||||
case games::sdvx::SDVX_OVERLAY_TOP:
|
case games::sdvx::SDVX_OVERLAY_TOP:
|
||||||
this->init_pos.y = padding;
|
this->init_pos.y = padding;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
|||||||
// get string index
|
// get string index
|
||||||
ULONG string_index = 0;
|
ULONG string_index = 0;
|
||||||
if (button_caps.IsStringRange && button_caps.Range.StringMin != 0) {
|
if (button_caps.IsStringRange && button_caps.Range.StringMin != 0) {
|
||||||
string_index = button_caps.Range.StringMin + static_cast<ULONG>(button_output_caps_list.size()) - 1;
|
string_index = button_caps.Range.StringMin + static_cast<ULONG>(button_output_caps_names.size());
|
||||||
}
|
}
|
||||||
else if (!button_caps.IsStringRange && button_caps.NotRange.StringIndex != 0) {
|
else if (!button_caps.IsStringRange && button_caps.NotRange.StringIndex != 0) {
|
||||||
string_index = button_caps.NotRange.StringIndex;
|
string_index = button_caps.NotRange.StringIndex;
|
||||||
|
|||||||
@@ -138,8 +138,15 @@ static void touch_initialize() {
|
|||||||
}
|
}
|
||||||
SPICETOUCH_INITIALIZED = true;
|
SPICETOUCH_INITIALIZED = true;
|
||||||
|
|
||||||
|
if (!RI_MGR) {
|
||||||
|
log_fatal(
|
||||||
|
LOG_MODULE_NAME,
|
||||||
|
"touch_initialize() - RI Manager not available, called too early! "
|
||||||
|
"This is a BUG in spice, please file a bug report with log.txt.");
|
||||||
|
}
|
||||||
|
|
||||||
// initialize handler
|
// initialize handler
|
||||||
if (RI_MGR && rawinput::touch::is_enabled(RI_MGR.get())) {
|
if (rawinput::touch::is_enabled(RI_MGR.get())) {
|
||||||
TOUCH_HANDLER = new RawInputTouchHandler();
|
TOUCH_HANDLER = new RawInputTouchHandler();
|
||||||
} else if (Win8Handler::is_available()) {
|
} else if (Win8Handler::is_available()) {
|
||||||
TOUCH_HANDLER = new Win8Handler();
|
TOUCH_HANDLER = new Win8Handler();
|
||||||
@@ -166,13 +173,26 @@ static inline void touch_unregister_window(HWND hWnd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_touch_available() {
|
bool is_touch_available(LPCSTR caller) {
|
||||||
|
static bool called_once = false;
|
||||||
|
|
||||||
|
if (!RI_MGR) {
|
||||||
|
log_fatal(
|
||||||
|
LOG_MODULE_NAME,
|
||||||
|
"is_touch_available({}) - RI Manager not available, called too early! "
|
||||||
|
"This is a BUG in spice, please file a bug report with log.txt.",
|
||||||
|
caller);
|
||||||
|
}
|
||||||
|
|
||||||
// initialize touch handler
|
// initialize touch handler
|
||||||
touch_initialize();
|
touch_initialize();
|
||||||
|
|
||||||
// Check if a touch handler has been set. No need to call `is_available` here
|
if (!called_once) {
|
||||||
// as `touch_initialize` does that.
|
log_misc("touch", "is_touch_available called by: {}, returning {}",
|
||||||
|
caller, (TOUCH_HANDLER != nullptr) ? "TRUE" : "false");
|
||||||
|
called_once = true;
|
||||||
|
}
|
||||||
|
|
||||||
return TOUCH_HANDLER != nullptr;
|
return TOUCH_HANDLER != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +222,7 @@ static LRESULT CALLBACK SpiceTouchWndProc(HWND hWnd, UINT msg, WPARAM wParam, LP
|
|||||||
SPICETOUCH_REGISTERED_TOUCH = true;
|
SPICETOUCH_REGISTERED_TOUCH = true;
|
||||||
|
|
||||||
// check if touch is available
|
// check if touch is available
|
||||||
if (is_touch_available()) {
|
if (is_touch_available("SpiceTouchWndProc")) {
|
||||||
|
|
||||||
// notify the handler of our window
|
// notify the handler of our window
|
||||||
TOUCH_HANDLER->window_register(hWnd);
|
TOUCH_HANDLER->window_register(hWnd);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ extern int SPICETOUCH_TOUCH_Y;
|
|||||||
extern int SPICETOUCH_TOUCH_WIDTH;
|
extern int SPICETOUCH_TOUCH_WIDTH;
|
||||||
extern int SPICETOUCH_TOUCH_HEIGHT;
|
extern int SPICETOUCH_TOUCH_HEIGHT;
|
||||||
|
|
||||||
bool is_touch_available();
|
bool is_touch_available(LPCSTR caller);
|
||||||
|
|
||||||
void touch_attach_wnd(HWND hWnd);
|
void touch_attach_wnd(HWND hWnd);
|
||||||
void touch_attach_dx_hook();
|
void touch_attach_dx_hook();
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
#include "execexe.h"
|
||||||
|
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
|
||||||
|
namespace execexe {
|
||||||
|
|
||||||
|
static HMODULE execexe_module = nullptr;
|
||||||
|
static decltype(&LoadLibraryW) execexe_LoadLibraryW = nullptr;
|
||||||
|
static decltype(&GetModuleHandleW) execexe_GetModuleHandleW = nullptr;
|
||||||
|
static decltype(&GetProcAddress) execexe_GetProcAddress = nullptr;
|
||||||
|
static decltype(&CreateFileA) execexe_CreateFileA = nullptr;
|
||||||
|
static decltype(&CreateFileW) execexe_CreateFileW = nullptr;
|
||||||
|
static decltype(&CloseHandle) execexe_CloseHandle = nullptr;
|
||||||
|
|
||||||
|
static std::wstring plugins_dir;
|
||||||
|
static acioemu::ACIOHandle *acio = nullptr;
|
||||||
|
static std::wstring port_name;
|
||||||
|
static bool port_opened = false;
|
||||||
|
|
||||||
|
static HANDLE WINAPI execexe_CreateFileA_hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||||
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||||
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
||||||
|
const auto lpFileNameW = s2ws(lpFileName);
|
||||||
|
if (lpFileNameW == port_name) {
|
||||||
|
if (!port_opened) {
|
||||||
|
port_opened = acio->open(port_name.c_str());
|
||||||
|
} else {
|
||||||
|
log_info("execexe", "ignored handle open. ({})", ws2s(port_name));
|
||||||
|
}
|
||||||
|
SetLastError(0);
|
||||||
|
return (HANDLE) acio;
|
||||||
|
}
|
||||||
|
return execexe_CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||||
|
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HANDLE WINAPI execexe_CreateFileW_hook(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||||
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||||
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
||||||
|
if (lpFileName == port_name && acio->open(lpFileName)) {
|
||||||
|
if (!port_opened) {
|
||||||
|
port_opened = acio->open(port_name.c_str());
|
||||||
|
} else {
|
||||||
|
log_info("execexe", "ignored handle open. ({})", ws2s(port_name));
|
||||||
|
}
|
||||||
|
SetLastError(0);
|
||||||
|
return (HANDLE) acio;
|
||||||
|
} else {
|
||||||
|
return execexe_CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||||
|
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static WINBOOL WINAPI execexe_CloseHandle_hook(HANDLE hObject) {
|
||||||
|
if (hObject == acio && port_opened) {
|
||||||
|
log_info("execexe", "ignored handle close. ({})", ws2s(port_name));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return execexe_CloseHandle(hObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE init() {
|
||||||
|
execexe_module = libutils::load_library("execexe.dll");
|
||||||
|
execexe_LoadLibraryW = libutils::get_proc<decltype(&LoadLibraryW)>(execexe_module, MAKEINTRESOURCE(34));
|
||||||
|
execexe_GetModuleHandleW = libutils::get_proc<decltype(&GetModuleHandleW)>(execexe_module, MAKEINTRESOURCE(25));
|
||||||
|
execexe_GetProcAddress = libutils::get_proc<decltype(&GetProcAddress)>(execexe_module, MAKEINTRESOURCE(27));
|
||||||
|
execexe_CloseHandle = libutils::get_proc<decltype(&CloseHandle)>(execexe_module, MAKEINTRESOURCE(7));
|
||||||
|
execexe_CreateFileA = libutils::get_proc<decltype(&CreateFileA)>(execexe_module, MAKEINTRESOURCE(9));
|
||||||
|
execexe_CreateFileW = libutils::get_proc<decltype(&CreateFileW)>(execexe_module, MAKEINTRESOURCE(11));
|
||||||
|
|
||||||
|
auto module_path = libutils::module_file_name(nullptr);
|
||||||
|
module_path = module_path.replace_extension("");
|
||||||
|
module_path = module_path.replace_filename(module_path.filename().wstring() + L"_Data");
|
||||||
|
plugins_dir = (module_path / L"Plugins" / L"x86_64").wstring() + L"\\";
|
||||||
|
|
||||||
|
return execexe_module;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle) {
|
||||||
|
static bool init = false;
|
||||||
|
if (init)
|
||||||
|
return;
|
||||||
|
init = true;
|
||||||
|
|
||||||
|
port_name = portName;
|
||||||
|
acio = acioHandle;
|
||||||
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(7),
|
||||||
|
execexe_CloseHandle_hook, &execexe_CloseHandle);
|
||||||
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(9),
|
||||||
|
execexe_CreateFileA_hook, &execexe_CreateFileA);
|
||||||
|
detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(11),
|
||||||
|
execexe_CreateFileW_hook, &execexe_CreateFileW);
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE load_library(const char *module_name, bool fatal) {
|
||||||
|
std::wstring module_name_w = s2ws(module_name);
|
||||||
|
std::wstring plugin_path = plugins_dir + module_name_w;
|
||||||
|
HMODULE module = execexe_LoadLibraryW(plugin_path.c_str());
|
||||||
|
if (module != nullptr) {
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
module = execexe_LoadLibraryW(module_name_w.c_str());
|
||||||
|
if (module != nullptr) {
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatal) {
|
||||||
|
log_fatal("execexe", "failed to load library {}", module_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE get_module(const char *module_name, bool fatal) {
|
||||||
|
std::wstring module_name_w = s2ws(module_name);
|
||||||
|
std::wstring plugin_path = plugins_dir + module_name_w;
|
||||||
|
|
||||||
|
HMODULE module = execexe_GetModuleHandleW(plugin_path.c_str());
|
||||||
|
if (module != nullptr) {
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
module = execexe_GetModuleHandleW(module_name_w.c_str());
|
||||||
|
if (module != nullptr) {
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatal) {
|
||||||
|
log_fatal("execexe", "failed to get module {}", module_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal) {
|
||||||
|
FARPROC proc = execexe_GetProcAddress(module, proc_name);
|
||||||
|
if (proc != nullptr) {
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatal) {
|
||||||
|
log_fatal("execexe", "proc {} not found", proc_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool trampoline(const char *dll, const char *func, void *hook, void **orig) {
|
||||||
|
HMODULE module = get_module(dll);
|
||||||
|
FARPROC proc = get_proc(module, func);
|
||||||
|
|
||||||
|
return detour::trampoline(
|
||||||
|
reinterpret_cast<void *>(proc),
|
||||||
|
hook,
|
||||||
|
orig
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool trampoline_try(const char *dll, const char *func, void *hook, void **orig) {
|
||||||
|
HMODULE module = get_module(dll, false);
|
||||||
|
if (module == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FARPROC proc = get_proc(module, func, false);
|
||||||
|
if (proc == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return detour::trampoline(
|
||||||
|
reinterpret_cast<void *>(proc),
|
||||||
|
hook,
|
||||||
|
orig
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <windows.h>
|
||||||
|
#include "acioemu/handle.h"
|
||||||
|
|
||||||
|
namespace execexe {
|
||||||
|
HMODULE init();
|
||||||
|
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle);
|
||||||
|
HMODULE load_library(const char *module_name, bool fatal = true);
|
||||||
|
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal = true);
|
||||||
|
HMODULE get_module(const char *module_name, bool fatal = true);
|
||||||
|
bool trampoline(const char *dll, const char *func, void *hook, void **orig);
|
||||||
|
bool trampoline_try(const char *dll, const char *func, void *hook, void **orig);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T get_proc(HMODULE module, const char *proc_name, bool fatal = true) {
|
||||||
|
return reinterpret_cast<T>(get_proc(module, proc_name, fatal));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool trampoline(const char *dll, const char *func, T hook, T *orig) {
|
||||||
|
return trampoline(
|
||||||
|
dll,
|
||||||
|
func,
|
||||||
|
reinterpret_cast<void *>(hook),
|
||||||
|
reinterpret_cast<void **>(orig));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool trampoline_try(const char *dll, const char *func, T hook, T *orig) {
|
||||||
|
return trampoline_try(
|
||||||
|
dll,
|
||||||
|
func,
|
||||||
|
reinterpret_cast<void *>(hook),
|
||||||
|
reinterpret_cast<void **>(orig));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -264,3 +264,53 @@ std::vector<uint8_t> *fileutils::bin_read(const std::filesystem::path &path) {
|
|||||||
}
|
}
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path fileutils::get_config_file_path(const std::string module, const std::string filename, bool* file_exists) {
|
||||||
|
// try %appdata%\spice2x path first, if it exists
|
||||||
|
const auto appdata_spice2x = std::filesystem::path(_wgetenv(L"APPDATA")) / "spice2x" / filename;
|
||||||
|
if (fileutils::file_exists(appdata_spice2x)) {
|
||||||
|
log_info(module, "loading config from %appdata%\\spice2x\\{}", filename);
|
||||||
|
if (file_exists) {
|
||||||
|
*file_exists = true;
|
||||||
|
}
|
||||||
|
return appdata_spice2x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback to older %appdata% path (older spice2x or mainline spicetools), if it exists
|
||||||
|
const auto appdata = std::filesystem::path(_wgetenv(L"APPDATA")) / filename;
|
||||||
|
if (fileutils::file_exists(appdata)) {
|
||||||
|
log_info(module, "loading config from %appdata%\\{}", filename);
|
||||||
|
if (file_exists) {
|
||||||
|
*file_exists = true;
|
||||||
|
}
|
||||||
|
return appdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefer new path if no existing file found
|
||||||
|
if (file_exists) {
|
||||||
|
*file_exists = false;
|
||||||
|
}
|
||||||
|
return appdata_spice2x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fileutils::write_config_file(const std::string_view &module, const std::filesystem::path path, std::string text) {
|
||||||
|
// attempt to undo %appdata% expansion to hide user name
|
||||||
|
const auto appdata = std::filesystem::path(_wgetenv(L"APPDATA")).string();
|
||||||
|
auto censored = path.string();
|
||||||
|
const auto substr_offset = censored.find(appdata);
|
||||||
|
if (substr_offset != std::string::npos) {
|
||||||
|
censored.replace(substr_offset, appdata.length(), "%appdata%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create directory path up to where the config file lives
|
||||||
|
if (!path.parent_path().empty() && !std::filesystem::exists(path.parent_path())) {
|
||||||
|
log_misc(module, "creating directory path to config file: {}", censored);
|
||||||
|
if (!fileutils::dir_create_recursive(path.parent_path())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save file
|
||||||
|
log_info(module, "saving config file: {}", censored);
|
||||||
|
return fileutils::text_write(path, text);
|
||||||
|
}
|
||||||
@@ -33,4 +33,7 @@ namespace fileutils {
|
|||||||
std::string text_read(const std::filesystem::path &file_path);
|
std::string text_read(const std::filesystem::path &file_path);
|
||||||
bool bin_write(const std::filesystem::path &path, uint8_t *data, size_t len);
|
bool bin_write(const std::filesystem::path &path, uint8_t *data, size_t len);
|
||||||
std::vector<uint8_t> *bin_read(const std::filesystem::path &path);
|
std::vector<uint8_t> *bin_read(const std::filesystem::path &path);
|
||||||
|
|
||||||
|
std::filesystem::path get_config_file_path(const std::string module, const std::string filename, bool* file_exists=nullptr);
|
||||||
|
bool write_config_file(const std::string_view &module, const std::filesystem::path path, std::string text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "peb.h"
|
#include "peb.h"
|
||||||
|
#include "util/fileutils.h"
|
||||||
|
|
||||||
std::filesystem::path libutils::module_file_name(HMODULE module) {
|
std::filesystem::path libutils::module_file_name(HMODULE module) {
|
||||||
std::wstring buf;
|
std::wstring buf;
|
||||||
@@ -323,3 +324,35 @@ intptr_t libutils::offset2rva(const std::filesystem::path &path, intptr_t offset
|
|||||||
|
|
||||||
return rva;
|
return rva;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void libutils::check_duplicate_dlls() {
|
||||||
|
const auto &spice_bin_path = libutils::module_file_name(nullptr).parent_path();
|
||||||
|
if (MODULE_PATH == spice_bin_path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &file : std::filesystem::directory_iterator(MODULE_PATH)) {
|
||||||
|
const auto &filename = file.path().filename();
|
||||||
|
const auto extension = strtolower(filename.extension().string());
|
||||||
|
|
||||||
|
if (extension == ".dll" &&
|
||||||
|
fileutils::file_exists(spice_bin_path / filename)) {
|
||||||
|
log_warning(
|
||||||
|
"libutils",
|
||||||
|
"DLL CONFLICT WARNING\n\n\n"
|
||||||
|
"-------------------------------------------------------------------\n"
|
||||||
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||||
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||||
|
"{} exists in BOTH of these directories:\n\n"
|
||||||
|
" 1. {}\n"
|
||||||
|
" 2. {}\n\n"
|
||||||
|
"due to Windows DLL load order rules, #1 will load instead of #2.\n"
|
||||||
|
"this has unintended consequences and may crash your game!\n"
|
||||||
|
"resolve the conflict by deleting the stale copy of the DLL\n"
|
||||||
|
"-------------------------------------------------------------------\n\n\n",
|
||||||
|
filename.string(),
|
||||||
|
(spice_bin_path / filename).string(),
|
||||||
|
(MODULE_PATH / filename).string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,8 @@ namespace libutils {
|
|||||||
return try_library(module_name.c_str());
|
return try_library(module_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_duplicate_dlls();
|
||||||
|
|
||||||
// get module handle helpers
|
// get module handle helpers
|
||||||
HMODULE get_module(const char *module_name);
|
HMODULE get_module(const char *module_name);
|
||||||
HMODULE try_module(const char *module_name);
|
HMODULE try_module(const char *module_name);
|
||||||
|
|||||||
@@ -2,44 +2,83 @@
|
|||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "external/fmt/include/fmt/format.h"
|
#include "external/fmt/include/fmt/format.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
|
||||||
namespace unity_utils {
|
namespace unity_utils {
|
||||||
|
|
||||||
std::string get_unity_player_args() {
|
std::string get_unity_player_args() {
|
||||||
std::string args = "";
|
std::string args = "";
|
||||||
// windowed
|
// windowed
|
||||||
if (GRAPHICS_WINDOWED) {
|
if (GRAPHICS_WINDOWED) {
|
||||||
args += " -screen-fullscreen 0";
|
args += " -screen-fullscreen 0";
|
||||||
|
|
||||||
// window size - by default unity player will attempt to create a window that fills the
|
// window size - by default unity player will attempt to create a window that fills the
|
||||||
// screen, so instead fall back to 1080p resolution
|
// screen, so instead fall back to 1080p resolution
|
||||||
uint32_t w = 1920;
|
uint32_t w = 1920;
|
||||||
uint32_t h = 1080;
|
uint32_t h = 1080;
|
||||||
if (GRAPHICS_WINDOW_SIZE.has_value()) {
|
if (GRAPHICS_WINDOW_SIZE.has_value()) {
|
||||||
w = GRAPHICS_WINDOW_SIZE.value().first;
|
w = GRAPHICS_WINDOW_SIZE.value().first;
|
||||||
h = GRAPHICS_WINDOW_SIZE.value().second;
|
h = GRAPHICS_WINDOW_SIZE.value().second;
|
||||||
}
|
|
||||||
args += fmt::format(" -screen-width {} -screen-height {}", w, h);
|
|
||||||
|
|
||||||
// window border
|
|
||||||
// eventually we should launch the player inside a parent window that we have full control
|
|
||||||
// over using -parentHWND so we can let the user resize it by dragging the border...
|
|
||||||
if (GRAPHICS_WINDOW_STYLE.has_value()) {
|
|
||||||
if (GRAPHICS_WINDOW_STYLE == cfg::WindowDecorationMode::Borderless) {
|
|
||||||
args += " -popupwindow";
|
|
||||||
}
|
}
|
||||||
|
args += fmt::format(" -screen-width {} -screen-height {}", w, h);
|
||||||
|
|
||||||
|
// window border
|
||||||
|
// eventually we should launch the player inside a parent window that we have full control
|
||||||
|
// over using -parentHWND so we can let the user resize it by dragging the border...
|
||||||
|
if (GRAPHICS_WINDOW_STYLE.has_value()) {
|
||||||
|
if (GRAPHICS_WINDOW_STYLE == cfg::WindowDecorationMode::Borderless) {
|
||||||
|
args += " -popupwindow";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// need to specify this, otherwise it gets cached and uses previous value
|
||||||
|
args += " -screen-fullscreen 1";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// need to specify this, otherwise it gets cached and uses previous value
|
// monitor
|
||||||
args += " -screen-fullscreen 1";
|
if (D3D9_ADAPTER.has_value()) {
|
||||||
|
args += fmt::format(" -monitor {}", D3D9_ADAPTER.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
// monitor
|
static std::string cmdLine;
|
||||||
if (D3D9_ADAPTER.has_value()) {
|
static decltype(GetCommandLineA) *GetCommandLineA_orig = nullptr;
|
||||||
args += fmt::format(" -monitor {}", D3D9_ADAPTER.value());
|
|
||||||
|
static LPSTR WINAPI GetCommandLineA_hook() {
|
||||||
|
return (LPSTR) cmdLine.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
return args;
|
void set_args(const std::string &args) {
|
||||||
}
|
static bool init = false;
|
||||||
|
if (!init) {
|
||||||
|
init = true;
|
||||||
|
detour::trampoline_try("kernel32.dll", "GetCommandLineA",
|
||||||
|
(void*)GetCommandLineA_hook, (void**)&GetCommandLineA_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdLine = args;
|
||||||
|
log_info("unity", "unity player args: ```{}```", cmdLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool show = false;
|
||||||
|
static decltype(ShowCursor) *ShowCursor_orig = nullptr;
|
||||||
|
|
||||||
|
static int WINAPI ShowCursor_hook(BOOL bShow) {
|
||||||
|
return show;
|
||||||
|
}
|
||||||
|
|
||||||
|
void force_show_cursor(bool bShow) {
|
||||||
|
static bool init = false;
|
||||||
|
if (!init) {
|
||||||
|
init = true;
|
||||||
|
detour::trampoline_try("user32.dll", "ShowCursor",
|
||||||
|
(void*)ShowCursor_hook, (void**)&ShowCursor_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
show = bShow;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4,4 +4,6 @@
|
|||||||
|
|
||||||
namespace unity_utils {
|
namespace unity_utils {
|
||||||
std::string get_unity_player_args();
|
std::string get_unity_player_args();
|
||||||
|
void set_args(const std::string &args);
|
||||||
|
void force_show_cursor(bool bShow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,3 +298,16 @@ static inline int get_async_secondary_mouse() {
|
|||||||
int vk = GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON;
|
int vk = GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON;
|
||||||
return GetAsyncKeyState(vk);
|
return GetAsyncKeyState(vk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool parse_width_height(const std::string wh, std::pair<uint32_t, uint32_t> &result) {
|
||||||
|
std::string s = wh;
|
||||||
|
uint32_t w, h;
|
||||||
|
const auto remove_spaces = [](const char& c) { return c == ' '; };
|
||||||
|
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
|
||||||
|
if (sscanf(s.c_str(), "%u,%u", &w, &h) == 2) {
|
||||||
|
result = std::pair(w, h);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user