diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a506de9..24a246ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ endif() if(VITA) add_definitions(-DVITA) - set(VITA_FLAGS "-O2 -mcpu=cortex-a9 -mfpu=neon -ffast-math -ftree-vectorize -fno-lto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive") + set(VITA_FLAGS "-O2 -mcpu=cortex-a9 -mfpu=neon -fno-lto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${VITA_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VITA_FLAGS}") list(APPEND VANILLA_LIBS "-lSceMotion_stub -lSceTouch_stub -lSceAudio_stub -lSceAudioIn_stub -lSceCtrl_stub -lSceGxm_stub \ diff --git a/README.md b/README.md index f88b5596..cf6d74e6 100644 --- a/README.md +++ b/README.md @@ -37,13 +37,12 @@ https://github.com/Cpasjuste/psp2shell ### Controls -Game is optimized for touch controls. - -- Left/Right analog stick - Map scrolling +- Left analog stick - Cursor movement / Map scrolling (switch between both modes with a 3-fingress press on the rear touchpad) +- Right analog stick - Map scrolling +- CROSS - Left mouse button - CIRCLE - Right mouse button (Cancel building, deselect unit..) -- CROSS - G (Guard Area) -- SQUARE - F (Formation. RA only I guess) -- TRIANGLE - X (Scatter Units) +- SQUARE - G (Guard Area) +- TRIANGLE - F (Formation. RA only) - D-Pad Up/Right/Down/Left - 1/2/3/4 button - R1 - Alt (force move) - L1 - Ctrl (force attack) @@ -52,10 +51,19 @@ Game is optimized for touch controls. Use R1 + D-Pad to create teams (1-4) and D-Pad to select them (same as Ctrl + 1-4 on keyboard). You can use DPad numbers while entering savegame names. +Left analog stick can be used for both cursor movement (good for builing or preciece movement) or map scrolling (useful during combat when you're giving command with a touchpad). Cursor movement mode is default. To switch between both modes use 3-finger touch on the rear touchpad. + +You can change cursor movement speed by editing ```ControllerPointerSpeed``` option under ```[Vita]``` section inside ```conquer.ini```/```redalert.ini``` files. + ### Other -Game supports nearest and linear filtering. Nearest is used by default and it produces sharp, but pixelated image (that's especially noticeable on text). Linear is smooth, but somewhat blurred. To select linear filtering edit -```ux0:data/VanillaTD/vanillatd/conquer.ini``` or ```ux0:data/VanillaRA/vanillara/redalert.ini``` and change ```Scaler``` option to ```linear``` +Config files for VanillaTD and VanillaRA are located at ```ux0:data/VanillaTD/vanillatd/conquer.ini``` and ```ux0:data/VanillaRA/vanillara/redalert.ini```. + +To preserve original aspect ratio set ```Boxing=yes``` option. + +If you want to display the game at native resolution without any scaling set ```ScaleGameSurface=no``` (```[Vita]``` section). + +Game supports nearest and linear filtering. Nearest is used by default and it produces sharp, but pixelated image (that's especially noticeable on text). Linear is smooth, but somewhat blurred. To select linear filtering set ```Scaler``` option to ```linear``` ``` [Video] diff --git a/common/settings.cpp b/common/settings.cpp index f00c3b1b..dc5920c4 100644 --- a/common/settings.cpp +++ b/common/settings.cpp @@ -27,6 +27,11 @@ SettingsClass::SettingsClass() Video.Scaler = "nearest"; Video.Driver = "default"; Video.PixelFormat = "default"; + +#ifdef VITA + Vita.ScaleGameSurface = true; + Vita.ControllerPointerSpeed = 10; +#endif } void SettingsClass::Load(INIClass& ini) @@ -52,11 +57,6 @@ void SettingsClass::Load(INIClass& ini) Video.Driver = ini.Get_String("Video", "Driver", Video.Driver); Video.PixelFormat = ini.Get_String("Video", "PixelFormat", Video.PixelFormat); -#ifdef VITA - //touch to mouse translates badly with boxing on - Video.Boxing = false; -#endif - /* ** VQA and WSA interpolation mode 0 = scanlines, 1 = vertical doubling, 2 = linear */ @@ -68,6 +68,11 @@ void SettingsClass::Load(INIClass& ini) if (Video.Boxing || Mouse.RawInput) { Video.HardwareCursor = false; } + +#ifdef VITA + Vita.ScaleGameSurface = ini.Get_Bool("Vita", "ScaleGameSurface", Vita.ScaleGameSurface); + Vita.ControllerPointerSpeed = ini.Get_Int("Vita", "ControllerPointerSpeed", Vita.ControllerPointerSpeed); +#endif } void SettingsClass::Save(INIClass& ini) @@ -97,4 +102,9 @@ 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_Int("Vita", "ControllerPointerSpeed", Vita.ControllerPointerSpeed); +#endif } diff --git a/common/settings.h b/common/settings.h index aa4a6c2c..19b4f0c6 100644 --- a/common/settings.h +++ b/common/settings.h @@ -33,6 +33,14 @@ class SettingsClass std::string Driver; std::string PixelFormat; } Video; + +#ifdef VITA + struct + { + bool ScaleGameSurface; + int ControllerPointerSpeed; + } Vita; +#endif }; extern SettingsClass Settings; diff --git a/common/video.h b/common/video.h index d9c7f4ae..16dee111 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; + +SDL_Rect Get_Render_Rect(); +void Get_Game_Resolution(int& w, int& h); +void Set_Video_Mouse(int x, int y); +#endif + /* ** Set desired cursor image in game palette. */ diff --git a/common/video_sdl2.cpp b/common/video_sdl2.cpp index b9b6497d..6262b3f6 100644 --- a/common/video_sdl2.cpp +++ b/common/video_sdl2.cpp @@ -131,6 +131,38 @@ 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) { render_dst.w = win_w; @@ -147,6 +179,7 @@ static void Update_HWCursor_Settings() render_dst.x = 0; render_dst.y = 0; } +#endif /* ** Ensure cursor clip is in the desired state. @@ -428,6 +461,10 @@ void Move_Video_Mouse(int xrel, int yrel) void Get_Video_Mouse(int& x, int& y) { +#ifdef VITA + x = hwcursor.X; + y = hwcursor.Y; +#else if (Settings.Mouse.RawInput && (hwcursor.Clip || !Settings.Video.Windowed)) { x = hwcursor.X; y = hwcursor.Y; @@ -438,8 +475,28 @@ void Get_Video_Mouse(int& x, int& y) x /= scale_x; y /= scale_y; } +#endif } +#ifdef VITA +SDL_Rect Get_Render_Rect() +{ + return render_dst; +} + +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; +} +#endif + /*********************************************************************************************** * Reset_Video_Mode -- Resets video mode and deletes Direct Draw Object * * * diff --git a/common/wwkeyboard.cpp b/common/wwkeyboard.cpp index 3cda7744..8312b69b 100644 --- a/common/wwkeyboard.cpp +++ b/common/wwkeyboard.cpp @@ -611,15 +611,23 @@ void WWKeyboardClass::Fill_Buffer_From_System(void) } break; case SDL_CONTROLLERAXISMOTION: - HandleControllerAxisEvent(event.caxis); + Handle_Controller_Axis_Event(event.caxis); break; case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: - HandleControllerButtonEvent(event.cbutton); + Handle_Controller_Button_Event(event.cbutton); + break; + case SDL_FINGERDOWN: + case SDL_FINGERUP: + case SDL_FINGERMOTION: + Handle_Touch_Event( event.tfinger ); break; #endif } } +#ifdef VITA + Process_Controller_Axis_Motion(); +#endif #elif defined(_WIN32) if (!Is_Buffer_Full()) { MSG msg; @@ -648,6 +656,7 @@ typedef enum DirType : unsigned char DIR_NONE = 100 } DirType; +bool analogStickMouse = true; bool scrollActive = false; DirType scrollDirection = DIR_NONE; @@ -658,6 +667,16 @@ void WWKeyboardClass::OpenController() gameController = SDL_GameControllerOpen(i); } } + + int gameWidth; + int gameHeight; + Get_Game_Resolution(gameWidth, gameHeight); + emulatedPointerPosX = gameWidth / 2; + emulatedPointerPosY = gameHeight / 2; + +#if SDL_VERSION_ATLEAST( 2, 0, 10 ) + SDL_SetHint( SDL_HINT_TOUCH_MOUSE_EVENTS, "0" ); +#endif } void WWKeyboardClass::CloseController() @@ -668,12 +687,52 @@ void WWKeyboardClass::CloseController() } } -void WWKeyboardClass::HandleControllerAxisEvent(const SDL_ControllerAxisEvent & motion) +void WWKeyboardClass::Process_Controller_Axis_Motion() +{ + const uint32_t currentTime = SDL_GetTicks(); + const double deltaTime = currentTime - lastControllerTime; + lastControllerTime = currentTime; + + if (!analogStickMouse) + return; + + if ( controllerLeftXAxis != 0 || controllerLeftYAxis != 0 ) { + const int16_t xSign = ( controllerLeftXAxis > 0 ) - ( controllerLeftXAxis < 0 ); + const int16_t ySign = ( controllerLeftYAxis > 0 ) - ( controllerLeftYAxis < 0 ); + + emulatedPointerPosX += pow( std::abs( controllerLeftXAxis ), CONTROLLER_AXIS_SPEEDUP ) * xSign * deltaTime * Settings.Vita.ControllerPointerSpeed / CONTROLLER_SPEED_MOD; + emulatedPointerPosY += pow( std::abs( controllerLeftYAxis ), CONTROLLER_AXIS_SPEEDUP ) * ySign * deltaTime * Settings.Vita.ControllerPointerSpeed / CONTROLLER_SPEED_MOD; + + int width; + int height; + Get_Game_Resolution(width, height); + + if ( emulatedPointerPosX < 0 ) + emulatedPointerPosX = 0; + else if ( emulatedPointerPosX >= width ) + emulatedPointerPosX = width - 1; + + if ( emulatedPointerPosY < 0 ) + emulatedPointerPosY = 0; + else if ( emulatedPointerPosY >= height ) + emulatedPointerPosY = height - 1; + + Set_Video_Mouse(emulatedPointerPosX, emulatedPointerPosY); + } +} + +void WWKeyboardClass::Handle_Controller_Axis_Event(const SDL_ControllerAxisEvent & motion) { scrollActive = false; DirType directionX = DIR_NONE; DirType directionY = DIR_NONE; + int CONTROLLER_L_DEADZONE; + if (!analogStickMouse) + CONTROLLER_L_DEADZONE = CONTROLLER_L_DEADZONE_SCROLL; + else + CONTROLLER_L_DEADZONE = CONTROLLER_L_DEADZONE_MOUSE; + if (motion.axis == SDL_CONTROLLER_AXIS_LEFTX) { if (std::abs(motion.value) > CONTROLLER_L_DEADZONE) controllerLeftXAxis = motion.value; @@ -699,18 +758,23 @@ void WWKeyboardClass::HandleControllerAxisEvent(const SDL_ControllerAxisEvent & controllerRightYAxis = 0; } - if (controllerLeftXAxis != 0) { - scrollActive = true; - directionX = controllerLeftXAxis > 0 ? DIR_E : DIR_W; - } else if (controllerRightXAxis != 0) { - scrollActive = true; - directionX = controllerRightXAxis > 0 ? DIR_E : DIR_W; + if (!analogStickMouse) + { + if (controllerLeftXAxis != 0) { + scrollActive = true; + directionX = controllerLeftXAxis > 0 ? DIR_E : DIR_W; + } + if (controllerLeftYAxis != 0) { + scrollActive = true; + directionY = controllerLeftYAxis > 0 ? DIR_S : DIR_N; + } } - if (controllerLeftYAxis != 0) { + if (controllerRightXAxis != 0) { scrollActive = true; - directionY = controllerLeftYAxis > 0 ? DIR_S : DIR_N; - } else if (controllerRightYAxis != 0) { + directionX = controllerRightXAxis > 0 ? DIR_E : DIR_W; + } + if (controllerRightYAxis != 0) { scrollActive = true; directionY = controllerRightYAxis > 0 ? DIR_S : DIR_N; } @@ -733,7 +797,56 @@ void WWKeyboardClass::HandleControllerAxisEvent(const SDL_ControllerAxisEvent & scrollDirection = DIR_N; } -void WWKeyboardClass::HandleControllerButtonEvent(const SDL_ControllerButtonEvent & button) +void WWKeyboardClass::Handle_Touch_Event( const SDL_TouchFingerEvent & event ) +{ + // back touchpad + if ( event.touchId == 1 ) + { + if ( event.type == SDL_FINGERDOWN ) { + int backTouchNum = SDL_GetNumTouchFingers(event.touchId); + // 3 touches on back touchpad switch between left analog scroll and mouse + if (backTouchNum == 3) { + analogStickMouse = !analogStickMouse; + } + } + 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(); + + emulatedPointerPosX + = static_cast( screenWidth * event.x - renderRect.x ) * ( static_cast( gameWidth ) / renderRect.w ); + emulatedPointerPosY + = static_cast( screenHeight * event.y - renderRect.y ) * ( static_cast( gameHeight ) / renderRect.h ); + + 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); + } + } +} + +void WWKeyboardClass::Handle_Controller_Button_Event(const SDL_ControllerButtonEvent & button) { bool keyboardPress = false; bool mousePress = false; @@ -743,8 +856,8 @@ void WWKeyboardClass::HandleControllerButtonEvent(const SDL_ControllerButtonEven switch (button.button) { case SDL_CONTROLLER_BUTTON_A: - keyboardPress = true; - scancode = SDL_SCANCODE_G; + mousePress = true; + key = VK_LBUTTON; break; case SDL_CONTROLLER_BUTTON_B: mousePress = true; @@ -752,11 +865,11 @@ void WWKeyboardClass::HandleControllerButtonEvent(const SDL_ControllerButtonEven break; case SDL_CONTROLLER_BUTTON_X: keyboardPress = true; - scancode = SDL_SCANCODE_F; + scancode = SDL_SCANCODE_G; break; case SDL_CONTROLLER_BUTTON_Y: keyboardPress = true; - scancode = SDL_SCANCODE_X; + scancode = SDL_SCANCODE_F; break; case SDL_CONTROLLER_BUTTON_BACK: keyboardPress = true; @@ -808,6 +921,11 @@ bool WWKeyboardClass::ScrollActive() return scrollActive; } +bool WWKeyboardClass::IsAnalogOnlyScroll() +{ + return !analogStickMouse; +} + unsigned char WWKeyboardClass::GetScrollDirection() { return scrollDirection; diff --git a/common/wwkeyboard.h b/common/wwkeyboard.h index 9e3bc3e8..e1708595 100644 --- a/common/wwkeyboard.h +++ b/common/wwkeyboard.h @@ -731,6 +731,7 @@ class WWKeyboardClass void OpenController(); void CloseController(); bool ScrollActive(); + bool IsAnalogOnlyScroll(); unsigned char GetScrollDirection(); #endif @@ -783,12 +784,21 @@ class WWKeyboardClass int DownSkip; #ifdef VITA - void HandleControllerAxisEvent(const SDL_ControllerAxisEvent & motion); - void HandleControllerButtonEvent(const SDL_ControllerButtonEvent & button); + void Handle_Controller_Axis_Event(const SDL_ControllerAxisEvent & motion); + void Handle_Controller_Button_Event(const SDL_ControllerButtonEvent & button); + void Handle_Touch_Event( const SDL_TouchFingerEvent & event ); + void Process_Controller_Axis_Motion(); + + // used to convert user-friendly pointer speed values into more useable ones + const double CONTROLLER_SPEED_MOD = 2000000.0; + + // bigger value correndsponds to faster pointer movement speed with bigger stick axis values + const double CONTROLLER_AXIS_SPEEDUP = 1.03; enum { - CONTROLLER_L_DEADZONE = 6000, + CONTROLLER_L_DEADZONE_SCROLL = 6000, + CONTROLLER_L_DEADZONE_MOUSE = 3000, CONTROLLER_R_DEADZONE = 6000 }; @@ -797,6 +807,11 @@ class WWKeyboardClass int16_t controllerLeftYAxis = 0; int16_t controllerRightXAxis = 0; int16_t controllerRightYAxis = 0; + uint32_t lastControllerTime = 0; + float emulatedPointerPosX = 0; + float emulatedPointerPosY = 0; + SDL_FingerID firstFingerId = 0; + int16_t numTouches = 0; #endif }; diff --git a/redalert/scroll.cpp b/redalert/scroll.cpp index d2638d38..1113b2b0 100644 --- a/redalert/scroll.cpp +++ b/redalert/scroll.cpp @@ -104,8 +104,9 @@ void ScrollClass::AI(KeyNumType& input, int x, int y) int scrollDistance = (7 - Options.ScrollRate) * 20; Scroll_Map((DirType)scrollDirection, scrollDistance, true); } - // scroll only with analog sticks for now - noscroll = true; + // scroll only with analog sticks + if (Keyboard->IsAnalogOnlyScroll()) + noscroll = true; #endif if (!noscroll) { diff --git a/redalert/startup.cpp b/redalert/startup.cpp index 4990fae5..bb3116da 100644 --- a/redalert/startup.cpp +++ b/redalert/startup.cpp @@ -182,6 +182,9 @@ int main(int argc, char* argv[]) #ifdef VITA scePowerSetArmClockFrequency(444); + //scePowerSetGpuClockFrequency(222); + scePowerSetBusClockFrequency(222); + scePowerSetGpuXbarClockFrequency(166); #endif // printf("in program.\n");getch(); diff --git a/tiberiandawn/scroll.cpp b/tiberiandawn/scroll.cpp index f7c2bbaf..4db8f02e 100644 --- a/tiberiandawn/scroll.cpp +++ b/tiberiandawn/scroll.cpp @@ -108,8 +108,9 @@ void ScrollClass::AI(KeyNumType& input, int x, int y) int scrollDistance = (7 - Options.ScrollRate) * 20; Scroll_Map((DirType)scrollDirection, scrollDistance, true); } - // scroll only with analog sticks for now - noscroll = true; + // scroll only with analog sticks + if (Keyboard->IsAnalogOnlyScroll()) + noscroll = true; #endif if (!noscroll) { diff --git a/tiberiandawn/startup.cpp b/tiberiandawn/startup.cpp index ffffc3b2..1566e71d 100644 --- a/tiberiandawn/startup.cpp +++ b/tiberiandawn/startup.cpp @@ -213,6 +213,9 @@ int main(int argc, char** argv) { #ifdef VITA scePowerSetArmClockFrequency(444); + //scePowerSetGpuClockFrequency(222); + scePowerSetBusClockFrequency(222); + scePowerSetGpuXbarClockFrequency(166); #endif CCDebugString("C&C95 - Starting up.\n");