diff --git a/.github/workflows/build-switch.yml b/.github/workflows/build-switch.yml
new file mode 100644
index 00000000..46e1d501
--- /dev/null
+++ b/.github/workflows/build-switch.yml
@@ -0,0 +1,28 @@
+name: re3 cmake devkitA64 (Nintendo Switch)
+on:
+ pull_request:
+ push:
+ release:
+ types: published
+jobs:
+ build-nintendo-switch:
+ runs-on: ubuntu-latest
+ container: devkitpro/devkita64:latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ submodules: 'true'
+ - name: "Build files"
+ run: |
+ /opt/devkitpro/portlibs/switch/bin/aarch64-none-elf-cmake -S. -Bbuild -DRE3_AUDIO=OAL -DLIBRW_PLATFORM=GL3 -DLIBRW_GL3_GFXLIB=GLFW -DRE3_WITH_OPUS=False -DRE3_VENDORED_LIBRW=True -DRE3_INSTALL=True
+ cmake --build build --parallel
+ - name: "Create binary package (cpack)"
+ working-directory: ./build
+ run: |
+ cpack
+ - name: "Archive binary package (github artifacts)"
+ uses: actions/upload-artifact@v2
+ with:
+ name: "switch-gl3"
+ path: build/*.zip
+ if-no-files-found: error
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 327d8cc7..2ce82727 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -26,6 +26,24 @@
"compilerArgs": ["-ggdb"],
"cStandard": "gnu11",
"cppStandard": "gnu++14"
+ },
+ {
+ "name": "devkitPro aarch64 (Nintendo Switch)",
+ "compilerPath": "${env:DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++",
+ "includePath": [
+ "${default}",
+ "${env:DEVKITPRO}/portlibs/switch/include",
+ "${env:DEVKITPRO}/libnx/include"
+ ],
+ "intelliSenseMode": "gcc-arm64",
+ "cStandard": "gnu11",
+ "cppStandard": "gnu++11",
+ "defines": [
+ "__SWITCH__",
+ "LIBRW",
+ "RW_GL3",
+ "AUDIO_OAL"
+ ]
}
],
"version": 4
diff --git a/.vscode/settings.json b/.vscode/settings.json
index fee80960..98870ba1 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -2,8 +2,13 @@
"C_Cpp.default.cStandard": "gnu11",
"C_Cpp.default.cppStandard": "gnu++14",
"C_Cpp.default.includePath": [
+ "src",
"src/animation",
"src/audio",
+ "src/audio/eax",
+ "src/audio/oal",
+ "src/buildings",
+ "src/collision",
"src/control",
"src/core",
"src/entities",
@@ -15,8 +20,9 @@
"src/peds",
"src/renderer",
"src/rw",
- "src/save",
- "src/skel",
+ "src/save/",
+ "src/skel/",
+ "src/skel/glfw",
"src/text",
"src/vehicles",
"src/weapons",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5396d3b4..adf3c29f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,15 +1,26 @@
-cmake_minimum_required(VERSION 3.8)
+cmake_minimum_required(VERSION 3.14)
set(EXECUTABLE re3)
set(PROJECT RE3)
project(${EXECUTABLE} C CXX)
+set(${PROJECT}_AUTHOR "${PROJECT} Team")
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1 "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
message(STATUS "Building ${CMAKE_PROJECT_NAME} GIT SHA1: ${GIT_SHA1}")
+if(NINTENDO_SWITCH)
+ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/nx")
+ include(NXFunctions)
+endif()
+
+if(NOT COMMAND re3_platform_target)
+ function(re3_platform_target)
+ endfunction()
+endif()
+
if(WIN32)
set(${PROJECT}_AUDIOS "OAL" "MSS")
else()
@@ -66,6 +77,8 @@ if(${PROJECT}_INSTALL)
set(os "-apple")
elseif(UNIX)
set(os "-linux")
+ elseif(NINTENDO_SWITCH)
+ set(os "-switch")
else()
set(compiler "-UNK")
message(WARNING "Unknown os. Created cpack package will be wrong. (override using cpack -P)")
diff --git a/README.md b/README.md
index 9ccabf1e..bcbecaba 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
[![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FGTAmodding%2Fre3%2Fbadge%3Fref%3Dmaster&style=flat)](https://actions-badge.atrox.dev/GTAmodding/re3/goto?ref=master)
diff --git a/cmake/nx/NXFunctions.cmake b/cmake/nx/NXFunctions.cmake
new file mode 100644
index 00000000..cf3f974b
--- /dev/null
+++ b/cmake/nx/NXFunctions.cmake
@@ -0,0 +1,38 @@
+if(NOT COMMAND nx_generate_nacp)
+ message(FATAL_ERROR "The `nx_generate_nacp` cmake command is not available. Please use an appropriate Nintendo Switch toolchain.")
+endif()
+
+if(NOT COMMAND nx_create_nro)
+ message(FATAL_ERROR "The `nx_create_nro` cmake command is not available. Please use an appropriate Nintendo Switch toolchain.")
+endif()
+
+set(CMAKE_EXECUTABLE_SUFFIX ".elf")
+
+function(re3_platform_target TARGET)
+ cmake_parse_arguments(RPT "INSTALL" "" "" ${ARGN})
+
+ get_target_property(TARGET_TYPE "${TARGET}" TYPE)
+ if(TARGET_TYPE STREQUAL "EXECUTABLE")
+ nx_generate_nacp(${TARGET}.nacp
+ NAME "${TARGET}"
+ AUTHOR "${${PROJECT}_AUTHOR}"
+ VERSION "1.0.0-${GIT_SHA1}"
+ )
+
+ nx_create_nro(${TARGET}
+ NACP ${TARGET}.nacp
+ ICON "${PROJECT_SOURCE_DIR}/res/images/logo_256.jpg"
+ )
+
+ if(${PROJECT}_INSTALL AND RPT_INSTALL)
+ get_target_property(TARGET_OUTPUT_NAME ${TARGET} OUTPUT_NAME)
+ if(NOT TARGET_OUTPUT_NAME)
+ set(TARGET_OUTPUT_NAME "${TARGET}")
+ endif()
+
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_OUTPUT_NAME}.nro"
+ DESTINATION "."
+ )
+ endif()
+ endif()
+endfunction()
diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt
index d4034411..d7b7c956 100644
Binary files a/gamefiles/TEXT/american.gxt and b/gamefiles/TEXT/american.gxt differ
diff --git a/gamefiles/TEXT/french.gxt b/gamefiles/TEXT/french.gxt
index 16c7a716..3dece994 100644
Binary files a/gamefiles/TEXT/french.gxt and b/gamefiles/TEXT/french.gxt differ
diff --git a/gamefiles/TEXT/german.gxt b/gamefiles/TEXT/german.gxt
index c3309d61..7f25bd05 100644
Binary files a/gamefiles/TEXT/german.gxt and b/gamefiles/TEXT/german.gxt differ
diff --git a/gamefiles/TEXT/italian.gxt b/gamefiles/TEXT/italian.gxt
index b30b74f4..5a060a9a 100644
Binary files a/gamefiles/TEXT/italian.gxt and b/gamefiles/TEXT/italian.gxt differ
diff --git a/gamefiles/TEXT/polish.gxt b/gamefiles/TEXT/polish.gxt
index d771427b..782f656d 100755
Binary files a/gamefiles/TEXT/polish.gxt and b/gamefiles/TEXT/polish.gxt differ
diff --git a/gamefiles/TEXT/russian.gxt b/gamefiles/TEXT/russian.gxt
index 0075c691..914f5b52 100644
Binary files a/gamefiles/TEXT/russian.gxt and b/gamefiles/TEXT/russian.gxt differ
diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt
index 8980eb4d..cb884689 100644
Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ
diff --git a/gamefiles/models/frontend_nsw.txd b/gamefiles/models/frontend_nsw.txd
new file mode 100644
index 00000000..1379a1a7
Binary files /dev/null and b/gamefiles/models/frontend_nsw.txd differ
diff --git a/gamefiles/models/nswbtns.txd b/gamefiles/models/nswbtns.txd
new file mode 100644
index 00000000..0b1756ee
Binary files /dev/null and b/gamefiles/models/nswbtns.txd differ
diff --git a/logo.svg b/res/images/logo.svg
similarity index 100%
rename from logo.svg
rename to res/images/logo.svg
diff --git a/logo.png b/res/images/logo_1024.png
similarity index 100%
rename from logo.png
rename to res/images/logo_1024.png
diff --git a/res/images/logo_256.jpg b/res/images/logo_256.jpg
new file mode 100644
index 00000000..595d2c3b
Binary files /dev/null and b/res/images/logo_256.jpg differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 28090d7e..9cbd87a0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -54,9 +54,13 @@ target_compile_definitions(${EXECUTABLE} PRIVATE USE_OUR_VERSIONING)
if(${PROJECT}_AUDIO STREQUAL "OAL")
find_package(OpenAL REQUIRED)
- target_include_directories(${EXECUTABLE} PRIVATE ${OPENAL_INCLUDE_DIR})
- target_link_libraries(${EXECUTABLE} PRIVATE ${OPENAL_LIBRARY})
- target_compile_definitions(${EXECUTABLE} PRIVATE ${OPENAL_DEFINITIONS})
+ if(TARGET OpenAL::OpenAL)
+ target_link_libraries(${EXECUTABLE} PRIVATE OpenAL::OpenAL)
+ else()
+ target_include_directories(${EXECUTABLE} PRIVATE ${OPENAL_INCLUDE_DIR})
+ target_link_libraries(${EXECUTABLE} PRIVATE ${OPENAL_LIBRARY})
+ target_compile_definitions(${EXECUTABLE} PRIVATE ${OPENAL_DEFINITIONS})
+ endif()
target_compile_definitions(${EXECUTABLE} PRIVATE AUDIO_OAL)
elseif(${PROJECT}_AUDIO STREQUAL "MSS")
find_package(MilesSDK REQUIRED)
@@ -120,13 +124,19 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
)
endif()
+if(NINTENDO_SWITCH)
+ set(${PROJECT}_C_CXX_EXTENSIONS ON)
+else()
+ set(${PROJECT}_C_CXX_EXTENSIONS OFF)
+endif()
+
set_target_properties(${EXECUTABLE}
PROPERTIES
C_STANDARD 11
- C_EXTENSIONS OFF
+ C_EXTENSIONS ${${PROJECT}_C_CXX_EXTENSIONS}
C_STANDARD_REQUIRED ON
CXX_STANDARD 11
- CXX_EXTENSIONS OFF
+ CXX_EXTENSIONS ${${PROJECT}_C_CXX_EXTENSIONS}
CXX_STANDARD_REQUIRED ON
)
@@ -140,3 +150,5 @@ if(${PROJECT}_INSTALL)
install(FILES $ DESTINATION "." OPTIONAL)
endif()
endif()
+
+re3_platform_target(${EXECUTABLE} INSTALL)
diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp
index e72af7e4..8775792f 100644
--- a/src/core/ControllerConfig.cpp
+++ b/src/core/ControllerConfig.cpp
@@ -2644,6 +2644,14 @@ const char *PlayStationButtons[][MAX_CONTROLLERACTIONS] =
#undef PS2_CROSS
#undef PS2_SQUARE
+const char *NintendoSwitchButtons_noIcons[][MAX_CONTROLLERACTIONS] =
+ CONTROLLER_BUTTONS("Y", "A", "B", "X", "L", "ZL", "LS", "R", "ZR", "RS", "BACK");
+
+#ifdef BUTTON_ICONS
+const char *NintendoSwitchButtons[][MAX_CONTROLLERACTIONS] =
+ CONTROLLER_BUTTONS("~T~", "~O~", "~X~", "~Q~", "~K~", "~M~", "~A~", "~J~", "~V~", "~C~", "BACK");
+#endif
+
#undef CONTROLLER_BUTTONS
#undef VFB
@@ -2664,6 +2672,9 @@ void CControllerConfigManager::GetWideStringOfCommandKeys(uint16 action, wchar *
case CMenuManager::CONTROLLER_DUALSHOCK4:
Buttons = CFont::ButtonsSlot != -1 ? PlayStationButtons : PlayStationButtons_noIcons;
break;
+ case CMenuManager::CONTROLLER_NINTENDO_SWITCH:
+ Buttons = CFont::ButtonsSlot != -1 ? NintendoSwitchButtons : NintendoSwitchButtons_noIcons;
+ break;
default:
#endif
Buttons = CFont::ButtonsSlot != -1 ? XboxButtons : XboxButtons_noIcons;
@@ -2679,6 +2690,9 @@ void CControllerConfigManager::GetWideStringOfCommandKeys(uint16 action, wchar *
case CMenuManager::CONTROLLER_DUALSHOCK4:
Buttons = PlayStationButtons_noIcons;
break;
+ case CMenuManager::CONTROLLER_NINTENDO_SWITCH:
+ Buttons = NintendoSwitchButtons_noIcons;
+ break;
default:
Buttons = XboxButtons_noIcons;
break;
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index b5d12d58..666774fe 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -142,8 +142,12 @@ int8 CMenuManager::m_PrefsIslandLoading = ISLAND_LOADING_LOW;
#endif
#ifdef GAMEPAD_MENU
+#ifdef __SWITCH__
+int8 CMenuManager::m_PrefsControllerType = CONTROLLER_NINTENDO_SWITCH;
+#else
int8 CMenuManager::m_PrefsControllerType = CONTROLLER_XBOXONE;
#endif
+#endif
int32 CMenuManager::OS_Language = LANG_ENGLISH;
int8 CMenuManager::m_PrefsUseVibration;
@@ -3674,6 +3678,7 @@ const char* controllerTypesPaths[] = {
"MODELS/FRONTEND_DS4.TXD",
"MODELS/FRONTEND_X360.TXD",
"MODELS/FRONTEND_XONE.TXD",
+ "MODELS/FRONTEND_NSW.TXD",
};
void
@@ -3686,6 +3691,9 @@ CMenuManager::LoadController(int8 type)
case CONTROLLER_DUALSHOCK4:
CFont::LoadButtons("MODELS/PS3BTNS.TXD");
break;
+ case CONTROLLER_NINTENDO_SWITCH:
+ CFont::LoadButtons("MODELS/NSWBTNS.TXD");
+ break;
default:
CFont::LoadButtons("MODELS/X360BTNS.TXD");
break;
@@ -5925,6 +5933,18 @@ CMenuManager::PrintController(void)
TEXT_L2R2_Y += 5.0f;
TEXT_SELECT_X += 3.0f;
break;
+ case CONTROLLER_NINTENDO_SWITCH:
+ TEXT_L1_Y += 5.0f;
+ TEXT_L1_Y_VEH = TEXT_L1_Y;
+ TEXT_R1_Y += 5.0f;
+ TEXT_TRIANGLE_Y += 3.0f;
+ TEXT_CIRCLE_Y += 3.0f;
+ TEXT_CROSS_Y += 3.0f;
+ TEXT_LSTICK_Y -= 23.0f;
+ TEXT_DPAD_Y += 25.0;
+ TEXT_RSTICK_Y += 1.0f;
+ TEXT_R3_Y += 1.0f;
+ break;
};
if (m_DisplayControllerOnFoot) {
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 32e5ef9d..6e6c40f7 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -760,6 +760,7 @@ public:
CONTROLLER_DUALSHOCK4,
CONTROLLER_XBOX360,
CONTROLLER_XBOXONE,
+ CONTROLLER_NINTENDO_SWITCH,
};
static int8 m_PrefsControllerType;
diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp
index c22b2e3a..5eecd841 100644
--- a/src/core/MenuScreensCustom.cpp
+++ b/src/core/MenuScreensCustom.cpp
@@ -36,7 +36,7 @@
#ifdef CUSTOM_FRONTEND_OPTIONS
-#ifdef IMPROVED_VIDEOMODE
+#if defined(IMPROVED_VIDEOMODE) && !defined(GTA_HANDHELD)
#define VIDEOMODE_SELECTOR MENUACTION_CFO_SELECT, "FEM_SCF", { new CCFOSelect((int8*)&FrontEndMenuManager.m_nPrefsWindowed, "VideoMode", "Windowed", screenModes, 2, true, ScreenModeAfterChange, true) },
#else
#define VIDEOMODE_SELECTOR
@@ -388,7 +388,7 @@ void DetectJoystickGoBack() {
#endif
#ifdef GAMEPAD_MENU
-const char* controllerTypes[] = { "FEC_DS2", "FEC_DS3", "FEC_DS4", "FEC_360", "FEC_ONE" };
+const char* controllerTypes[] = { "FEC_DS2", "FEC_DS3", "FEC_DS4", "FEC_360", "FEC_ONE", "FEC_NSW" };
void ControllerTypeAfterChange(int8 before, int8 after)
{
FrontEndMenuManager.LoadController(after);
@@ -418,10 +418,10 @@ CMenuScreenCustom aScreens[MENUPAGES] = {
},
// MENUPAGE_CONTROLLER_SETTINGS = 4
-#ifdef GAMEPAD_MENU
+#if defined(GAMEPAD_MENU) && !defined(GTA_HANDHELD)
{ "FET_AGS", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil,
#else
- { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
+ { "FET_AGS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil,
#endif
MENUACTION_CTRLCONFIG, "FEC_CCF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
MENUACTION_CTRLDISPLAY, "FEC_CDP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
@@ -753,7 +753,11 @@ CMenuScreenCustom aScreens[MENUPAGES] = {
// MENUPAGE_OPTIONS = 41
{ "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil,
+#ifdef GTA_HANDHELD
+ MENUACTION_CHANGEMENU, "FET_CTL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS },
+#else
MENUACTION_CHANGEMENU, "FET_CTL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC },
+#endif
MENUACTION_LOADRADIO, "FET_AUD", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS },
MENUACTION_CHANGEMENU, "FET_DIS", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
#ifdef GRAPHICS_MENU_OPTIONS
@@ -887,7 +891,9 @@ CMenuScreenCustom aScreens[MENUPAGES] = {
{ "FET_GFX", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS,
new CCustomScreenLayout({MENUSPRITE_MAINMENU, 50, 0, 20, FONT_HEADING, FESCREEN_LEFT_ALIGN, true, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), GraphicsGoBack,
+#ifndef GTA_HANDHELD
MENUACTION_SCREENRES, "FED_RES", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS },
+#endif
MENUACTION_WIDESCREEN, "FED_WIS", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS },
VIDEOMODE_SELECTOR
MENUACTION_FRAMESYNC, "FEM_VSC", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS },
diff --git a/src/core/common.h b/src/core/common.h
index 3f69a394..0d0528b1 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -11,6 +11,10 @@
#define __STDC_LIMIT_MACROS // so we get UINT32_MAX etc
#endif
+#ifdef __SWITCH__
+#include
+#endif
+
#include
#include
#include
diff --git a/src/core/config.h b/src/core/config.h
index 1e9bf6d2..d26f9546 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -157,6 +157,11 @@ enum Config {
#define GTA_VERSION GTA3_PC_11
+// Enable configuration for handheld console ports
+#if defined(__SWITCH__) || defined(PSP2)
+ #define GTA_HANDHELD
+#endif
+
#if defined GTA_PS2
# define GTA_PS2_STUFF
# define RANDOMSPLASH
@@ -166,7 +171,9 @@ enum Config {
# define PS2_MENU
#elif defined GTA_PC
# define EXTERNAL_3D_SOUND
-# define PC_PLAYER_CONTROLS // mouse player/cam mode
+# ifndef GTA_HANDHELD
+# define PC_PLAYER_CONTROLS // mouse player/cam mode
+# endif
# define GTA_REPLAY
# define GTA_SCENE_EDIT
# define PC_MENU
@@ -322,7 +329,7 @@ enum Config {
#if !defined(RW_GL3) && defined(_WIN32)
#define XINPUT
#endif
-#if defined XINPUT || (defined RW_GL3 && !defined LIBRW_SDL2 && !defined __SWITCH__)
+#if defined XINPUT || (defined RW_GL3 && !defined LIBRW_SDL2 && !defined GTA_HANDHELD)
#define DETECT_JOYSTICK_MENU // Then we'll expect user to enter Controller->Detect joysticks if his joystick isn't detected at the start.
#endif
#define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m
@@ -348,7 +355,7 @@ enum Config {
//# define PS2_MENU_USEALLPAGEICONS
#else
-# ifdef XINPUT
+# if defined(XINPUT) || defined(GTA_HANDHELD)
# define GAMEPAD_MENU // Add gamepad menu
# endif
@@ -467,6 +474,14 @@ enum Config {
#undef PEDS_REPORT_CRIMES_ON_PHONE
#endif
+#ifdef GTA_HANDHELD
+ #define IGNORE_MOUSE_KEYBOARD // ignore mouse & keyboard input
+#endif
+
+#ifdef __SWITCH__
+ #define USE_UNNAMED_SEM // named semaphores are unsupported on the switch
+#endif
+
#endif // VANILLA_DEFINES
#if defined(AUDIO_OAL) && !defined(EXTERNAL_3D_SOUND)
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 4914cd9c..980ec845 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -45,9 +45,7 @@
#include "Population.h"
#include "IniFile.h"
-#ifdef DETECT_JOYSTICK_MENU
#include "crossplatform.h"
-#endif
#ifndef _WIN32
#include "assert.h"
diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp
index 577983b6..e69c22e1 100644
--- a/src/skel/crossplatform.cpp
+++ b/src/skel/crossplatform.cpp
@@ -198,6 +198,20 @@ char* casepath(char const* path, bool checkPathFirst)
size_t rl = 0;
DIR* d;
+ char* c;
+
+ #if defined(__SWITCH__) || defined(PSP2)
+ if( (c = strstr(p, ":/")) != NULL) // scheme used by some environments, eg. switch, vita
+ {
+ size_t deviceNameOffset = c - p + 3;
+ char* deviceNamePath = (char*)alloca(deviceNameOffset + 1);
+ strlcpy(deviceNamePath, p, deviceNameOffset);
+ deviceNamePath[deviceNameOffset] = 0;
+ d = opendir(deviceNamePath);
+ p = c + 1;
+ }
+ else
+ #endif
if (p[0] == '/' || p[0] == '\\')
{
d = opendir("/");
@@ -212,7 +226,7 @@ char* casepath(char const* path, bool checkPathFirst)
bool cantProceed = false; // just convert slashes in what's left in string, don't correct case of letters(because we can't)
bool mayBeTrailingSlash = false;
- char* c;
+
while (c = strsep(&p, "/\\"))
{
// May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid)
@@ -279,3 +293,133 @@ char* casepath(char const* path, bool checkPathFirst)
return out;
}
#endif
+
+#ifdef __SWITCH__
+/* Taken from glibc */
+char *realpath(const char *name, char *resolved)
+{
+ char *rpath, *dest = NULL;
+ const char *start, *end, *rpath_limit;
+ long int path_max;
+
+ /* As per Single Unix Specification V2 we must return an error if
+ either parameter is a null pointer. We extend this to allow
+ the RESOLVED parameter to be NULL in case the we are expected to
+ allocate the room for the return value. */
+ if (!name)
+ return NULL;
+
+ /* As per Single Unix Specification V2 we must return an error if
+ the name argument points to an empty string. */
+ if (name[0] == '\0')
+ return NULL;
+
+#ifdef PATH_MAX
+ path_max = PATH_MAX;
+#else
+ path_max = pathconf(name, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 1024;
+#endif
+
+ if (!resolved)
+ {
+ rpath = (char*)malloc(path_max);
+ if (!rpath)
+ return NULL;
+ }
+ else
+ rpath = resolved;
+ rpath_limit = rpath + path_max;
+
+ if (name[0] != '/')
+ {
+ if (!getcwd(rpath, path_max))
+ {
+ rpath[0] = '\0';
+ goto error;
+ }
+ dest = (char*)memchr(rpath, '\0', path_max);
+ }
+ else
+ {
+ rpath[0] = '/';
+ dest = rpath + 1;
+ }
+
+ for (start = end = name; *start; start = end)
+ {
+ /* Skip sequence of multiple path-separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath + 1)
+ while ((--dest)[-1] != '/')
+ ;
+ }
+ else
+ {
+ size_t new_size;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rpath_limit)
+ {
+ ptrdiff_t dest_offset = dest - rpath;
+ char *new_rpath;
+
+ if (resolved)
+ {
+ if (dest > rpath + 1)
+ dest--;
+ *dest = '\0';
+ goto error;
+ }
+ new_size = rpath_limit - rpath;
+ if (end - start + 1 > path_max)
+ new_size += end - start + 1;
+ else
+ new_size += path_max;
+ new_rpath = (char *)realloc(rpath, new_size);
+ if (!new_rpath)
+ goto error;
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+
+ dest = rpath + dest_offset;
+ }
+
+ dest = (char*)memcpy(dest, start, end - start);
+ *dest = '\0';
+ }
+ }
+ if (dest > rpath + 1 && dest[-1] == '/')
+ --dest;
+ *dest = '\0';
+
+ return rpath;
+
+error:
+ if (!resolved)
+ free(rpath);
+ return NULL;
+}
+
+ssize_t readlink (const char * __path, char * __buf, size_t __buflen)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h
index aa90ce5a..67bb4282 100644
--- a/src/skel/crossplatform.h
+++ b/src/skel/crossplatform.h
@@ -157,3 +157,28 @@ bool FindNextFile(HANDLE, WIN32_FIND_DATA*);
void FileTimeToSystemTime(time_t*, SYSTEMTIME*);
void GetDateFormat(int, int, SYSTEMTIME*, int, char*, int);
#endif
+
+#ifdef __SWITCH__
+
+// tweak glfw values for switch to match expected pc bindings
+#ifdef GLFW_GAMEPAD_BUTTON_A
+ #undef GLFW_GAMEPAD_BUTTON_A
+#endif
+#define GLFW_GAMEPAD_BUTTON_A 1
+
+#ifdef GLFW_GAMEPAD_BUTTON_B
+ #undef GLFW_GAMEPAD_BUTTON_B
+#endif
+#define GLFW_GAMEPAD_BUTTON_B 0
+
+#ifdef GLFW_GAMEPAD_BUTTON_X
+ #undef GLFW_GAMEPAD_BUTTON_X
+#endif
+#define GLFW_GAMEPAD_BUTTON_X 3
+
+#ifdef GLFW_GAMEPAD_BUTTON_Y
+ #undef GLFW_GAMEPAD_BUTTON_Y
+#endif
+#define GLFW_GAMEPAD_BUTTON_Y 2
+
+#endif
diff --git a/src/skel/events.cpp b/src/skel/events.cpp
index 3e1e95b3..87447819 100644
--- a/src/skel/events.cpp
+++ b/src/skel/events.cpp
@@ -821,7 +821,9 @@ PadHandler(RsEvent event, void *param)
RwBool
AttachInputDevices(void)
{
+#ifndef IGNORE_MOUSE_KEYBOARD
RsInputDeviceAttach(rsKEYBOARD, KeyboardHandler);
+#endif
RsInputDeviceAttach(rsPAD, PadHandler);
diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp
index 44f0c83a..92574953 100644
--- a/src/skel/glfw/glfw.cpp
+++ b/src/skel/glfw/glfw.cpp
@@ -12,12 +12,14 @@ DWORD _dwOperatingSystemVersion;
#include "resource.h"
#else
long _dwOperatingSystemVersion;
+#ifndef __SWITCH__
#ifndef __APPLE__
#include
#else
#include
#include
#endif
+#endif
#include
#include
#include
@@ -51,7 +53,7 @@ long _dwOperatingSystemVersion;
#include "MemoryMgr.h"
// We found out that GLFW's keyboard input handling is still pretty delayed/not stable, so now we fetch input from X11 directly on Linux.
-#if !defined _WIN32 && !defined __APPLE__ && !defined __SWITCH__ // && !defined WAYLAND
+#if !defined _WIN32 && !defined __APPLE__ && !defined GTA_HANDHELD // && !defined WAYLAND
#define GET_KEYBOARD_INPUT_FROM_X11
#endif
@@ -324,6 +326,78 @@ psNativeTextureSupport(void)
#define CMDSTR LPSTR
#endif
+/*
+ *****************************************************************************
+ */
+
+#ifdef __SWITCH__
+
+static HidVibrationValue SwitchVibrationValues[2];
+static HidVibrationDeviceHandle SwitchVibrationDeviceHandles[2][2];
+static HidVibrationDeviceHandle SwitchVibrationDeviceGC;
+
+static PadState SwitchPad;
+
+static Result HidInitializationResult[2];
+static Result HidInitializationGCResult;
+
+static void _psInitializeVibration()
+{
+ HidInitializationResult[0] = hidInitializeVibrationDevices(SwitchVibrationDeviceHandles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
+ if(R_FAILED(HidInitializationResult[0])) {
+ printf("Failed to initialize VibrationDevice for Handheld Mode\n");
+ }
+ HidInitializationResult[1] = hidInitializeVibrationDevices(SwitchVibrationDeviceHandles[1], 2, HidNpadIdType_No1, HidNpadStyleSet_NpadFullCtrl);
+ if(R_FAILED(HidInitializationResult[1])) {
+ printf("Failed to initialize VibrationDevice for Detached Mode\n");
+ }
+ HidInitializationGCResult = hidInitializeVibrationDevices(&SwitchVibrationDeviceGC, 1, HidNpadIdType_No1, HidNpadStyleTag_NpadGc);
+ if(R_FAILED(HidInitializationResult[1])) {
+ printf("Failed to initialize VibrationDevice for GC Mode\n");
+ }
+
+ SwitchVibrationValues[0].freq_low = 160.0f;
+ SwitchVibrationValues[0].freq_high = 320.0f;
+
+ padConfigureInput(1, HidNpadStyleSet_NpadFullCtrl);
+ padInitializeDefault(&SwitchPad);
+}
+
+static void _psHandleVibration()
+{
+ padUpdate(&SwitchPad);
+
+ uint8 target_device = padIsHandheld(&SwitchPad) ? 0 : 1;
+
+ if(R_SUCCEEDED(HidInitializationResult[target_device])) {
+ CPad* pad = CPad::GetPad(0);
+
+ // value conversion based on SDL2 switch port
+ SwitchVibrationValues[0].amp_high = SwitchVibrationValues[0].amp_low = pad->ShakeFreq == 0 ? 0.0f : 320.0f;
+ SwitchVibrationValues[0].freq_low = pad->ShakeFreq == 0.0 ? 160.0f : (float)pad->ShakeFreq * 1.26f;
+ SwitchVibrationValues[0].freq_high = pad->ShakeFreq == 0.0 ? 320.0f : (float)pad->ShakeFreq * 1.26f;
+
+ if (pad->ShakeDur < CTimer::GetTimeStepInMilliseconds())
+ pad->ShakeDur = 0;
+ else
+ pad->ShakeDur -= CTimer::GetTimeStepInMilliseconds();
+ if (pad->ShakeDur == 0) pad->ShakeFreq = 0;
+
+
+ if(target_device == 1 && R_SUCCEEDED(HidInitializationGCResult)) {
+ // gamecube rumble
+ hidSendVibrationGcErmCommand(SwitchVibrationDeviceGC, pad->ShakeFreq > 0 ? HidVibrationGcErmCommand_Start : HidVibrationGcErmCommand_Stop);
+ }
+
+ memcpy(&SwitchVibrationValues[1], &SwitchVibrationValues[0], sizeof(HidVibrationValue));
+ hidSendVibrationValues(SwitchVibrationDeviceHandles[target_device], SwitchVibrationValues, 2);
+ }
+}
+#else
+static void _psInitializeVibration() {}
+static void _psHandleVibration() {}
+#endif
+
/*
*****************************************************************************
*/
@@ -407,6 +481,8 @@ psInitialize(void)
#endif
#endif
+
+ _psInitializeVibration();
gGameState = GS_START_UP;
TRACE("gGameState = GS_START_UP");
@@ -484,6 +560,9 @@ psInitialize(void)
_dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size);
debug("Physical memory size %llu\n", _dwMemAvailPhys);
debug("Available physical memory %llu\n", size);
+#elif defined (__SWITCH__)
+ svcGetInfo(&_dwMemAvailPhys, InfoType_UsedMemorySize, CUR_PROCESS_HANDLE, 0);
+ debug("Physical memory size %llu\n", _dwMemAvailPhys);
#else
struct sysinfo systemInfo;
sysinfo(&systemInfo);
@@ -949,13 +1028,15 @@ void psPostRWinit(void)
RwVideoMode vm;
RwEngineGetVideoModeInfo(&vm, GcurSelVM);
+ glfwSetFramebufferSizeCallback(PSGLOBAL(window), resizeCB);
+#ifndef IGNORE_MOUSE_KEYBOARD
#ifndef GET_KEYBOARD_INPUT_FROM_X11
glfwSetKeyCallback(PSGLOBAL(window), keypressCB);
#endif
- glfwSetFramebufferSizeCallback(PSGLOBAL(window), resizeCB);
glfwSetScrollCallback(PSGLOBAL(window), scrollCB);
glfwSetCursorPosCallback(PSGLOBAL(window), cursorCB);
glfwSetCursorEnterCallback(PSGLOBAL(window), cursorEnterCB);
+#endif
glfwSetWindowIconifyCallback(PSGLOBAL(window), windowIconifyCB);
glfwSetWindowFocusCallback(PSGLOBAL(window), windowFocusCB);
glfwSetJoystickCallback(joysChangeCB);
@@ -1791,7 +1872,7 @@ main(int argc, char *argv[])
InitMemoryMgr();
#endif
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__SWITCH__)
struct sigaction act;
act.sa_sigaction = terminateHandler;
act.sa_flags = SA_SIGINFO;
@@ -2455,6 +2536,8 @@ void CapturePad(RwInt32 padID)
if ( Abs(rightStickPos.y) > 0.3f )
pad->PCTempJoyState.RightStickY = (int32)(rightStickPos.y * 128.0f);
}
+
+ _psHandleVibration();
return;
}
diff --git a/utils/gxt/american.txt b/utils/gxt/american.txt
index d8f79f05..57ec4d74 100644
--- a/utils/gxt/american.txt
+++ b/utils/gxt/american.txt
@@ -8061,6 +8061,9 @@ XBOX 360 CONTROLLER
[FEC_ONE]
XBOX ONE CONTROLLER
+[FEC_NSW]
+NINTENDO SWITCH CONTROLLER
+
[FEC_TYP]
GAMEPAD TYPE
diff --git a/utils/gxt/french.txt b/utils/gxt/french.txt
index bd4acf96..bdb12c7b 100644
--- a/utils/gxt/french.txt
+++ b/utils/gxt/french.txt
@@ -8329,6 +8329,9 @@ XBOX 360 CONTROLLER
[FEC_ONE]
XBOX ONE CONTROLLER
+[FEC_NSW]
+NINTENDO SWITCH CONTROLLER
+
[FEC_TYP]
GAMEPAD TYPE
diff --git a/utils/gxt/german.txt b/utils/gxt/german.txt
index 5f5c53c4..b77cb17c 100644
--- a/utils/gxt/german.txt
+++ b/utils/gxt/german.txt
@@ -8146,6 +8146,9 @@ XBOX 360 CONTROLLER
[FEC_ONE]
XBOX ONE CONTROLLER
+[FEC_NSW]
+NINTENDO SWITCH CONTROLLER
+
[FEC_TYP]
GAMEPAD-TYP
diff --git a/utils/gxt/italian.txt b/utils/gxt/italian.txt
index 803b7fbf..9dfee85c 100644
--- a/utils/gxt/italian.txt
+++ b/utils/gxt/italian.txt
@@ -8158,6 +8158,9 @@ XBOX 360 CONTROLLER
[FEC_ONE]
XBOX ONE CONTROLLER
+[FEC_NSW]
+NINTENDO SWITCH CONTROLLER
+
[FEC_TYP]
GAMEPAD TYPE
diff --git a/utils/gxt/polish.txt b/utils/gxt/polish.txt
index 33716291..98d373ef 100755
--- a/utils/gxt/polish.txt
+++ b/utils/gxt/polish.txt
@@ -8067,6 +8067,9 @@ XBOX 360 CONTROLLER
[FEC_ONE]
XBOX ONE CONTROLLER
+[FEC_NSW]
+NINTENDO SWITCH CONTROLLER
+
[FEC_TYP]
GAMEPAD TYPE
diff --git a/utils/gxt/russian.txt b/utils/gxt/russian.txt
index 221e59f5..3b42bb21 100644
--- a/utils/gxt/russian.txt
+++ b/utils/gxt/russian.txt
@@ -8069,6 +8069,9 @@ DUALSHOCK 4
[FEC_ONE]
КОНТРОЛЛЕР XBOX ONE
+[FEC_NSW]
+КОНТРОЛЛЕР NINTENDO SWITCH
+
[FEC_TYP]
ГЕЙМПАД
diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt
index 5f108d3b..2775d342 100644
--- a/utils/gxt/spanish.txt
+++ b/utils/gxt/spanish.txt
@@ -8128,6 +8128,9 @@ MANDO DE XBOX 360
[FEC_ONE]
MANDO DE XBOX ONE
+[FEC_NSW]
+MANDO DE NINTENDO SWITCH
+
[FEC_TYP]
TIPO DE MANDO