Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3707a86c79 | ||
|
|
eea3ec7f95 | ||
|
|
4a2c6761fc | ||
|
|
7a4e179f4c | ||
|
|
11eaadb739 | ||
|
|
41b77b54ea | ||
|
|
22689bd9ee | ||
|
|
831535c86f | ||
|
|
ce43955784 | ||
|
|
e85f4f4309 | ||
|
|
00b3f33530 | ||
|
|
1b0116a0cb | ||
|
|
486281427c | ||
|
|
8ccdc415bc | ||
|
|
008049265d | ||
|
|
fef407b839 | ||
|
|
084570bc4b | ||
|
|
3d91e0c3e3 | ||
|
|
b5a942b4fe | ||
|
|
5c5cc8453d | ||
|
|
30495795cd | ||
|
|
073cdd2815 | ||
|
|
fe21c73f75 | ||
|
|
a6cba2ce2a | ||
|
|
9afd971b43 | ||
|
|
b0f9136fe8 | ||
|
|
b513439565 | ||
|
|
42494e5019 | ||
|
|
8653234cb3 | ||
|
|
6a14761770 | ||
|
|
399a5c93b2 | ||
|
|
be2db3c95a | ||
|
|
7f7ac4c5fb | ||
|
|
7ca98bb496 | ||
|
|
e9cf27411b | ||
|
|
d8f1a5a118 | ||
|
|
07ea2d8ec4 | ||
|
|
2c63963134 | ||
|
|
c9d9e71631 | ||
|
|
69726baa48 | ||
|
|
c02a44d020 | ||
|
|
1c0c3eb6aa | ||
|
|
7f9f30181e | ||
|
|
2bc788beea | ||
|
|
4a0d20c1a1 | ||
|
|
2ea9efd622 | ||
|
|
723f4ab16b | ||
|
|
a242ae78eb | ||
|
|
c037e1465f | ||
|
|
3e8578f2fd | ||
|
|
0050646ad7 | ||
|
|
f2ef7e345f | ||
|
|
3c0698d14b | ||
|
|
ec677c8d26 | ||
|
|
f115c82512 | ||
|
|
9f4f8ab15b | ||
|
|
532d8bcaee | ||
|
|
2978b8443c | ||
|
|
3b1fbcd9d3 | ||
|
|
de4d4c27c7 | ||
|
|
91bf6ad996 | ||
|
|
312885bec1 | ||
|
|
8641e1b3ba | ||
|
|
ca203d96b0 | ||
|
|
6774c8731a | ||
|
|
b603f3b75c | ||
|
|
b546826b67 | ||
|
|
a39263aeb5 | ||
|
|
ecaa5b9dee | ||
|
|
7fcc468353 | ||
|
|
52952942e9 | ||
|
|
81dc449637 | ||
|
|
ce25524ed9 | ||
|
|
30a3522def | ||
|
|
f62de70aa5 | ||
|
|
ec190adc51 | ||
|
|
7095824874 | ||
|
|
b243f48fff | ||
|
|
3bc052e948 | ||
|
|
482e237d08 | ||
|
|
86f38ab024 | ||
|
|
c837d736bb | ||
|
|
ab94fd484f | ||
|
|
1508b11044 | ||
|
|
b4e18d1b63 | ||
|
|
f49272288d | ||
|
|
f1dd82c65e | ||
|
|
7aa7eaffb9 | ||
|
|
6577fa9810 | ||
|
|
6aabc4eca8 | ||
|
|
bf5b3d3c99 | ||
|
|
420eb39c16 | ||
|
|
6dd764c04c | ||
|
|
95d5141a2b | ||
|
|
51c6c3904d | ||
|
|
32a39afc75 | ||
|
|
fd967cc2a3 | ||
|
|
8c0bb09667 | ||
|
|
8c753d6cfe | ||
|
|
276e681f29 | ||
|
|
f23b17e1b8 | ||
|
|
f1e10fa4b1 | ||
|
|
be67cd03cb | ||
|
|
d7dfe12fb4 | ||
|
|
be437afd2f | ||
|
|
f72688773a | ||
|
|
fb328d8d92 | ||
|
|
36e6d2fcc7 | ||
|
|
7b3293341b | ||
|
|
0a7b72a51b | ||
|
|
6265973cc6 | ||
|
|
f1edc47a80 | ||
|
|
8f60d5c80f | ||
|
|
c42489fa81 | ||
|
|
66b60c988a | ||
|
|
5d20e98aba | ||
|
|
617ee3f96c | ||
|
|
083f7c2e4f | ||
|
|
a8ea1795bf | ||
|
|
8a6cb4b5a8 | ||
|
|
53edf065a5 | ||
|
|
bf65be483d | ||
|
|
1e90047368 | ||
|
|
abd1160f87 | ||
|
|
55d7dd9d89 | ||
|
|
b7eb1afb86 | ||
|
|
25ddb4a531 | ||
|
|
79f7c2224b | ||
|
|
8adda4fc7d | ||
|
|
5d23743133 | ||
|
|
2558e5d6a6 | ||
|
|
859b81b7e0 | ||
|
|
30369f58a9 | ||
|
|
30afc80a64 | ||
|
|
949eee8d08 | ||
|
|
1fae30bd33 | ||
|
|
d8817bf0f3 | ||
|
|
5279b10b67 | ||
|
|
391f46be22 | ||
|
|
44809bf28f | ||
|
|
3cd113c46f | ||
|
|
3d195c6a4d | ||
|
|
423d30ac29 | ||
|
|
b07b73e005 | ||
|
|
418d9c4684 | ||
|
|
1801a48eaa | ||
|
|
8e8fbcdd2e | ||
|
|
d5834de5e7 | ||
|
|
a52e3fe1e5 | ||
|
|
eb261bc2bf | ||
|
|
7b5f735714 | ||
|
|
404c2c4f43 | ||
|
|
57f1a33e51 | ||
|
|
fa277352b0 | ||
|
|
f502984e05 | ||
|
|
c205b5bfd3 | ||
|
|
c6625e137d | ||
|
|
0ad7e1d715 | ||
|
|
1f8d5be9a7 | ||
|
|
21673affbb | ||
|
|
a0a1255ef3 | ||
|
|
206a5ec7f6 | ||
|
|
8661273568 | ||
|
|
6aed340831 | ||
|
|
f7bfb6aea1 | ||
|
|
c5ae117cf8 | ||
|
|
a1c9dc3f12 | ||
|
|
0f3e70706d | ||
|
|
722ca67b87 | ||
|
|
981897df8c | ||
|
|
3a066dfc03 | ||
|
|
870481e34e | ||
|
|
9f5f2334d7 | ||
|
|
330a66c81c | ||
|
|
92b4d4dc32 | ||
|
|
531fab51be | ||
|
|
3f027fad63 | ||
|
|
6eb46dd63c | ||
|
|
70830ae016 | ||
|
|
8a88a736ad | ||
|
|
d580d2be9a | ||
|
|
0e3fc0e981 | ||
|
|
4907b2dd32 | ||
|
|
3ad2a5760e | ||
|
|
e474a09642 | ||
|
|
f5296c9f79 | ||
|
|
f8e1ed3920 | ||
|
|
9aeca88946 | ||
|
|
3961c066be | ||
|
|
4aeb3da6eb | ||
|
|
bf9e370ddd | ||
|
|
7c72fa98fd | ||
|
|
0824586db9 | ||
|
|
8a22c6d929 | ||
|
|
8f76619d7d | ||
|
|
d94d9fc5d7 | ||
|
|
38312f8add | ||
|
|
d52b1e1b5a | ||
|
|
06c9d9b826 | ||
|
|
20a669dbbb | ||
|
|
68c8c431a2 | ||
|
|
d6b1fdfa7b | ||
|
|
6ac9208c7f | ||
|
|
fdcfaf3fad | ||
|
|
dd08dfafc8 | ||
|
|
22a019abb1 | ||
|
|
e112ae75eb | ||
|
|
0de1073094 | ||
|
|
18a1a6afe6 | ||
|
|
149bd86a89 | ||
|
|
dbe67853dc | ||
|
|
4f30be19b1 | ||
|
|
0347033d89 | ||
|
|
5fc36d5743 | ||
|
|
c745ec18bb | ||
|
|
0e84317fbc | ||
|
|
b7df075dec | ||
|
|
da3e30f735 | ||
|
|
9bd0ea0ba6 | ||
|
|
91df63c660 | ||
|
|
bea8abd60d | ||
|
|
86bb226db4 | ||
|
|
5bbdc7f821 | ||
|
|
f23b0ca493 | ||
|
|
538b503bcb | ||
|
|
cabc56550b |
@@ -9,11 +9,14 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: hendrikmuhs/ccache-action@v1.2.5
|
||||
with:
|
||||
key: Linux
|
||||
- name: Install Packages
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get upgrade
|
||||
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qtbase5-dev libqt5svg5-dev build-essential nasm git zip
|
||||
sudo apt-get -y install cmake ninja-build libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
echo "GIT_REVISION=$(git describe --tags --always)" >> $GITHUB_ENV
|
||||
@@ -32,6 +35,9 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: hendrikmuhs/ccache-action@v1.2.5
|
||||
with:
|
||||
key: Windows
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
path-type: inherit
|
||||
@@ -39,20 +45,19 @@ jobs:
|
||||
install: >-
|
||||
make
|
||||
mingw-w64-x86_64-cmake
|
||||
mingw-w64-x86_64-ninja
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-hidapi
|
||||
mingw-w64-x86_64-freetype
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-jasper
|
||||
mingw-w64-x86_64-qt5
|
||||
mingw-w64-x86_64-qt6
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-hidapi
|
||||
mingw-w64-x86_64-speexdsp
|
||||
mingw-w64-x86_64-libsamplerate
|
||||
mingw-w64-x86_64-python3-pip
|
||||
mingw-w64-x86_64-python3-pyopenssl
|
||||
mingw-w64-x86_64-nasm
|
||||
mingw-w64-x86_64-minizip
|
||||
git
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
# CMake build directory
|
||||
Build/
|
||||
Bin/
|
||||
# VSCode Configuration
|
||||
.vscode/
|
||||
# Clangd cache
|
||||
.cache/
|
||||
.cache/
|
||||
# Archlinux Package
|
||||
Package/ArchLinux/pkg/
|
||||
Package/ArchLinux/rmg/
|
||||
Package/ArchLinux/src/
|
||||
Package/ArchLinux/*.pkg.*
|
||||
# Clangd compile_commands.json
|
||||
compile_commands.json
|
||||
@@ -5,6 +5,9 @@ cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
option(PORTABLE_INSTALL "Portable Installation" ON)
|
||||
option(NO_GIT_CLONE "Disables git clone usage for 3rdParty dependencies" OFF)
|
||||
option(UPDATER "Enables updater" ${PORTABLE_INSTALL})
|
||||
option(DISCORD_RPC "Enables Discord Rich Presence" ON)
|
||||
option(USE_CCACHE "Enables usage of ccache when ccache has been found" ON)
|
||||
|
||||
project(RMG)
|
||||
|
||||
@@ -17,11 +20,25 @@ execute_process(
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if (USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if (CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
else(CCACHE_FOUND)
|
||||
set(USE_CCACHE OFF)
|
||||
endif(CCACHE_FOUND)
|
||||
endif(USE_CCACHE)
|
||||
|
||||
if (NOT PORTABLE_INSTALL AND (WIN32 OR MSYS))
|
||||
message(WARNING "Not-Portable build not supported on windows, re-enabling PORTABLE_INSTALL!")
|
||||
set(PORTABLE_INSTALL ON)
|
||||
endif()
|
||||
|
||||
if (NOT PORTABLE_INSTALL AND UPDATER)
|
||||
message(WARNING "Not-Portable builds don't support the updater, disabling UPDATER")
|
||||
set(UPDATER OFF)
|
||||
endif()
|
||||
|
||||
if (PORTABLE_INSTALL)
|
||||
set(CMAKE_INSTALL_PREFIX "")
|
||||
set(INSTALL_PATH "Bin/${CMAKE_BUILD_TYPE}")
|
||||
@@ -41,6 +58,8 @@ else()
|
||||
set(ICON_INSTALL_PATH "share/icons/hicolor/scalable/apps/")
|
||||
endif()
|
||||
|
||||
add_subdirectory(Source/3rdParty)
|
||||
|
||||
add_subdirectory(Source/RMG-Core)
|
||||
add_subdirectory(Source/RMG)
|
||||
add_subdirectory(Source/RMG-Audio)
|
||||
@@ -59,15 +78,17 @@ if (WIN32)
|
||||
add_subdirectory(Source/Installer)
|
||||
|
||||
add_custom_target(bundle_dependencies
|
||||
COMMAND "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/" "/mingw64/bin"
|
||||
COMMAND bash "${CMAKE_SOURCE_DIR}/Source/Script/BundleDependencies.sh" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}/RMG.exe" "${CMAKE_SOURCE_DIR}/Bin/${CMAKE_BUILD_TYPE}" "/mingw64/bin"
|
||||
)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
add_subdirectory(Source/3rdParty)
|
||||
install(FILES ${MUPEN64PLUSCORE_LIB}
|
||||
DESTINATION ${CORE_INSTALL_PATH}
|
||||
)
|
||||
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf Data/stylesheet.qss
|
||||
install(FILES ${MUPEN64PLUSCORE_INI} Data/font.ttf
|
||||
DESTINATION ${DATA_INSTALL_PATH}
|
||||
)
|
||||
install(FILES ${SDL_GAMECONTROLLERDB}
|
||||
DESTINATION ${DATA_INSTALL_PATH}
|
||||
)
|
||||
file(GLOB GENERATED_CHEAT_FILES ${CMAKE_SOURCE_DIR}/Data/Cheats/Generated/*.cht)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
[0CA6AEDA-BB9CFDD9-C:45]
|
||||
Name=Carnivale - Cenzo's Adventure (USA) (Prototype)
|
||||
|
||||
$Infinite Max Silver & Gold Coins
|
||||
Note=This seems to act as Health?
|
||||
810A2E7E 001E
|
||||
810A2E80 001E
|
||||
810A2E82 001E
|
||||
|
||||
$Infinite Max Peas
|
||||
Note=Max Pea Shooter Ammo
|
||||
810A2E7A 001E
|
||||
|
||||
$Unlock Everything
|
||||
Note=This Unlocks All Items in Single & All Multi Player Characters and Tracks.(Thanks Retroben!)
|
||||
810A2E90 0003
|
||||
810A2E92 87F9
|
||||
810A2E94 87F9
|
||||
|
||||
$Press L for Warp Select (Single Mode)
|
||||
Note=Press the L-Button as you go through a door (Thanks SubDrag!)
|
||||
D00A3359 0020
|
||||
800CA85B 00??
|
||||
01 Blue Background Race
|
||||
02 Dark Mountains Race
|
||||
03 Purple/Yellow Mountains Race
|
||||
04 Cloud Floor Race (from the locked main area)
|
||||
05 Main Area
|
||||
06 Maze
|
||||
07 King Race Super Rat Ride
|
||||
08 Mallet Game
|
||||
09 Duck Game
|
||||
0A Puppet Show (Come back later)
|
||||
0B Rock Paper Scissors Game
|
||||
0C Create Password
|
||||
0D Main Menu
|
||||
0E Select New Game
|
||||
0F Boss Intro Guy with hammer
|
||||
10 Options Menu
|
||||
11 Boss Intro Meet Strongman
|
||||
12 Main Menu
|
||||
|
||||
$Max Strength in Mallet Game
|
||||
811B08A6 0162
|
||||
|
||||
$Perfect Aim In Mallet Game (Line up and Shoot)
|
||||
Note=Use with Max Strength in Mallet Game. Wait until the Eyeball is past the 2 Red Lines (centre) and then press A
|
||||
811B0BD4 FFF2
|
||||
811B0B28 FDD2
|
||||
811605C8 FDD2
|
||||
81153148 FDD2
|
||||
|
||||
$1 Lap to Race (All Characters & Races)
|
||||
Note=For Single and Multi Player Modes. This will display 1 of 3, but on the first checkpoint you will get the message "You win" 1 Lap to race will also make you come in 1st and win. a big thanks to Parasyte for working with me on this! You are "Magic" lol
|
||||
81060020 2400
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
[7BD65F9E-76B6A083-C:45]
|
||||
Name=007 - The World is Not Enough (U) (Prototype - 2020 release)
|
||||
|
||||
$Enable Cheats Menu
|
||||
800811F0 0005
|
||||
|
||||
$Invincible
|
||||
80130ACD 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$All Weapons
|
||||
80130AE0 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$All Gadgets
|
||||
80130AE1 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$All Missions
|
||||
80130AE2 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Infinite Health (All Levels)
|
||||
81045D68 2400
|
||||
|
||||
$Infinite Ammo (All Guns for all Levels)
|
||||
Note=The Clip will count down but you will never run out of Ammo.
|
||||
81040730 2400
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[8825E18B-3297746B-C:50]
|
||||
Name=Aidyn Chronicles - The First Mage (Europe) (Prototype) (2)
|
||||
|
||||
$Infinite\Max Health
|
||||
80279308 001E
|
||||
|
||||
$Infinite\99 Health Potions
|
||||
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
|
||||
80278D3B 0063
|
||||
|
||||
$Have\Max Gold
|
||||
50000401 0000
|
||||
80277AA5 00FF
|
||||
|
||||
$Have\Max Total XP
|
||||
50000401 0000
|
||||
8027931D 00FF
|
||||
|
||||
$Have\Max Total XP Remaning to Start
|
||||
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
|
||||
50000401 0000
|
||||
80279321 00FF
|
||||
|
||||
$Play As Character
|
||||
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
|
||||
810E108E ????
|
||||
25F9 Alaron
|
||||
2A43 Marari Female
|
||||
2C17 Spirit
|
||||
2CC0 Marari Male
|
||||
2D4A GiantBat
|
||||
2E82 Chaos Trooper
|
||||
3094 Gryphon
|
||||
324D Ogre
|
||||
32CC GiantRat
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[8EAA1A2C-61C09930-C:00]
|
||||
Name=Aidyn Chronicles - The First Mage (USA) (Prototype)
|
||||
|
||||
$Infinite\Max Health
|
||||
80275AA1 001E
|
||||
|
||||
$Infinite\99 Health Potions
|
||||
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
|
||||
8027540F 0063
|
||||
|
||||
$Have\Max Gold
|
||||
50000401 0000
|
||||
8027423E 00FF
|
||||
|
||||
$Have\Max Total XP
|
||||
50000401 0000
|
||||
80275AB6 00FF
|
||||
|
||||
$Have\Max Total XP Remaning to Start
|
||||
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
|
||||
50000401 0000
|
||||
80275ABA 00FF
|
||||
|
||||
$Play As Character
|
||||
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
|
||||
810E0D6E ????
|
||||
25F9 Alaron
|
||||
2A43 Marari Female
|
||||
2C17 Spirit
|
||||
2CC0 Marari Male
|
||||
2D4A GiantBat
|
||||
2E82 Chaos Trooper
|
||||
3094 Gryphon
|
||||
324D Ogre
|
||||
32CC GiantRat
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
[A92E0966-341C3912-C:45]
|
||||
Name=007 - The World is Not Enough (U) (Beta) [!]
|
||||
|
||||
$Invincible
|
||||
8011E157 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Have All Gadgets
|
||||
8011E159 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Enable All Missions
|
||||
8011E15A 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Have All Weapons
|
||||
8011E158 00??
|
||||
01 On
|
||||
00 Off
|
||||
|
||||
$Infinite Health (All Levels)
|
||||
8106AC88 2400
|
||||
|
||||
$Infinite Ammo (All Guns for all Levels)
|
||||
8106246C 2400
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[D0E29F11-E029063F-C:50]
|
||||
Name=Aidyn Chronicles - The First Mage (Europe) (Prototype) (1)
|
||||
|
||||
$Infinite\Max Health
|
||||
80279208 001E
|
||||
|
||||
$Infinite\99 Health Potions
|
||||
Note=Do Not put this cheat on until you have collected your 1st Health Potion from the 1st Cheat or you will not be able to get into the Sub menu and Continue the game.
|
||||
80278C3B 0063
|
||||
|
||||
$Have\Max Gold
|
||||
50000401 0000
|
||||
802779A5 00FF
|
||||
|
||||
$Have\Max Total XP
|
||||
50000401 0000
|
||||
8027921D 00FF
|
||||
|
||||
$Have\Max Total XP Remaning to Start
|
||||
Note=This will give you 16777215 Total XP Remaning to start with and after your 1st batle will allow you to buy your Max Stats
|
||||
50000401 0000
|
||||
80279221 00FF
|
||||
|
||||
$Play As Character
|
||||
Note=Enable this at the start of a Game, before a next Level, or before a Cutscene to become your chosen option.
|
||||
810E0F9E ????
|
||||
25F9 Alaron
|
||||
2A43 Marari Female
|
||||
2C17 Spirit
|
||||
2CC0 Marari Male
|
||||
2D4A GiantBat
|
||||
2E82 Chaos Trooper
|
||||
3094 Gryphon
|
||||
324D Ogre
|
||||
32CC GiantRat
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
[E48E01F5-E6E51F9B-C:59]
|
||||
Name=Carmageddon 64 (E) (M4) (Eng-Spa-Fre-Ita) [!]
|
||||
|
||||
$Have Everything Unlocked
|
||||
Note=This will unlock Cars, Races, Missions and the in-built Cheat Menu. This will also replace all the Zombies with Dinosaurs. To access Cheat menu options: Pause Game: Use Control Stick, to scroll the Cheat Menu. Press A, to activate Cheats
|
||||
801BE43D 000F
|
||||
|
||||
$Have Infinite\Invunerability
|
||||
81097EAC ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Free Repairs
|
||||
81097EC4 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Underwater Ability
|
||||
81097EF4 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Turbo
|
||||
81097E34 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Mega Turbo
|
||||
81097E4C ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Hot Rod
|
||||
81097E64 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Turbo Nitrous
|
||||
81097E7C ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Frozen Opponents
|
||||
81097F24 ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Grip-O-Matic Tires
|
||||
8109805C ????
|
||||
0BBB On
|
||||
0000 Off
|
||||
|
||||
$Have Infinite\Mine Dropping Ability
|
||||
81098118 ????
|
||||
0064 On
|
||||
0000 Off
|
||||
|
||||
$Freeze Timer at 04:59
|
||||
Note=Do not enable until count down to race is finished
|
||||
811BE21E 3A70
|
||||
|
||||
$Max Credits
|
||||
Note=This is also Infinite until disabled
|
||||
811BE29A FFFF
|
||||
|
||||
$Max Kills
|
||||
Note=This will automatically Clear the stage if enabled and go back to the stage menu
|
||||
81094BEE 01F4
|
||||
|
||||
$Have All Groups Completed
|
||||
Note=This gives you all Cups for all Groups.
|
||||
50002801 0000
|
||||
801BE35C 0002
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
[F1642508-BEE60CF6-C:45]
|
||||
Name=Bust-A-Move 3 DX (USA) (Prototype)
|
||||
|
||||
$Always Have\guide line on
|
||||
800558CC 0082
|
||||
|
||||
$Pointer always active
|
||||
D0055BA0 0002
|
||||
80055BA0 0082
|
||||
|
||||
$Play As Select\Player 1
|
||||
800E1E50 00??
|
||||
00 Bubbloon
|
||||
01 Twinkie
|
||||
02 Prettio
|
||||
03 Marina
|
||||
04 Musashi
|
||||
05 Luna
|
||||
06 Jack
|
||||
07 SSB
|
||||
08 Dragoon
|
||||
09 Gnome
|
||||
10 Monkey
|
||||
11 furby? (looks like 2 balloons)
|
||||
12 Blue Gnome
|
||||
13 1 of the two Ballons
|
||||
14 Water under ballons
|
||||
|
||||
$Play As Select\Player 2
|
||||
800E1E58 00??
|
||||
00 Bubbloon
|
||||
01 Twinkie
|
||||
02 Prettio
|
||||
03 Marina
|
||||
04 Musashi
|
||||
05 Luna
|
||||
06 Jack
|
||||
07 SSB
|
||||
08 Dragoon
|
||||
09 Gnome
|
||||
10 Monkey
|
||||
11 furby? (looks like 2 balloons)
|
||||
12 Blue Gnome
|
||||
13 1 of the two Ballons
|
||||
14 Water under ballons
|
||||
|
||||
$Next Bubble Select\Player 1
|
||||
800EBA19 00??
|
||||
00 No Bubble
|
||||
01 Red
|
||||
02 Green
|
||||
03 Blue
|
||||
04 Yellow
|
||||
05 Orange
|
||||
06 Purple
|
||||
07 White
|
||||
08 Black
|
||||
|
||||
$Next Bubble Select\Player 2
|
||||
800EBB09 00??
|
||||
00 No Bubble
|
||||
01 Red
|
||||
02 Green
|
||||
03 Blue
|
||||
04 Yellow
|
||||
05 Orange
|
||||
06 Purple
|
||||
07 White
|
||||
08 Black
|
||||
|
||||
$Press GS Button to Reset Player 2 score to 0
|
||||
8809C5C0 0000
|
||||
8809C5C2 0000
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
[F7AA4F819F41CB4236792A8145684627]
|
||||
Name=Yoshi's Story (CHN) (iQue)
|
||||
|
||||
$Infinite\Health
|
||||
Note=This is for All Yoshis All levels
|
||||
50000804 0000
|
||||
8012FD1F 00??
|
||||
08 Infinite Health
|
||||
09 Infinite Max Health
|
||||
|
||||
$Infinite\Eggs (Once You Get One)
|
||||
Note=This is for All Yoshis All levels
|
||||
8103E52C 2400
|
||||
|
||||
$Infinite\Lives
|
||||
Note=This is for All Yoshis All levels
|
||||
8012FD5F 00FF
|
||||
|
||||
$Press GS Button To Have All Fruit
|
||||
8812F93B 001E
|
||||
|
||||
$Enable All Levels (Trial Mode)
|
||||
8112FDC4 FFFF
|
||||
8112FDC6 FFFF
|
||||
|
||||
@@ -11,8 +11,8 @@ license=('GPLv3')
|
||||
provides=("$_pkgname")
|
||||
conflicts=("$_pkgname")
|
||||
|
||||
depends=("hidapi" "libsamplerate" "minizip" "sdl2" "zlib" "freetype2" "qt5-base" "qt5-svg")
|
||||
makedepends=("git" "pkg-config" "nasm" "cmake" "rustup")
|
||||
depends=("hidapi" "libsamplerate" "minizip" "sdl2" "zlib" "freetype2" "qt6-base" "qt6-svg" "xdg-user-dirs")
|
||||
makedepends=("git" "pkg-config" "nasm" "cmake" "cargo" "ninja")
|
||||
|
||||
source=("git+https://github.com/Rosalie241/${_pkgname}.git")
|
||||
sha256sums=('SKIP')
|
||||
@@ -26,26 +26,21 @@ pkgver()
|
||||
|
||||
prepare()
|
||||
{
|
||||
cd "$srcdir/${_pkgname}"
|
||||
|
||||
mkdir -p build
|
||||
mkdir -p "$srcdir/${_pkgname}/build"
|
||||
}
|
||||
|
||||
build()
|
||||
{
|
||||
cd "$srcdir/${_pkgname}/build"
|
||||
|
||||
cmake -S "$srcdir/${_pkgname}" -B "$srcdir/${_pkgname}/build" \
|
||||
-DCMAKE_BUILD_TYPE="Release" \
|
||||
-DPORTABLE_INSTALL="OFF" \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-G "Unix Makefiles"
|
||||
make
|
||||
-G "Ninja" \
|
||||
|
||||
cmake --build "$srcdir/${_pkgname}/build"
|
||||
}
|
||||
|
||||
package()
|
||||
{
|
||||
cd "$srcdir/${_pkgname}/build"
|
||||
|
||||
make install DESTDIR="$pkgdir"
|
||||
cmake --install "$srcdir/${_pkgname}/build" --prefix="$pkgdir/usr"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 445 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 47 KiB |
@@ -18,13 +18,184 @@
|
||||
<caption>During A Game</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InGame.png</image>
|
||||
</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>Cheats</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Cheats.png</image>
|
||||
</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>Settings</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/Settings.png</image>
|
||||
</screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>Input Settings</caption>
|
||||
<image type="source">https://github.com/Rosalie241/RMG/raw/master/Package/Screenshots/InputSettings.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<description/>
|
||||
<releases>
|
||||
<release version="v0.3.2" date="2023-02-06" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix ndd/d64 files in zip files not working when the disk file is inside a subdirectory inside the zip file</li>
|
||||
<li>Fix ndd/d64 files in zip files not working correctly on windows</li>
|
||||
<li>Fix controller image in RMG-Input sometimes being stuck when having a trigger bound to a button</li>
|
||||
<li>Fix trigger mapping in RMG-Input</li>
|
||||
<li>Remove "Invert Axis Mapped To LRZ" setting in RMG-Input</li>
|
||||
<li>Add "Sort Results After Search" ROM Browser setting</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.1" date="2023-02-04" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix taking a screenshot not working in some cases</li>
|
||||
<li>Fix some games being unable to save due to having an illegal character in the save filename</li>
|
||||
<li>Fix OSD tab crash in GLideN64</li>
|
||||
<li>Fix an issue where the graphics plugin would show the 64DD IPL as ROM name in the settings even after booting a cartridge</li>
|
||||
<li>Fix "Refresh ROM List" in Hotkeys tab in settings dialog not reverting back to defaults when clicking on 'restore defaults'</li>
|
||||
<li>Fix "Remove Duplicate Keybindings" in settings dialog not behaving correctly in some cases</li>
|
||||
<li>Fix fallback application icons not respecting system icon theme on linux</li>
|
||||
<li>Add support for ndd/d64 files in zip files</li>
|
||||
<li>Add support for using the basename of the ROM filename for covers</li>
|
||||
<li>Add support for binding multiple inputs in RMG-Input</li>
|
||||
<li>Improve behavior of window when launching RMG with a ROM using the commandline</li>
|
||||
<li>Improve behavior of error message when emulation fails</li>
|
||||
<li>Improve behavior of hotkey buttons in settings dialog</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.3.0" date="2023-01-23" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix GLideN64 not being able to load texture packs from relative paths</li>
|
||||
<li>Fix "Save State Slot" keybindings not working in fullscreen</li>
|
||||
<li>Fix deadzone percentage being incorrect when set to 0% in RMG-Input</li>
|
||||
<li>Fix low deadzone value not working in RMG-Input (thank you porcino)</li>
|
||||
<li>Fix toolbar being hidden when ending emulation while in fullscreen</li>
|
||||
<li>Fix zip files with japanese characters in the file name not being able to be opened on windows</li>
|
||||
<li>Fix ROM Browser not returning to a maximized state when ending emulation</li>
|
||||
<li>Fix ROM Browser not opening maximized when closing RMG with it maximized</li>
|
||||
<li>Fix window not being able to be maximized during emulation when scaling is enabled</li>
|
||||
<li>Fix read-only ROM files not being able to be opened on linux</li>
|
||||
<li>Remove "Allow Manual Window Resizing" setting due to it being always enabled</li>
|
||||
<li>Remove Styles tab from settings dialog on windows</li>
|
||||
<li>Add "Play Game with Cartridge" to context menu when a 64DD disk is selected in the ROM Browser</li>
|
||||
<li>Add "Open ROM Directory" to context menu in the ROM Browser</li>
|
||||
<li>Add an On-Screen Display (see the OSD tab in the settings dialog for settings)</li>
|
||||
<li>Add Theme setting to settings dialog (see Interface -> Miscellaneous, this is a replacement for the previous Styles settings)</li>
|
||||
<li>Improve error message when opening a zip file fails</li>
|
||||
<li>Improve tab order and naming in settings dialog</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.9" date="2023-01-03" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix wrong 64DD Disk extension being listed in empty ROM browser</li>
|
||||
<li>Fix memory corruption when having 64DD Disk files</li>
|
||||
<li>Fix possible crash when render window wasn't visible yet</li>
|
||||
<li>Fix RMG changing the current directory on non-portable installs</li>
|
||||
<li>Remove Qt warning messages (you can view them by setting RMG_SHOW_DEBUG_QT_MESSAGES to 1)</li>
|
||||
<li>Change "Choose ROM Directory" to "Change ROM Directory"</li>
|
||||
<li>Add -q/--quit-after-emulation commandline option</li>
|
||||
<li>Add 2 more icons to menubar menus/items</li>
|
||||
<li>Add "Current Save State" tab to Hotkeys tab in settings dialog (this allows you to use a hotkey to change save state slots)</li>
|
||||
<li>Improve behavior of Hotkeys tab in settings dialog</li>
|
||||
<li>Improve behavior of window when exiting RMG while in-game</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.8" date="2023-01-01" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix 'Uniform Size (Grid View)' not being disabled during emulation</li>
|
||||
<li>Fix toolbar not respecting the view setting</li>
|
||||
<li>Fix being stuck at the loading screen when having more ROMs than the ROM search limit</li>
|
||||
<li>Improve error message when opening a ROM fails</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.7" date="2022-12-29" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix core error not showing when the statusbar was hidden</li>
|
||||
<li>Fix .ndd/.64d not being in the empty ROM Browser widget</li>
|
||||
<li>Fix .jpg/.jpeg files not working on covers on Windows</li>
|
||||
<li>Fix updater script not copying subdirectories on Windows (for portable installs)</li>
|
||||
<li>Fix 64DD Disks which required the development IPL not working</li>
|
||||
<li>Fix 64DD Disks showing the wrong internal ROM name (this fix requires clearing the ROM cache)</li>
|
||||
<li>Fix cover filenames allowing invalid characters (they will now be replaced by _)</li>
|
||||
<li>Add more icons to View menu in the menu bar</li>
|
||||
<li>Add 'Uniform Size (Grid View)' to View menu in the menu bar</li>
|
||||
<li>Add smooth scrolling to List View and Grid View</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.6" date="2022-12-28" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix default save state/game directory being incorrect on first run (on non-portable installs)</li>
|
||||
<li>Fix angrylion-rdp-plus not loading settings correctly</li>
|
||||
<li>Fix cheat settings not moving over when renaming a cheat</li>
|
||||
<li>Remove fullscreen resolution combobox from GLideN64 because it did nothing</li>
|
||||
<li>Remove File menu from menu bar</li>
|
||||
<li>Implement disk support without requiring a cartridge</li>
|
||||
<li>Add toolbar</li>
|
||||
<li>Add View menu to menu bar</li>
|
||||
<li>Add Grid view to ROM browser</li>
|
||||
<li>Add icons to all menu bar items</li>
|
||||
<li>Add log dialog</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.5" date="2022-12-14" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix incorrect controller being selected in RMG-Input when having 2 controllers with the same name</li>
|
||||
<li>Fix some UI elements being enabled while the 'Controller Is Plugged In' checkbox is disabled in RMG-Input</li>
|
||||
<li>Fix extra padding being added when having a controller selected and opening RMG-Input</li>
|
||||
<li>Fix creating a new profile in GLideN64</li>
|
||||
<li>Add Z-Trigger visualization in RMG-Input</li>
|
||||
<li>Remove Debugger checkbox in the settings dialog because it did nothing</li>
|
||||
<li>Remove About buttons in the plugin tab of the settings dialog because it did nothing</li>
|
||||
<li>Implement close button on all dialogs</li>
|
||||
<li>Implement custom style support (for Windows only)</li>
|
||||
<li>Implement the ability to remove/reset the main profile in RMG-Input</li>
|
||||
<li>Rename Interface tab in settings dialog to User Interface</li>
|
||||
<li>Migrate to Qt6 (currently the flatpak will remain Qt5)</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.4" date="2022-12-08" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Fix Discord Rich Presence breaking when opening the settings dialog</li>
|
||||
<li>Fix install update window not showing</li>
|
||||
<li>Fix 'Limit FPS' not working with new RMG-Audio (this disables the 'synchronize audio' option)</li>
|
||||
<li>Implement support for Japanese characters in the ROM header</li>
|
||||
<li>Implement dynamic buffer sizes in the ROM browser cache (this reduces the ROM browser cache size)</li>
|
||||
<li>Add more cheats from Gent</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.3" date="2022-12-05" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
<ul>
|
||||
<li>Add updater for portable installations</li>
|
||||
<li>Add Discord Rich Presence</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="v0.2.2" date="2022-12-03" type="stable">
|
||||
<description>
|
||||
<p>Changes:</p>
|
||||
|
||||
@@ -4,51 +4,6 @@ Rosalie's Mupen GUI is a free and open-source mupen64plus GUI written in C++.
|
||||
|
||||
It offers a simple-to-use user interface.
|
||||
|
||||
## System Requirements
|
||||
|
||||
* Operating System
|
||||
* Windows Or Linux
|
||||
* CPU
|
||||
* Intel or AMD processor with SSE2 support
|
||||
* RAM
|
||||
* 512MB or more
|
||||
* Graphics card
|
||||
* OpenGL 3.3 capable
|
||||
|
||||
## Building
|
||||
|
||||
#### Linux
|
||||
* Portable Debian/Ubuntu
|
||||
|
||||
```shell
|
||||
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt5-default build-essential nasm git zip
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
* Portable Fedora
|
||||
```shell
|
||||
sudo dnf install hidapi-devel libsamplerate-devel minizip-compat-devel SDL2-devel freetype-devel mesa-libGL-devel mesa-libGLU-devel zlib-ng-devel binutils-devel speexdsp-devel qt5-qtbase-devel qt5-qtsvg-devel gcc-c++ nasm git
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
When it's done building, executables can be found in `Bin/Release`
|
||||
|
||||
* Installation/Packaging
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -G "Unix Makefiles"
|
||||
make install
|
||||
```
|
||||
|
||||
#### Windows
|
||||
* Download & Install [MSYS2](https://www.msys2.org/)
|
||||
```
|
||||
sudo pacman -S git make mingw-w64-x86_64-cmake mingw-w64-x86_64-freetype mingw-w64-x86_64-gcc mingw-w64-x86_64-hidapi mingw-w64-x86_64-jasper mingw-w64-x86_64-libpng mingw-w64-x86_64-libsamplerate mingw-w64-x86_64-nasm mingw-w64-x86_64-python3-pip mingw-w64-x86_64-python3-pyopenssl mingw-w64-x86_64-qt5 mingw-w64-x86_64-rust mingw-w64-x86_64-SDL2
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
When it's done building, executables can be found in `Bin/Release`
|
||||
|
||||
## Support
|
||||
|
||||
Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for support
|
||||
@@ -56,3 +11,46 @@ Join the [Rosalie's Mupen GUI Discord Server](https://discord.gg/k9GuyJ2PpF) for
|
||||
## License
|
||||
|
||||
Rosalie's Mupen GUI is licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
||||
|
||||
## Showcase
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Building
|
||||
|
||||
#### Linux
|
||||
* Portable Debian/Ubuntu
|
||||
|
||||
```bash
|
||||
sudo apt-get -y install cmake libhidapi-dev libsamplerate0-dev libspeex-dev libminizip-dev libsdl2-dev libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev pkg-config zlib1g-dev binutils-dev libspeexdsp-dev qt6-base-dev libqt6svg6-dev build-essential nasm git zip ninja-build
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
* Portable Fedora
|
||||
```bash
|
||||
sudo dnf install hidapi-devel libsamplerate-devel minizip-compat-devel SDL2-devel freetype-devel mesa-libGL-devel mesa-libGLU-devel zlib-ng-devel binutils-devel speexdsp-devel qt6-qtbase-devel qt6-qtsvg-devel gcc-c++ nasm git ninja-build
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
When it's done building, executables can be found in `Bin/Release`
|
||||
|
||||
* Installation/Packaging
|
||||
```bash
|
||||
export src_dir="$(pwd)"
|
||||
export build_dir="$(pwd)/build"
|
||||
mkdir -p "$build_dir"
|
||||
cmake -S "$src_dir" -B "$build_dir" -DCMAKE_BUILD_TYPE="Release" -DPORTABLE_INSTALL="OFF" -DCMAKE_INSTALL_PREFIX="/usr" -G "Ninja"
|
||||
cmake --build "$build_dir"
|
||||
cmake --install "$build_dir" --prefix="/usr"
|
||||
```
|
||||
|
||||
#### Windows
|
||||
* Download & Install [MSYS2](https://www.msys2.org/)
|
||||
```bash
|
||||
pacman -S --needed make mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-hidapi mingw-w64-x86_64-freetype mingw-w64-x86_64-libpng mingw-w64-x86_64-SDL2 mingw-w64-x86_64-qt6 mingw-w64-x86_64-SDL2 mingw-w64-x86_64-hidapi mingw-w64-x86_64-speexdsp mingw-w64-x86_64-libsamplerate mingw-w64-x86_64-nasm mingw-w64-x86_64-minizip git
|
||||
./Source/Script/Build.sh Release
|
||||
```
|
||||
|
||||
When it's done building, executables can be found in `Bin/Release`
|
||||
|
||||
@@ -8,9 +8,9 @@ set(THIRDPARTY_DIR ${CMAKE_BINARY_DIR}/Source/3rdParty)
|
||||
find_program(RUST_CARGO cargo)
|
||||
if(${RUST_CARGO} STREQUAL "RUST_CARGO-NOTFOUND")
|
||||
message(WARNING "mupen64plus-input-gca will not be built due to not having cargo installed")
|
||||
set(BUILD_INPUT_GCA "0")
|
||||
set(BUILD_INPUT_GCA OFF)
|
||||
else()
|
||||
set(BUILD_INPUT_GCA "1")
|
||||
set(BUILD_INPUT_GCA ON)
|
||||
endif()
|
||||
|
||||
set(M64P_CORE_DIR ${THIRDPARTY_DIR}/mupen64plus-core)
|
||||
@@ -24,9 +24,20 @@ else(WIN32)
|
||||
set(CORE_FILE "libmupen64plus.so")
|
||||
endif(WIN32)
|
||||
|
||||
set(BASE_CMAKE_CONFIGURE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
|
||||
if (USE_CCACHE)
|
||||
set(CMAKE_CONFIGURE_ARGS ${BASE_CMAKE_CONFIGURE_ARGS} -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache)
|
||||
set(MAKE_CC_COMPILER "ccache ${CMAKE_C_COMPILER}")
|
||||
set(MAKE_CXX_COMPILER "ccache ${CMAKE_CXX_COMPILER}")
|
||||
else(USE_CCACHE)
|
||||
set(CMAKE_CONFIGURE_ARGS ${BASE_CMAKE_CONFIGURE_ARGS})
|
||||
set(MAKE_CC_COMPILER "${CMAKE_C_COMPILER}")
|
||||
set(MAKE_CXX_COMPILER "${CMAKE_CXX_COMPILER}")
|
||||
endif(USE_CCACHE)
|
||||
|
||||
if(NOT NO_GIT_CLONE)
|
||||
set(MUPEN64PLUSCORE_URL "https://github.com/mupen64plus/mupen64plus-core")
|
||||
set(MUPEN64PLUSCORE_TAG "f63e1b35063241738d848f73311496b76c8aa918")
|
||||
set(MUPEN64PLUSCORE_URL "https://github.com/Rosalie241/mupen64plus-core")
|
||||
set(MUPEN64PLUSCORE_TAG "022e7de28067ac633ca23d405e9f0c4ed5cc368b")
|
||||
|
||||
set(MUPEN64PLUS_RSP_CXD4_URL "https://github.com/mupen64plus/mupen64plus-rsp-cxd4")
|
||||
set(MUPEN64PLUS_RSP_CXD4_TAG "39f79201baa15890c4cbae92f2215a634cc3ee6d")
|
||||
@@ -44,13 +55,22 @@ if(NOT NO_GIT_CLONE)
|
||||
set(MUPEN64PLUS_INPUT_GCA_TAG "21639fb13dfa797a7c0949ffd9bbda9a3456fc69")
|
||||
|
||||
set(MUPEN64PLUS_GFX_ANGRYLION_URL "https://github.com/Rosalie241/angrylion-rdp-plus")
|
||||
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "9d71074f6b71750e99ad06a713f28a9c32ad15cb")
|
||||
set(MUPEN64PLUS_GFX_ANGRYLION_TAG "158e74d4ec1c818289cd19c3a05e498c3ceff758")
|
||||
|
||||
set(MUPEN64PLUS_GFX_GLIDEN64_URL "https://github.com/gonetz/GLideN64")
|
||||
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "a2ecb92e954fdc1dd1130b331935f04381b29e28")
|
||||
set(MUPEN64PLUS_GFX_GLIDEN64_TAG "263a7bd2ca81759ece98209bd282a6c1173a129f")
|
||||
|
||||
set(MUPEN64PLUS_GFX_PARALLEL_URL "https://github.com/Rosalie241/parallel-rdp-standalone")
|
||||
set(MUPEN64PLUS_GFX_PARALLEL_TAG "693f607728aca78d94ba5d45b0ce119b4ccbcd8c")
|
||||
set(MUPEN64PLUS_GFX_PARALLEL_TAG "48abaa5e082add7848e6f98648111c69c4a71632")
|
||||
|
||||
set(DISCORD_RPC_URL "https://github.com/discord/discord-rpc")
|
||||
set(DISCORD_RPC_TAG "963aa9f3e5ce81a4682c6ca3d136cddda614db33")
|
||||
|
||||
set(IMGUI_URL "https://github.com/ocornut/imgui")
|
||||
set(IMGUI_TAG "d7c8516a4b848c0291e3d75b627c0843f515f591")
|
||||
|
||||
set(SDL_GAMECONTROLLERDB_URL "https://github.com/gabomdq/SDL_GameControllerDB")
|
||||
set(SDL_GAMECONTROLLERDB_TAG "0562b00eaf5c0308c49d329b79263d2dae1c3a85")
|
||||
endif(NOT NO_GIT_CLONE)
|
||||
|
||||
ExternalProject_Add(mupen64plus-core
|
||||
@@ -62,7 +82,7 @@ ExternalProject_Add(mupen64plus-core
|
||||
GIT_REPOSITORY ${MUPEN64PLUSCORE_URL}
|
||||
GIT_TAG ${MUPEN64PLUSCORE_TAG}
|
||||
|
||||
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0
|
||||
BUILD_COMMAND make all OSD=0 NEW_DYNAREC=1 TARGET=${CORE_FILE} DEBUG=$<CONFIG:Debug> KEYBINDINGS=0 CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${M64P_CORE_DIR}/projects/unix
|
||||
@@ -81,7 +101,7 @@ ExternalProject_Add(mupen64plus-rsp-cxd4
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_RSP_CXD4_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_RSP_CXD4_TAG}
|
||||
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> POSTFIX=
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> POSTFIX= CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-cxd4/projects/unix
|
||||
@@ -99,7 +119,7 @@ ExternalProject_Add(mupen64plus-rsp-hle
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_RSP_HLE_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_RSP_HLE_TAG}
|
||||
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug>
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-rsp-hle/projects/unix
|
||||
@@ -117,7 +137,7 @@ ExternalProject_Add(mupen64plus-rsp-parallel
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-rsp-parallel/mupen64plus-rsp-parallel.${SO_EXT}
|
||||
DEPENDS mupen64plus-core
|
||||
@@ -132,7 +152,7 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
|
||||
GIT_REPOSITORY ${MUPEN64PLUS_INPUT_RAPHNET_URL}
|
||||
GIT_TAG ${MUPEN64PLUS_INPUT_RAPHNET_TAG}
|
||||
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug>
|
||||
BUILD_COMMAND make all APIDIR=${APIDIR} DEBUG=$<CONFIG:Debug> CC=${MAKE_CC_COMPILER} CXX=${MAKE_CXX_COMPILER}
|
||||
BUILD_IN_SOURCE False
|
||||
|
||||
BINARY_DIR ${THIRDPARTY_DIR}/mupen64plus-input-raphnetraw/projects/unix
|
||||
@@ -141,7 +161,7 @@ ExternalProject_Add(mupen64plus-input-raphnetraw
|
||||
DEPENDS mupen64plus-core
|
||||
)
|
||||
|
||||
if (${BUILD_INPUT_GCA} STREQUAL "1")
|
||||
if (BUILD_INPUT_GCA)
|
||||
ExternalProject_Add(mupen64plus-input-gca
|
||||
SOURCE_DIR mupen64plus-input-gca/
|
||||
|
||||
@@ -157,15 +177,16 @@ if (${BUILD_INPUT_GCA} STREQUAL "1")
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-input-gca/target/release/${GCA_LIB}
|
||||
DEPENDS mupen64plus-core
|
||||
)
|
||||
endif()
|
||||
endif(BUILD_INPUT_GCA)
|
||||
|
||||
set(GLIDEN64_DIR "${THIRDPARTY_DIR}/mupen64plus-video-GLideN64")
|
||||
set(GLIDEN64_BUILD_DIR "${GLIDEN64_DIR}/projects/cmake")
|
||||
if (MSYS)
|
||||
set(GLIDEN64_CUSTOM_INI "${GLIDEN64_DIR}/ini/GLideN64.custom.ini")
|
||||
if (WIN32)
|
||||
set(GLIDEN64_LIB "${GLIDEN64_BUILD_DIR}/mupen64plus-video-GLideN64.${SO_EXT}")
|
||||
else()
|
||||
else(WIN32)
|
||||
set(GLIDEN64_LIB "${GLIDEN64_BUILD_DIR}/plugin/${CMAKE_BUILD_TYPE}/mupen64plus-video-GLideN64.${SO_EXT}")
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
set(GLIDENUI_TRANSLATIONS_LANGS "de;es;fr;it;ja;pl;pt_BR")
|
||||
foreach(LANG ${GLIDENUI_TRANSLATIONS_LANGS})
|
||||
@@ -181,7 +202,7 @@ ExternalProject_Add(mupen64plus-video-angrylion-plus
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DBUILD_MUPEN64PLUS=ON -DBUILD_PROJECT64=OFF -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS -DBUILD_MUPEN64PLUS=ON -DBUILD_PROJECT64=OFF -DUSE_QT5=OFF ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-video-angrylion-plus/mupen64plus-video-angrylion-plus.${SO_EXT}
|
||||
DEPENDS mupen64plus-core
|
||||
@@ -196,14 +217,12 @@ ExternalProject_Add(mupen64plus-video-GLideN64
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE False
|
||||
CMAKE_ARGS -DMUPENPLUSAPI=ON -DMUPENPLUSAPI_GLIDENUI=ON -DUSE_SYSTEM_LIBS=ON -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS -DMUPENPLUSAPI=ON -DMUPENPLUSAPI_GLIDENUI=ON -DGLIDENUI_QT6=ON -DUSE_SYSTEM_LIBS=ON ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
SOURCE_SUBDIR ./src/
|
||||
BINARY_DIR ${GLIDEN64_BUILD_DIR}
|
||||
|
||||
BUILD_BYPRODUCTS ${GLIDEN64_LIB}
|
||||
BUILD_BYPRODUCTS ${GLIDEN64_DIR}/ini/GLideN64.custom.ini
|
||||
BUILD_BYPRODUCTS ${GLIDENUI_TRANSLATIONS}
|
||||
)
|
||||
|
||||
ExternalProject_Add(mupen64plus-video-parallel
|
||||
@@ -215,12 +234,82 @@ ExternalProject_Add(mupen64plus-video-parallel
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
CMAKE_ARGS -DUSE_QT5=OFF ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/mupen64plus-video-parallel/mupen64plus-video-parallel.${SO_EXT}
|
||||
DEPENDS mupen64plus-core
|
||||
)
|
||||
|
||||
if (DISCORD_RPC)
|
||||
ExternalProject_Add(discord-rpc
|
||||
SOURCE_DIR discord-rpc
|
||||
|
||||
GIT_REPOSITORY ${DISCORD_RPC_URL}
|
||||
GIT_TAG ${DISCORD_RPC_TAG}
|
||||
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_IN_SOURCE True
|
||||
CMAKE_ARGS -DBUILD_EXAMPLES=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON ${CMAKE_CONFIGURE_ARGS}
|
||||
|
||||
BUILD_BYPRODUCTS ${THIRDPARTY_DIR}/discord-rpc/src/libdiscord-rpc.a
|
||||
)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
set(IMGUI_DIR ${THIRDPARTY_DIR}/imgui)
|
||||
set(IMGUI_BUILD_DIR ${IMGUI_DIR}/build)
|
||||
set(IMGUI_SOURCES_IN
|
||||
${IMGUI_DIR}/imgui_draw.cpp
|
||||
${IMGUI_DIR}/imgui_tables.cpp
|
||||
${IMGUI_DIR}/imgui_widgets.cpp
|
||||
${IMGUI_DIR}/imgui.cpp
|
||||
${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp
|
||||
${IMGUI_DIR}/backends/imgui_impl_opengl3.h
|
||||
${IMGUI_DIR}/backends/imgui_impl_opengl3_loader.h
|
||||
)
|
||||
set(IMGUI_SOURCES_OUT
|
||||
${IMGUI_BUILD_DIR}/imgui_draw.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_tables.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_widgets.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_impl_opengl3.cpp
|
||||
${IMGUI_BUILD_DIR}/imgui_impl_opengl3.h
|
||||
${IMGUI_BUILD_DIR}/imgui_impl_opengl3_loader.h
|
||||
)
|
||||
ExternalProject_Add(imgui
|
||||
SOURCE_DIR imgui
|
||||
|
||||
GIT_REPOSITORY ${IMGUI_URL}
|
||||
GIT_TAG ${IMGUI_TAG}
|
||||
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${IMGUI_BUILD_DIR}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} -E copy ${IMGUI_SOURCES_IN} ${IMGUI_BUILD_DIR}
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_BYPRODUCTS ${IMGUI_SOURCES_OUT}
|
||||
)
|
||||
|
||||
set(SDL_GAMECONTROLLERDB_DIR ${THIRDPARTY_DIR}/SDL_GameControllerDB)
|
||||
set(SDL_GAMECONTROLLERDB_BUILD_DIR ${SDL_GAMECONTROLLERDB_DIR}/build)
|
||||
set(SDL_GAMECONTROLLERDB_SOURCES_IN
|
||||
${SDL_GAMECONTROLLERDB_DIR}/gamecontrollerdb.txt
|
||||
)
|
||||
set(SDL_GAMECONTROLLERDB_SOURCES_OUT
|
||||
${SDL_GAMECONTROLLERDB_BUILD_DIR}/gamecontrollerdb.txt
|
||||
)
|
||||
ExternalProject_Add(SDL_GameControllerDB
|
||||
SOURCE_DIR SDL_GameControllerDB
|
||||
|
||||
GIT_REPOSITORY ${SDL_GAMECONTROLLERDB_URL}
|
||||
GIT_TAG ${SDL_GAMECONTROLLERDB_TAG}
|
||||
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${SDL_GAMECONTROLLERDB_BUILD_DIR}
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} -E copy ${SDL_GAMECONTROLLERDB_SOURCES_IN} ${SDL_GAMECONTROLLERDB_SOURCES_OUT}
|
||||
INSTALL_COMMAND ""
|
||||
|
||||
BUILD_BYPRODUCTS ${SDL_GAMECONTROLLERDB_SOURCES_OUT}
|
||||
)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-core BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUSCORE_LIB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
set(MUPEN64PLUSCORE_INI ${M64P_CORE_DIR}/data/mupen64plus.ini PARENT_SCOPE)
|
||||
@@ -237,16 +326,28 @@ set(MUPEN64PLUS_PLUGIN_RSP_PARALLEL ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
ExternalProject_Get_property(mupen64plus-input-raphnetraw BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_INPUT_RAPHNET ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
if (${BUILD_INPUT_GCA} STREQUAL "1")
|
||||
if (BUILD_INPUT_GCA)
|
||||
ExternalProject_Get_property(mupen64plus-input-gca BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_INPUT_GCA ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
endif()
|
||||
endif(BUILD_INPUT_GCA)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-video-angrylion-plus BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_ANGRYLION ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-video-GLideN64 BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_GLIDEN64 ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_GLIDEN64 ${BUILD_BYPRODUCTS} ${GLIDENUI_TRANSLATIONS} ${GLIDEN64_CUSTOM_INI} PARENT_SCOPE)
|
||||
|
||||
ExternalProject_Get_property(mupen64plus-video-parallel BUILD_BYPRODUCTS)
|
||||
set(MUPEN64PLUS_PLUGIN_GFX_PARALLEL ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
if (DISCORD_RPC)
|
||||
ExternalProject_Get_property(discord-rpc BUILD_BYPRODUCTS)
|
||||
set(DISCORD_RPC_LIB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
ExternalProject_Get_property(imgui BUILD_BYPRODUCTS)
|
||||
set(IMGUI_SOURCES ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
set(IMGUI_DIR ${THIRDPARTY_DIR}/imgui PARENT_SCOPE)
|
||||
|
||||
ExternalProject_Get_property(SDL_GameControllerDB BUILD_BYPRODUCTS)
|
||||
set(SDL_GAMECONTROLLERDB ${BUILD_BYPRODUCTS} PARENT_SCOPE)
|
||||
|
||||
@@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
find_package(Qt5 COMPONENTS Gui Widgets Core REQUIRED)
|
||||
find_package(Qt6 COMPONENTS Gui Widgets Core REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||
@@ -36,7 +36,7 @@ target_link_libraries(RMG-Audio
|
||||
${SDL2_LIBRARIES}
|
||||
${SPEEX_LIBRARIES}
|
||||
${SAMPLERATE_LIBRARIES}
|
||||
Qt5::Gui Qt5::Widgets
|
||||
Qt6::Gui Qt6::Widgets
|
||||
)
|
||||
|
||||
target_include_directories(RMG-Audio PRIVATE
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
|
||||
using namespace UserInterface;
|
||||
|
||||
MainDialog::MainDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
|
||||
MainDialog::MainDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
this->setupUi(this);
|
||||
this->setWindowIcon(QIcon(":Resource/RMG.png"));
|
||||
|
||||
this->setIconsForEmulationInfoText();
|
||||
|
||||
this->volumeSlider->setValue(CoreSettingsGetIntValue(SettingsID::Audio_Volume));
|
||||
this->muteCheckBox->setChecked(CoreSettingsGetBoolValue(SettingsID::Audio_Muted));
|
||||
|
||||
@@ -38,6 +40,21 @@ MainDialog::~MainDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void MainDialog::setIconsForEmulationInfoText(void)
|
||||
{
|
||||
QLabel* labels[] = {
|
||||
this->infoIconLabel_0
|
||||
};
|
||||
|
||||
QIcon infoIcon = QIcon::fromTheme("information-line");
|
||||
QPixmap infoIconPixmap = infoIcon.pixmap(16, 16);
|
||||
|
||||
for (QLabel* label : labels)
|
||||
{
|
||||
label->setPixmap(infoIconPixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void MainDialog::hideEmulationInfoText(void)
|
||||
{
|
||||
QHBoxLayout *layouts[] = {this->emulationInfoLayout};
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
~MainDialog(void);
|
||||
|
||||
private:
|
||||
void setIconsForEmulationInfoText(void);
|
||||
void hideEmulationInfoText(void);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -324,7 +324,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="emulationInfoLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<widget class="QLabel" name="infoIconLabel_0">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -335,7 +335,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="UIResources.qrc">:/Resource/Info.ico</pixmap>
|
||||
<pixmap>:/Resource/Info.ico</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,6 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>Resource/RMG.png</file>
|
||||
<file>Resource/Info.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -9,6 +9,9 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||
pkg_check_modules(MINIZIP REQUIRED minizip)
|
||||
if (WIN32)
|
||||
pkg_check_modules(ICONV REQUIRED iconv)
|
||||
endif(WIN32)
|
||||
|
||||
configure_file(Config.hpp.in Config.hpp)
|
||||
|
||||
@@ -18,6 +21,7 @@ set(RMG_CORE_SOURCES
|
||||
m64p/ConfigApi.cpp
|
||||
m64p/PluginApi.cpp
|
||||
CachedRomHeaderAndSettings.cpp
|
||||
ConvertStringEncoding.cpp
|
||||
Settings/Settings.cpp
|
||||
SpeedLimiter.cpp
|
||||
RomSettings.cpp
|
||||
@@ -29,10 +33,12 @@ set(RMG_CORE_SOURCES
|
||||
SaveState.cpp
|
||||
Callback.cpp
|
||||
Plugins.cpp
|
||||
Version.cpp
|
||||
Cheats.cpp
|
||||
VidExt.cpp
|
||||
Video.cpp
|
||||
Error.cpp
|
||||
Unzip.cpp
|
||||
Core.cpp
|
||||
Key.cpp
|
||||
Rom.cpp
|
||||
@@ -50,8 +56,15 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DISCORD_RPC)
|
||||
list(APPEND RMG_CORE_SOURCES
|
||||
DiscordRpc.cpp
|
||||
)
|
||||
add_definitions(-DDISCORD_RPC)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
if (PORTABLE_INSTALL)
|
||||
add_definitions(-DPORTABLE_INSTALL)
|
||||
add_definitions(-DPORTABLE_INSTALL)
|
||||
endif(PORTABLE_INSTALL)
|
||||
|
||||
add_library(RMG-Core STATIC ${RMG_CORE_SOURCES})
|
||||
@@ -61,13 +74,20 @@ if(UNIX)
|
||||
endif(UNIX)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(RMG-Core wsock32 ws2_32)
|
||||
target_link_libraries(RMG-Core wsock32 ws2_32 ${ICONV_LIBRARIES})
|
||||
endif(WIN32)
|
||||
|
||||
target_link_libraries(RMG-Core
|
||||
${MINIZIP_LIBRARIES}
|
||||
)
|
||||
|
||||
if (DISCORD_RPC)
|
||||
target_link_libraries(RMG-Core
|
||||
${DISCORD_RPC_LIB}
|
||||
)
|
||||
add_dependencies(RMG-Core discord-rpc)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
target_include_directories(RMG-Core PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
|
||||
@@ -18,16 +18,30 @@
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else // Linux
|
||||
#include <linux/limits.h>
|
||||
#endif // _WIN32
|
||||
|
||||
//
|
||||
// Local Defines
|
||||
//
|
||||
|
||||
#define MAX_FILENAME_LEN 4096
|
||||
#define ROMHEADER_NAME_LEN 21
|
||||
#ifdef _WIN32
|
||||
#define MAX_FILENAME_LEN MAX_PATH
|
||||
#else // Linux
|
||||
#define MAX_FILENAME_LEN PATH_MAX
|
||||
#endif // _WIN32
|
||||
#define ROMHEADER_NAME_LEN 256
|
||||
#define GOODNAME_LEN 256
|
||||
#define MD5_LEN 33
|
||||
|
||||
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCache_03"
|
||||
#ifdef _WIN32
|
||||
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheWindows_05"
|
||||
#else // Linux
|
||||
#define CACHE_FILE_MAGIC "RMGCoreHeaderAndSettingsCacheLinux_05"
|
||||
#endif // _WIN32
|
||||
#define CACHE_FILE_ITEMS_MAX 10000
|
||||
|
||||
//
|
||||
@@ -39,6 +53,7 @@ struct l_CacheEntry
|
||||
std::filesystem::path fileName;
|
||||
osal_files_file_time fileTime;
|
||||
|
||||
CoreRomType type;
|
||||
CoreRomHeader header;
|
||||
CoreRomSettings settings;
|
||||
};
|
||||
@@ -90,6 +105,7 @@ void CoreReadRomHeaderAndSettingsCache(void)
|
||||
char headerNameBuf[ROMHEADER_NAME_LEN];
|
||||
char goodNameBuf[GOODNAME_LEN];
|
||||
char md5Buf[MD5_LEN];
|
||||
uint32_t size;
|
||||
l_CacheEntry cacheEntry;
|
||||
|
||||
inputStream.open(get_cache_file_name(), std::ios::binary);
|
||||
@@ -108,27 +124,34 @@ void CoreReadRomHeaderAndSettingsCache(void)
|
||||
|
||||
// read all file entries
|
||||
#define FREAD(x) inputStream.read((char*)&x, sizeof(x))
|
||||
#define FREAD_STR(x) inputStream.read((char*)x, sizeof(x))
|
||||
#define FREAD_STR(x, y) inputStream.read((char*)x, y)
|
||||
while (!inputStream.eof())
|
||||
{
|
||||
// reset buffers
|
||||
size = 0;
|
||||
memset(fileNameBuf, 0, sizeof(fileNameBuf));
|
||||
memset(headerNameBuf, 0, sizeof(headerNameBuf));
|
||||
memset(goodNameBuf, 0, sizeof(goodNameBuf));
|
||||
memset(md5Buf, 0, sizeof(md5Buf));
|
||||
|
||||
// file info
|
||||
FREAD_STR(fileNameBuf);
|
||||
FREAD(size);
|
||||
FREAD_STR(fileNameBuf, size);
|
||||
cacheEntry.fileName = std::filesystem::path(fileNameBuf);
|
||||
FREAD(cacheEntry.fileTime);
|
||||
// type
|
||||
FREAD(cacheEntry.type);
|
||||
// header
|
||||
FREAD_STR(headerNameBuf);
|
||||
FREAD(size);
|
||||
FREAD_STR(headerNameBuf, size);
|
||||
cacheEntry.header.Name = std::string(headerNameBuf);
|
||||
FREAD(cacheEntry.header.CRC1);
|
||||
FREAD(cacheEntry.header.CRC2);
|
||||
// (partial) settings
|
||||
FREAD_STR(goodNameBuf);
|
||||
FREAD_STR(md5Buf);
|
||||
FREAD(size);
|
||||
FREAD_STR(goodNameBuf, size);
|
||||
FREAD(size);
|
||||
FREAD_STR(md5Buf, size);
|
||||
cacheEntry.settings.GoodName = std::string(goodNameBuf);
|
||||
cacheEntry.settings.MD5 = std::string(md5Buf);
|
||||
|
||||
@@ -148,6 +171,7 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
|
||||
char headerNameBuf[ROMHEADER_NAME_LEN];
|
||||
char goodNameBuf[GOODNAME_LEN];
|
||||
char md5Buf[MD5_LEN];
|
||||
uint32_t size;
|
||||
l_CacheEntry cacheEntry;
|
||||
|
||||
// only save cache when the entries have changed
|
||||
@@ -167,12 +191,13 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
|
||||
|
||||
// write each entry in the file
|
||||
#define FWRITE(x) outputStream.write((char*)&x, sizeof(x))
|
||||
#define FWRITE_STR(x) outputStream.write((char*)x, sizeof(x))
|
||||
#define FWRITE_STR(x, y) outputStream.write((char*)x, y)
|
||||
for (auto iter = l_CacheEntries.cbegin(); iter != l_CacheEntries.end(); iter++)
|
||||
{
|
||||
cacheEntry = (*iter);
|
||||
|
||||
// reset buffers
|
||||
size = 0;
|
||||
memset(fileNameBuf, 0, sizeof(fileNameBuf));
|
||||
memset(headerNameBuf, 0, sizeof(headerNameBuf));
|
||||
memset(goodNameBuf, 0, sizeof(goodNameBuf));
|
||||
@@ -185,15 +210,25 @@ bool CoreSaveRomHeaderAndSettingsCache(void)
|
||||
strncpy(md5Buf, cacheEntry.settings.MD5.c_str(), sizeof(md5Buf));
|
||||
|
||||
// file info
|
||||
FWRITE_STR(fileNameBuf);
|
||||
size = cacheEntry.fileName.wstring().size() * sizeof(wchar_t);
|
||||
FWRITE(size);
|
||||
FWRITE_STR(fileNameBuf, size);
|
||||
FWRITE(cacheEntry.fileTime);
|
||||
// type
|
||||
FWRITE(cacheEntry.type);
|
||||
// header
|
||||
FWRITE_STR(headerNameBuf);
|
||||
size = cacheEntry.header.Name.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(headerNameBuf, size);
|
||||
FWRITE(cacheEntry.header.CRC1);
|
||||
FWRITE(cacheEntry.header.CRC2);
|
||||
// (partial) settings
|
||||
FWRITE_STR(goodNameBuf);
|
||||
FWRITE_STR(md5Buf);
|
||||
size = cacheEntry.settings.GoodName.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(goodNameBuf, size);
|
||||
size = cacheEntry.settings.MD5.size();
|
||||
FWRITE(size);
|
||||
FWRITE_STR(md5Buf, size);
|
||||
}
|
||||
#undef FWRITE
|
||||
#undef FWRITE_STR
|
||||
@@ -207,7 +242,7 @@ bool CoreHasRomHeaderAndSettingsCached(std::filesystem::path file)
|
||||
return get_cache_entry_iter(file) != l_CacheEntries.end();
|
||||
}
|
||||
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader& header, CoreRomSettings& settings)
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType& type, CoreRomHeader& header, CoreRomSettings& settings)
|
||||
{
|
||||
auto iter = get_cache_entry_iter(file);
|
||||
if (iter == l_CacheEntries.end())
|
||||
@@ -215,12 +250,13 @@ bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
|
||||
return false;
|
||||
}
|
||||
|
||||
type = (*iter).type;
|
||||
header = (*iter).header;
|
||||
settings = (*iter).settings;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader header, CoreRomSettings settings)
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings)
|
||||
{
|
||||
l_CacheEntry cacheEntry;
|
||||
|
||||
@@ -238,6 +274,7 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
|
||||
|
||||
cacheEntry.fileName = file;
|
||||
cacheEntry.fileTime = osal_files_get_file_time(file);
|
||||
cacheEntry.type = type;
|
||||
cacheEntry.header = header;
|
||||
cacheEntry.settings = settings;
|
||||
|
||||
@@ -245,3 +282,10 @@ bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader
|
||||
l_CacheEntriesChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreClearRomHeaderAndSettingsCache(void)
|
||||
{
|
||||
l_CacheEntries.clear();
|
||||
l_CacheEntriesChanged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "Rom.hpp"
|
||||
#include "RomHeader.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
|
||||
@@ -30,10 +31,14 @@ bool CoreHasRomHeaderAndSettingsCached(std::filesystem::path file);
|
||||
|
||||
// returns whether retrieving the rom header & settings
|
||||
// for given filename succeeds
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader& header, CoreRomSettings& settings);
|
||||
bool CoreGetCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType& type, CoreRomHeader& header, CoreRomSettings& settings);
|
||||
|
||||
// returns whether adding cached rom header & settings
|
||||
// for given filename succeeds
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomHeader header, CoreRomSettings settings);
|
||||
bool CoreAddCachedRomHeaderAndSettings(std::filesystem::path file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
|
||||
|
||||
// returns whether clearing rom header & settings cache
|
||||
// succeeds
|
||||
bool CoreClearRomHeaderAndSettingsCache(void);
|
||||
|
||||
#endif // CORE_CACHEDROMHEADERANDSETTINGS_HPP
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "Core.hpp"
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static bool l_SetupCallbacks = false;
|
||||
static std::function<void(enum CoreDebugMessageType, std::string)> l_DebugCallbackFunc;
|
||||
static std::function<void(enum CoreDebugMessageType, std::string, std::string)> l_DebugCallbackFunc;
|
||||
|
||||
//
|
||||
// Internal Functions
|
||||
@@ -28,7 +29,20 @@ void CoreDebugCallback(void* context, int level, const char* message)
|
||||
return;
|
||||
}
|
||||
|
||||
l_DebugCallbackFunc((CoreDebugMessageType)level, std::string(message));
|
||||
std::string contextString((const char*)context);
|
||||
std::string messageString(message);
|
||||
|
||||
// convert string encoding accordingly
|
||||
if (messageString.starts_with("IS64:"))
|
||||
{
|
||||
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::EUC_JP);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageString = CoreConvertStringEncoding(message, CoreStringEncoding::Shift_JIS);
|
||||
}
|
||||
|
||||
l_DebugCallbackFunc((CoreDebugMessageType)level, contextString, messageString);
|
||||
}
|
||||
|
||||
void CoreStateCallback(void* context, m64p_core_param param, int value)
|
||||
@@ -40,7 +54,7 @@ void CoreStateCallback(void* context, m64p_core_param param, int value)
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string)> debugCallbackFunc)
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc)
|
||||
{
|
||||
l_DebugCallbackFunc = debugCallbackFunc;
|
||||
l_SetupCallbacks = true;
|
||||
|
||||
@@ -32,6 +32,6 @@ enum class CoreDebugMessageType
|
||||
Verbose = 5
|
||||
};
|
||||
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string)> debugCallbackFunc);
|
||||
bool CoreSetupCallbacks(std::function<void(enum CoreDebugMessageType, std::string, std::string)> debugCallbackFunc);
|
||||
|
||||
#endif // CORE_CALLBACK_HPP
|
||||
|
||||
@@ -717,6 +717,7 @@ bool CoreUpdateCheat(CoreCheat oldCheat, CoreCheat newCheat)
|
||||
CoreRomHeader romHeader;
|
||||
CoreRomSettings romSettings;
|
||||
std::filesystem::path cheatFilePath;
|
||||
CoreCheatOption cheatOption;
|
||||
|
||||
if (!CoreGetCurrentRomHeader(romHeader) ||
|
||||
!CoreGetCurrentRomSettings(romSettings))
|
||||
@@ -726,6 +727,23 @@ bool CoreUpdateCheat(CoreCheat oldCheat, CoreCheat newCheat)
|
||||
|
||||
cheatFilePath = get_user_cheat_file_path(romHeader, romSettings);
|
||||
|
||||
// copy over cheat settings when name has changed
|
||||
if (oldCheat.Name != newCheat.Name)
|
||||
{
|
||||
CoreEnableCheat(newCheat, CoreIsCheatEnabled(oldCheat));
|
||||
|
||||
// only set option to new cheat when
|
||||
// retrieving from old one succeeds
|
||||
if (CoreGetCheatOption(oldCheat, cheatOption))
|
||||
{
|
||||
CoreSetCheatOption(newCheat, cheatOption);
|
||||
}
|
||||
|
||||
// reset old cheat settings
|
||||
CoreEnableCheat(oldCheat, false);
|
||||
CoreResetCheatOption(oldCheat);
|
||||
}
|
||||
|
||||
// try to find old cheat in user cheats,
|
||||
// when it isnt found, it's most likely a system cheat
|
||||
auto iter = find_user_cheat_using_name(oldCheat.Name);
|
||||
@@ -892,6 +910,29 @@ bool CoreGetCheatOption(CoreCheat cheat, CoreCheatOption& option)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CoreResetCheatOption(CoreCheat cheat)
|
||||
{
|
||||
CoreRomSettings romSettings;
|
||||
std::string settingSection;
|
||||
std::string settingKey;
|
||||
|
||||
if (!cheat.HasOptions)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CoreGetCurrentRomSettings(romSettings))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
settingSection = romSettings.MD5 + " Cheats";
|
||||
settingKey = "Cheat \"" + cheat.Name + "\" Option";
|
||||
|
||||
CoreSettingsSetValue(settingSection, settingKey, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreApplyCheats(void)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
@@ -136,6 +136,9 @@ bool CoreSetCheatOption(CoreCheat cheat, CoreCheatOption option);
|
||||
// attempts to retrieve the currently's set cheat's option
|
||||
bool CoreGetCheatOption(CoreCheat cheat, CoreCheatOption& option);
|
||||
|
||||
// attempts to reset the cheat option
|
||||
bool CoreResetCheatOption(CoreCheat cheat);
|
||||
|
||||
// attempts to apply the enabled cheats to the currently opened ROM
|
||||
bool CoreApplyCheats(void);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define CORE_VERSION "${GIT_VERSION}"
|
||||
|
||||
#ifndef PORTABLE_INSTALL
|
||||
#define CORE_INSTAlL_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
#define CORE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
|
||||
#endif // PORTABLE_INSTALL
|
||||
|
||||
#endif // CORE_CONFIG_HPP
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
|
||||
#include "Error.hpp"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include <iconv.h>
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encoding)
|
||||
{
|
||||
std::string error;
|
||||
std::string encodingString;
|
||||
|
||||
iconv_t cd;
|
||||
|
||||
char inputBuf[256] = {0};
|
||||
char outputBuf[256] = {0};
|
||||
|
||||
char* inputBufPtr = (char*)str.c_str();
|
||||
char* outputBufPtr = outputBuf;
|
||||
|
||||
size_t inputBufSize = str.size();
|
||||
size_t outputBufSize = sizeof(outputBuf);
|
||||
|
||||
if (encoding == CoreStringEncoding::EUC_JP)
|
||||
{
|
||||
encodingString = "EUC-JP";
|
||||
}
|
||||
else
|
||||
{
|
||||
encodingString = "Shift_JIS";
|
||||
}
|
||||
|
||||
cd = iconv_open("UTF-8//TRANSLIT//IGNORE", encodingString.c_str());
|
||||
if (cd == (iconv_t)-1)
|
||||
{
|
||||
error = "CoreConvertStringEncoding Failed: ";
|
||||
error += "iconv_open Failed: ";
|
||||
error += errno;
|
||||
CoreSetError(error);
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t ret = iconv(cd, &inputBufPtr, &inputBufSize, &outputBufPtr, &outputBufSize);
|
||||
if (ret == -1)
|
||||
{
|
||||
error = "CoreConvertStringEncoding Failed: ";
|
||||
error += "iconv Failed: ";
|
||||
error += errno;
|
||||
CoreSetError(error);
|
||||
|
||||
// reset iconv
|
||||
iconv(cd, nullptr, nullptr, nullptr, nullptr);
|
||||
iconv_close(cd);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// reset iconv
|
||||
iconv(cd, nullptr, nullptr, nullptr, nullptr);
|
||||
iconv_close(cd);
|
||||
|
||||
return std::string(outputBuf);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_CONVERTSTRINGENCODING_HPP
|
||||
#define CORE_CONVERTSTRINGENCODING_HPP
|
||||
#ifdef CORE_INTERNAL
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class CoreStringEncoding : int
|
||||
{
|
||||
EUC_JP = 0,
|
||||
Shift_JIS = 1
|
||||
};
|
||||
|
||||
// attempts to convert the string (which uses encoding) to UTF-8,
|
||||
// on failure, returns original string
|
||||
std::string CoreConvertStringEncoding(std::string str, CoreStringEncoding encoding);
|
||||
|
||||
#endif // CORE_INTERNAL
|
||||
#endif // CORE_CONVERTSTRINGENCODING_HPP
|
||||
@@ -9,35 +9,40 @@
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "Core.hpp"
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
#include "DiscordRpc.hpp"
|
||||
#endif // DISCORD_RPC
|
||||
#include "osal/osal_dynlib.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "m64p/api/version.h"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static osal_dynlib_lib_handle l_CoreLibHandle;
|
||||
static char l_CoreContextString[20];
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
std::string find_core_lib(void)
|
||||
std::filesystem::path find_core_lib(void)
|
||||
{
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(CoreGetCoreDirectory()))
|
||||
{
|
||||
std::string path = entry.path().string();
|
||||
if (path.ends_with(OSAL_DYNLIB_LIB_EXT_STR))
|
||||
std::filesystem::path path = entry.path();
|
||||
if (path.has_extension() &&
|
||||
path.extension() == OSAL_DYNLIB_LIB_EXT_STR)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return std::filesystem::path();
|
||||
}
|
||||
|
||||
bool config_override_user_dirs(void)
|
||||
@@ -74,11 +79,14 @@ bool config_override_user_dirs(void)
|
||||
|
||||
bool CoreInit(void)
|
||||
{
|
||||
std::string error;
|
||||
std::string core_file;
|
||||
m64p_error m64p_ret;
|
||||
std::string error;
|
||||
std::filesystem::path core_file;
|
||||
m64p_error m64p_ret;
|
||||
bool ret = false;
|
||||
|
||||
// initialize context string
|
||||
std::strcpy(l_CoreContextString, "[CORE] ");
|
||||
|
||||
core_file = find_core_lib();
|
||||
if (core_file.empty())
|
||||
{
|
||||
@@ -87,7 +95,7 @@ bool CoreInit(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
l_CoreLibHandle = osal_dynlib_open(core_file.c_str());
|
||||
l_CoreLibHandle = osal_dynlib_open(core_file);
|
||||
if (l_CoreLibHandle == nullptr)
|
||||
{
|
||||
error = "osal_dynlib_open Failed: ";
|
||||
@@ -112,7 +120,7 @@ bool CoreInit(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
m64p_ret = m64p::Core.Startup(FRONTEND_API_VERSION, CoreGetUserConfigDirectory().string().c_str(), CoreGetSharedDataDirectory().string().c_str(), nullptr, CoreDebugCallback, nullptr, CoreStateCallback);
|
||||
m64p_ret = m64p::Core.Startup(FRONTEND_API_VERSION, CoreGetUserConfigDirectory().string().c_str(), CoreGetSharedDataDirectory().string().c_str(), (void*)l_CoreContextString, CoreDebugCallback, nullptr, CoreStateCallback);
|
||||
if (m64p_ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreInit M64P::Core.Startup() Failed: ";
|
||||
@@ -153,6 +161,11 @@ bool CoreInit(void)
|
||||
|
||||
CoreReadRomHeaderAndSettingsCache();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcInit();
|
||||
CoreDiscordRpcUpdate(false);
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -186,6 +199,10 @@ void CoreShutdown(void)
|
||||
|
||||
CoreSaveRomHeaderAndSettingsCache();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcShutdown();
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
m64p::Core.Unhook();
|
||||
m64p::Config.Unhook();
|
||||
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
#include "RomHeader.hpp"
|
||||
#include "Callback.hpp"
|
||||
#include "Plugins.hpp"
|
||||
#include "Version.hpp"
|
||||
#include "Cheats.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Unzip.hpp"
|
||||
#include "Video.hpp"
|
||||
#include "Key.hpp"
|
||||
#include "Rom.hpp"
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Directories.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Core.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
@@ -123,7 +123,7 @@ std::filesystem::path CoreGetCoreDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Core";
|
||||
#else // Not Portable
|
||||
directory = CORE_INSTAlL_PREFIX;
|
||||
directory = CORE_INSTALL_PREFIX;
|
||||
directory += "/lib/RMG/Core";
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
@@ -135,7 +135,7 @@ std::filesystem::path CoreGetPluginDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Plugin";
|
||||
#else // Not Portable
|
||||
directory = CORE_INSTAlL_PREFIX;
|
||||
directory = CORE_INSTALL_PREFIX;
|
||||
directory += "/lib/RMG/Plugin";
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
@@ -180,7 +180,7 @@ std::filesystem::path CoreGetDefaultSaveDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Save/Game";
|
||||
#else // Not Portable
|
||||
directory = CoreGetUserDataDirectory();
|
||||
directory = CoreGetDefaultUserDataDirectory();
|
||||
directory += "/Save/Game";
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
@@ -192,7 +192,7 @@ std::filesystem::path CoreGetDefaultSaveStateDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Save/State";
|
||||
#else // Not Portable
|
||||
directory = CoreGetUserDataDirectory();
|
||||
directory = CoreGetDefaultUserDataDirectory();
|
||||
directory += "/Save/State";
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
@@ -233,7 +233,7 @@ std::filesystem::path CoreGetSharedDataDirectory(void)
|
||||
#ifdef PORTABLE_INSTALL
|
||||
directory = "Data";
|
||||
#else // Not Portable
|
||||
directory = CORE_INSTAlL_PREFIX;
|
||||
directory = CORE_INSTALL_PREFIX;
|
||||
directory += "/share/RMG";
|
||||
#endif // PORTABLE_INSTALL
|
||||
return directory;
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Settings/Settings.hpp"
|
||||
#include "DiscordRpc.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
#include "RomHeader.hpp"
|
||||
|
||||
#include <../3rdParty/discord-rpc/include/discord_rpc.h>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
void CoreDiscordRpcInit(void)
|
||||
{
|
||||
if (!CoreSettingsGetBoolValue(SettingsID::GUI_DiscordRpc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Discord_Initialize("801450412280119356", nullptr, 0, "");
|
||||
}
|
||||
|
||||
void CoreDiscordRpcShutdown(void)
|
||||
{
|
||||
Discord_Shutdown();
|
||||
}
|
||||
|
||||
void CoreDiscordRpcUpdate(bool inGame)
|
||||
{
|
||||
std::string smallImageKey;
|
||||
std::string largeImageKey;
|
||||
std::string details;
|
||||
|
||||
if (!CoreSettingsGetBoolValue(SettingsID::GUI_DiscordRpc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (inGame)
|
||||
{
|
||||
CoreRomSettings romSettings;
|
||||
CoreRomHeader romHeader;
|
||||
|
||||
// make sure we retrieve the rom settings & header
|
||||
if (!CoreGetCurrentRomSettings(romSettings) ||
|
||||
!CoreGetCurrentRomHeader(romHeader))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
smallImageKey = "rmg-icon";
|
||||
largeImageKey = romHeader.Name;
|
||||
details = romSettings.GoodName;
|
||||
|
||||
// replace ' ' with '_' and replace '&' with '_'
|
||||
// also tolower the entire string
|
||||
std::replace(largeImageKey.begin(),largeImageKey.end(),' ','_');
|
||||
std::replace(largeImageKey.begin(),largeImageKey.end(),'&','_');
|
||||
std::transform(largeImageKey.begin(), largeImageKey.end(), largeImageKey.begin(), ::tolower);
|
||||
}
|
||||
else
|
||||
{
|
||||
largeImageKey = "rmg-icon";
|
||||
details = "Not in-game";
|
||||
}
|
||||
|
||||
DiscordRichPresence discordPresence;
|
||||
memset(&discordPresence, 0, sizeof(discordPresence));
|
||||
discordPresence.smallImageKey = smallImageKey.c_str();
|
||||
discordPresence.largeImageKey = largeImageKey.c_str();
|
||||
discordPresence.largeImageText = "Rosalie's Mupen GUI";
|
||||
discordPresence.details = details.c_str();
|
||||
discordPresence.startTimestamp = time(nullptr);
|
||||
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_DISCORDRPC_HPP
|
||||
#define CORE_DISCORDRPC_HPP
|
||||
|
||||
// initializes the discord rpc library
|
||||
void CoreDiscordRpcInit(void);
|
||||
|
||||
// shuts down the discord rpc library
|
||||
void CoreDiscordRpcShutdown(void);
|
||||
|
||||
// updates the state of the discord rpc library
|
||||
void CoreDiscordRpcUpdate(bool inGame);
|
||||
|
||||
#endif // CORE_DISCORDRPC_HPP
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "Cheats.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Rom.hpp"
|
||||
#ifdef DISCORD_RPC
|
||||
#include "DiscordRpc.hpp"
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
@@ -123,8 +126,11 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
|
||||
return false;
|
||||
}
|
||||
|
||||
// set disk file in media loader
|
||||
CoreMediaLoaderSetDiskFile(n64ddrom);
|
||||
// set disk file in media loader when ROM is a cartridge
|
||||
if (CoreGetRomType() == CoreRomType::Cartridge)
|
||||
{
|
||||
CoreMediaLoaderSetDiskFile(n64ddrom);
|
||||
}
|
||||
|
||||
// apply core settings overlay
|
||||
apply_coresettings_overlay();
|
||||
@@ -132,6 +138,10 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
|
||||
// apply game core settings overrides
|
||||
apply_game_coresettings_overlay();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcUpdate(true);
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_EXECUTE, 0, nullptr);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
@@ -147,6 +157,13 @@ bool CoreStartEmulation(std::filesystem::path n64rom, std::filesystem::path n64d
|
||||
// restore plugin settings
|
||||
CoreApplyPluginSettings();
|
||||
|
||||
// reset media loader state
|
||||
CoreResetMediaLoader();
|
||||
|
||||
#ifdef DISCORD_RPC
|
||||
CoreDiscordRpcUpdate(false);
|
||||
#endif // DISCORD_RPC
|
||||
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,12 @@ bool CoreSetupMediaLoader(void)
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path ddRom)
|
||||
void CoreResetMediaLoader(void)
|
||||
{
|
||||
l_DdDiskFile = ddRom;
|
||||
l_DdRomFile = "";
|
||||
}
|
||||
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path disk)
|
||||
{
|
||||
l_DdDiskFile = disk;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
// sets up the medialoader
|
||||
bool CoreSetupMediaLoader(void);
|
||||
|
||||
// resets media loader state
|
||||
void CoreResetMediaLoader(void);
|
||||
|
||||
// sets the media loader disk file
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path ddRom);
|
||||
void CoreMediaLoaderSetDiskFile(std::filesystem::path disk);
|
||||
|
||||
#endif // CORE_MEDIALOADER_HPP
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "Plugins.hpp"
|
||||
#include "Callback.hpp"
|
||||
#include "Directories.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Emulation.hpp"
|
||||
@@ -21,6 +23,7 @@
|
||||
#include "m64p/Api.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstring>
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
@@ -28,6 +31,7 @@
|
||||
|
||||
static m64p::PluginApi l_Plugins[(int)CorePluginType::Input];
|
||||
static std::string l_PluginFiles[(int)CorePluginType::Input];
|
||||
static char l_PluginContext[(int)CorePluginType::Input][20];
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
@@ -101,6 +105,32 @@ std::string get_plugin_type_name(CorePluginType type)
|
||||
return name + " Plugin";
|
||||
}
|
||||
|
||||
std::string get_plugin_context_name(CorePluginType type)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
name = "[UNKNOWN]";
|
||||
break;
|
||||
case CorePluginType::Rsp:
|
||||
name = "[RSP] ";
|
||||
break;
|
||||
case CorePluginType::Gfx:
|
||||
name = "[GFX] ";
|
||||
break;
|
||||
case CorePluginType::Audio:
|
||||
name = "[AUDIO] ";
|
||||
break;
|
||||
case CorePluginType::Input:
|
||||
name = "[INPUT] ";
|
||||
break;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool apply_plugin_settings(std::string pluginSettings[4])
|
||||
{
|
||||
std::string error;
|
||||
@@ -121,6 +151,9 @@ bool apply_plugin_settings(std::string pluginSettings[4])
|
||||
|
||||
pluginType = (CorePluginType)(i + 1);
|
||||
|
||||
// copy context string to a c string using strcpy
|
||||
std::strcpy(l_PluginContext[(int)pluginType], get_plugin_context_name(pluginType).c_str());
|
||||
|
||||
if (settingValue != l_PluginFiles[i])
|
||||
{
|
||||
plugin = &l_Plugins[i];
|
||||
@@ -179,7 +212,7 @@ bool apply_plugin_settings(std::string pluginSettings[4])
|
||||
}
|
||||
|
||||
// attempt to start plugin
|
||||
ret = plugin->Startup(m64p::Core.GetHandle(), nullptr, nullptr);
|
||||
ret = plugin->Startup(m64p::Core.GetHandle(), (void*)l_PluginContext[(int)pluginType], CoreDebugCallback);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "apply_plugin_settings (";
|
||||
|
||||
@@ -8,15 +8,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Rom.hpp"
|
||||
#include "Directories.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "MediaLoader.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "RomSettings.hpp"
|
||||
#include "Cheats.hpp"
|
||||
#include "osal/osal_files.hpp"
|
||||
|
||||
#include <unzip.h>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
//
|
||||
// Local Defines
|
||||
@@ -28,31 +32,136 @@
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static bool l_HasRomOpen = false;
|
||||
static bool l_HasRomOpen = false;
|
||||
static bool l_HasDisk = false;
|
||||
static bool l_HasExtractedDisk = false;
|
||||
static std::filesystem::path l_ExtractedDiskPath;
|
||||
|
||||
//
|
||||
// Local Functions
|
||||
//
|
||||
|
||||
static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
static std::string to_lower_str(std::string str)
|
||||
{
|
||||
std::string resultString = str;
|
||||
|
||||
std::transform(resultString.begin(), resultString.end(), resultString.begin(),
|
||||
[](unsigned char c)
|
||||
{
|
||||
return std::tolower(c);
|
||||
}
|
||||
);
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
static voidpf zlib_filefunc_open(voidpf opaque, const void* filename, int mode)
|
||||
{
|
||||
std::filesystem::path path = *(std::filesystem::path*)filename;
|
||||
|
||||
// we need a static filestream
|
||||
static std::ifstream fileStream;
|
||||
|
||||
// attempt to open file
|
||||
fileStream.open(path, std::ios::binary);
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (voidpf)&fileStream;
|
||||
}
|
||||
|
||||
static uLong zlib_filefunc_read(voidpf opaque, voidpf stream, void* buf, uLong size)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
fileStream->read((char*)buf, size);
|
||||
return fileStream->fail() ? 0 : size;
|
||||
}
|
||||
|
||||
static ZPOS64_T zlib_filefunc_tell(voidpf opaque, voidpf stream)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
return fileStream->tellg();
|
||||
}
|
||||
|
||||
static long zlib_filefunc_seek(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
std::ios_base::seekdir seekOrigin;
|
||||
|
||||
switch (origin)
|
||||
{
|
||||
default:
|
||||
return 0;
|
||||
case ZLIB_FILEFUNC_SEEK_CUR:
|
||||
seekOrigin = std::ios::cur;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END:
|
||||
seekOrigin = std::ios::end;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET:
|
||||
seekOrigin = std::ios::beg;
|
||||
break;
|
||||
}
|
||||
|
||||
fileStream->seekg(offset, seekOrigin);
|
||||
return fileStream->fail() ? -1 : 0;
|
||||
}
|
||||
|
||||
static int zlib_filefunc_close(voidpf opaque, voidpf stream)
|
||||
{
|
||||
std::ifstream* fileStream = (std::ifstream*)stream;
|
||||
fileStream->close();
|
||||
return fileStream->fail() ? -1 : 0;
|
||||
}
|
||||
|
||||
static int zlib_filefunc_testerror(voidpf opaque, voidpf stream)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
static bool read_zip_file(std::filesystem::path file, std::filesystem::path* extractedFileName, bool* isDisk, char** buf, int* size)
|
||||
{
|
||||
std::string error;
|
||||
std::fstream fileStream;
|
||||
int fileStreamLen;
|
||||
char* fileStreamBuf;
|
||||
|
||||
unzFile zipFile;
|
||||
unz_global_info zipInfo;
|
||||
unzFile zipFile;
|
||||
unz_global_info64 zipInfo;
|
||||
|
||||
zipFile = unzOpen(file.string().c_str());
|
||||
zlib_filefunc64_def filefuncs;
|
||||
filefuncs.zopen64_file = zlib_filefunc_open;
|
||||
filefuncs.zread_file = zlib_filefunc_read;
|
||||
filefuncs.zwrite_file = nullptr;
|
||||
filefuncs.ztell64_file = zlib_filefunc_tell;
|
||||
filefuncs.zseek64_file = zlib_filefunc_seek;
|
||||
filefuncs.zclose_file = zlib_filefunc_close;
|
||||
filefuncs.zerror_file = zlib_filefunc_testerror;
|
||||
filefuncs.opaque = nullptr;
|
||||
|
||||
zipFile = unzOpen2_64((const void*)&file, &filefuncs);
|
||||
if (zipFile == nullptr)
|
||||
{
|
||||
error = "read_zip_file: unzOpen Failed!";
|
||||
if (errno == 0)
|
||||
{
|
||||
error = "read_zip_file: unzOpen Failed!";
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "read_zip_file: unzOpen Failed: ";
|
||||
error += "failed to open file: ";
|
||||
error += strerror(errno);
|
||||
error += " (";
|
||||
error += std::to_string(errno);
|
||||
error += ")";
|
||||
}
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
|
||||
if (unzGetGlobalInfo64(zipFile, &zipInfo) != UNZ_OK)
|
||||
{
|
||||
error = "read_zip_file: unzGetGlobalInfo Failed!";
|
||||
CoreSetError(error);
|
||||
@@ -74,9 +183,13 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
// make sure file has supported file format,
|
||||
// if it does, read it in memory
|
||||
std::filesystem::path fileNamePath(fileName);
|
||||
if (fileNamePath.extension() == ".z64" ||
|
||||
fileNamePath.extension() == ".v64" ||
|
||||
fileNamePath.extension() == ".n64")
|
||||
std::string fileExtension = fileNamePath.has_extension() ? fileNamePath.extension().string() : "";
|
||||
fileExtension = to_lower_str(fileExtension);
|
||||
if (fileExtension == ".z64" ||
|
||||
fileExtension == ".v64" ||
|
||||
fileExtension == ".n64" ||
|
||||
fileExtension == ".ndd" ||
|
||||
fileExtension == ".d64")
|
||||
{
|
||||
char* buffer;
|
||||
char* outBuffer;
|
||||
@@ -148,8 +261,10 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
}
|
||||
} while (bytes_read > 0);
|
||||
|
||||
*size = total_bytes_read;
|
||||
*buf = outBuffer;
|
||||
*size = total_bytes_read;
|
||||
*buf = outBuffer;
|
||||
*extractedFileName = fileNamePath;
|
||||
*isDisk = (fileExtension == ".ndd" || fileExtension == ".d64");
|
||||
unzCloseCurrentFile(zipFile);
|
||||
unzClose(zipFile);
|
||||
free(buffer);
|
||||
@@ -180,17 +295,21 @@ static bool read_zip_file(std::filesystem::path file, char** buf, int* size)
|
||||
|
||||
static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
|
||||
{
|
||||
std::string error;
|
||||
std::fstream fileStream;
|
||||
int fileStreamLen;
|
||||
char* fileStreamBuf;
|
||||
std::string error;
|
||||
std::ifstream fileStream;
|
||||
int fileStreamLen;
|
||||
char* fileStreamBuf;
|
||||
|
||||
// attempt to open file
|
||||
fileStream.open(file);
|
||||
fileStream.open(file, std::ios::binary);
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
error = "read_raw_file Failed: ";
|
||||
error += "failed to open file!";
|
||||
error += "failed to open file: ";
|
||||
error += strerror(errno);
|
||||
error += " (";
|
||||
error += std::to_string(errno);
|
||||
error += ")";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
@@ -222,6 +341,32 @@ static bool read_raw_file(std::filesystem::path file, char** buf, int* size)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_file(std::filesystem::path file, char* buf, int size)
|
||||
{
|
||||
std::string error;
|
||||
std::ofstream fileStream;
|
||||
|
||||
// attempt to open file
|
||||
fileStream.open(file, std::ios::binary);
|
||||
if (!fileStream.is_open())
|
||||
{
|
||||
error = "write_file Failed: ";
|
||||
error += "failed to open file: ";
|
||||
error += strerror(errno);
|
||||
error += " (";
|
||||
error += std::to_string(errno);
|
||||
error += ")";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// write buffer to file
|
||||
fileStream.write(buf, size);
|
||||
|
||||
fileStream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
@@ -230,8 +375,9 @@ bool CoreOpenRom(std::filesystem::path file)
|
||||
{
|
||||
std::string error;
|
||||
m64p_error ret;
|
||||
char* buf;
|
||||
int buf_size;
|
||||
char* buf = nullptr;
|
||||
int buf_size = 0;
|
||||
std::string file_extension;
|
||||
|
||||
if (!m64p::Core.IsHooked())
|
||||
{
|
||||
@@ -246,12 +392,67 @@ bool CoreOpenRom(std::filesystem::path file)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.has_extension() && file.extension() == ".zip")
|
||||
file_extension = file.has_extension() ? file.extension().string() : "";
|
||||
file_extension = to_lower_str(file_extension);
|
||||
|
||||
if (file_extension == ".zip")
|
||||
{
|
||||
if (!read_zip_file(file, &buf, &buf_size))
|
||||
std::filesystem::path extracted_file;
|
||||
bool is_disk = false;
|
||||
|
||||
if (!read_zip_file(file, &extracted_file, &is_disk, &buf, &buf_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_disk)
|
||||
{
|
||||
std::filesystem::path disk_file;
|
||||
disk_file = CoreGetUserCacheDirectory();
|
||||
disk_file += "/extracted_disks/";
|
||||
disk_file += extracted_file.filename();
|
||||
|
||||
// attempt to create extraction directory
|
||||
try
|
||||
{
|
||||
if (!std::filesystem::exists(disk_file.parent_path()))
|
||||
{
|
||||
if (!std::filesystem::create_directory(disk_file.parent_path()))
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = "CoreOpenRom Failed: ";
|
||||
error += "Failed to create \"";
|
||||
error += disk_file.parent_path().string();
|
||||
error += "\"!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// attempt to write temporary file
|
||||
if (!write_file(disk_file, buf, buf_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CoreMediaLoaderSetDiskFile(disk_file);
|
||||
|
||||
l_ExtractedDiskPath = disk_file;
|
||||
}
|
||||
|
||||
l_HasDisk = is_disk;
|
||||
l_HasExtractedDisk = is_disk;
|
||||
}
|
||||
else if (file_extension == ".d64" ||
|
||||
file_extension == ".ndd")
|
||||
{
|
||||
CoreMediaLoaderSetDiskFile(file);
|
||||
l_HasDisk = true;
|
||||
l_HasExtractedDisk = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -259,17 +460,29 @@ bool CoreOpenRom(std::filesystem::path file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
l_HasDisk = false;
|
||||
l_HasExtractedDisk = false;
|
||||
}
|
||||
|
||||
if (l_HasDisk)
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_DISK_OPEN, 0, nullptr);
|
||||
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_DISK_OPEN) Failed: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_OPEN, buf_size, buf);
|
||||
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
|
||||
free(buf);
|
||||
}
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_OPEN, buf_size, buf);
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreOpenRom: m64p::Core.DoCommand(M64CMD_ROM_OPEN) Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
l_HasRomOpen = (ret == M64ERR_SUCCESS);
|
||||
|
||||
if (l_HasRomOpen)
|
||||
@@ -288,6 +501,11 @@ bool CoreHasRomOpen(void)
|
||||
return l_HasRomOpen;
|
||||
}
|
||||
|
||||
CoreRomType CoreGetRomType(void)
|
||||
{
|
||||
return l_HasDisk ? CoreRomType::Disk : CoreRomType::Cartridge;
|
||||
}
|
||||
|
||||
bool CoreCloseRom(void)
|
||||
{
|
||||
std::string error;
|
||||
@@ -311,10 +529,19 @@ bool CoreCloseRom(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_CLOSE, 0, nullptr);
|
||||
if (l_HasDisk)
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_DISK_CLOSE, 0, nullptr);
|
||||
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_DISK_CLOSE) Failed: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = m64p::Core.DoCommand(M64CMD_ROM_CLOSE, 0, nullptr);
|
||||
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_ROM_CLOSE) Failed: ";
|
||||
}
|
||||
|
||||
if (ret != M64ERR_SUCCESS)
|
||||
{
|
||||
error = "CoreCloseRom: m64p::Core.DoCommand(M64CMD_ROM_CLOSE) Failed: ";
|
||||
error += m64p::Core.ErrorMessage(ret);
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
@@ -323,6 +550,32 @@ bool CoreCloseRom(void)
|
||||
// clear default ROM settings
|
||||
CoreClearCurrentDefaultRomSettings();
|
||||
|
||||
// if removing the temporary extracted disk file
|
||||
// fails, then we shouldn't break the state of
|
||||
// whether we currently have an open ROM/disk,
|
||||
// so we can safely say the ROM/disk isn't open
|
||||
// anymore here
|
||||
l_HasRomOpen = false;
|
||||
|
||||
// attempt to clean temporary extracted disk file
|
||||
if (l_HasExtractedDisk)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!std::filesystem::remove(l_ExtractedDiskPath))
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = "CoreCloseRom: Failed to remove \"";
|
||||
error += l_ExtractedDiskPath.string();
|
||||
error += "\"!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,21 @@
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
enum class CoreRomType
|
||||
{
|
||||
Cartridge = 0,
|
||||
Disk = 1
|
||||
};
|
||||
|
||||
// opens the given file as ROM
|
||||
bool CoreOpenRom(std::filesystem::path file);
|
||||
|
||||
// returns whether core has a ROM opened
|
||||
bool CoreHasRomOpen(void);
|
||||
|
||||
// returns the opened ROM's type
|
||||
CoreRomType CoreGetRomType(void);
|
||||
|
||||
// closes ROM
|
||||
bool CoreCloseRom(void);
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#define CORE_INTERNAL
|
||||
#include "RomHeader.hpp"
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
#include "Emulation.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "Error.hpp"
|
||||
@@ -46,6 +48,7 @@ bool CoreGetCurrentRomHeader(CoreRomHeader& header)
|
||||
header.CRC1 = ntohl(m64p_header.CRC1);
|
||||
header.CRC2 = ntohl(m64p_header.CRC2);
|
||||
header.CountryCode = m64p_header.Country_code;
|
||||
header.Name = std::string((char*)m64p_header.Name);
|
||||
header.Name = CoreConvertStringEncoding((char*)m64p_header.Name, CoreStringEncoding::Shift_JIS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define CORE_INTERNAL
|
||||
#include "RomSettings.hpp"
|
||||
#include "Emulation.hpp"
|
||||
#include "RomHeader.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "Rom.hpp"
|
||||
|
||||
#include "Settings/Settings.hpp"
|
||||
#include "ConvertStringEncoding.hpp"
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
@@ -46,7 +49,7 @@ bool CoreGetCurrentRomSettings(CoreRomSettings& settings)
|
||||
return false;
|
||||
}
|
||||
|
||||
settings.GoodName = std::string(m64p_settings.goodname);
|
||||
settings.GoodName = CoreConvertStringEncoding(m64p_settings.goodname, CoreStringEncoding::Shift_JIS);
|
||||
settings.MD5 = std::string(m64p_settings.MD5);
|
||||
settings.SaveType = m64p_settings.savetype;
|
||||
settings.DisableExtraMem = m64p_settings.disableextramem;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "Settings.hpp"
|
||||
|
||||
#include "Directories.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "Version.hpp"
|
||||
#include "m64p/Api.hpp"
|
||||
#include "Error.hpp"
|
||||
#include "m64p/api/m64p_types.h"
|
||||
@@ -140,9 +140,6 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::GUI_SettingsDialogHeight:
|
||||
setting = {SETTING_SECTION_GUI, "SettingsDialogHeight", 0};
|
||||
break;
|
||||
case SettingsID::GUI_AllowManualResizing:
|
||||
setting = {SETTING_SECTION_GUI, "AllowManualResizing", true};
|
||||
break;
|
||||
case SettingsID::GUI_HideCursorInEmulation:
|
||||
setting = {SETTING_SECTION_GUI, "HideCursorInEmulation", false};
|
||||
break;
|
||||
@@ -161,8 +158,44 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::GUI_AutomaticFullscreen:
|
||||
setting = {SETTING_SECTION_GUI, "AutomaticFullscreen", false};
|
||||
break;
|
||||
case SettingsID::GUI_ShowVerboseLogMessages:
|
||||
setting = {SETTING_SECTION_GUI, "ShowVerboseLogMessages", false};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayEnabled:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayEnabled", true};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayLocation:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayLocation", 0};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayPaddingX:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayPaddingX", 20};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayPaddingY:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayPaddingY", 20};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayOpacity:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayOpacity", 0.5f};
|
||||
break;
|
||||
case SettingsID::GUI_OnScreenDisplayDuration:
|
||||
setting = {SETTING_SECTION_GUI, "OnScreenDisplayDuration", 3};
|
||||
break;
|
||||
case SettingsID::GUI_Toolbar:
|
||||
setting = {SETTING_SECTION_GUI, "Toolbar", true};
|
||||
break;
|
||||
case SettingsID::GUI_StatusBar:
|
||||
setting = {SETTING_SECTION_GUI, "StatusBar", true};
|
||||
break;
|
||||
case SettingsID::GUI_Theme:
|
||||
setting = {SETTING_SECTION_GUI, "Theme", "Native"};
|
||||
break;
|
||||
case SettingsID::GUI_CheckForUpdates:
|
||||
setting = {SETTING_SECTION_GUI, "CheckForUpdates", true};
|
||||
break;
|
||||
case SettingsID::GUI_DiscordRpc:
|
||||
setting = {SETTING_SECTION_GUI, "DiscordRpc", true};
|
||||
break;
|
||||
case SettingsID::GUI_Version:
|
||||
setting = {SETTING_SECTION_GUI, "Version", CORE_VERSION};
|
||||
setting = {SETTING_SECTION_GUI, "Version", CoreGetVersion()};
|
||||
break;
|
||||
|
||||
case SettingsID::Core_GFX_Plugin:
|
||||
@@ -353,17 +386,14 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::KeyBinding_RemoveDuplicates:
|
||||
setting = {SETTING_SECTION_KEYBIND, "RemoveDuplicates", true};
|
||||
break;
|
||||
case SettingsID::KeyBinding_OpenROM:
|
||||
setting = {SETTING_SECTION_KEYBIND, "OpenROM", "Ctrl+O"};
|
||||
case SettingsID::KeyBinding_StartROM:
|
||||
setting = {SETTING_SECTION_KEYBIND, "StartROM", "Ctrl+O"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_OpenCombo:
|
||||
setting = {SETTING_SECTION_KEYBIND, "OpenCombo", "Ctrl+Shift+O"};
|
||||
case SettingsID::KeyBinding_StartCombo:
|
||||
setting = {SETTING_SECTION_KEYBIND, "StartCombo", "Ctrl+Shift+O"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_StartEmulation:
|
||||
setting = {SETTING_SECTION_KEYBIND, "StartEmulation", "F11"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_EndEmulation:
|
||||
setting = {SETTING_SECTION_KEYBIND, "EndEmulation", "F12"};
|
||||
case SettingsID::KeyBinding_Shutdown:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Shutdown", "F12"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_RefreshROMList:
|
||||
setting = {SETTING_SECTION_KEYBIND, "RefreshROMList", "F5"};
|
||||
@@ -380,15 +410,12 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::KeyBinding_Resume:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Resume", "F2"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_GenerateBitmap:
|
||||
setting = {SETTING_SECTION_KEYBIND, "GenerateBitmap", "F3"};
|
||||
case SettingsID::KeyBinding_Screenshot:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Screenshot", "F3"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_LimitFPS:
|
||||
setting = {SETTING_SECTION_KEYBIND, "LimitFPS", "F4"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SwapDisk:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SwapDisk", "Ctrl+D"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveState:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveState", "F5"};
|
||||
break;
|
||||
@@ -407,6 +434,36 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::KeyBinding_GSButton:
|
||||
setting = {SETTING_SECTION_KEYBIND, "GSButton", "F9"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot0:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot0", "Ctrl+0"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot1:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot1", "Ctrl+1"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot2:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot2", "Ctrl+2"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot3:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot3", "Ctrl+3"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot4:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot4", "Ctrl+4"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot5:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot5", "Ctrl+5"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot6:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot6", "Ctrl+6"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot7:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot7", "Ctrl+7"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot8:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot8", "Ctrl+8"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_SaveStateSlot9:
|
||||
setting = {SETTING_SECTION_KEYBIND, "SaveStateSlot9", "Ctrl+9"};
|
||||
break;
|
||||
case SettingsID::KeyBinding_Fullscreen:
|
||||
setting = {SETTING_SECTION_KEYBIND, "Fullscreen", "Alt+Return"};
|
||||
break;
|
||||
@@ -420,6 +477,9 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::RomBrowser_Geometry:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Geometry", ""};
|
||||
break;
|
||||
case SettingsID::RomBrowser_Maximized:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Maximized", false};
|
||||
break;
|
||||
case SettingsID::RomBrowser_Recursive:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Recursive", true};
|
||||
break;
|
||||
@@ -430,7 +490,28 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "Columns", std::vector<int>({0, 1, 2})};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ColumnSizes:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({0, 250, 1, 100, 2, 100})};
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ColumnSizes", std::vector<int>({-1, -1, -1})};
|
||||
break;
|
||||
case SettingsID::RomBrowser_SortAfterSearch:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "SortAfterSearch", true};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ViewMode:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ViewMode", 0};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ListViewSortSection:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ListViewSortSection", 0};
|
||||
break;
|
||||
case SettingsID::RomBrowser_ListViewSortOrder:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "ListViewSortOrder", 0};
|
||||
break;
|
||||
case SettingsID::RomBrowser_GridViewIconWidth:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "GridViewIconWidth", 180};
|
||||
break;
|
||||
case SettingsID::RomBrowser_GridViewIconHeight:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "GridViewIconHeight", 126};
|
||||
break;
|
||||
case SettingsID::RomBrowser_GridViewUniformItemSizes:
|
||||
setting = {SETTING_SECTION_ROMBROWSER, "GridViewUniformItemSizes", true};
|
||||
break;
|
||||
|
||||
case SettingsID::Settings_HasForceUsedSetOnce:
|
||||
@@ -462,7 +543,7 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
setting = {SETTING_SECTION_AUDIO, "Muted", false};
|
||||
break;
|
||||
case SettingsID::Audio_Synchronize:
|
||||
setting = {SETTING_SECTION_AUDIO, "Synchronize", true};
|
||||
setting = {SETTING_SECTION_AUDIO, "Synchronize", false};
|
||||
break;
|
||||
|
||||
case SettingsID::Input_PluggedIn:
|
||||
@@ -492,9 +573,6 @@ static l_Setting get_setting(SettingsID settingId)
|
||||
case SettingsID::Input_RemoveDuplicateMappings:
|
||||
setting = {"", "RemoveDuplicateMappings"};
|
||||
break;
|
||||
case SettingsID::Input_InvertAxis:
|
||||
setting = {"", "InvertAxis"};
|
||||
break;
|
||||
case SettingsID::Input_A_InputType:
|
||||
setting = {"", "A_InputType"};
|
||||
break;
|
||||
@@ -917,6 +995,94 @@ static bool config_option_default_set(std::string section, std::string key, m64p
|
||||
return ret == M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static bool int_list_to_string(std::vector<int> intList, std::string& string)
|
||||
{
|
||||
for (int i = 0; i < intList.size(); i++)
|
||||
{
|
||||
int num = intList.at(i);
|
||||
string += std::to_string(num);
|
||||
|
||||
// don't add seperator at end
|
||||
// of the list
|
||||
if (i < (intList.size() - 1))
|
||||
{
|
||||
string += ";";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_to_int_list(std::string string, std::vector<int>& intList)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(string);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
{
|
||||
try
|
||||
{
|
||||
intList.emplace_back(std::stoi(tmp_str));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = "string_to_int_list: std::stroi threw an exception!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_list_to_string(std::vector<std::string> stringList, std::string& string)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
for (int i = 0; i < stringList.size(); i++)
|
||||
{
|
||||
std::string str = stringList.at(i);
|
||||
|
||||
// ensure the string doesn't contain
|
||||
// the separator character
|
||||
if (str.find(";") != std::string::npos)
|
||||
{
|
||||
error = "string_list_to_string: string cannot contain ';'!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
string += str;
|
||||
|
||||
// don't add separator at end
|
||||
// of the list
|
||||
if (i < (stringList.size() - 1))
|
||||
{
|
||||
string += ";";
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool string_to_string_list(std::string string, std::vector<std::string>& stringList)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(string);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
{
|
||||
stringList.emplace_back(tmp_str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
@@ -951,7 +1117,7 @@ bool CoreSettingsUpgrade(void)
|
||||
|
||||
// we don't need to do anything
|
||||
// when the core version and the settings version match
|
||||
if (settingsVersion == CORE_VERSION)
|
||||
if (settingsVersion == CoreGetVersion())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -972,11 +1138,27 @@ bool CoreSettingsUpgrade(void)
|
||||
CoreSettingsSetValue(SettingsID::Core_ScreenshotPath, CoreGetDefaultScreenshotDirectory());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (settingsVersion == "v0.2.1" ||
|
||||
settingsVersion == "v0.2.2" ||
|
||||
settingsVersion == "v0.2.3")
|
||||
{
|
||||
// sadly when introducing the new RMG-Audio based on mupen64plus-audio-sdl
|
||||
// 1) sync audio seems to cause crackling for some users
|
||||
// 2) sync audio breaks the 'Limit FPS' option
|
||||
// so to fix those issues, we'll disable the sync audio option
|
||||
// if it's enabled
|
||||
if (CoreSettingsGetBoolValue(SettingsID::Audio_Synchronize))
|
||||
{
|
||||
CoreSettingsSetValue(SettingsID::Audio_Synchronize, false);
|
||||
}
|
||||
}
|
||||
|
||||
// save core version
|
||||
return CoreSettingsSetValue(SettingsID::GUI_Version, std::string(CORE_VERSION));
|
||||
CoreSettingsSetValue(SettingsID::GUI_Version, CoreGetVersion());
|
||||
CoreSettingsSave();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreSettingsSetupDefaults(void)
|
||||
@@ -1015,7 +1197,7 @@ bool CoreSettingsSetupDefaults(void)
|
||||
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_BOOL, &setting.DefaultValue.boolValue, setting.Description.c_str());
|
||||
break;
|
||||
case M64TYPE_FLOAT:
|
||||
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_FLOAT, &setting.DefaultValue.intValue, setting.Description.c_str());
|
||||
ret = config_option_default_set(setting.Section, setting.Key, M64TYPE_FLOAT, &setting.DefaultValue.floatValue, setting.Description.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1099,10 +1281,19 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string value)
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<int> value)
|
||||
{
|
||||
std::string value_str;
|
||||
for (const int& num : value)
|
||||
if (!int_list_to_string(value, value_str))
|
||||
{
|
||||
value_str += std::to_string(num);
|
||||
value_str += ";";
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, value_str);
|
||||
}
|
||||
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<std::string> value)
|
||||
{
|
||||
std::string value_str;
|
||||
if (!string_list_to_string(value, value_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, value_str);
|
||||
}
|
||||
@@ -1135,10 +1326,19 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::string
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<int> value)
|
||||
{
|
||||
std::string value_str;
|
||||
for (const int& num : value)
|
||||
if (!int_list_to_string(value, value_str))
|
||||
{
|
||||
value_str += std::to_string(num);
|
||||
value_str += ";";
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, section, value_str);
|
||||
}
|
||||
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<std::string> value)
|
||||
{
|
||||
std::string value_str;
|
||||
if (!string_list_to_string(value, value_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(settingId, section, value_str);
|
||||
}
|
||||
@@ -1167,10 +1367,19 @@ bool CoreSettingsSetValue(std::string section, std::string key, std::string valu
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<int> value)
|
||||
{
|
||||
std::string value_str;
|
||||
for (const int& num : value)
|
||||
if (!int_list_to_string(value, value_str))
|
||||
{
|
||||
value_str += std::to_string(num);
|
||||
value_str += ";";
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(section, key, value_str);
|
||||
}
|
||||
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<std::string> value)
|
||||
{
|
||||
std::string value_str;
|
||||
if (!string_list_to_string(value, value_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return CoreSettingsSetValue(section, key, value_str);
|
||||
}
|
||||
@@ -1243,6 +1452,12 @@ std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId)
|
||||
return CoreSettingsGetIntListValue(settingId, setting.Section);
|
||||
}
|
||||
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId)
|
||||
{
|
||||
l_Setting setting = get_setting(settingId);
|
||||
return CoreSettingsGetStringListValue(settingId, setting.Section);
|
||||
}
|
||||
|
||||
int CoreSettingsGetIntValue(SettingsID settingId, std::string section)
|
||||
{
|
||||
l_Setting setting = get_setting(settingId);
|
||||
@@ -1283,25 +1498,31 @@ std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId, std::string s
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(settingId, section);
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(value_str);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
if (!string_to_int_list(value_str, value))
|
||||
{
|
||||
try
|
||||
{
|
||||
value.emplace_back(std::stoi(tmp_str));
|
||||
}
|
||||
catch (...)
|
||||
{ // ignore exception
|
||||
continue;
|
||||
}
|
||||
return std::vector<int>();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId, std::string section)
|
||||
{
|
||||
l_Setting setting = get_setting(settingId);
|
||||
std::vector<std::string> value;
|
||||
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(settingId, section);
|
||||
|
||||
if (!string_to_string_list(value_str, value))
|
||||
{
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
int CoreSettingsGetIntValue(std::string section, std::string key, int defaultValue)
|
||||
{
|
||||
int value = defaultValue;
|
||||
@@ -1330,27 +1551,31 @@ std::string CoreSettingsGetStringValue(std::string section, std::string key)
|
||||
return std::string(value);
|
||||
}
|
||||
|
||||
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key, std::vector<int> defaultValue)
|
||||
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key)
|
||||
{
|
||||
std::vector<int> value;
|
||||
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(section, key);
|
||||
|
||||
// split string by ';'
|
||||
// and append list with each item
|
||||
std::stringstream value_str_stream(value_str);
|
||||
std::string tmp_str;
|
||||
while (std::getline(value_str_stream, tmp_str, ';'))
|
||||
if (!string_to_int_list(value_str, value))
|
||||
{
|
||||
try
|
||||
{
|
||||
value.emplace_back(std::stoi(tmp_str));
|
||||
}
|
||||
catch (...)
|
||||
{ // ignore exception
|
||||
continue;
|
||||
}
|
||||
return std::vector<int>();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(std::string section, std::string key)
|
||||
{
|
||||
std::vector<std::string> value;
|
||||
|
||||
std::string value_str;
|
||||
value_str = CoreSettingsGetStringValue(section, key);
|
||||
|
||||
if (!string_to_string_list(value_str, value))
|
||||
{
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
@@ -43,6 +43,8 @@ bool CoreSettingsSetValue(SettingsID settingId, float value);
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string value);
|
||||
// sets setting as int list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<int> value);
|
||||
// sets setting as string list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::vector<std::string> value);
|
||||
|
||||
// sets setting in section as int value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, int value);
|
||||
@@ -54,6 +56,8 @@ bool CoreSettingsSetValue(SettingsID settingId, std::string section, float value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::string value);
|
||||
// sets setting in section as int list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<int> value);
|
||||
// sets setting as section as string list value
|
||||
bool CoreSettingsSetValue(SettingsID settingId, std::string section, std::vector<std::string> value);
|
||||
|
||||
#ifdef CORE_INTERNAL
|
||||
// sets key in section as int value
|
||||
@@ -66,6 +70,8 @@ bool CoreSettingsSetValue(std::string section, std::string key, float value);
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::string value);
|
||||
// sets key in section as int list value
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<int> value);
|
||||
// sets key in section as string list value
|
||||
bool CoreSettingsSetValue(std::string section, std::string key, std::vector<std::string> value);
|
||||
#endif // CORE_INTERNAL
|
||||
|
||||
// retrieves default setting as int
|
||||
@@ -78,6 +84,8 @@ float CoreSettingsGetDefaultFloatValue(SettingsID settingId);
|
||||
std::string CoreSettingsGetDefaultStringValue(SettingsID settingId);
|
||||
// retrieves default setting as int list
|
||||
std::vector<int> CoreSettingsGetDefaultIntListValue(SettingsID settingId);
|
||||
// retrieves default setting as string list
|
||||
std::vector<std::string> CoreSettingsGetDefaultStringListValue(SettingsID settingId);
|
||||
|
||||
// retrieves setting as int
|
||||
int CoreSettingsGetIntValue(SettingsID settingId);
|
||||
@@ -89,6 +97,8 @@ float CoreSettingsGetFloatValue(SettingsID settingId);
|
||||
std::string CoreSettingsGetStringValue(SettingsID settingId);
|
||||
// retrieves setting as int list
|
||||
std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId);
|
||||
// retrieves setting as string list
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId);
|
||||
|
||||
// retrieves setting in section as int
|
||||
int CoreSettingsGetIntValue(SettingsID settingId, std::string section);
|
||||
@@ -100,6 +110,8 @@ float CoreSettingsGetFloatValue(SettingsID settingId, std::string section);
|
||||
std::string CoreSettingsGetStringValue(SettingsID settingId, std::string section);
|
||||
// retrieves setting in section as int list
|
||||
std::vector<int> CoreSettingsGetIntListValue(SettingsID settingId, std::string section);
|
||||
// retrieves setting in section as string list
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(SettingsID settingId, std::string section);
|
||||
|
||||
#ifdef CORE_INTERNAL
|
||||
// retrieves key in section as int
|
||||
@@ -112,6 +124,8 @@ float CoreSettingsGetFloatValue(std::string section, std::string key, float defa
|
||||
std::string CoreSettingsGetStringValue(std::string section, std::string key);
|
||||
// retrieves key in section as int list
|
||||
std::vector<int> CoreSettingsGetIntListValue(std::string section, std::string key);
|
||||
// retrieves key in section as string list
|
||||
std::vector<std::string> CoreSettingsGetStringListValue(std::string section, std::string key);
|
||||
#endif // CORE_INTERNAL
|
||||
|
||||
#endif // CORE_SETTINGS_HPP
|
||||
|
||||
@@ -6,13 +6,24 @@ enum class SettingsID
|
||||
// GUI Settings
|
||||
GUI_SettingsDialogWidth = 0,
|
||||
GUI_SettingsDialogHeight,
|
||||
GUI_AllowManualResizing,
|
||||
GUI_HideCursorInEmulation,
|
||||
GUI_HideCursorInFullscreenEmulation,
|
||||
GUI_StatusbarMessageDuration,
|
||||
GUI_PauseEmulationOnFocusLoss,
|
||||
GUI_ResumeEmulationOnFocus,
|
||||
GUI_AutomaticFullscreen,
|
||||
GUI_ShowVerboseLogMessages,
|
||||
GUI_OnScreenDisplayEnabled,
|
||||
GUI_OnScreenDisplayLocation,
|
||||
GUI_OnScreenDisplayPaddingX,
|
||||
GUI_OnScreenDisplayPaddingY,
|
||||
GUI_OnScreenDisplayOpacity,
|
||||
GUI_OnScreenDisplayDuration,
|
||||
GUI_Toolbar,
|
||||
GUI_StatusBar,
|
||||
GUI_Theme,
|
||||
GUI_CheckForUpdates,
|
||||
GUI_DiscordRpc,
|
||||
GUI_Version,
|
||||
|
||||
// Core Plugin Settings
|
||||
@@ -87,35 +98,51 @@ enum class SettingsID
|
||||
|
||||
// GUI KeyBindings
|
||||
KeyBinding_RemoveDuplicates,
|
||||
KeyBinding_OpenROM,
|
||||
KeyBinding_OpenCombo,
|
||||
KeyBinding_StartEmulation,
|
||||
KeyBinding_EndEmulation,
|
||||
KeyBinding_StartROM,
|
||||
KeyBinding_StartCombo,
|
||||
KeyBinding_Shutdown,
|
||||
KeyBinding_RefreshROMList,
|
||||
KeyBinding_Exit,
|
||||
KeyBinding_SoftReset,
|
||||
KeyBinding_HardReset,
|
||||
KeyBinding_Resume,
|
||||
KeyBinding_GenerateBitmap,
|
||||
KeyBinding_Screenshot,
|
||||
KeyBinding_LimitFPS,
|
||||
KeyBinding_SwapDisk,
|
||||
KeyBinding_SaveState,
|
||||
KeyBinding_SaveAs,
|
||||
KeyBinding_LoadState,
|
||||
KeyBinding_Load,
|
||||
KeyBinding_Cheats,
|
||||
KeyBinding_GSButton,
|
||||
KeyBinding_SaveStateSlot0,
|
||||
KeyBinding_SaveStateSlot1,
|
||||
KeyBinding_SaveStateSlot2,
|
||||
KeyBinding_SaveStateSlot3,
|
||||
KeyBinding_SaveStateSlot4,
|
||||
KeyBinding_SaveStateSlot5,
|
||||
KeyBinding_SaveStateSlot6,
|
||||
KeyBinding_SaveStateSlot7,
|
||||
KeyBinding_SaveStateSlot8,
|
||||
KeyBinding_SaveStateSlot9,
|
||||
KeyBinding_Fullscreen,
|
||||
KeyBinding_Settings,
|
||||
|
||||
// RomBrowser Settings
|
||||
RomBrowser_Directory,
|
||||
RomBrowser_Geometry,
|
||||
RomBrowser_Maximized,
|
||||
RomBrowser_Recursive,
|
||||
RomBrowser_MaxItems,
|
||||
RomBrowser_Columns,
|
||||
RomBrowser_ColumnSizes,
|
||||
|
||||
RomBrowser_SortAfterSearch,
|
||||
RomBrowser_ViewMode,
|
||||
RomBrowser_ListViewSortSection,
|
||||
RomBrowser_ListViewSortOrder,
|
||||
RomBrowser_GridViewIconWidth,
|
||||
RomBrowser_GridViewIconHeight,
|
||||
RomBrowser_GridViewUniformItemSizes,
|
||||
|
||||
// Settings Settings
|
||||
Settings_HasForceUsedSetOnce,
|
||||
|
||||
@@ -140,7 +167,6 @@ enum class SettingsID
|
||||
Input_GameboyRom,
|
||||
Input_GameboySave,
|
||||
Input_RemoveDuplicateMappings,
|
||||
Input_InvertAxis,
|
||||
Input_A_InputType,
|
||||
Input_A_Name,
|
||||
Input_A_Data,
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Unzip.hpp"
|
||||
#include "Error.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <unzip.h>
|
||||
|
||||
//
|
||||
// Local Defines
|
||||
//
|
||||
|
||||
#define UNZIP_READ_SIZE 67108860 /* 64 MiB */
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
bool CoreUnzip(std::filesystem::path file, std::filesystem::path path)
|
||||
{
|
||||
std::string error;
|
||||
|
||||
unzFile zipFile;
|
||||
unz_global_info zipInfo;
|
||||
std::ofstream outputStream;
|
||||
char* read_buffer = (char*)malloc(UNZIP_READ_SIZE);
|
||||
size_t bytes_read = 0;
|
||||
|
||||
if (read_buffer == nullptr)
|
||||
{
|
||||
error = "CoreUnzip: malloc Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
zipFile = unzOpen(file.string().c_str());
|
||||
if (zipFile == nullptr)
|
||||
{
|
||||
free(read_buffer);
|
||||
error = "CoreUnzip: unzOpen Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
error = "CoreUnzip: unzGetGlobalInfo Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < zipInfo.number_entry; i++)
|
||||
{
|
||||
unz_file_info fileInfo;
|
||||
char fileName[PATH_MAX];
|
||||
std::filesystem::path targetPath;
|
||||
|
||||
// ensure we can retrieve the current file info
|
||||
if (unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, PATH_MAX, nullptr, 0, nullptr, 0) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzGetCurrentFileInfo Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
targetPath = path;
|
||||
targetPath += "/";
|
||||
targetPath += fileName;
|
||||
|
||||
if (targetPath.string().ends_with("/"))
|
||||
{ // directory
|
||||
try
|
||||
{
|
||||
if (!std::filesystem::is_directory(targetPath) &&
|
||||
!std::filesystem::create_directory(targetPath))
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: std::filesystem::create_directory(";
|
||||
error += targetPath.string();
|
||||
error += ") Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // file
|
||||
if (unzOpenCurrentFile(zipFile) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzOpenCurrentFile Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
outputStream.open(targetPath, std::ios::trunc | std::ios::binary);
|
||||
if (!outputStream.is_open())
|
||||
{
|
||||
free(read_buffer);
|
||||
unzCloseCurrentFile(zipFile);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: failed to open file!";
|
||||
error += targetPath.string();
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
bytes_read = unzReadCurrentFile(zipFile, read_buffer, UNZIP_READ_SIZE);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzCloseCurrentFile(zipFile);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzReadCurrentFile Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{ // write data to file
|
||||
outputStream.write(read_buffer, bytes_read);
|
||||
}
|
||||
} while (bytes_read > 0);
|
||||
|
||||
outputStream.close();
|
||||
unzCloseCurrentFile(zipFile);
|
||||
}
|
||||
|
||||
// break when we've iterated over all entries
|
||||
if ((i + 1) >= zipInfo.number_entry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// move to next file
|
||||
if (unzGoToNextFile(zipFile) != UNZ_OK)
|
||||
{
|
||||
free(read_buffer);
|
||||
unzClose(zipFile);
|
||||
error = "CoreUnzip: unzGoToNextFile Failed!";
|
||||
CoreSetError(error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unzClose(zipFile);
|
||||
free(read_buffer);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_UNZIP_HPP
|
||||
#define CORE_UNZIP_HPP
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
// attempts to unzip the file to path
|
||||
bool CoreUnzip(std::filesystem::path file, std::filesystem::path path);
|
||||
|
||||
#endif // CORE_UNZIP_HPP
|
||||
@@ -7,10 +7,14 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
QTableView
|
||||
#include "Version.hpp"
|
||||
#include "Config.hpp"
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
std::string CoreGetVersion(void)
|
||||
{
|
||||
border: none;
|
||||
color: #0096d3;
|
||||
selection-color: #FFFFFF;
|
||||
selection-background-color: #0096d3;
|
||||
return std::string(CORE_VERSION);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CORE_VERSION_HPP
|
||||
#define CORE_VERSION_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
// returns the current RMG-Core version (as string)
|
||||
std::string CoreGetVersion(void);
|
||||
|
||||
#endif // CORE_VERSION_HPP
|
||||
@@ -168,7 +168,9 @@ typedef enum {
|
||||
M64CMD_NETPLAY_GET_VERSION,
|
||||
M64CMD_NETPLAY_CLOSE,
|
||||
M64CMD_PIF_OPEN,
|
||||
M64CMD_ROM_SET_SETTINGS
|
||||
M64CMD_ROM_SET_SETTINGS,
|
||||
M64CMD_DISK_OPEN,
|
||||
M64CMD_DISK_CLOSE
|
||||
} m64p_command;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define OSAL_DYNLIB_HPP
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@@ -25,11 +26,11 @@ typedef void* osal_dynlib_lib_sym;
|
||||
|
||||
// returns library handle for given filename,
|
||||
// return nullptr when invalid library
|
||||
osal_dynlib_lib_handle osal_dynlib_open(const char *);
|
||||
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path);
|
||||
|
||||
// retrieves symbol handle for given library
|
||||
// handle, returns nullptr when not found
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle, const char *);
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle, const char* symbol);
|
||||
|
||||
// closes library handle
|
||||
void osal_dynlib_close(osal_dynlib_lib_handle);
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
osal_dynlib_lib_handle osal_dynlib_open(const char* file)
|
||||
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path)
|
||||
{
|
||||
return dlopen(file, RTLD_LAZY);
|
||||
return dlopen(path.string().c_str(), RTLD_LAZY);
|
||||
}
|
||||
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char *sym)
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char* symbol)
|
||||
{
|
||||
return dlsym(handle, sym);
|
||||
return dlsym(handle, symbol);
|
||||
}
|
||||
|
||||
void osal_dynlib_close(osal_dynlib_lib_handle handle)
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
*/
|
||||
#include "osal_dynlib.hpp"
|
||||
|
||||
osal_dynlib_lib_handle osal_dynlib_open(const char* file)
|
||||
osal_dynlib_lib_handle osal_dynlib_open(std::filesystem::path path)
|
||||
{
|
||||
return LoadLibrary(file);
|
||||
return LoadLibraryW(path.wstring().c_str());
|
||||
}
|
||||
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char *sym)
|
||||
osal_dynlib_lib_sym osal_dynlib_sym(osal_dynlib_lib_handle handle, const char* symbol)
|
||||
{
|
||||
return GetProcAddress(handle, sym);
|
||||
return GetProcAddress(handle, symbol);
|
||||
}
|
||||
|
||||
void osal_dynlib_close(osal_dynlib_lib_handle handle)
|
||||
|
||||
@@ -17,8 +17,9 @@ osal_files_file_time osal_files_get_file_time(std::filesystem::path file)
|
||||
BOOL ret;
|
||||
HANDLE file_handle;
|
||||
FILETIME file_time;
|
||||
ULARGE_INTEGER ularge_int;
|
||||
|
||||
file_handle = CreateFileA(file.string().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
file_handle = CreateFileW(file.wstring().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return -1;
|
||||
@@ -36,7 +37,8 @@ osal_files_file_time osal_files_get_file_time(std::filesystem::path file)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// this is probably incorrect but it doesn't matter
|
||||
// for our use-case
|
||||
return file_time.dwLowDateTime + file_time.dwHighDateTime;
|
||||
ularge_int.LowPart = file_time.dwLowDateTime;
|
||||
ularge_int.HighPart = file_time.dwHighDateTime;
|
||||
|
||||
return ularge_int.QuadPart;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ set(CMAKE_AUTOUIC ON)
|
||||
# disable lib prefix
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
find_package(Qt5 COMPONENTS Gui Widgets Core Svg REQUIRED)
|
||||
find_package(Qt6 COMPONENTS Gui Widgets Core Svg REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||
@@ -17,7 +17,9 @@ set(RMG_INPUT_SOURCES
|
||||
UserInterface/Widget/ControllerWidget.ui
|
||||
UserInterface/Widget/ControllerWidget.cpp
|
||||
UserInterface/Widget/ControllerImageWidget.cpp
|
||||
UserInterface/Widget/CustomButton.cpp
|
||||
UserInterface/Widget/MappingButton.cpp
|
||||
UserInterface/Widget/AddMappingButton.cpp
|
||||
UserInterface/Widget/RemoveMappingButton.cpp
|
||||
UserInterface/EventFilter.cpp
|
||||
UserInterface/OptionsDialog.ui
|
||||
UserInterface/OptionsDialog.cpp
|
||||
@@ -41,4 +43,4 @@ target_include_directories(RMG-Input PRIVATE
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(RMG-Input Qt5::Gui Qt5::Widgets Qt5::Svg)
|
||||
target_link_libraries(RMG-Input Qt6::Gui Qt6::Widgets Qt6::Svg)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
using namespace UserInterface;
|
||||
|
||||
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
|
||||
MainDialog::MainDialog(QWidget* parent, Thread::SDLThread* sdlThread) : QDialog(parent)
|
||||
{
|
||||
this->setupUi(this);
|
||||
this->setWindowIcon(QIcon(":Resource/RMG.png"));
|
||||
@@ -111,9 +111,11 @@ void MainDialog::openInputDevice(QString deviceName, int deviceNum)
|
||||
currentJoystick = SDL_JoystickOpen(deviceNum);
|
||||
currentController = nullptr;
|
||||
}
|
||||
|
||||
currentDeviceNum = deviceNum;
|
||||
joystickId = SDL_JoystickGetDeviceInstanceID(deviceNum);
|
||||
controllerWidget->SetCurrentJoystickID(joystickId);
|
||||
controllerWidget->SetIsCurrentJoystickGameController(currentController != nullptr);
|
||||
}
|
||||
|
||||
void MainDialog::closeInputDevice()
|
||||
|
||||
@@ -28,7 +28,7 @@ private:
|
||||
QString deviceName;
|
||||
int deviceNum;
|
||||
|
||||
bool operator== (inputDevice_t other)
|
||||
bool operator== (inputDevice_t other) const
|
||||
{
|
||||
return other.deviceNum == deviceNum &&
|
||||
other.deviceName == deviceName;
|
||||
|
||||
@@ -18,11 +18,13 @@ OptionsDialog::OptionsDialog(QWidget* parent, OptionsDialogSettings settings) :
|
||||
{
|
||||
this->setupUi(this);
|
||||
|
||||
this->setIconsForEmulationInfoText();
|
||||
|
||||
this->controllerPakComboBox->setCurrentIndex(settings.ControllerPak);
|
||||
this->gameboyRomLineEdit->setText(QString::fromStdString(settings.GameboyRom));
|
||||
this->gameboySaveLineEdit->setText(QString::fromStdString(settings.GameboySave));
|
||||
this->removeDuplicateMappingsCheckbox->setChecked(settings.RemoveDuplicateMappings);
|
||||
this->invertAxisCheckBox->setChecked(settings.InvertAxis);
|
||||
|
||||
if (!CoreIsEmulationRunning() && !CoreIsEmulationPaused())
|
||||
{
|
||||
this->hideEmulationInfoText();
|
||||
@@ -39,6 +41,21 @@ OptionsDialogSettings OptionsDialog::GetSettings()
|
||||
return this->settings;
|
||||
}
|
||||
|
||||
void OptionsDialog::setIconsForEmulationInfoText(void)
|
||||
{
|
||||
QLabel* labels[] = {
|
||||
this->infoIconLabel_0
|
||||
};
|
||||
|
||||
QIcon infoIcon = QIcon::fromTheme("information-line");
|
||||
QPixmap infoIconPixmap = infoIcon.pixmap(16, 16);
|
||||
|
||||
for (QLabel* label : labels)
|
||||
{
|
||||
label->setPixmap(infoIconPixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::hideEmulationInfoText(void)
|
||||
{
|
||||
QHBoxLayout *layouts[] = {this->emulationInfoLayout_1};
|
||||
@@ -66,7 +83,6 @@ void OptionsDialog::on_buttonBox_clicked(QAbstractButton *button)
|
||||
this->settings.GameboyRom = this->gameboyRomLineEdit->text().toStdString();
|
||||
this->settings.GameboySave = this->gameboySaveLineEdit->text().toStdString();
|
||||
this->settings.RemoveDuplicateMappings = this->removeDuplicateMappingsCheckbox->isChecked();
|
||||
this->settings.InvertAxis = this->invertAxisCheckBox->isChecked();
|
||||
}
|
||||
|
||||
this->accept();
|
||||
|
||||
@@ -24,7 +24,6 @@ struct OptionsDialogSettings
|
||||
|
||||
// UI settings
|
||||
bool RemoveDuplicateMappings = false;
|
||||
bool InvertAxis = false;
|
||||
};
|
||||
|
||||
namespace UserInterface
|
||||
@@ -43,6 +42,7 @@ private:
|
||||
bool hasSaved = false;
|
||||
OptionsDialogSettings settings;
|
||||
|
||||
void setIconsForEmulationInfoText(void);
|
||||
void hideEmulationInfoText(void);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="emulationInfoLayout_1">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="infoIconLabel_0">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -162,7 +162,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="UIResources.qrc">:/Resource/Info.ico</pixmap>
|
||||
<pixmap>:/Resource/Info.ico</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
@@ -202,13 +202,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="invertAxisCheckBox">
|
||||
<property name="text">
|
||||
<string>Invert Axes Mapped To LRZ</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="svg21"
|
||||
sodipodi:docname="Controller.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -23,15 +23,17 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.28240146"
|
||||
inkscape:cx="-426.69751"
|
||||
inkscape:cy="3454.3023"
|
||||
inkscape:zoom="0.070600365"
|
||||
inkscape:cx="6019.7989"
|
||||
inkscape:cy="1600.5583"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg21" />
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<path
|
||||
id="Dark-Grey-Background"
|
||||
serif:id="Dark Grey Background"
|
||||
@@ -111,4 +113,39 @@
|
||||
style="fill:#ec3f21"
|
||||
id="circle18" />
|
||||
</g>
|
||||
</svg>
|
||||
<g
|
||||
id="layer2"
|
||||
inkscape:label="Z-Button"
|
||||
style="display:inline;opacity:1;stroke-width:1;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
transform="matrix(50.366966,0,0,50.366966,3240.0678,-579.56452)"><g
|
||||
id="layer2-0"
|
||||
inkscape:label="Z-Button"
|
||||
style="clip-rule:evenodd;display:inline;fill-rule:evenodd;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"><rect
|
||||
style="clip-rule:evenodd;display:inline;opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.999999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917-0-4"
|
||||
width="11.478539"
|
||||
height="16.72587"
|
||||
x="-32.517441"
|
||||
y="86.256668"
|
||||
ry="3.4675589"
|
||||
inkscape:label="btnZ-outline"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><rect
|
||||
style="display:inline;opacity:1;fill:#bcbdbf;fill-opacity:1;stroke:none;stroke-width:0.960842;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917-8"
|
||||
width="10.956328"
|
||||
height="16.177647"
|
||||
x="-32.225891"
|
||||
y="86.523468"
|
||||
ry="3.3539019"
|
||||
inkscape:label="btnZ"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><g
|
||||
aria-label="Z"
|
||||
style="font-style:normal;font-weight:normal;font-size:5.73478px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;clip-rule:evenodd;display:inline;opacity:1;fill:#56575b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.751267;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="text1921-7"
|
||||
transform="matrix(1.3310888,0,0,1.3310888,-67.459296,-40.853038)"><path
|
||||
d="m 28.805176,99.685474 h 3.514231 v 0.652446 l -2.242948,2.71338 h 2.307352 v 0.81485 h -3.64304 v -0.65244 l 2.242948,-2.71338 h -2.178543 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#56575b;fill-opacity:1;stroke-width:0.751267;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="path2008-2"
|
||||
inkscape:connector-curvature="0" /></g></g></g></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
@@ -8,7 +8,7 @@
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="svg21"
|
||||
sodipodi:docname="Controller_NoAnalogStick.svg"
|
||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -23,15 +23,17 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.14120073"
|
||||
inkscape:cx="2549.5619"
|
||||
inkscape:cy="3325.0536"
|
||||
inkscape:zoom="0.099843994"
|
||||
inkscape:cx="2829.4141"
|
||||
inkscape:cy="3475.4219"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1007"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg21" />
|
||||
inkscape:current-layer="svg21"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<path
|
||||
id="Dark-Grey-Background"
|
||||
serif:id="Dark Grey Background"
|
||||
@@ -101,4 +103,36 @@
|
||||
style="fill:#ec3f21"
|
||||
id="circle18" />
|
||||
</g>
|
||||
</svg>
|
||||
<g
|
||||
id="layer2"
|
||||
inkscape:label="Z-Button"
|
||||
style="display:inline;opacity:1;stroke-width:1;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
transform="matrix(50.366966,0,0,50.366966,3240.0678,-579.56452)"><rect
|
||||
style="clip-rule:evenodd;display:inline;opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.999999;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917-0"
|
||||
width="11.478539"
|
||||
height="16.72587"
|
||||
x="-32.517441"
|
||||
y="86.256668"
|
||||
ry="3.4675589"
|
||||
inkscape:label="btnZ-outline"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><rect
|
||||
style="display:inline;opacity:1;fill:#bcbdbf;fill-opacity:1;stroke:none;stroke-width:0.960842;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;image-rendering:auto"
|
||||
id="rect1917"
|
||||
width="10.956328"
|
||||
height="16.177647"
|
||||
x="-32.225891"
|
||||
y="86.523468"
|
||||
ry="3.3539019"
|
||||
inkscape:label="btnZ"
|
||||
class="theme-button"
|
||||
ojd-button="Z" /><g
|
||||
aria-label="Z"
|
||||
style="font-style:normal;font-weight:normal;font-size:5.73478px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;clip-rule:evenodd;display:inline;opacity:1;fill:#56575b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.751267;stroke-linejoin:round;stroke-miterlimit:2;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="text1921"
|
||||
transform="matrix(1.3310888,0,0,1.3310888,-67.459296,-40.853038)"><path
|
||||
d="m 28.805176,99.685474 h 3.514231 v 0.652446 l -2.242948,2.71338 h 2.307352 v 0.81485 h -3.64304 v -0.65244 l 2.242948,-2.71338 h -2.178543 z"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#56575b;fill-opacity:1;stroke-width:0.751267;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="path2008"
|
||||
inkscape:connector-curvature="0" /></g></g></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="6939.9795"
|
||||
height="6772.564"
|
||||
viewBox="0 0 6939.9795 6772.564"
|
||||
version="1.1"
|
||||
xml:space="preserve"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="svg21"
|
||||
sodipodi:docname="Controller_Pressed_ZTrigger.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs25" /><sodipodi:namedview
|
||||
id="namedview23"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.099843994"
|
||||
inkscape:cx="2468.8516"
|
||||
inkscape:cy="3856.0156"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg21"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<g
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
|
||||
id="g5916"
|
||||
transform="matrix(1.0882331,0,0,1.0882331,512.32815,1416.6572)"><circle
|
||||
style="opacity:0.62;fill:#ececec;fill-rule:evenodd;stroke-width:0.280377"
|
||||
id="path42"
|
||||
cx="1267.6501"
|
||||
cy="2546.3296"
|
||||
r="180.5985" /></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -15,7 +15,7 @@
|
||||
<file>Resource/Controller_Pressed_Start.svg</file>
|
||||
<file>Resource/Controller_Pressed_LeftTrigger.svg</file>
|
||||
<file>Resource/Controller_Pressed_RightTrigger.svg</file>
|
||||
<file>Resource/Controller_Pressed_ZTrigger.svg</file>
|
||||
<file>Resource/RMG.png</file>
|
||||
<file>Resource/Info.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "AddMappingButton.hpp"
|
||||
#include "ControllerWidget.hpp"
|
||||
#include "MappingButton.hpp"
|
||||
|
||||
using namespace UserInterface::Widget;
|
||||
|
||||
AddMappingButton::AddMappingButton(QWidget* parent) : QPushButton(parent)
|
||||
{
|
||||
}
|
||||
|
||||
AddMappingButton::~AddMappingButton()
|
||||
{
|
||||
}
|
||||
|
||||
void AddMappingButton::Initialize(ControllerWidget* widget, MappingButton* button)
|
||||
{
|
||||
this->controllerWidget = widget;
|
||||
this->mappingButton = button;
|
||||
|
||||
connect(this, &QPushButton::released, [=]
|
||||
{
|
||||
emit this->controllerWidget->on_AddMappingButton_Released(this->mappingButton);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef ADDMAPPINGBUTTON_HPP
|
||||
#define ADDMAPPINGBUTTON_HPP
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
namespace Widget
|
||||
{
|
||||
|
||||
// we can't include ControllerWidget.hpp
|
||||
// because that header includes this header,
|
||||
// so forward-declare it to prevent issues
|
||||
class ControllerWidget;
|
||||
class MappingButton;
|
||||
|
||||
class AddMappingButton : public QPushButton
|
||||
{
|
||||
private:
|
||||
ControllerWidget* controllerWidget = nullptr;
|
||||
MappingButton* mappingButton = nullptr;
|
||||
|
||||
public:
|
||||
AddMappingButton(QWidget* parent);
|
||||
~AddMappingButton();
|
||||
|
||||
void Initialize(ControllerWidget* widget, MappingButton* button);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ADDMAPPINGBUTTON_HPP
|
||||
@@ -125,6 +125,7 @@ void ControllerImageWidget::paintEvent(QPaintEvent *event)
|
||||
{ N64ControllerButton::CButtonRight, ":Resource/Controller_Pressed_CButtonRight.svg" },
|
||||
{ N64ControllerButton::LeftTrigger, ":Resource/Controller_Pressed_LeftTrigger.svg" },
|
||||
{ N64ControllerButton::RightTrigger, ":Resource/Controller_Pressed_RightTrigger.svg" },
|
||||
{ N64ControllerButton::ZTrigger, ":Resource/Controller_Pressed_ZTrigger.svg" }
|
||||
};
|
||||
|
||||
static const QString baseImageUri = ":Resource/Controller_NoAnalogStick.svg";
|
||||
|
||||
@@ -58,6 +58,7 @@ ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) :
|
||||
{ N64ControllerButton::CButtonRight, this->cbuttonRightButton },
|
||||
{ N64ControllerButton::LeftTrigger, this->leftTriggerButton },
|
||||
{ N64ControllerButton::RightTrigger, this->rightTriggerButton },
|
||||
{ N64ControllerButton::ZTrigger, this->zTriggerButton }
|
||||
});
|
||||
|
||||
this->joystickWidgetMappings.append(
|
||||
@@ -90,7 +91,7 @@ ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) :
|
||||
{ this->analogStickRightButton, SettingsID::Input_AnalogStickRight_InputType, SettingsID::Input_AnalogStickRight_Name, SettingsID::Input_AnalogStickRight_Data, SettingsID::Input_AnalogStickRight_ExtraData },
|
||||
});
|
||||
|
||||
CustomButton* buttonList[] =
|
||||
MappingButton* buttonList[] =
|
||||
{
|
||||
// dpad
|
||||
this->dpadUpButton,
|
||||
@@ -121,7 +122,7 @@ ControllerWidget::ControllerWidget(QWidget* parent, EventFilter* eventFilter) :
|
||||
this->setupButtonWidgets.append(button);
|
||||
}
|
||||
|
||||
|
||||
this->on_controllerPluggedCheckBox_toggled(false);
|
||||
this->initializeButtons();
|
||||
}
|
||||
|
||||
@@ -132,37 +133,50 @@ ControllerWidget::~ControllerWidget()
|
||||
|
||||
void ControllerWidget::initializeButtons()
|
||||
{
|
||||
CustomButton* buttonList[] =
|
||||
struct
|
||||
{
|
||||
MappingButton* mappingButton;
|
||||
AddMappingButton* addMappingButton;
|
||||
RemoveMappingButton* removeMappingButton;
|
||||
} mappingList[] =
|
||||
{
|
||||
// dpad
|
||||
this->dpadUpButton,
|
||||
this->dpadDownButton,
|
||||
this->dpadLeftButton,
|
||||
this->dpadRightButton,
|
||||
{ this->dpadUpButton, this->dpadUpAddButton, this->dpadUpRemoveButton },
|
||||
{ this->dpadDownButton, this->dpadDownAddButton, this->dpadDownRemoveButton },
|
||||
{ this->dpadLeftButton, this->dpadLeftAddButton, this->dpadLeftRemoveButton },
|
||||
{ this->dpadRightButton, this->dpadRightAddButton, this->dpadRightRemoveButton },
|
||||
// analog stick
|
||||
this->analogStickUpButton,
|
||||
this->analogStickDownButton,
|
||||
this->analogStickLeftButton,
|
||||
this->analogStickRightButton,
|
||||
{ this->analogStickUpButton, this->analogStickUpAddButton, this->analogStickUpRemoveButton },
|
||||
{ this->analogStickDownButton, this->analogStickDownAddButton, this->analogStickDownRemoveButton },
|
||||
{ this->analogStickLeftButton, this->analogStickLeftAddButton, this->analogStickLeftRemoveButton },
|
||||
{ this->analogStickRightButton, this->analogStickRightAddButton, this->analogStickRightRemoveButton },
|
||||
// cbuttons
|
||||
this->cbuttonUpButton,
|
||||
this->cbuttonDownButton,
|
||||
this->cbuttonLeftButton,
|
||||
this->cbuttonRightButton,
|
||||
{ this->cbuttonUpButton, this->cbuttonUpAddButton, this->cbuttonUpRemoveButton },
|
||||
{ this->cbuttonDownButton, this->cbuttonDownAddButton, this->cbuttonDownRemoveButton },
|
||||
{ this->cbuttonLeftButton, this->cbuttonLeftAddButton, this->cbuttonLeftRemoveButton },
|
||||
{ this->cbuttonRightButton, this->cbuttonRightAddButton, this->cbuttonRightRemoveButton },
|
||||
// triggers
|
||||
this->leftTriggerButton,
|
||||
this->rightTriggerButton,
|
||||
this->zTriggerButton,
|
||||
{ this->leftTriggerButton, this->leftTriggerAddButton, this->leftTriggerRemoveButton },
|
||||
{ this->rightTriggerButton, this->rightTriggerAddButton, this->rightTriggerRemoveButton },
|
||||
{ this->zTriggerButton, this->zTriggerAddButton, this->zTriggerRemoveButton },
|
||||
// buttons
|
||||
this->aButton,
|
||||
this->bButton,
|
||||
this->startButton,
|
||||
{ this->aButton, this->aAddButton, this->aRemoveButton },
|
||||
{ this->bButton, this->bAddButton, this->bRemoveButton },
|
||||
{ this->startButton, this->startAddButton, this->startRemoveButton },
|
||||
};
|
||||
|
||||
for (auto& button : buttonList)
|
||||
for (auto& mapping : mappingList)
|
||||
{
|
||||
button->Initialize(this);
|
||||
button->setText(" ");
|
||||
// initialize buttons
|
||||
mapping.mappingButton->Initialize(this);
|
||||
mapping.addMappingButton->Initialize(this, mapping.mappingButton);
|
||||
mapping.removeMappingButton->Initialize(this, mapping.mappingButton);
|
||||
|
||||
// clear text & set icon
|
||||
mapping.addMappingButton->setText("");
|
||||
mapping.removeMappingButton->setText("");
|
||||
mapping.addMappingButton->setIcon(QIcon::fromTheme("add-line"));
|
||||
mapping.removeMappingButton->setIcon(QIcon::fromTheme("delete-back-line"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +225,7 @@ void ControllerWidget::enableAllChildren()
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerWidget::removeDuplicates(CustomButton* button)
|
||||
void ControllerWidget::removeDuplicates(MappingButton* button)
|
||||
{
|
||||
std::string section = this->getCurrentSettingsSection().toStdString();
|
||||
|
||||
@@ -228,11 +242,20 @@ void ControllerWidget::removeDuplicates(CustomButton* button)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((buttonWidget->GetInputType() == button->GetInputType()) &&
|
||||
(buttonWidget->GetInputData() == button->GetInputData()) &&
|
||||
(buttonWidget->GetExtraInputData() == button->GetExtraInputData()))
|
||||
std::vector<int> inputType;
|
||||
std::vector<int> inputData;
|
||||
std::vector<int> extraInputData;
|
||||
|
||||
inputType = button->GetInputType();
|
||||
inputData = button->GetInputData();
|
||||
extraInputData = button->GetExtraInputData();
|
||||
|
||||
for (int i = 0; i < inputType.size(); i++)
|
||||
{
|
||||
buttonWidget->Clear();
|
||||
if (buttonWidget->HasInputData((InputType)inputType.at(i), inputData.at(i), extraInputData.at(i)))
|
||||
{
|
||||
buttonWidget->RemoveInputData((InputType)inputType.at(i), inputData.at(i), extraInputData.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,6 +315,13 @@ void ControllerWidget::CheckInputDeviceSettings()
|
||||
std::string deviceName = CoreSettingsGetStringValue(SettingsID::Input_DeviceName, section);
|
||||
int deviceNum = CoreSettingsGetIntValue(SettingsID::Input_DeviceNum, section);
|
||||
|
||||
// do nothing when input device combobox
|
||||
// is empty
|
||||
if (this->inputDeviceComboBox->count() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// clear (not found) devices first
|
||||
int notFoundIndex = this->inputDeviceComboBox->findText("(not found)", Qt::MatchFlag::MatchEndsWith);
|
||||
if (notFoundIndex != -1)
|
||||
@@ -302,11 +332,11 @@ void ControllerWidget::CheckInputDeviceSettings()
|
||||
|
||||
int deviceNameIndex = this->inputDeviceComboBox->findText(QString::fromStdString(deviceName), Qt::MatchFlag::MatchStartsWith);
|
||||
int deviceNumIndex = this->inputDeviceComboBox->findData(deviceNum);
|
||||
|
||||
if ((deviceNameIndex == deviceNumIndex) &&
|
||||
(deviceNameIndex != -1))
|
||||
|
||||
if ((deviceNumIndex != -1) &&
|
||||
(this->inputDeviceComboBox->itemText(deviceNumIndex).startsWith(QString::fromStdString(deviceName))))
|
||||
{ // full match
|
||||
this->inputDeviceComboBox->setCurrentIndex(deviceNameIndex);
|
||||
this->inputDeviceComboBox->setCurrentIndex(deviceNumIndex);
|
||||
}
|
||||
else if (deviceNameIndex != -1)
|
||||
{ // name only match
|
||||
@@ -363,7 +393,7 @@ void ControllerWidget::on_profileComboBox_currentIndexChanged(int value)
|
||||
// reload settings from section
|
||||
this->LoadSettings(this->getCurrentSettingsSection());
|
||||
// reload input device settings
|
||||
CheckInputDeviceSettings();
|
||||
this->CheckInputDeviceSettings();
|
||||
}
|
||||
|
||||
void ControllerWidget::on_inputDeviceComboBox_currentIndexChanged(int value)
|
||||
@@ -398,34 +428,37 @@ void ControllerWidget::on_controllerPluggedCheckBox_toggled(bool value)
|
||||
QWidget* widgetList[] =
|
||||
{
|
||||
// dpad
|
||||
this->dpadUpButton,
|
||||
this->dpadDownButton,
|
||||
this->dpadLeftButton,
|
||||
this->dpadRightButton,
|
||||
this->groupBox,
|
||||
this->dpadUpButton, this->dpadUpAddButton, this->dpadUpRemoveButton,
|
||||
this->dpadDownButton, this->dpadDownAddButton, this->dpadDownRemoveButton,
|
||||
this->dpadLeftButton, this->dpadLeftAddButton, this->dpadLeftRemoveButton,
|
||||
this->dpadRightButton, this->dpadRightAddButton, this->dpadRightRemoveButton,
|
||||
// analog stick
|
||||
this->analogStickUpButton,
|
||||
this->analogStickDownButton,
|
||||
this->analogStickLeftButton,
|
||||
this->analogStickRightButton,
|
||||
this->groupBox_2,
|
||||
this->analogStickUpButton, this->analogStickUpAddButton, this->analogStickUpRemoveButton,
|
||||
this->analogStickDownButton, this->analogStickDownAddButton, this->analogStickDownRemoveButton,
|
||||
this->analogStickLeftButton, this->analogStickLeftAddButton, this->analogStickLeftRemoveButton,
|
||||
this->analogStickRightButton, this->analogStickRightAddButton, this->analogStickRightRemoveButton,
|
||||
// cbuttons
|
||||
this->cbuttonUpButton,
|
||||
this->cbuttonDownButton,
|
||||
this->cbuttonLeftButton,
|
||||
this->cbuttonRightButton,
|
||||
this->groupBox_3,
|
||||
this->cbuttonUpButton, this->cbuttonUpAddButton, this->cbuttonUpRemoveButton,
|
||||
this->cbuttonDownButton, this->cbuttonDownAddButton, this->cbuttonDownRemoveButton,
|
||||
this->cbuttonLeftButton, this->cbuttonLeftAddButton, this->cbuttonLeftRemoveButton,
|
||||
this->cbuttonRightButton, this->cbuttonRightAddButton, this->cbuttonRightRemoveButton,
|
||||
// triggers
|
||||
this->leftTriggerButton,
|
||||
this->rightTriggerButton,
|
||||
this->zTriggerButton,
|
||||
this->leftTriggerButton, this->leftTriggerAddButton, this->leftTriggerRemoveButton,
|
||||
this->rightTriggerButton, this->rightTriggerAddButton, this->rightTriggerRemoveButton,
|
||||
this->zTriggerButton, this->zTriggerAddButton, this->zTriggerRemoveButton,
|
||||
// buttons
|
||||
this->aButton,
|
||||
this->bButton,
|
||||
this->startButton,
|
||||
this->groupBox_6,
|
||||
this->aButton, this->aAddButton, this->aRemoveButton,
|
||||
this->bButton, this->bAddButton, this->bRemoveButton,
|
||||
this->startButton, this->startAddButton, this->startRemoveButton,
|
||||
// misc UI elements
|
||||
this->deadZoneSlider,
|
||||
this->optionsButton,
|
||||
this->profileComboBox,
|
||||
this->removeProfileButton,
|
||||
//this->setupButton,
|
||||
this->resetButton,
|
||||
this->inputDeviceComboBox,
|
||||
this->inputDeviceRefreshButton
|
||||
@@ -446,11 +479,15 @@ void ControllerWidget::on_removeProfileButton_clicked()
|
||||
if (this->profileComboBox->currentIndex() == 0)
|
||||
{
|
||||
QMessageBox messageBox(this);
|
||||
messageBox.setIcon(QMessageBox::Icon::Critical);
|
||||
messageBox.setWindowTitle("Error");
|
||||
messageBox.setText("Cannot remove main profile!");
|
||||
messageBox.addButton(QMessageBox::Ok);
|
||||
messageBox.exec();
|
||||
messageBox.setIcon(QMessageBox::Icon::Warning);
|
||||
messageBox.setText("Are you sure you want to reset the main profile?");
|
||||
messageBox.addButton(QMessageBox::Yes);
|
||||
messageBox.addButton(QMessageBox::No);
|
||||
if (messageBox.exec() == QMessageBox::Yes)
|
||||
{
|
||||
this->SaveDefaultSettings();
|
||||
this->LoadSettings(this->getCurrentSettingsSection());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -471,15 +508,6 @@ void ControllerWidget::on_removeProfileButton_clicked()
|
||||
this->profileComboBox->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void ControllerWidget::on_setupButton_clicked()
|
||||
{
|
||||
this->currentInSetup = true;
|
||||
this->currentSetupButtonWidgetIndex = 0;
|
||||
|
||||
this->setupButtonWidgets.at(0)->setFocus(Qt::OtherFocusReason);
|
||||
this->setupButtonWidgets.at(0)->click();
|
||||
}
|
||||
|
||||
void ControllerWidget::on_resetButton_clicked()
|
||||
{
|
||||
this->LoadSettings();
|
||||
@@ -497,7 +525,7 @@ void ControllerWidget::on_optionsButton_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerWidget::on_CustomButton_released(CustomButton* button)
|
||||
void ControllerWidget::on_MappingButton_Released(MappingButton* button)
|
||||
{
|
||||
if (this->currentButton != nullptr)
|
||||
{
|
||||
@@ -512,11 +540,23 @@ void ControllerWidget::on_CustomButton_released(CustomButton* button)
|
||||
this->disableAllChildren();
|
||||
}
|
||||
|
||||
void ControllerWidget::on_CustomButton_TimerFinished(CustomButton* button)
|
||||
void ControllerWidget::on_AddMappingButton_Released(MappingButton* button)
|
||||
{
|
||||
this->addMappingToButton = true;
|
||||
button->click();
|
||||
}
|
||||
|
||||
void ControllerWidget::on_RemoveMappingButton_Released(MappingButton* button)
|
||||
{
|
||||
button->RemoveLastInputData();
|
||||
}
|
||||
|
||||
void ControllerWidget::on_MappingButton_TimerFinished(MappingButton* button)
|
||||
{
|
||||
if (this->currentButton == button)
|
||||
{
|
||||
this->currentButton = nullptr;
|
||||
this->currentButton = nullptr;
|
||||
this->addMappingToButton = false;
|
||||
}
|
||||
|
||||
button->RestoreState();
|
||||
@@ -524,11 +564,12 @@ void ControllerWidget::on_CustomButton_TimerFinished(CustomButton* button)
|
||||
this->enableAllChildren();
|
||||
}
|
||||
|
||||
void ControllerWidget::on_CustomButton_DataSet(CustomButton* button)
|
||||
void ControllerWidget::on_MappingButton_DataSet(MappingButton* button)
|
||||
{
|
||||
this->enableAllChildren();
|
||||
this->removeDuplicates(button);
|
||||
this->currentButton = nullptr;
|
||||
this->currentButton = nullptr;
|
||||
this->addMappingToButton = false;
|
||||
}
|
||||
|
||||
void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
@@ -549,6 +590,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
if ((event->type == SDL_CONTROLLERBUTTONDOWN) ||
|
||||
(event->type == SDL_CONTROLLERBUTTONUP))
|
||||
{ // gamepad button
|
||||
if (!this->isCurrentJoystickGameController)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
joystickId = event->cbutton.which;
|
||||
inputType = InputType::GamepadButton;
|
||||
sdlButton = event->cbutton.button;
|
||||
@@ -557,6 +603,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
}
|
||||
else
|
||||
{ // joystick button
|
||||
if (this->isCurrentJoystickGameController)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
joystickId = event->jbutton.which;
|
||||
inputType = InputType::JoystickButton;
|
||||
sdlButton = event->jbutton.button;
|
||||
@@ -575,12 +626,24 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
{
|
||||
if (sdlButtonPressed)
|
||||
{
|
||||
this->currentButton->SetInputData(
|
||||
inputType,
|
||||
sdlButton,
|
||||
0,
|
||||
sdlButtonName
|
||||
);
|
||||
if (this->addMappingToButton)
|
||||
{
|
||||
this->currentButton->AddInputData(
|
||||
inputType,
|
||||
sdlButton,
|
||||
0,
|
||||
sdlButtonName
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->currentButton->SetInputData(
|
||||
inputType,
|
||||
sdlButton,
|
||||
0,
|
||||
sdlButtonName
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -588,8 +651,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
// update controller button state
|
||||
for (auto& button : this->buttonWidgetMappings)
|
||||
{
|
||||
if (button.buttonWidget->GetInputType() == inputType &&
|
||||
button.buttonWidget->GetInputData() == sdlButton)
|
||||
if (button.buttonWidget->HasInputData(inputType, sdlButton))
|
||||
{
|
||||
this->controllerImageWidget->SetButtonState(button.button, sdlButtonPressed);
|
||||
}
|
||||
@@ -598,8 +660,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
// update controller analog stick state
|
||||
for (auto& joystick : this->joystickWidgetMappings)
|
||||
{
|
||||
if (joystick.buttonWidget->GetInputType() == inputType &&
|
||||
joystick.buttonWidget->GetInputData() == sdlButton)
|
||||
if (joystick.buttonWidget->HasInputData(inputType, sdlButton))
|
||||
{
|
||||
switch (joystick.direction)
|
||||
{
|
||||
@@ -643,6 +704,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
|
||||
if (event->type == SDL_CONTROLLERAXISMOTION)
|
||||
{ // gamepad axis
|
||||
if (!this->isCurrentJoystickGameController)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
joystickId = event->caxis.which;
|
||||
inputType = InputType::GamepadAxis;
|
||||
sdlAxis = event->caxis.axis;
|
||||
@@ -652,6 +718,11 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
}
|
||||
else
|
||||
{ // joystick axis
|
||||
if (this->isCurrentJoystickGameController)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
joystickId = event->jaxis.which;
|
||||
inputType = InputType::JoystickAxis;
|
||||
sdlAxis = event->jaxis.axis;
|
||||
@@ -677,24 +748,24 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
{
|
||||
if (sdlAxisButtonPressed)
|
||||
{
|
||||
// invert axis for left, right & z trigger mappings
|
||||
if (this->optionsDialogSettings.InvertAxis)
|
||||
if (this->addMappingToButton)
|
||||
{
|
||||
if (this->currentButton == this->leftTriggerButton ||
|
||||
this->currentButton == this->rightTriggerButton ||
|
||||
this->currentButton == this->zTriggerButton)
|
||||
{
|
||||
sdlAxisDirection = (sdlAxisDirection == 1 ? 0 : 1);
|
||||
sdlAxisName = "axis " + QString::number(sdlAxis);
|
||||
sdlAxisName += sdlAxisDirection > 0 ? "+" : "-";
|
||||
}
|
||||
this->currentButton->AddInputData(
|
||||
inputType,
|
||||
sdlAxis,
|
||||
sdlAxisDirection,
|
||||
sdlAxisName
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->currentButton->SetInputData(
|
||||
inputType,
|
||||
sdlAxis,
|
||||
sdlAxisDirection,
|
||||
sdlAxisName
|
||||
);
|
||||
}
|
||||
this->currentButton->SetInputData(
|
||||
inputType,
|
||||
sdlAxis,
|
||||
sdlAxisDirection,
|
||||
sdlAxisName
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -702,9 +773,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
// update controller button state
|
||||
for (auto& button : this->buttonWidgetMappings)
|
||||
{
|
||||
if (button.buttonWidget->GetInputType() == inputType &&
|
||||
button.buttonWidget->GetInputData() == sdlAxis &&
|
||||
button.buttonWidget->GetExtraInputData() == sdlAxisDirection)
|
||||
if (button.buttonWidget->HasInputData(inputType, sdlAxis, sdlAxisDirection))
|
||||
{
|
||||
this->controllerImageWidget->SetButtonState(button.button, sdlAxisButtonPressed);
|
||||
}
|
||||
@@ -713,9 +782,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
// update controller analog stick state
|
||||
for (auto& joystick : this->joystickWidgetMappings)
|
||||
{
|
||||
if (joystick.buttonWidget->GetInputType() == inputType &&
|
||||
joystick.buttonWidget->GetInputData() == sdlAxis &&
|
||||
joystick.buttonWidget->GetExtraInputData() == sdlAxisDirection)
|
||||
if (joystick.buttonWidget->HasInputData(inputType, sdlAxis, sdlAxisDirection))
|
||||
{
|
||||
const int value = -(double)((double)sdlAxisValue / SDL_AXIS_PEAK * 100);
|
||||
|
||||
@@ -758,12 +825,24 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
{
|
||||
if (sdlButtonPressed)
|
||||
{
|
||||
this->currentButton->SetInputData(
|
||||
InputType::Keyboard,
|
||||
sdlButton,
|
||||
0,
|
||||
SDL_GetScancodeName(sdlButton)
|
||||
);
|
||||
if (this->addMappingToButton)
|
||||
{
|
||||
this->currentButton->AddInputData(
|
||||
InputType::Keyboard,
|
||||
sdlButton,
|
||||
0,
|
||||
SDL_GetScancodeName(sdlButton)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->currentButton->SetInputData(
|
||||
InputType::Keyboard,
|
||||
sdlButton,
|
||||
0,
|
||||
SDL_GetScancodeName(sdlButton)
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -771,8 +850,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
// update controller button state
|
||||
for (auto& button : this->buttonWidgetMappings)
|
||||
{
|
||||
if (button.buttonWidget->GetInputType() == InputType::Keyboard &&
|
||||
button.buttonWidget->GetInputData() == sdlButton)
|
||||
if (button.buttonWidget->HasInputData(InputType::Keyboard, sdlButton))
|
||||
{
|
||||
this->controllerImageWidget->SetButtonState(button.button, sdlButtonPressed);
|
||||
}
|
||||
@@ -781,8 +859,7 @@ void ControllerWidget::on_MainDialog_SdlEvent(SDL_Event* event)
|
||||
// update controller analog stick state
|
||||
for (auto& joystick : this->joystickWidgetMappings)
|
||||
{
|
||||
if (joystick.buttonWidget->GetInputType() == InputType::Keyboard &&
|
||||
joystick.buttonWidget->GetInputData() == sdlButton)
|
||||
if (joystick.buttonWidget->HasInputData(InputType::Keyboard, sdlButton))
|
||||
{
|
||||
switch (joystick.direction)
|
||||
{
|
||||
@@ -897,20 +974,40 @@ void ControllerWidget::LoadSettings(QString sectionQString)
|
||||
this->controllerPluggedCheckBox->setChecked(CoreSettingsGetBoolValue(SettingsID::Input_PluggedIn, section));
|
||||
this->deadZoneSlider->setValue(CoreSettingsGetIntValue(SettingsID::Input_Deadzone, section));
|
||||
this->optionsDialogSettings.RemoveDuplicateMappings = CoreSettingsGetBoolValue(SettingsID::Input_RemoveDuplicateMappings, section);
|
||||
this->optionsDialogSettings.InvertAxis = CoreSettingsGetBoolValue(SettingsID::Input_InvertAxis, section);
|
||||
this->optionsDialogSettings.ControllerPak = CoreSettingsGetIntValue(SettingsID::Input_Pak, section);
|
||||
this->optionsDialogSettings.GameboyRom = CoreSettingsGetStringValue(SettingsID::Input_GameboyRom, section);
|
||||
this->optionsDialogSettings.GameboySave = CoreSettingsGetStringValue(SettingsID::Input_GameboySave, section);
|
||||
|
||||
for (auto& buttonSetting : this->buttonSettingMappings)
|
||||
{
|
||||
enum InputType type = (InputType)CoreSettingsGetIntValue(buttonSetting.inputTypeSettingsId, section);
|
||||
std::string name = CoreSettingsGetStringValue(buttonSetting.nameSettingsId, section);
|
||||
int data = CoreSettingsGetIntValue(buttonSetting.dataSettingsId, section);
|
||||
int extraData = CoreSettingsGetIntValue(buttonSetting.extraDataSettingsId, section);
|
||||
buttonSetting.button->Clear();
|
||||
|
||||
buttonSetting.button->SetInputData(type, data, extraData, QString::fromStdString(name));
|
||||
std::vector<int> types = CoreSettingsGetIntListValue(buttonSetting.inputTypeSettingsId, section);
|
||||
std::vector<std::string> names = CoreSettingsGetStringListValue(buttonSetting.nameSettingsId, section);
|
||||
std::vector<int> data = CoreSettingsGetIntListValue(buttonSetting.dataSettingsId, section);
|
||||
std::vector<int> extraData = CoreSettingsGetIntListValue(buttonSetting.extraDataSettingsId, section);
|
||||
|
||||
int count = std::min(extraData.size(), std::min(types.size(), std::min(names.size(), data.size())));
|
||||
|
||||
if (count == 0)
|
||||
{ // attempt to load old profile type
|
||||
types.push_back(CoreSettingsGetIntValue(buttonSetting.inputTypeSettingsId, section));
|
||||
names.push_back(CoreSettingsGetStringValue(buttonSetting.nameSettingsId, section));
|
||||
data.push_back(CoreSettingsGetIntValue(buttonSetting.dataSettingsId, section));
|
||||
extraData.push_back(CoreSettingsGetIntValue(buttonSetting.extraDataSettingsId, section));
|
||||
count = 1;
|
||||
}
|
||||
|
||||
// add all input data
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
buttonSetting.button->AddInputData((InputType)types[i], data[i], extraData[i], QString::fromStdString(names.at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
// force refresh some UI elements
|
||||
this->on_deadZoneSlider_valueChanged(this->deadZoneSlider->value());
|
||||
this->on_controllerPluggedCheckBox_toggled(this->IsPluggedIn());
|
||||
}
|
||||
|
||||
void ControllerWidget::SaveDefaultSettings()
|
||||
@@ -928,14 +1025,13 @@ void ControllerWidget::SaveDefaultSettings()
|
||||
CoreSettingsSetValue(SettingsID::Input_Deadzone, section, 9);
|
||||
CoreSettingsSetValue(SettingsID::Input_Pak, section, 0);
|
||||
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, true);
|
||||
CoreSettingsSetValue(SettingsID::Input_InvertAxis, section, true);
|
||||
|
||||
for (auto& buttonSetting : this->buttonSettingMappings)
|
||||
{
|
||||
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, (int)InputType::Invalid);
|
||||
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, std::string(" "));
|
||||
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, 0);
|
||||
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, 0);
|
||||
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, std::vector<int>({ (int)InputType::Invalid }));
|
||||
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, std::vector<std::string>({ std::string() }));
|
||||
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, std::vector<int>({ 0 }));
|
||||
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, std::vector<int>({ 0 }));
|
||||
}
|
||||
|
||||
CoreSettingsSave();
|
||||
@@ -962,12 +1058,11 @@ void ControllerWidget::SaveSettings()
|
||||
CoreSettingsSetValue(SettingsID::Input_GameboyRom, section, this->optionsDialogSettings.GameboyRom);
|
||||
CoreSettingsSetValue(SettingsID::Input_GameboySave, section, this->optionsDialogSettings.GameboySave);
|
||||
CoreSettingsSetValue(SettingsID::Input_RemoveDuplicateMappings, section, this->optionsDialogSettings.RemoveDuplicateMappings);
|
||||
CoreSettingsSetValue(SettingsID::Input_InvertAxis, section, this->optionsDialogSettings.InvertAxis);
|
||||
|
||||
for (auto& buttonSetting : this->buttonSettingMappings)
|
||||
{
|
||||
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, (int)buttonSetting.button->GetInputType());
|
||||
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, buttonSetting.button->text().toStdString());
|
||||
CoreSettingsSetValue(buttonSetting.inputTypeSettingsId, section, buttonSetting.button->GetInputType());
|
||||
CoreSettingsSetValue(buttonSetting.nameSettingsId, section, buttonSetting.button->GetInputText());
|
||||
CoreSettingsSetValue(buttonSetting.dataSettingsId, section, buttonSetting.button->GetInputData());
|
||||
CoreSettingsSetValue(buttonSetting.extraDataSettingsId, section, buttonSetting.button->GetExtraInputData());
|
||||
}
|
||||
@@ -980,3 +1075,8 @@ void ControllerWidget::SetCurrentJoystickID(SDL_JoystickID joystickId)
|
||||
this->currentJoystickId = joystickId;
|
||||
}
|
||||
|
||||
void ControllerWidget::SetIsCurrentJoystickGameController(bool isGameController)
|
||||
{
|
||||
this->isCurrentJoystickGameController = isGameController;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef CONTROLLERWIDGET_H
|
||||
#define CONTROLLERWIDGET_H
|
||||
|
||||
#include "CustomButton.hpp"
|
||||
#include "MappingButton.hpp"
|
||||
#include "ControllerImageWidget.hpp"
|
||||
|
||||
#include "UserInterface/EventFilter.hpp"
|
||||
@@ -39,23 +39,24 @@ private:
|
||||
OptionsDialogSettings optionsDialogSettings;
|
||||
|
||||
QList<QString> inputDeviceNameList;
|
||||
CustomButton* currentButton = nullptr;
|
||||
|
||||
MappingButton* currentButton = nullptr;
|
||||
bool addMappingToButton = false;
|
||||
|
||||
struct buttonWidgetMapping
|
||||
{
|
||||
enum N64ControllerButton button;
|
||||
CustomButton* buttonWidget;
|
||||
MappingButton* buttonWidget;
|
||||
};
|
||||
|
||||
struct axisWidgetMapping
|
||||
{
|
||||
enum InputAxisDirection direction;
|
||||
CustomButton* buttonWidget;
|
||||
MappingButton* buttonWidget;
|
||||
};
|
||||
|
||||
struct buttonSettingMapping
|
||||
{
|
||||
CustomButton* button;
|
||||
MappingButton* button;
|
||||
SettingsID inputTypeSettingsId;
|
||||
SettingsID nameSettingsId;
|
||||
SettingsID dataSettingsId;
|
||||
@@ -65,9 +66,7 @@ private:
|
||||
QList<buttonWidgetMapping> buttonWidgetMappings;
|
||||
QList<axisWidgetMapping> joystickWidgetMappings;
|
||||
QList<buttonSettingMapping> buttonSettingMappings;
|
||||
QList<CustomButton*> setupButtonWidgets;
|
||||
int currentSetupButtonWidgetIndex = 0;
|
||||
bool currentInSetup = false;
|
||||
QList<MappingButton*> setupButtonWidgets;
|
||||
|
||||
void initializeButtons();
|
||||
|
||||
@@ -77,11 +76,12 @@ private:
|
||||
void disableAllChildren();
|
||||
void enableAllChildren();
|
||||
|
||||
void removeDuplicates(CustomButton* button);
|
||||
void removeDuplicates(MappingButton* button);
|
||||
|
||||
QString getCurrentSettingsSection();
|
||||
|
||||
SDL_JoystickID currentJoystickId = -1;
|
||||
SDL_JoystickID currentJoystickId = -1;
|
||||
bool isCurrentJoystickGameController = false;
|
||||
|
||||
public:
|
||||
ControllerWidget(QWidget* parent, EventFilter* eventFilter);
|
||||
@@ -105,6 +105,7 @@ public:
|
||||
void SaveSettings();
|
||||
|
||||
void SetCurrentJoystickID(SDL_JoystickID joystickId);
|
||||
void SetIsCurrentJoystickGameController(bool isGameController);
|
||||
|
||||
private slots:
|
||||
void on_deadZoneSlider_valueChanged(int value);
|
||||
@@ -117,15 +118,18 @@ private slots:
|
||||
void on_controllerPluggedCheckBox_toggled(bool value);
|
||||
|
||||
void on_removeProfileButton_clicked();
|
||||
void on_setupButton_clicked();
|
||||
|
||||
void on_resetButton_clicked();
|
||||
void on_optionsButton_clicked();
|
||||
|
||||
public slots:
|
||||
void on_CustomButton_released(CustomButton* button);
|
||||
void on_CustomButton_TimerFinished(CustomButton* button);
|
||||
void on_CustomButton_DataSet(CustomButton* button);
|
||||
void on_MappingButton_Released(MappingButton* button);
|
||||
void on_MappingButton_TimerFinished(MappingButton* button);
|
||||
void on_MappingButton_DataSet(MappingButton* button);
|
||||
|
||||
void on_AddMappingButton_Released(MappingButton* button);
|
||||
void on_RemoveMappingButton_Released(MappingButton* button);
|
||||
|
||||
void on_MainDialog_SdlEvent(SDL_Event* event);
|
||||
void on_MainDialog_SdlEventPollFinished();
|
||||
signals:
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "CustomButton.hpp"
|
||||
#include "ControllerWidget.hpp"
|
||||
|
||||
using namespace UserInterface::Widget;
|
||||
|
||||
CustomButton::CustomButton(QWidget* parent) : QPushButton(parent)
|
||||
{
|
||||
this->countDownTimer = new QTimer(this);
|
||||
connect(this->countDownTimer, &QTimer::timeout, this, &CustomButton::on_countDownTimer_triggered);
|
||||
}
|
||||
|
||||
CustomButton::~CustomButton()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CustomButton::Initialize(QWidget* widget)
|
||||
{
|
||||
this->controllerWidget = (ControllerWidget*)widget;
|
||||
|
||||
connect(this, &QPushButton::released,
|
||||
[=]
|
||||
{
|
||||
emit this->controllerWidget->on_CustomButton_released(this);
|
||||
});
|
||||
}
|
||||
|
||||
void CustomButton::Clear()
|
||||
{
|
||||
this->inputType = InputType::Invalid;
|
||||
this->inputData = 0;
|
||||
this->extraInputData = 0;
|
||||
this->savedInputData = 0;
|
||||
this->savedExtraInputData = 0;
|
||||
this->setText(" ");
|
||||
}
|
||||
|
||||
void CustomButton::StartTimer()
|
||||
{
|
||||
this->currentCountDownNum = 5;
|
||||
this->on_countDownTimer_triggered();
|
||||
this->countDownTimer->start(1000);
|
||||
}
|
||||
|
||||
void CustomButton::StopTimer()
|
||||
{
|
||||
this->countDownTimer->stop();
|
||||
}
|
||||
|
||||
void CustomButton::SetInputData(enum InputType type, int value, int extraValue, QString name)
|
||||
{
|
||||
this->inputType = type;
|
||||
this->inputData = value;
|
||||
this->extraInputData = extraValue;
|
||||
this->setText(name);
|
||||
this->StopTimer();
|
||||
emit this->controllerWidget->on_CustomButton_DataSet(this);
|
||||
}
|
||||
|
||||
enum InputType CustomButton::GetInputType()
|
||||
{
|
||||
return this->inputType;
|
||||
}
|
||||
|
||||
int CustomButton::GetInputData()
|
||||
{
|
||||
return this->inputData;
|
||||
}
|
||||
|
||||
int CustomButton::GetExtraInputData()
|
||||
{
|
||||
return this->extraInputData;
|
||||
}
|
||||
|
||||
void CustomButton::SaveState()
|
||||
{
|
||||
this->savedInputType = this->inputType;
|
||||
this->savedInputData = this->inputData;
|
||||
this->savedExtraInputData = this->extraInputData;
|
||||
this->savedText = this->text();
|
||||
}
|
||||
|
||||
void CustomButton::RestoreState()
|
||||
{
|
||||
this->inputType = this->savedInputType;
|
||||
this->inputData = this->savedInputData;
|
||||
this->extraInputData = this->savedExtraInputData;
|
||||
this->setText(this->savedText);
|
||||
}
|
||||
|
||||
void CustomButton::on_countDownTimer_triggered()
|
||||
{
|
||||
this->setText(QString::number(this->currentCountDownNum));
|
||||
|
||||
if (this->currentCountDownNum == 0)
|
||||
{
|
||||
this->setText("");
|
||||
this->currentCountDownNum = 5;
|
||||
this->countDownTimer->stop();
|
||||
emit this->controllerWidget->on_CustomButton_TimerFinished(this);
|
||||
}
|
||||
|
||||
this->currentCountDownNum--;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CUSTOMBUTTON_HPP
|
||||
#define CUSTOMBUTTON_HPP
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
namespace Widget
|
||||
{
|
||||
|
||||
// we can't include ControllerWidget.hpp
|
||||
// because that header includes this header,
|
||||
// so forward-declare it to prevent issues
|
||||
class ControllerWidget;
|
||||
|
||||
class CustomButton : public QPushButton
|
||||
{
|
||||
private:
|
||||
QTimer* countDownTimer = nullptr;
|
||||
ControllerWidget* controllerWidget = nullptr;
|
||||
int currentCountDownNum = 0;
|
||||
enum InputType inputType = InputType::Invalid;
|
||||
int inputData = 0;
|
||||
int extraInputData = 0;
|
||||
|
||||
enum InputType savedInputType = InputType::Invalid;
|
||||
int savedInputData = 0;
|
||||
int savedExtraInputData = 0;
|
||||
QString savedText;
|
||||
public:
|
||||
CustomButton(QWidget* parent);
|
||||
~CustomButton();
|
||||
void Initialize(QWidget* widget);
|
||||
void Clear();
|
||||
|
||||
void StartTimer();
|
||||
void StopTimer();
|
||||
|
||||
|
||||
void SetInputData(enum InputType type, int value, int extraValue, QString name);
|
||||
enum InputType GetInputType();
|
||||
int GetInputData();
|
||||
int GetExtraInputData();
|
||||
|
||||
void SaveState();
|
||||
void RestoreState();
|
||||
|
||||
private slots:
|
||||
void on_countDownTimer_triggered();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // CUSTOMBUTTON_HPP
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "MappingButton.hpp"
|
||||
#include "ControllerWidget.hpp"
|
||||
|
||||
using namespace UserInterface::Widget;
|
||||
|
||||
MappingButton::MappingButton(QWidget* parent) : QPushButton(parent)
|
||||
{
|
||||
this->countDownTimer = new QTimer(this);
|
||||
connect(this->countDownTimer, &QTimer::timeout, this, &MappingButton::on_countDownTimer_triggered);
|
||||
}
|
||||
|
||||
MappingButton::~MappingButton()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MappingButton::Initialize(ControllerWidget* widget)
|
||||
{
|
||||
this->controllerWidget = widget;
|
||||
|
||||
connect(this, &QPushButton::released, [=]
|
||||
{
|
||||
emit this->controllerWidget->on_MappingButton_Released(this);
|
||||
});
|
||||
|
||||
this->setText(" ");
|
||||
}
|
||||
|
||||
void MappingButton::Clear()
|
||||
{
|
||||
this->inputData.clear();
|
||||
this->savedInputData.clear();
|
||||
this->setText(" ");
|
||||
}
|
||||
|
||||
void MappingButton::StartTimer()
|
||||
{
|
||||
this->currentCountDownNum = 5;
|
||||
this->on_countDownTimer_triggered();
|
||||
this->countDownTimer->start(1000);
|
||||
}
|
||||
|
||||
void MappingButton::StopTimer()
|
||||
{
|
||||
this->countDownTimer->stop();
|
||||
}
|
||||
|
||||
void MappingButton::SetInputData(enum InputType type, int value, int extraValue, QString name)
|
||||
{
|
||||
// don't add stub
|
||||
if (name.simplified().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->inputData.clear();
|
||||
this->inputData.push_back(
|
||||
{
|
||||
type,
|
||||
value,
|
||||
extraValue,
|
||||
name
|
||||
}
|
||||
);
|
||||
|
||||
this->reloadText();
|
||||
this->StopTimer();
|
||||
|
||||
emit this->controllerWidget->on_MappingButton_DataSet(this);
|
||||
}
|
||||
|
||||
void MappingButton::AddInputData(enum InputType type, int value, int extraValue, QString name)
|
||||
{
|
||||
// don't add stub
|
||||
if (name.simplified().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->HasInputData(type, value, extraValue))
|
||||
{
|
||||
this->inputData.push_back(
|
||||
{
|
||||
type,
|
||||
value,
|
||||
extraValue,
|
||||
name
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this->reloadText();
|
||||
this->StopTimer();
|
||||
|
||||
emit this->controllerWidget->on_MappingButton_DataSet(this);
|
||||
}
|
||||
|
||||
void MappingButton::RemoveLastInputData(void)
|
||||
{
|
||||
if (!this->inputData.empty())
|
||||
{
|
||||
this->inputData.pop_back();
|
||||
}
|
||||
|
||||
this->reloadText();
|
||||
}
|
||||
|
||||
void MappingButton::RemoveInputData(InputType type, int value, int extraValue)
|
||||
{
|
||||
auto iter = this->getInputDataIter(type, value, extraValue);
|
||||
if (iter == this->inputData.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->inputData.erase(iter);
|
||||
this->reloadText();
|
||||
}
|
||||
|
||||
bool MappingButton::HasInputData(enum InputType type, int value, int extraValue)
|
||||
{
|
||||
return this->getInputDataIter(type, value, extraValue) != this->inputData.end();
|
||||
}
|
||||
|
||||
std::vector<int> MappingButton::GetInputType()
|
||||
{
|
||||
std::vector<int> inputTypeList;
|
||||
|
||||
for (const auto& data : this->inputData)
|
||||
{
|
||||
inputTypeList.push_back((int)data.Type);
|
||||
}
|
||||
|
||||
return inputTypeList;
|
||||
}
|
||||
|
||||
std::vector<int> MappingButton::GetInputData()
|
||||
{
|
||||
std::vector<int> inputDataList;
|
||||
|
||||
for (const auto& data : this->inputData)
|
||||
{
|
||||
inputDataList.push_back(data.Data);
|
||||
}
|
||||
|
||||
return inputDataList;
|
||||
}
|
||||
|
||||
std::vector<int> MappingButton::GetExtraInputData()
|
||||
{
|
||||
std::vector<int> extraInputDataList;
|
||||
|
||||
for (const auto& data : this->inputData)
|
||||
{
|
||||
extraInputDataList.push_back(data.ExtraData);
|
||||
}
|
||||
|
||||
return extraInputDataList;
|
||||
}
|
||||
|
||||
std::vector<std::string> MappingButton::GetInputText()
|
||||
{
|
||||
std::vector<std::string> inputTextList;
|
||||
|
||||
for (const auto& data : this->inputData)
|
||||
{
|
||||
inputTextList.push_back(data.Text.toStdString());
|
||||
}
|
||||
|
||||
return inputTextList;
|
||||
}
|
||||
|
||||
void MappingButton::SaveState()
|
||||
{
|
||||
this->savedInputData = this->inputData;
|
||||
}
|
||||
|
||||
void MappingButton::RestoreState()
|
||||
{
|
||||
this->inputData = this->savedInputData;
|
||||
this->reloadText();
|
||||
}
|
||||
|
||||
void MappingButton::on_countDownTimer_triggered()
|
||||
{
|
||||
this->setText(QString::number(this->currentCountDownNum));
|
||||
|
||||
if (this->currentCountDownNum == 0)
|
||||
{
|
||||
this->setText("");
|
||||
this->currentCountDownNum = 5;
|
||||
this->countDownTimer->stop();
|
||||
emit this->controllerWidget->on_MappingButton_TimerFinished(this);
|
||||
}
|
||||
|
||||
this->currentCountDownNum--;
|
||||
}
|
||||
|
||||
void MappingButton::reloadText()
|
||||
{
|
||||
QString text;
|
||||
QFontMetrics fontMetrics(this->font());
|
||||
|
||||
int size = this->inputData.size();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
text += this->inputData.at(i).Text;
|
||||
|
||||
// only add comma when
|
||||
// not at the last item
|
||||
if (i < (size - 1))
|
||||
{
|
||||
text += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
QString elidedText = fontMetrics.elidedText(text, Qt::ElideRight, this->width());
|
||||
|
||||
// needed for spacing
|
||||
if (elidedText.isEmpty())
|
||||
{
|
||||
elidedText = " ";
|
||||
}
|
||||
|
||||
this->setToolTip(text);
|
||||
this->setText(elidedText);
|
||||
}
|
||||
|
||||
std::vector<MappingButtonInputDataType>::iterator MappingButton::getInputDataIter(InputType type, int value, int extraValue)
|
||||
{
|
||||
auto predicate = [type, value, extraValue](const auto& entry)
|
||||
{
|
||||
return entry.Type == type &&
|
||||
(value == -1 || entry.Data == value) &&
|
||||
(extraValue == -1 || entry.ExtraData == extraValue);
|
||||
};
|
||||
|
||||
return std::find_if(this->inputData.begin(), this->inputData.end(), predicate);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef MAPPINGBUTTON_HPP
|
||||
#define MAPPINGBUTTON_HPP
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
namespace Widget
|
||||
{
|
||||
|
||||
// we can't include ControllerWidget.hpp
|
||||
// because that header includes this header,
|
||||
// so forward-declare it to prevent issues
|
||||
class ControllerWidget;
|
||||
|
||||
struct MappingButtonInputDataType
|
||||
{
|
||||
InputType Type;
|
||||
int Data;
|
||||
int ExtraData;
|
||||
QString Text;
|
||||
};
|
||||
|
||||
class MappingButton : public QPushButton
|
||||
{
|
||||
private:
|
||||
QTimer* countDownTimer = nullptr;
|
||||
ControllerWidget* controllerWidget = nullptr;
|
||||
int currentCountDownNum = 0;
|
||||
|
||||
std::vector<MappingButtonInputDataType> inputData;
|
||||
|
||||
std::vector<MappingButtonInputDataType> savedInputData;
|
||||
|
||||
void reloadText();
|
||||
|
||||
std::vector<MappingButtonInputDataType>::iterator getInputDataIter(InputType type, int value, int extraValue);
|
||||
|
||||
public:
|
||||
MappingButton(QWidget* parent);
|
||||
~MappingButton();
|
||||
|
||||
void Initialize(ControllerWidget* widget);
|
||||
void Clear();
|
||||
|
||||
void StartTimer();
|
||||
void StopTimer();
|
||||
|
||||
void SetInputData(InputType type, int value, int extraValue, QString name);
|
||||
void AddInputData(InputType type, int value, int extraValue, QString name);
|
||||
|
||||
void RemoveLastInputData(void);
|
||||
void RemoveInputData(InputType type, int value, int extraValue);
|
||||
|
||||
bool HasInputData(InputType type, int value = -1, int extraValue = -1);
|
||||
|
||||
std::vector<int> GetInputType();
|
||||
std::vector<int> GetInputData();
|
||||
std::vector<int> GetExtraInputData();
|
||||
std::vector<std::string> GetInputText();
|
||||
|
||||
void SaveState();
|
||||
void RestoreState();
|
||||
|
||||
private slots:
|
||||
void on_countDownTimer_triggered();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MAPPINGBUTTON_HPP
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "RemoveMappingButton.hpp"
|
||||
#include "ControllerWidget.hpp"
|
||||
#include "MappingButton.hpp"
|
||||
|
||||
using namespace UserInterface::Widget;
|
||||
|
||||
RemoveMappingButton::RemoveMappingButton(QWidget* parent) : QPushButton(parent)
|
||||
{
|
||||
}
|
||||
|
||||
RemoveMappingButton::~RemoveMappingButton()
|
||||
{
|
||||
}
|
||||
|
||||
void RemoveMappingButton::Initialize(ControllerWidget* widget, MappingButton* button)
|
||||
{
|
||||
this->controllerWidget = widget;
|
||||
this->mappingButton = button;
|
||||
|
||||
connect(this, &QPushButton::released, [=]
|
||||
{
|
||||
emit this->controllerWidget->on_RemoveMappingButton_Released(this->mappingButton);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef REMOVEMAPPINGBUTTON_HPP
|
||||
#define REMOVEMAPPINGBUTTON_HPP
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
namespace UserInterface
|
||||
{
|
||||
namespace Widget
|
||||
{
|
||||
|
||||
// we can't include ControllerWidget.hpp
|
||||
// because that header includes this header,
|
||||
// so forward-declare it to prevent issues
|
||||
class ControllerWidget;
|
||||
class MappingButton;
|
||||
|
||||
class RemoveMappingButton : public QPushButton
|
||||
{
|
||||
private:
|
||||
ControllerWidget* controllerWidget = nullptr;
|
||||
MappingButton* mappingButton = nullptr;
|
||||
|
||||
public:
|
||||
RemoveMappingButton(QWidget* parent);
|
||||
~RemoveMappingButton();
|
||||
|
||||
void Initialize(ControllerWidget* widget, MappingButton* button);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // REMOVEMAPPINGBUTTON_HPP
|
||||
@@ -49,9 +49,10 @@
|
||||
|
||||
struct InputMapping
|
||||
{
|
||||
InputType Type = InputType::Invalid;
|
||||
int Data = 0;
|
||||
int ExtraData = 0;
|
||||
std::vector<int> Type;
|
||||
std::vector<int> Data;
|
||||
std::vector<int> ExtraData;
|
||||
int Count = 0;
|
||||
};
|
||||
|
||||
struct InputProfile
|
||||
@@ -122,9 +123,18 @@ static bool l_KeyboardState[SDL_NUM_SCANCODES];
|
||||
static void load_inputmapping_settings(InputMapping* mapping, std::string section,
|
||||
SettingsID inputTypeSettingsId, SettingsID dataSettingsId, SettingsID extraDataSettingsId)
|
||||
{
|
||||
mapping->Type = (InputType)CoreSettingsGetIntValue(inputTypeSettingsId, section);
|
||||
mapping->Data = CoreSettingsGetIntValue(dataSettingsId, section);
|
||||
mapping->ExtraData = CoreSettingsGetIntValue(extraDataSettingsId, section);
|
||||
mapping->Type = CoreSettingsGetIntListValue(inputTypeSettingsId, section);
|
||||
mapping->Data = CoreSettingsGetIntListValue(dataSettingsId, section);
|
||||
mapping->ExtraData = CoreSettingsGetIntListValue(extraDataSettingsId, section);
|
||||
mapping->Count = std::min(mapping->Type.size(), std::min(mapping->Data.size(), mapping->ExtraData.size()));
|
||||
|
||||
if (mapping->Count == 0)
|
||||
{ // try to load old profile type
|
||||
mapping->Type.push_back(CoreSettingsGetIntValue(inputTypeSettingsId, section));
|
||||
mapping->Data.push_back(CoreSettingsGetIntValue(dataSettingsId, section));
|
||||
mapping->ExtraData.push_back(CoreSettingsGetIntValue(extraDataSettingsId, section));
|
||||
mapping->Count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_settings(void)
|
||||
@@ -286,88 +296,104 @@ static void close_controllers(void)
|
||||
|
||||
static int get_button_state(InputProfile* profile, InputMapping* inputMapping)
|
||||
{
|
||||
switch (inputMapping->Type)
|
||||
int state = 0;
|
||||
|
||||
for (int i = 0; i < inputMapping->Count; i++)
|
||||
{
|
||||
case InputType::GamepadButton:
|
||||
const int data = inputMapping->Data.at(i);
|
||||
const int extraData = inputMapping->ExtraData.at(i);
|
||||
|
||||
switch ((InputType)inputMapping->Type[i])
|
||||
{
|
||||
return SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)inputMapping->Data);
|
||||
};
|
||||
case InputType::GamepadAxis:
|
||||
{
|
||||
int axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)inputMapping->Data);
|
||||
return (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
|
||||
};
|
||||
case InputType::JoystickButton:
|
||||
{
|
||||
return SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
|
||||
};
|
||||
case InputType::JoystickAxis:
|
||||
{
|
||||
int axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
|
||||
return (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
|
||||
case InputType::GamepadButton:
|
||||
{
|
||||
state |= SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
|
||||
} break;
|
||||
case InputType::GamepadAxis:
|
||||
{
|
||||
int axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)data);
|
||||
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
|
||||
} break;
|
||||
case InputType::JoystickButton:
|
||||
{
|
||||
state |= SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
|
||||
} break;
|
||||
case InputType::JoystickAxis:
|
||||
{
|
||||
int axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), data);
|
||||
state |= (abs(axis_value) >= (SDL_AXIS_PEAK / 2) && (extraData ? axis_value > 0 : axis_value < 0)) ? 1 : 0;
|
||||
} break;
|
||||
case InputType::Keyboard:
|
||||
{
|
||||
state |= l_KeyboardState[data] ? 1 : 0;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case InputType::Keyboard:
|
||||
{
|
||||
return l_KeyboardState[inputMapping->Data] ? 1 : 0;
|
||||
};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return state;
|
||||
}
|
||||
|
||||
// returns axis input scaled to the range [-1, 1]
|
||||
static double get_axis_state(InputProfile* profile, InputMapping* inputMapping, int direction, double value)
|
||||
{
|
||||
switch (inputMapping->Type)
|
||||
{
|
||||
case InputType::GamepadButton:
|
||||
{
|
||||
int buttonState = SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)inputMapping->Data);
|
||||
return buttonState ? direction : value;
|
||||
} break;
|
||||
case InputType::GamepadAxis:
|
||||
{
|
||||
double axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)inputMapping->Data);
|
||||
if (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)
|
||||
{
|
||||
axis_value = (axis_value / SDL_AXIS_PEAK);
|
||||
axis_value = abs(axis_value) * direction;
|
||||
return axis_value;
|
||||
}
|
||||
} break;
|
||||
case InputType::JoystickButton:
|
||||
{
|
||||
int buttonState = SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
|
||||
return buttonState ? direction : value;
|
||||
} break;
|
||||
case InputType::JoystickAxis:
|
||||
{
|
||||
double axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), inputMapping->Data);
|
||||
if (inputMapping->ExtraData ? axis_value > 0 : axis_value < 0)
|
||||
{
|
||||
axis_value = (axis_value / SDL_AXIS_PEAK);
|
||||
axis_value = abs(axis_value) * direction;
|
||||
return axis_value;
|
||||
}
|
||||
} break;
|
||||
case InputType::Keyboard:
|
||||
{
|
||||
return l_KeyboardState[inputMapping->Data] ? direction : value;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
int state = 0;
|
||||
|
||||
return value;
|
||||
for (int i = 0; i < inputMapping->Count; i++)
|
||||
{
|
||||
const int data = inputMapping->Data.at(i);
|
||||
const int extraData = inputMapping->ExtraData.at(i);
|
||||
|
||||
switch ((InputType)inputMapping->Type[i])
|
||||
{
|
||||
case InputType::GamepadButton:
|
||||
{
|
||||
int buttonState = SDL_GameControllerGetButton(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerButton)data);
|
||||
state |= buttonState;
|
||||
} break;
|
||||
case InputType::GamepadAxis:
|
||||
{
|
||||
double axis_value = SDL_GameControllerGetAxis(profile->InputDevice.GetGameControllerHandle(), (SDL_GameControllerAxis)data);
|
||||
if (extraData ? axis_value > 0 : axis_value < 0)
|
||||
{
|
||||
axis_value = (axis_value / SDL_AXIS_PEAK);
|
||||
axis_value = abs(axis_value) * direction;
|
||||
return axis_value;
|
||||
}
|
||||
} break;
|
||||
case InputType::JoystickButton:
|
||||
{
|
||||
int buttonState = SDL_JoystickGetButton(profile->InputDevice.GetJoystickHandle(), data);
|
||||
state |= buttonState;
|
||||
} break;
|
||||
case InputType::JoystickAxis:
|
||||
{
|
||||
double axis_value = SDL_JoystickGetAxis(profile->InputDevice.GetJoystickHandle(), data);
|
||||
if (extraData ? axis_value > 0 : axis_value < 0)
|
||||
{
|
||||
axis_value = (axis_value / SDL_AXIS_PEAK);
|
||||
axis_value = abs(axis_value) * direction;
|
||||
return axis_value;
|
||||
}
|
||||
} break;
|
||||
case InputType::Keyboard:
|
||||
{
|
||||
state |= l_KeyboardState[data];
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state ? direction : value;
|
||||
}
|
||||
|
||||
static double simulate_deadzone(double n64InputAxis, double maxAxis, int deadzone, double axisRange)
|
||||
{
|
||||
double axisAbsolute = std::abs(n64InputAxis);
|
||||
|
||||
if (axisAbsolute < deadzone)
|
||||
if (axisAbsolute <= deadzone)
|
||||
{
|
||||
axisAbsolute = 0; // No input when inside deadzone
|
||||
}
|
||||
@@ -450,6 +476,8 @@ static unsigned char data_crc(unsigned char *data, int length)
|
||||
|
||||
void sdl_init()
|
||||
{
|
||||
std::filesystem::path gameControllerDbPath;
|
||||
|
||||
for (int subsystem : {SDL_INIT_GAMECONTROLLER, SDL_INIT_VIDEO, SDL_INIT_HAPTIC})
|
||||
{
|
||||
if (!SDL_WasInit(subsystem))
|
||||
@@ -457,6 +485,12 @@ void sdl_init()
|
||||
SDL_InitSubSystem(subsystem);
|
||||
}
|
||||
}
|
||||
|
||||
gameControllerDbPath = CoreGetSharedDataDirectory();
|
||||
gameControllerDbPath += "/gamecontrollerdb.txt";
|
||||
|
||||
// load mappings from file
|
||||
SDL_GameControllerAddMappingsFromFile(gameControllerDbPath.string().c_str());
|
||||
}
|
||||
|
||||
void sdl_quit()
|
||||
|
||||
@@ -5,21 +5,37 @@ set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
find_package(Qt5 COMPONENTS Gui Widgets Core REQUIRED)
|
||||
find_package(Qt6 COMPONENTS Gui Widgets Core OpenGL REQUIRED)
|
||||
|
||||
if (PORTABLE_INSTALL)
|
||||
add_definitions(-DPORTABLE_INSTALL)
|
||||
endif(PORTABLE_INSTALL)
|
||||
|
||||
if (UPDATER)
|
||||
find_package(Qt6 COMPONENTS Network REQUIRED)
|
||||
add_definitions(-DUPDATER)
|
||||
endif(UPDATER)
|
||||
|
||||
if (DISCORD_RPC)
|
||||
add_definitions(-DDISCORD_RPC)
|
||||
endif(DISCORD_RPC)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED sdl2)
|
||||
|
||||
configure_file(Config.hpp.in Config.hpp)
|
||||
|
||||
set(RMG_SOURCES
|
||||
UserInterface/MainWindow.cpp
|
||||
UserInterface/MainWindow.ui
|
||||
UserInterface/Widget/RomBrowserWidget.cpp
|
||||
UserInterface/Widget/RomBrowserListViewWidget.cpp
|
||||
UserInterface/Widget/RomBrowserGridViewWidget.cpp
|
||||
UserInterface/Widget/RomBrowserLoadingWidget.cpp
|
||||
UserInterface/Widget/RomBrowserEmptyWidget.cpp
|
||||
UserInterface/Widget/RomBrowserEmptyWidget.ui
|
||||
UserInterface/Widget/OGLWidget.cpp
|
||||
UserInterface/Widget/KeybindButton.cpp
|
||||
UserInterface/Dialog/SettingsDialog.cpp
|
||||
UserInterface/Dialog/SettingsDialog.ui
|
||||
UserInterface/Dialog/SettingsDialog.qrc
|
||||
UserInterface/Dialog/CheatsDialog.cpp
|
||||
UserInterface/Dialog/CheatsDialog.ui
|
||||
UserInterface/Dialog/AddCheatDialog.cpp
|
||||
@@ -30,6 +46,8 @@ set(RMG_SOURCES
|
||||
UserInterface/Dialog/RomInfoDialog.ui
|
||||
UserInterface/Dialog/AboutDialog.cpp
|
||||
UserInterface/Dialog/AboutDialog.ui
|
||||
UserInterface/Dialog/LogDialog.cpp
|
||||
UserInterface/Dialog/LogDialog.ui
|
||||
UserInterface/NoFocusDelegate.cpp
|
||||
UserInterface/EventFilter.cpp
|
||||
UserInterface/UIResources.rc
|
||||
@@ -37,20 +55,38 @@ set(RMG_SOURCES
|
||||
Thread/RomSearcherThread.cpp
|
||||
Thread/EmulationThread.cpp
|
||||
Utilities/QtKeyToSdl2Key.cpp
|
||||
OnScreenDisplay.cpp
|
||||
Callbacks.cpp
|
||||
VidExt.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
if (UPDATER)
|
||||
list(APPEND RMG_SOURCES
|
||||
UserInterface/Dialog/UpdateDialog.cpp
|
||||
UserInterface/Dialog/UpdateDialog.ui
|
||||
UserInterface/Dialog/DownloadUpdateDialog.cpp
|
||||
UserInterface/Dialog/DownloadUpdateDialog.ui
|
||||
UserInterface/Dialog/InstallUpdateDialog.cpp
|
||||
UserInterface/Dialog/InstallUpdateDialog.ui
|
||||
)
|
||||
endif(UPDATER)
|
||||
|
||||
set_source_files_properties(${IMGUI_SOURCES} PROPERTIES GENERATED TRUE)
|
||||
list(APPEND RMG_SOURCES ${IMGUI_SOURCES})
|
||||
|
||||
if (CMAKE_BUILD_TYPE MATCHES Release)
|
||||
add_executable(RMG WIN32 ${RMG_SOURCES})
|
||||
else()
|
||||
add_executable(RMG ${RMG_SOURCES})
|
||||
endif()
|
||||
|
||||
add_dependencies(RMG
|
||||
imgui
|
||||
)
|
||||
|
||||
target_link_libraries(RMG
|
||||
RMG-Core
|
||||
${SDL2_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(RMG PRIVATE
|
||||
@@ -58,6 +94,12 @@ target_include_directories(RMG PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
${IMGUI_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(RMG Qt5::Gui Qt5::Widgets)
|
||||
target_link_libraries(RMG Qt6::Gui Qt6::Widgets Qt6::OpenGL)
|
||||
|
||||
if (UPDATER)
|
||||
target_link_libraries(RMG Qt6::Network)
|
||||
endif(UPDATER)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
//
|
||||
|
||||
static CoreCallbacks* l_CoreCallbacks = nullptr;
|
||||
static bool l_showVerboseMessages = false;
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
@@ -36,6 +37,8 @@ bool CoreCallbacks::Init(void)
|
||||
// needed for Qt
|
||||
qRegisterMetaType<CoreDebugMessageType>("CoreDebugMessageType");
|
||||
|
||||
this->LoadSettings();
|
||||
|
||||
l_CoreCallbacks = this;
|
||||
return CoreSetupCallbacks(this->coreDebugCallback);
|
||||
}
|
||||
@@ -45,12 +48,23 @@ void CoreCallbacks::Stop(void)
|
||||
l_CoreCallbacks = nullptr;
|
||||
}
|
||||
|
||||
void CoreCallbacks::coreDebugCallback(CoreDebugMessageType type, std::string message)
|
||||
void CoreCallbacks::LoadSettings(void)
|
||||
{
|
||||
l_showVerboseMessages = CoreSettingsGetBoolValue(SettingsID::GUI_ShowVerboseLogMessages);
|
||||
}
|
||||
|
||||
void CoreCallbacks::coreDebugCallback(CoreDebugMessageType type, std::string context, std::string message)
|
||||
{
|
||||
if (l_CoreCallbacks == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
emit l_CoreCallbacks->OnCoreDebugCallback(type, QString::fromStdString(message));
|
||||
// only show verbose messages when enabled
|
||||
if (!l_showVerboseMessages && type == CoreDebugMessageType::Verbose)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
emit l_CoreCallbacks->OnCoreDebugCallback(type, QString::fromStdString(context), QString::fromStdString(message));
|
||||
}
|
||||
|
||||
@@ -27,11 +27,13 @@ public:
|
||||
bool Init(void);
|
||||
void Stop(void);
|
||||
|
||||
void LoadSettings(void);
|
||||
|
||||
private:
|
||||
static void coreDebugCallback(CoreDebugMessageType type, std::string message);
|
||||
static void coreDebugCallback(CoreDebugMessageType type, std::string context, std::string message);
|
||||
|
||||
signals:
|
||||
void OnCoreDebugCallback(CoreDebugMessageType type, QString message);
|
||||
void OnCoreDebugCallback(CoreDebugMessageType type, QString context, QString message);
|
||||
};
|
||||
|
||||
#endif // RMG_CALLBACKS_HPP
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef CONFIG_HPP
|
||||
#define CONFIG_HPP
|
||||
|
||||
#define WINDOW_TITLE "Rosalie's Mupen GUI (${GIT_VERSION})"
|
||||
#define VERSION_STR "${GIT_VERSION}"
|
||||
|
||||
#endif // CONFIG_HPP
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "OnScreenDisplay.hpp"
|
||||
|
||||
#include <RMG-Core/Core.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <chrono>
|
||||
|
||||
//
|
||||
// Local Variables
|
||||
//
|
||||
|
||||
static bool l_Initialized = false;
|
||||
static bool l_Enabled = false;
|
||||
static bool l_RenderingPaused = false;
|
||||
|
||||
static std::chrono::time_point<std::chrono::high_resolution_clock> l_MessageTime;
|
||||
static std::string l_Message;
|
||||
static int l_MessagePosition = 1;
|
||||
static float l_MessagePaddingX = 20.0f;
|
||||
static float l_MessagePaddingY = 20.0f;
|
||||
static float l_MessageOpacity = 1.0f;
|
||||
static int l_MessageDuration = 3;
|
||||
|
||||
//
|
||||
// Exported Functions
|
||||
//
|
||||
|
||||
bool OnScreenDisplayInit(void)
|
||||
{
|
||||
if (l_Initialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
if (!ImGui_ImplOpenGL3_Init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
l_Initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnScreenDisplayShutdown(void)
|
||||
{
|
||||
if (!l_Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
l_Message = "";
|
||||
l_Initialized = false;
|
||||
l_RenderingPaused = false;
|
||||
}
|
||||
|
||||
void OnScreenDisplayLoadSettings(void)
|
||||
{
|
||||
l_Enabled = CoreSettingsGetBoolValue(SettingsID::GUI_OnScreenDisplayEnabled);
|
||||
l_MessagePosition = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayLocation);
|
||||
l_MessagePaddingX = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayPaddingX);
|
||||
l_MessagePaddingY = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayPaddingY);
|
||||
l_MessageOpacity = CoreSettingsGetFloatValue(SettingsID::GUI_OnScreenDisplayOpacity);
|
||||
l_MessageDuration = CoreSettingsGetIntValue(SettingsID::GUI_OnScreenDisplayDuration);
|
||||
}
|
||||
|
||||
bool OnScreenDisplaySetDisplaySize(int width, int height)
|
||||
{
|
||||
if (!l_Initialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
io.DisplaySize = ImVec2((float)width, (float)height);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnScreenDisplaySetMessage(std::string message)
|
||||
{
|
||||
if (!l_Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
l_Message = message;
|
||||
l_MessageTime = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void OnScreenDisplayRender(void)
|
||||
{
|
||||
if (!l_Initialized || !l_Enabled || l_RenderingPaused || l_Message.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
const int secondsPassed = std::chrono::duration_cast<std::chrono::seconds>(currentTime - l_MessageTime).count();
|
||||
if (secondsPassed >= l_MessageDuration)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui::SetNextWindowBgAlpha(l_MessageOpacity);
|
||||
|
||||
// right bottom = ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - 20.0f, io.DisplaySize.y - 20.0f), ImGuiCond_Always, ImVec2(1.0f, 1.0f));
|
||||
// right top = ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - 20.0f, 20.0f), ImGuiCond_Always, ImVec2(1.0f, 0));
|
||||
// left bottom = ImGui::SetNextWindowPos(ImVec2(20.0f, io.DisplaySize.y - 20.0f), ImGuiCond_Always, ImVec2(0.0f, 1.0f));
|
||||
// left top = ImGui::SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiCond_Always, ImVec2(0.0f, 0.0f));
|
||||
switch (l_MessagePosition)
|
||||
{
|
||||
default:
|
||||
case 0: // left bottom
|
||||
ImGui::SetNextWindowPos(ImVec2(l_MessagePaddingX, io.DisplaySize.y - l_MessagePaddingY), ImGuiCond_Always, ImVec2(0.0f, 1.0f));
|
||||
break;
|
||||
case 1: // left top
|
||||
ImGui::SetNextWindowPos(ImVec2(l_MessagePaddingX, l_MessagePaddingY), ImGuiCond_Always, ImVec2(0.0f, 0.0f));
|
||||
break;
|
||||
case 2: // right top
|
||||
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - l_MessagePaddingX, l_MessagePaddingY), ImGuiCond_Always, ImVec2(1.0f, 0));
|
||||
break;
|
||||
case 3: // right bottom
|
||||
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x - l_MessagePaddingX, io.DisplaySize.y - l_MessagePaddingY), ImGuiCond_Always, ImVec2(1.0f, 1.0f));
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::Begin("Message", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing);
|
||||
ImGui::Text("%s", l_Message.c_str());
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
|
||||
void OnScreenDisplayPause(void)
|
||||
{
|
||||
l_RenderingPaused = true;
|
||||
}
|
||||
|
||||
void OnScreenDisplayResume(void)
|
||||
{
|
||||
l_RenderingPaused = false;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Rosalie's Mupen GUI - https://github.com/Rosalie241/RMG
|
||||
* Copyright (C) 2020 Rosalie Wanders <rosalie@mailbox.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef RMG_ONSCREENDISPLAY_HPP
|
||||
#define RMG_ONSCREENDISPLAY_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
// attempts to initialize the OSD
|
||||
bool OnScreenDisplayInit(void);
|
||||
|
||||
// shuts down the OSD when initialized
|
||||
void OnScreenDisplayShutdown(void);
|
||||
|
||||
// loads settings for the OSD
|
||||
void OnScreenDisplayLoadSettings(void);
|
||||
|
||||
// sets the display size for the OSD
|
||||
bool OnScreenDisplaySetDisplaySize(int width, int height);
|
||||
|
||||
// sets the current message to the OSD
|
||||
void OnScreenDisplaySetMessage(std::string message);
|
||||
|
||||
// renders the OSD
|
||||
void OnScreenDisplayRender(void);
|
||||
|
||||
// pauses OSD rendering
|
||||
void OnScreenDisplayPause(void);
|
||||
|
||||
// resumes OSD rendering
|
||||
void OnScreenDisplayResume(void);
|
||||
|
||||
#endif // RMG_ONSCREENDISPLAY_HPP
|
||||
@@ -44,9 +44,8 @@ class EmulationThread : public QThread
|
||||
void on_VidExt_ResizeWindow(int, int);
|
||||
|
||||
void on_VidExt_Init(void);
|
||||
void on_VidExt_SetMode(int, int, int, int, int);
|
||||
void on_VidExt_SetWindowedModeWithRate(int, int, int, int, int);
|
||||
void on_VidExt_SetFullscreenModeWithRate(int, int, int, int, int);
|
||||
void on_VidExt_SetWindowedMode(int, int, int, int);
|
||||
void on_VidExt_SetFullscreenMode(int, int, int, int);
|
||||
void on_VidExt_SetCaption(QString);
|
||||
void on_VidExt_ToggleFS(bool);
|
||||
void on_VidExt_Quit(void);
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
using namespace Thread;
|
||||
|
||||
RomSearcherThread::RomSearcherThread(QObject *parent) : QThread(parent)
|
||||
{
|
||||
qRegisterMetaType<CoreRomType>("CoreRomType");
|
||||
qRegisterMetaType<CoreRomHeader>("CoreRomHeader");
|
||||
qRegisterMetaType<CoreRomSettings>("CoreRomSettings");
|
||||
}
|
||||
@@ -28,22 +30,22 @@ RomSearcherThread::~RomSearcherThread(void)
|
||||
|
||||
void RomSearcherThread::SetDirectory(QString directory)
|
||||
{
|
||||
this->rom_Directory = directory;
|
||||
this->directory = directory;
|
||||
}
|
||||
|
||||
void RomSearcherThread::SetRecursive(bool value)
|
||||
{
|
||||
this->rom_Search_Recursive = value;
|
||||
this->recursive = value;
|
||||
}
|
||||
|
||||
void RomSearcherThread::SetMaximumFiles(int value)
|
||||
{
|
||||
this->rom_Search_MaxItems = value;
|
||||
this->maxItems = value;
|
||||
}
|
||||
|
||||
void RomSearcherThread::Stop(void)
|
||||
{
|
||||
this->rom_Search_Stop = true;
|
||||
this->stop = true;
|
||||
while (this->isRunning())
|
||||
{
|
||||
this->wait();
|
||||
@@ -52,12 +54,12 @@ void RomSearcherThread::Stop(void)
|
||||
|
||||
void RomSearcherThread::run(void)
|
||||
{
|
||||
this->rom_Search_Stop = false;
|
||||
this->rom_Search(this->rom_Directory);
|
||||
this->stop = false;
|
||||
this->searchDirectory(this->directory);
|
||||
return;
|
||||
}
|
||||
|
||||
void RomSearcherThread::rom_Search(QString directory)
|
||||
void RomSearcherThread::searchDirectory(QString directory)
|
||||
{
|
||||
QDir dir(directory);
|
||||
|
||||
@@ -69,11 +71,12 @@ void RomSearcherThread::rom_Search(QString directory)
|
||||
filter << "*.D64";
|
||||
filter << "*.ZIP";
|
||||
|
||||
QDirIterator::IteratorFlag flag = this->rom_Search_Recursive ?
|
||||
QDirIterator::IteratorFlag flag = this->recursive ?
|
||||
QDirIterator::Subdirectories :
|
||||
QDirIterator::NoIteratorFlags;
|
||||
QDirIterator romDirIt(directory, filter, QDir::Files, flag);
|
||||
|
||||
CoreRomType type;
|
||||
CoreRomHeader header;
|
||||
CoreRomSettings settings;
|
||||
bool ret;
|
||||
@@ -83,39 +86,55 @@ void RomSearcherThread::rom_Search(QString directory)
|
||||
{
|
||||
QString file = romDirIt.next();
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
if (CoreHasRomHeaderAndSettingsCached(file.toStdU32String()))
|
||||
{ // found cache entry
|
||||
ret = CoreGetCachedRomHeaderAndSettings(file.toStdU32String(), header, settings);
|
||||
ret = CoreGetCachedRomHeaderAndSettings(file.toStdU32String(), type, header, settings);
|
||||
}
|
||||
else
|
||||
{ // no cache entry
|
||||
// open rom, retrieve rom settings & header
|
||||
ret = CoreOpenRom(file.toStdU32String()) &&
|
||||
ret = CoreOpenRom(file.toStdU32String()) &&
|
||||
CoreGetCurrentRomSettings(settings) &&
|
||||
CoreGetCurrentRomHeader(header);
|
||||
if (ret)
|
||||
{
|
||||
type = CoreGetRomType();
|
||||
}
|
||||
// always close the ROM,
|
||||
// even when retrieving rom info failed
|
||||
ret = CoreCloseRom() && ret;
|
||||
if (ret)
|
||||
{ // add to cache when everything succeeded
|
||||
CoreAddCachedRomHeaderAndSettings(file.toStdU32String(), header, settings);
|
||||
CoreAddCachedRomHeaderAndSettings(file.toStdU32String(), type, header, settings);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
if (count++ >= this->rom_Search_MaxItems)
|
||||
if (count++ >= this->maxItems)
|
||||
{
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
emit this->on_Rom_Found(file, header, settings);
|
||||
emit this->RomFound(file, type, header, settings);
|
||||
}
|
||||
|
||||
if (this->rom_Search_Stop)
|
||||
if (this->stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// ensure the UI thread has some breathing room
|
||||
// instead of being locked up and unable to render anything
|
||||
if (timer.elapsed() < 10)
|
||||
{
|
||||
QThread::msleep(10 - timer.elapsed());
|
||||
}
|
||||
}
|
||||
|
||||
emit this->Finished(this->stop);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,15 +33,16 @@ class RomSearcherThread : public QThread
|
||||
void run(void) override;
|
||||
|
||||
private:
|
||||
QString rom_Directory;
|
||||
bool rom_Search_Recursive;
|
||||
int rom_Search_MaxItems;
|
||||
bool rom_Search_Stop = false;
|
||||
QString directory;
|
||||
bool recursive = false;
|
||||
int maxItems = 0;
|
||||
bool stop = false;
|
||||
|
||||
void rom_Search(QString);
|
||||
void searchDirectory(QString);
|
||||
|
||||
signals:
|
||||
void on_Rom_Found(QString file, CoreRomHeader header, CoreRomSettings settings);
|
||||
void RomFound(QString file, CoreRomType type, CoreRomHeader header, CoreRomSettings settings);
|
||||
void Finished(bool canceled);
|
||||
};
|
||||
} // namespace Thread
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
*/
|
||||
#include "AboutDialog.hpp"
|
||||
|
||||
#include "Config.hpp"
|
||||
#include <RMG-Core/Core.hpp>
|
||||
|
||||
using namespace UserInterface::Dialog;
|
||||
|
||||
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
|
||||
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
this->setupUi(this);
|
||||
|
||||
this->versionLabel->setText(QString("RMG %1").arg(VERSION_STR));
|
||||
this->versionLabel->setText(QString("RMG %1").arg(QString::fromStdString(CoreGetVersion())));
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Copyright © 2020-2022 Rosalie Wanders</string>
|
||||
<string>Copyright © 2020-2023 Rosalie Wanders</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
using namespace UserInterface::Dialog;
|
||||
|
||||
AddCheatDialog::AddCheatDialog(QWidget *parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
|
||||
AddCheatDialog::AddCheatDialog(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
this->setupUi(this);
|
||||
|
||||
|
||||