From 4cb9e043e19a95f93ebf53b48f606533743668ec Mon Sep 17 00:00:00 2001 From: OmniBlade Date: Sun, 17 Jul 2022 23:13:50 +0100 Subject: [PATCH] Initial Vita port. Based on Northfear's work for the Kyuhen homebrew contest. --- cmake/VitaPackage.cmake | 93 ++++++++++++++++++++++++++ cmake/template.xml | 11 +++ common/CMakeLists.txt | 31 +++++++++ common/debugstring.cpp | 15 +++++ common/file_posix.cpp | 54 +++++++++++++++ common/mixfile.h | 13 ++++ common/mssleep.h | 2 + common/paths_vita.cpp | 97 +++++++++++++++++++++++++++ common/settings.cpp | 23 +++++++ common/settings.h | 9 +++ common/sockets.h | 21 ++++-- common/video.h | 11 +++ common/video_sdl2.cpp | 57 ++++++++++++++++ common/wspudp.cpp | 4 +- common/wwkeyboard.cpp | 130 +++++++++++++++++++++++++++++++++++- common/wwkeyboard.h | 21 ++++++ common/wwstd.h | 3 + redalert/CMakeLists.txt | 10 ++- redalert/globals.cpp | 3 + redalert/startup.cpp | 18 ++++- tiberiandawn/CMakeLists.txt | 8 +++ tiberiandawn/startup.cpp | 20 +++++- 22 files changed, 643 insertions(+), 11 deletions(-) create mode 100644 cmake/VitaPackage.cmake create mode 100644 cmake/template.xml create mode 100644 common/paths_vita.cpp diff --git a/cmake/VitaPackage.cmake b/cmake/VitaPackage.cmake new file mode 100644 index 00000000..5be1077c --- /dev/null +++ b/cmake/VitaPackage.cmake @@ -0,0 +1,93 @@ +include (CMakeParseArguments) +include("${VITASDK}/share/vita.cmake" REQUIRED) +set(GenerateVPKCurrentDir ${CMAKE_CURRENT_LIST_DIR}) + +function(generate_vita_package target) + set (options) + set (oneValueArgs + APP_NAME + TITLE_ID + ICON + TEMPLATE + LOAD_IMAGE + BACKGROUND + VERSION + ) + set (multiValueArgs) + cmake_parse_arguments(VITA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + get_target_property(VITA_EXECUTABLE ${target} OUTPUT_NAME) + + set(VITA_MKSFOEX_FLAGS "${VITA_MKSFOEX_FLAGS} -d ATTRIBUTE2=12") + vita_create_self(${VITA_EXECUTABLE}.self ${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}) + + if(NOT VITA_APP_NAME OR "${VITA_APP_NAME}" STREQUAL "") + set(VITA_APP_NAME "VitaApp") + endif() + + if(NOT VITA_TITLE_ID OR "${VITA_TITLE_ID}" STREQUAL "") + set(VITA_TITLE_ID "UNKN00000") + endif() + + if(NOT VITA_VERSION OR "${VITA_VERSION}" STREQUAL "") + set(VITA_VERSION "01.00") + endif() + + if(NOT VITA_TEMPLATE OR "${VITA_TEMPLATE}" STREQUAL "") + set(VITA_TEMPLATE ${GenerateVPKCurrentDir}/template.xml) + list(APPEND VPK_FILE_LIST FILE ${VITA_TEMPLATE} sce_sys/livearea/contents/template.xml) + endif() + + if(VITA_ICON) + find_package(ImageMagick COMPONENTS magick) + + if(ImageMagick_magick_FOUND) + set(ImageMagick_convert_FOUND TRUE) + set(ImageMagick_convert_EXECUTABLE ${ImageMagick_magick_EXECUTABLE}) + set(ImageMagick_convert_ARGS convert) + else() + find_package(ImageMagick COMPONENTS convert) + endif() + + if(NOT ImageMagick_convert_FOUND) + message(WARNING "ImageMagick was not found, icons will not be generated.") + endif() + + add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_icon0.png" + COMMAND ${ImageMagick_convert_EXECUTABLE} ${ImageMagick_convert_ARGS} -background none -density 72 -resize 128x128 -units "PixelsPerInch" -type Palette -colors 255 ${VITA_ICON} "${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_icon0.png" + MAIN_DEPENDENCY ${VITA_ICON} + COMMENT "Vita Bubble Icon Generation: ${VITA_EXECUTABLE}_icon0.png" + ) + + add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_startup.png" + COMMAND ${ImageMagick_convert_EXECUTABLE} ${ImageMagick_convert_ARGS} -background none -density 72 -resize 158x158 -gravity center -extent 280x158 -type Palette -units "PixelsPerInch" -colors 255 ${VITA_ICON} "${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_startup.png" + MAIN_DEPENDENCY ${VITA_ICON} + COMMENT "Vita Startup Icon Generation: ${VITA_EXECUTABLE}_startup.png" + ) + + add_custom_target(${VITA_EXECUTABLE}_icons + DEPENDS "${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_icon0.png" "${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_startup.png" + ) + + list(APPEND VPK_FILE_LIST FILE ${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_icon0.png sce_sys/icon0.png) + list(APPEND VPK_FILE_LIST FILE ${CMAKE_BINARY_DIR}/${VITA_EXECUTABLE}_startup.png sce_sys/livearea/contents/startup.png) + add_dependencies(${VITA_EXECUTABLE}.self-self ${VITA_EXECUTABLE}_icons) + endif() + + if(VITA_LOAD_IMAGE) + list(APPEND VPK_FILE_LIST FILE ${VITA_LOAD_IMAGE} sce_sys/pic0.png) + endif() + + if(VITA_BACKGROUND) + list(APPEND VPK_FILE_LIST FILE ${VITA_BACKGROUND} sce_sys/livearea/contents/bg.png) + endif() + + set(VITA_PACK_VPK_FLAGS "") + + vita_create_vpk(${VITA_EXECUTABLE}.vpk ${VITA_TITLE_ID} ${CMAKE_CURRENT_BINARY_DIR}/${VITA_EXECUTABLE}.self + VERSION ${VITA_VERSION} + NAME ${VITA_APP_NAME} + ${VPK_FILE_LIST} + ) + add_dependencies(${VITA_EXECUTABLE}.self-self ${target}) +endfunction() \ No newline at end of file diff --git a/cmake/template.xml b/cmake/template.xml new file mode 100644 index 00000000..509124e0 --- /dev/null +++ b/cmake/template.xml @@ -0,0 +1,11 @@ + + + + + bg.png + + + + startup.png + + diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 949ee609..fc4af382 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -102,6 +102,8 @@ set(COMMON_SRC if (WIN32) list(APPEND COMMON_SRC file_win.cpp paths_win.cpp) +elseif(VITA) + list(APPEND COMMON_SRC file_posix.cpp paths_vita.cpp) else() list(APPEND COMMON_SRC file_posix.cpp paths_posix.cpp) endif() @@ -172,6 +174,35 @@ target_compile_definitions(common PRIVATE FIXIT_FAST_LOAD $<$:_DEB # Make build check state of git to check for uncommitted changes. add_dependencies(common check_git) +if(VITA) + target_compile_definitions(common PUBLIC VITA) + target_compile_options(common PUBLIC + -O2 + -mcpu=cortex-a9 + -mfpu=neon + -ffast-math + -ftree-vectorize + -fno-lto + ) + target_link_libraries(common PUBLIC + SceMotion_stub + SceTouch_stub + SceAudio_stub + SceAudioIn_stub + SceCtrl_stub + SceGxm_stub + SceHid_stub + SceDisplay_stub + SceSysmodule_stub + SceCommonDialog_stub + ScePower_stub + SceAppUtil_stub + -Wl,--whole-archive + pthread + -Wl,--no-whole-archive + ) +endif() + if(WIN32) if(WIN9X) target_compile_definitions(common PUBLIC _WIN32_WINNT=0x400) diff --git a/common/debugstring.cpp b/common/debugstring.cpp index 2244eee8..1a6d39f6 100644 --- a/common/debugstring.cpp +++ b/common/debugstring.cpp @@ -9,6 +9,10 @@ #include #endif +#ifdef VITA +#include +#endif + static class DebugStateClass { public: @@ -66,6 +70,16 @@ void Debug_String_Log(unsigned level, const char* file, int line, const char* fm fflush(DebugState.File); } +#ifdef VITA + /* Don't print file and line numbers to stderr to avoid clogging it up with too much info */ + va_list args; + sceClibPrintf("%-5s: ", levels[level]); + va_start(args, fmt); + char msg[200]; + vsprintf(msg, fmt, args); + sceClibPrintf("%s\n", msg); + va_end(args); +#else /* Don't print file and line numbers to stderr to avoid clogging it up with too much info */ va_list args; fprintf(stderr, "%-5s: ", levels[level]); @@ -74,6 +88,7 @@ void Debug_String_Log(unsigned level, const char* file, int line, const char* fm fprintf(stderr, "\n"); va_end(args); fflush(stderr); +#endif } void Debug_String_File(const char* file) diff --git a/common/file_posix.cpp b/common/file_posix.cpp index 387512f9..9ac333d3 100644 --- a/common/file_posix.cpp +++ b/common/file_posix.cpp @@ -8,6 +8,12 @@ #include #include +#ifdef VITA +// TODO More definitions to move to a compat lib that tests for the symbols? +#define PATH_MAX 256 +#define FNM_CASEFOLD 0 +#endif + class Find_File_Data_Posix : public Find_File_Data { public: @@ -122,3 +128,51 @@ Find_File_Data* Find_File_Data::CreateFindData() { return new Find_File_Data_Posix(); } + +#ifdef VITA +#include +#include +#include + +#define PATH_MAX 256 + +std::string StringLower(std::string str) +{ + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; +} + +// fnmatch is missing from vita newlib, this is here until otherwise. +int fnmatch(const char* pattern, const char* string, int flags) +{ + //massive hackjob.. + std::string filename = string; + std::string filter = pattern; + filename = StringLower(filename); + filter = StringLower(filter); + std::vector filter_split; + std::string delimiter = "*"; + bool found = true; + + size_t pos = 0; + std::string token; + while ((pos = filter.find(delimiter)) != std::string::npos) { + token = filter.substr(0, pos); + filter_split.push_back(token); + filter.erase(0, pos + delimiter.length()); + } + + if (!filter_split.empty()) { + for (int i = 0; i < filter_split.size(); ++i) { + if (filename.find(filter_split[i]) == std::string::npos) { + found = false; + break; + } + } + } else { + found = filename.find(filter) != std::string::npos; + } + + return found ? 0 : 1; +} +#endif diff --git a/common/mixfile.h b/common/mixfile.h index 61d8ccc8..df1b2c27 100644 --- a/common/mixfile.h +++ b/common/mixfile.h @@ -34,6 +34,19 @@ #include // For basename() #endif +#ifdef VITA +// TODO Another set of functions to move to a compat lib that tests for the function? +#define PATH_MAX 256 +#define basename basename_vita + +// fails to link due to undefined basename. old newlib? +static char* basename_vita(const char* filename) +{ + char* p = strrchr(filename, '/'); + return p ? p + 1 : (char*)filename; +} +#endif + #ifndef _MAX_PATH #define _MAX_PATH PATH_MAX #endif diff --git a/common/mssleep.h b/common/mssleep.h index ef0dc26d..7e123cdb 100644 --- a/common/mssleep.h +++ b/common/mssleep.h @@ -10,6 +10,8 @@ #include #elif defined(_WIN32) #include +#elif defined VITA +#include #else /* Assuming recent posix*/ #define __USE_POSIX199309 #define _POSIX_C_SOURCE 199309L diff --git a/common/paths_vita.cpp b/common/paths_vita.cpp new file mode 100644 index 00000000..e6a8f533 --- /dev/null +++ b/common/paths_vita.cpp @@ -0,0 +1,97 @@ +// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free +// software: you can redistribute it and/or modify it under the terms of +// the GNU General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. + +// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed +// in the hope that it will be useful, but with permitted additional restrictions +// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT +// distributed with this program. You should have received a copy of the +// GNU General Public License along with permitted additional restrictions +// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection + +#include "paths.h" + +#include +#include +#include + +#define PATH_MAX 256 + +static std::string VitaGamePath; + +const char* PathsClass::Program_Path() +{ + if (ProgramPath.empty()) { + ProgramPath = VitaGamePath; + } + + return ProgramPath.c_str(); +} + +const char* PathsClass::Data_Path() +{ + if (DataPath.empty()) { + if (ProgramPath.empty()) { + // Init the program path first if it hasn't been done already. + Program_Path(); + } + + DataPath = VitaGamePath; + + if (!Suffix.empty()) { + DataPath += SEP + Suffix; + } + } + + return DataPath.c_str(); +} + +const char* PathsClass::User_Path() +{ + if (UserPath.empty()) { + UserPath = VitaGamePath; + + if (!Suffix.empty()) { + UserPath += SEP + Suffix; + } + + Create_Directory(UserPath.c_str()); + } + + return UserPath.c_str(); +} + +bool PathsClass::Create_Directory(const char* dirname) +{ + bool ret = true; + + if (dirname == nullptr) { + return ret; + } + + std::string temp = dirname; + size_t pos = 0; + do { + pos = temp.find_first_of("/", pos + 1); + sceIoMkdir(temp.substr(0, pos).c_str(), 0700); + } while (pos != std::string::npos); + + return ret; +} + +bool PathsClass::Is_Absolute(const char* path) +{ + return path != nullptr && path[0] == 'u' && path[1] == 'x' && path[2] == '0'; +} + +std::string PathsClass::Concatenate_Paths(const char* path1, const char* path2) +{ + return std::string(path1) + SEP + path2; +} + +std::string PathsClass::Argv_Path(const char* cmd_arg) +{ + VitaGamePath = cmd_arg; + return VitaGamePath; +} diff --git a/common/settings.cpp b/common/settings.cpp index bff02b6d..27ca6d44 100644 --- a/common/settings.cpp +++ b/common/settings.cpp @@ -11,7 +11,12 @@ SettingsClass::SettingsClass() */ Mouse.RawInput = true; Mouse.Sensitivity = 100; +#ifdef VITA + // Default to enabled on platforms where controller is likely to be primary method. + Mouse.ControllerEnabled = true; +#else Mouse.ControllerEnabled = false; +#endif Mouse.ControllerPointerSpeed = 10; Options.MouseWheelScrolling = true; @@ -32,6 +37,12 @@ SettingsClass::SettingsClass() Video.Scaler = "nearest"; Video.Driver = "default"; Video.PixelFormat = "default"; + +#ifdef VITA + Vita.ScaleGameSurface = true; + Vita.RearTouchEnabled = true; + Vita.RearTouchSpeed = 5; +#endif } void SettingsClass::Load(INIClass& ini) @@ -77,6 +88,12 @@ void SettingsClass::Load(INIClass& ini) if (Video.Boxing || Mouse.RawInput || Mouse.ControllerEnabled) { Video.HardwareCursor = false; } + +#ifdef VITA + Vita.ScaleGameSurface = ini.Get_Bool("Vita", "ScaleGameSurface", Vita.ScaleGameSurface); + Vita.RearTouchEnabled = ini.Get_Bool("Vita", "RearTouchEnabled", Vita.RearTouchEnabled); + Vita.RearTouchSpeed = ini.Get_Int("Vita", "RearTouchSpeed", Vita.RearTouchSpeed); +#endif } void SettingsClass::Save(INIClass& ini) @@ -111,4 +128,10 @@ void SettingsClass::Save(INIClass& ini) ** VQA and WSA interpolation mode 0 = scanlines, 1 = vertical doubling, 2 = linear */ ini.Put_Int("Video", "InterpolationMode", Video.InterpolationMode); + +#ifdef VITA + ini.Put_Bool("Vita", "ScaleGameSurface", Vita.ScaleGameSurface); + ini.Put_Bool("Vita", "RearTouchEnabled", Vita.RearTouchEnabled); + ini.Put_Int("Vita", "RearTouchSpeed", Vita.RearTouchSpeed); +#endif } diff --git a/common/settings.h b/common/settings.h index cd2b4ea3..f365c8cc 100644 --- a/common/settings.h +++ b/common/settings.h @@ -38,6 +38,15 @@ class SettingsClass std::string PixelFormat; } Video; +#ifdef VITA + struct + { + bool ScaleGameSurface; + bool RearTouchEnabled; + int RearTouchSpeed; + } Vita; +#endif + struct { bool MouseWheelScrolling; diff --git a/common/sockets.h b/common/sockets.h index fb2b052c..722d3953 100644 --- a/common/sockets.h +++ b/common/sockets.h @@ -29,22 +29,33 @@ static inline int socket_cleanup(void) { return WSACleanup(); } - #else /* Assume posix style sockets on non-windows */ +#ifdef VITA +// TODO vita networking stuff. +#include +#endif + #include #include #include // for getaddrinfo() and freeaddrinfo() +#ifndef VITA #include +#endif #include #include #include // for close() typedef int SOCKET; -#define INVALID_SOCKET (-1) -#define SOCKET_ERROR (-1) -#define closesocket(x) close(x) +#define INVALID_SOCKET (-1) +#define SOCKET_ERROR (-1) +#define closesocket(x) close(x) +#ifdef VITA // Hack around lack of ioctl for setting none blocking. +#define FIONBIO SO_NONBLOCK +#define ioctlsocket(x, y, z) setsockopt(x, SOL_SOCKET, y, z, sizeof(*(z))) +#else #define ioctlsocket(x, y, z) ioctl(x, y, z) -#define LastSocketError (errno) +#endif +#define LastSocketError (errno) #define WSAEISCONN EISCONN #define WSAEINPROGRESS EINPROGRESS diff --git a/common/video.h b/common/video.h index 6e9ae737..f8f4b11b 100644 --- a/common/video.h +++ b/common/video.h @@ -70,6 +70,17 @@ void Reset_Video_Mode(); unsigned Get_Free_Video_Memory(); void Wait_Blit(); +#ifdef VITA +#include + +const int32_t VITA_FULLSCREEN_WIDTH = 960; +const int32_t VITA_FULLSCREEN_HEIGHT = 544; + +void Get_Game_Resolution(int& w, int& h); +void Set_Video_Mouse(int x, int y); +SDL_Rect Get_Render_Rect(); +#endif + /* ** Set desired cursor image in game palette. */ diff --git a/common/video_sdl2.cpp b/common/video_sdl2.cpp index b84f7436..417841da 100644 --- a/common/video_sdl2.cpp +++ b/common/video_sdl2.cpp @@ -132,6 +132,39 @@ static void Update_HWCursor_Settings() /* ** Update screen boxing settings. */ +#ifdef VITA + if (hwcursor.GameW != VITA_FULLSCREEN_WIDTH || hwcursor.GameH != VITA_FULLSCREEN_HEIGHT) { + render_dst.x = 0; + render_dst.y = 0; + render_dst.w = hwcursor.GameW; + render_dst.h = hwcursor.GameH; + + if (Settings.Vita.ScaleGameSurface) { + //resize to fullscreen + if (Settings.Video.Boxing) { + if ((static_cast(VITA_FULLSCREEN_WIDTH) / VITA_FULLSCREEN_HEIGHT) + >= (static_cast(hwcursor.GameW) / hwcursor.GameH)) { + float scale = static_cast(VITA_FULLSCREEN_HEIGHT) / hwcursor.GameH; + render_dst.w = hwcursor.GameW * scale; + render_dst.h = VITA_FULLSCREEN_HEIGHT; + render_dst.x = (VITA_FULLSCREEN_WIDTH - render_dst.w) / 2; + } else { + float scale = static_cast(VITA_FULLSCREEN_WIDTH) / hwcursor.GameW; + render_dst.w = VITA_FULLSCREEN_WIDTH; + render_dst.h = hwcursor.GameH * scale; + render_dst.y = (VITA_FULLSCREEN_HEIGHT - render_dst.h) / 2; + } + } else { + render_dst.w = VITA_FULLSCREEN_WIDTH; + render_dst.h = VITA_FULLSCREEN_HEIGHT; + } + } else { + //center game area + render_dst.x = (VITA_FULLSCREEN_WIDTH - hwcursor.GameW) / 2; + render_dst.y = (VITA_FULLSCREEN_HEIGHT - hwcursor.GameH) / 2; + } + } +#else float ar = (float)hwcursor.GameW / hwcursor.GameH; if (Settings.Video.Boxing) { size_t colonPos = Settings.Video.BoxingAspectRatio.find(":"); @@ -166,6 +199,7 @@ static void Update_HWCursor_Settings() render_dst.x = 0; render_dst.y = 0; } +#endif /* ** Ensure cursor clip is in the desired state. @@ -279,7 +313,11 @@ bool Set_Video_Mode(int w, int h, int bits_per_pixel) } } +#ifdef VITA + renderer = SDL_CreateRenderer(window, renderer_index, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_PRESENTVSYNC); +#else renderer = SDL_CreateRenderer(window, renderer_index, SDL_RENDERER_TARGETTEXTURE); +#endif if (renderer == nullptr) { DBG_ERROR("SDL_CreateRenderer failed: %s", SDL_GetError()); Reset_Video_Mode(); @@ -459,6 +497,25 @@ void Get_Video_Mouse(int& x, int& y) } } +#ifdef VITA +void Get_Game_Resolution(int& w, int& h) +{ + w = hwcursor.GameW; + h = hwcursor.GameH; +} + +void Set_Video_Mouse(int x, int y) +{ + hwcursor.X = x; + hwcursor.Y = y; +} + +SDL_Rect Get_Render_Rect() +{ + return render_dst; +} +#endif + /*********************************************************************************************** * Reset_Video_Mode -- Resets video mode and deletes Direct Draw Object * * * diff --git a/common/wspudp.cpp b/common/wspudp.cpp index 1f0c8d82..e1b46020 100644 --- a/common/wspudp.cpp +++ b/common/wspudp.cpp @@ -53,7 +53,7 @@ extern WWKeyboardClass* Keyboard; #include #include -#ifndef _WIN32 +#if !defined _WIN32 && !defined VITA #include #endif @@ -210,7 +210,7 @@ bool UDPInterfaceClass::Open_Socket(SOCKET) LocalAddresses.Delete(0); } -#ifdef _WIN32 +#if defined _WIN32 || defined VITA /* ** Use gethostbyname to find the name of the local host. We will need this to look up ** the local ip address. diff --git a/common/wwkeyboard.cpp b/common/wwkeyboard.cpp index b7f2d683..70d6d223 100644 --- a/common/wwkeyboard.cpp +++ b/common/wwkeyboard.cpp @@ -647,7 +647,14 @@ void WWKeyboardClass::Fill_Buffer_From_System(void) case SDL_CONTROLLERBUTTONUP: Handle_Controller_Button_Event(event.cbutton); break; +#ifdef VITA + case SDL_FINGERDOWN: + case SDL_FINGERUP: + case SDL_FINGERMOTION: + Handle_Touch_Event(event.tfinger); + break; #endif +#endif // SDL2_BUILD } } #ifdef SDL2_BUILD @@ -682,6 +689,9 @@ void WWKeyboardClass::Open_Controller() GameController = SDL_GameControllerOpen(i); } } +#if SDL_VERSION_ATLEAST(2, 0, 10) && defined(VITA) + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); +#endif } void WWKeyboardClass::Close_Controller() @@ -698,6 +708,12 @@ void WWKeyboardClass::Process_Controller_Axis_Motion() const float deltaTime = currentTime - LastControllerTime; LastControllerTime = currentTime; +#ifdef VITA + if (!AnalogStickMouse) { + return; + } +#endif + if (ControllerLeftXAxis != 0 || ControllerLeftYAxis != 0) { const int16_t xSign = (ControllerLeftXAxis > 0) - (ControllerLeftXAxis < 0); const int16_t ySign = (ControllerLeftYAxis > 0) - (ControllerLeftYAxis < 0); @@ -717,6 +733,15 @@ void WWKeyboardClass::Handle_Controller_Axis_Event(const SDL_ControllerAxisEvent ScrollDirType directionX = SDIR_NONE; ScrollDirType directionY = SDIR_NONE; +#ifdef VITA + int CONTROLLER_L_DEADZONE; + if (!AnalogStickMouse) { + CONTROLLER_L_DEADZONE = CONTROLLER_L_DEADZONE_SCROLL; + } else { + CONTROLLER_L_DEADZONE = CONTROLLER_L_DEADZONE_MOUSE; + } +#endif + if (motion.axis == SDL_CONTROLLER_AXIS_LEFTX) { if (std::abs(motion.value) > CONTROLLER_L_DEADZONE) ControllerLeftXAxis = motion.value; @@ -744,6 +769,19 @@ void WWKeyboardClass::Handle_Controller_Axis_Event(const SDL_ControllerAxisEvent ControllerSpeedBoost = 1; } +#ifdef VITA + if (!AnalogStickMouse) { + if (ControllerLeftXAxis != 0) { + AnalogScrollActive = true; + directionX = ControllerLeftXAxis > 0 ? SDIR_E : SDIR_W; + } + if (ControllerLeftYAxis != 0) { + AnalogScrollActive = true; + directionY = ControllerLeftYAxis > 0 ? SDIR_S : SDIR_N; + } + } +#endif + if (ControllerRightXAxis != 0) { AnalogScrollActive = true; directionX = ControllerRightXAxis > 0 ? SDIR_E : SDIR_W; @@ -839,6 +877,17 @@ void WWKeyboardClass::Handle_Controller_Button_Event(const SDL_ControllerButtonE Get_Video_Mouse(x, y); Put_Mouse_Message(key, x, y, button.state == SDL_RELEASED); } + +#ifdef VITA + if (button.state == SDL_PRESSED + && (button.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || button.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER + || button.button == SDL_CONTROLLER_BUTTON_START)) { + if (SDL_GameControllerGetButton(GameController, SDL_CONTROLLER_BUTTON_LEFTSHOULDER) + && SDL_GameControllerGetButton(GameController, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) + && SDL_GameControllerGetButton(GameController, SDL_CONTROLLER_BUTTON_START)) + AnalogStickMouse = !AnalogStickMouse; + } +#endif } bool WWKeyboardClass::Is_Analog_Scroll_Active() @@ -850,7 +899,86 @@ unsigned char WWKeyboardClass::Get_Scroll_Direction() { return ScrollDirection; } -#endif +#ifdef VITA +bool WWKeyboardClass::Is_Analog_Only_Scroll() +{ + return !AnalogStickMouse; +} + +void WWKeyboardClass::Handle_Touch_Event(const SDL_TouchFingerEvent& event) +{ + // rear touchpad + if (event.touchId != 0) { + if (Settings.Vita.RearTouchEnabled) { + if (event.type == SDL_FINGERDOWN) { + ++RearNumTouches; + if (RearNumTouches == 1) { + RearFirstFingerId = event.fingerId; + } + LastRearTouchTime = SDL_GetTicks(); + } else if (event.type == SDL_FINGERUP) { + --RearNumTouches; + if ((RearNumTouches == 0) && (SDL_GetTicks() - LastRearTouchTime < REAR_LMB_DELAY)) { + int emulatedPointerPosX; + int emulatedPointerPosY; + Get_Video_Mouse(emulatedPointerPosX, emulatedPointerPosY); + Put_Mouse_Message(VK_LBUTTON, emulatedPointerPosX, emulatedPointerPosY, 0); + Put_Mouse_Message(VK_LBUTTON, emulatedPointerPosX, emulatedPointerPosY, 1); + } + } else if (event.type == SDL_FINGERMOTION) { + if (RearFirstFingerId == event.fingerId) { + float movX = event.dx * REAR_TOUCH_SPEED_MOD * Settings.Vita.RearTouchSpeed; + float movY = event.dy * REAR_TOUCH_SPEED_MOD * Settings.Vita.RearTouchSpeed; + Move_Video_Mouse(movX, movY); + } + } + } + return; + } + + if (event.type == SDL_FINGERDOWN) { + ++NumTouches; + if (NumTouches == 1) { + FirstFingerId = event.fingerId; + } + } else if (event.type == SDL_FINGERUP) { + --NumTouches; + } + + if (FirstFingerId == event.fingerId) { + const int screenWidth = 960; + const int screenHeight = 544; + int gameWidth; + int gameHeight; + Get_Game_Resolution(gameWidth, gameHeight); + SDL_Rect renderRect = Get_Render_Rect(); + + float emulatedPointerPosX = + static_cast(screenWidth * event.x - renderRect.x) * (static_cast(gameWidth) / renderRect.w); + float emulatedPointerPosY = static_cast(screenHeight * event.y - renderRect.y) + * (static_cast(gameHeight) / renderRect.h); + + if (emulatedPointerPosX < 0) + emulatedPointerPosX = 0; + else if (emulatedPointerPosX >= gameWidth) + emulatedPointerPosX = gameWidth - 1; + + if (emulatedPointerPosY < 0) + emulatedPointerPosY = 0; + else if (emulatedPointerPosY >= gameHeight) + emulatedPointerPosY = gameHeight - 1; + + Set_Video_Mouse(emulatedPointerPosX, emulatedPointerPosY); + + if (event.type == SDL_FINGERDOWN) { + Put_Mouse_Message(VK_LBUTTON, emulatedPointerPosX, emulatedPointerPosY, 0); + } else if (event.type == SDL_FINGERUP) { + Put_Mouse_Message(VK_LBUTTON, emulatedPointerPosX, emulatedPointerPosY, 1); + } + } +} +#endif // VITA +#endif // SDL2_BUILD /*********************************************************************************************** * WWKeyboardClass::Clear -- Clears the keyboard buffer. * diff --git a/common/wwkeyboard.h b/common/wwkeyboard.h index e49f364a..791c6157 100644 --- a/common/wwkeyboard.h +++ b/common/wwkeyboard.h @@ -877,6 +877,9 @@ class WWKeyboardClass void Open_Controller(); void Close_Controller(); bool Is_Analog_Scroll_Active(); +#ifdef VITA + bool Is_Analog_Only_Scroll(); +#endif unsigned char Get_Scroll_Direction(); #elif defined(SDL1_BUILD) bool Is_Gamepad_Active() @@ -947,7 +950,12 @@ class WWKeyboardClass enum { +#ifdef VITA + CONTROLLER_L_DEADZONE_MOUSE = 4000, + CONTROLLER_L_DEADZONE_SCROLL = 6000, +#else CONTROLLER_L_DEADZONE = 4000, +#endif CONTROLLER_R_DEADZONE = 6000, CONTROLLER_TRIGGER_R_DEADZONE = 3000 }; @@ -961,6 +969,19 @@ class WWKeyboardClass float ControllerSpeedBoost = 1; bool AnalogScrollActive = false; ScrollDirType ScrollDirection = SDIR_NONE; + +#ifdef VITA + bool AnalogStickMouse = true; + void Handle_Touch_Event(const SDL_TouchFingerEvent& event); + SDL_FingerID FirstFingerId = 0; + int16_t NumTouches = 0; + + static constexpr int REAR_TOUCH_SPEED_MOD = 100; + static constexpr int REAR_LMB_DELAY = 250; + uint32_t LastRearTouchTime = 0; + SDL_FingerID RearFirstFingerId = 0; + int16_t RearNumTouches = 0; +#endif #endif }; diff --git a/common/wwstd.h b/common/wwstd.h index ab99bcc1..439ba591 100644 --- a/common/wwstd.h +++ b/common/wwstd.h @@ -258,12 +258,15 @@ inline static void _splitpath(const char* path, char* drive, char* dir, char* fn } } +#ifndef VITA +// TODO Consider moving these functions to some kind of compat lib? inline static char* strupr(char* str) { for (int i = 0; i < strlen(str); i++) str[i] = toupper(str[i]); return str; } +#endif inline static void strrev(char* str) { diff --git a/redalert/CMakeLists.txt b/redalert/CMakeLists.txt index 60a3e854..2ccf6bba 100644 --- a/redalert/CMakeLists.txt +++ b/redalert/CMakeLists.txt @@ -280,4 +280,12 @@ if(BUILD_VANILLARA) -g3 -fno-omit-frame-pointer) target_link_options(VanillaRA PUBLIC -fsanitize=address) endif() -endif() \ No newline at end of file + if(VITA) + include(VitaPackage) + generate_vita_package(VanillaRA + APP_NAME "VanillaRA" + TITLE_ID "VCRA00001" + ICON "${CMAKE_SOURCE_DIR}/resources/vanillara_icon.svg" + ) + endif() +endif() diff --git a/redalert/globals.cpp b/redalert/globals.cpp index bfdd751c..186b1e54 100644 --- a/redalert/globals.cpp +++ b/redalert/globals.cpp @@ -650,7 +650,10 @@ int MouseInstalled; // // Variables for helping track how much time goes bye in routines // +#ifndef VITA +//multiple definition of `LogLevel' with openal vita port. int LogLevel = 0; +#endif unsigned int LogLevelTime[MAX_LOG_LEVEL] = {0}; unsigned int LogLastTime = 0; bool LogDump_Print = false; // true = print the Log time Stuff diff --git a/redalert/startup.cpp b/redalert/startup.cpp index d6b1a12c..2e72d50f 100644 --- a/redalert/startup.cpp +++ b/redalert/startup.cpp @@ -59,6 +59,13 @@ HINSTANCE ProgramInstance; #else #include #endif + +#ifdef VITA +int _newlib_heap_size_user = 340 * 1024 * 1024; +#include +#include +#endif + extern bool RA95AlreadyRunning; void Check_Use_Compressed_Shapes(void); void Read_Setup_Options(RawFileClass* config_file); @@ -289,7 +296,12 @@ int main(int argc, char* argv[]) /* ** Remember the current working directory and drive. */ - Paths.Init("vanillara", CONFIG_FILE_NAME, "REDALERT.MIX", args.ArgV[0]); +#ifdef VITA + const char* progpath = "ux0:data"; +#else + const char* progpath = args.ArgV[0]; +#endif + Paths.Init("vanillara", CONFIG_FILE_NAME, "REDALERT.MIX", progpath); CDFileClass::Refresh_Search_Drives(); if (Parse_Command_Line(args.ArgC, args.ArgV)) { @@ -515,6 +527,10 @@ int main(int argc, char* argv[]) return (EXIT_SUCCESS); } +#ifdef VITA + sceKernelExitProcess(0); +#endif + return (EXIT_SUCCESS); } diff --git a/tiberiandawn/CMakeLists.txt b/tiberiandawn/CMakeLists.txt index a26cf467..55a77e79 100644 --- a/tiberiandawn/CMakeLists.txt +++ b/tiberiandawn/CMakeLists.txt @@ -256,4 +256,12 @@ if(BUILD_VANILLATD) -g3 -fno-omit-frame-pointer) target_link_options(VanillaTD PUBLIC -fsanitize=address) endif() + if(VITA) + include(VitaPackage) + generate_vita_package(VanillaTD + APP_NAME "VanillaTD" + TITLE_ID "VCTD00001" + ICON "${CMAKE_SOURCE_DIR}/resources/vanillatd_icon.svg" + ) + endif() endif() diff --git a/tiberiandawn/startup.cpp b/tiberiandawn/startup.cpp index 0d46fdd3..7c9c1efe 100644 --- a/tiberiandawn/startup.cpp +++ b/tiberiandawn/startup.cpp @@ -52,6 +52,12 @@ HINSTANCE ProgramInstance; #include #endif +#ifdef VITA +int _newlib_heap_size_user = 340 * 1024 * 1024; +#include +#include +#endif + extern int ReadyToQuit; void Read_Setup_Options(RawFileClass* config_file); @@ -200,6 +206,9 @@ int DLL_Startup(const char* command_line_in) int main(int argc, char** argv) { +#ifdef VITA + scePowerSetArmClockFrequency(444); +#endif UtfArgs args(argc, argv); CCDebugString("C&C95 - Starting up.\n"); @@ -223,7 +232,12 @@ int main(int argc, char** argv) /* ** Remember the current working directory and drive. */ - Paths.Init("vanillatd", "CONQUER.INI", "CONQUER.MIX", args.ArgV[0]); +#ifdef VITA + const char* progpath = "ux0:data"; +#else + const char* progpath = args.ArgV[0]; +#endif + Paths.Init("vanillatd", "CONQUER.INI", "CONQUER.MIX", progpath); CDFileClass::Refresh_Search_Drives(); if (Parse_Command_Line(args.ArgC, args.ArgV)) { @@ -498,6 +512,10 @@ int main(int argc, char** argv) } } +#ifdef VITA + sceKernelExitProcess(0); +#endif + return (EXIT_SUCCESS); }