From 642a9cfb792e39d01048ea97c7e2bbe817a8fc6f Mon Sep 17 00:00:00 2001 From: Lorenzooone Date: Sun, 23 Mar 2025 23:27:05 +0100 Subject: [PATCH] Add N3DS XL Loopy 3D Mode --- CMakeLists.txt | 2 +- .../3dscapture_ftd3_shared_general.hpp | 2 + include/Menus/Main3DMenu.hpp | 44 ++++ include/Menus/RelativePositionMenu.hpp | 36 +-- .../SecondScreen3DRelativePositionMenu.hpp | 48 ++++ include/Menus/VideoMenu.hpp | 1 + include/devicecapture.hpp | 4 +- include/display_structs.hpp | 7 +- include/frontend.hpp | 34 ++- .../3dscapture_ftd3_driver_acquisition.cpp | 78 ++++-- .../3dscapture_ftd3_libusb_acquisition.cpp | 30 +++ .../3dscapture_ftd3_shared.cpp | 56 +++-- source/Menus/Main3DMenu.cpp | 233 ++++++++++++++++++ source/Menus/OptionSelectionMenu.cpp | 1 + source/Menus/RelativePositionMenu.cpp | 86 +++++-- .../SecondScreen3DRelativePositionMenu.cpp | 197 +++++++++++++++ source/Menus/StatusMenu.cpp | 2 +- source/Menus/VideoMenu.cpp | 8 + source/WindowScreen.cpp | 204 ++++++++++++--- source/WindowScreen_Menu.cpp | 156 +++++++++++- source/cc3dsfs.cpp | 2 + source/conversions.cpp | 30 +-- source/devicecapture.cpp | 37 ++- source/frontend.cpp | 64 ++++- 24 files changed, 1213 insertions(+), 149 deletions(-) create mode 100644 include/Menus/Main3DMenu.hpp create mode 100644 include/Menus/SecondScreen3DRelativePositionMenu.hpp create mode 100644 source/Menus/Main3DMenu.cpp create mode 100644 source/Menus/SecondScreen3DRelativePositionMenu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 95c0a03..741bc0a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -525,7 +525,7 @@ if(MSVC) else() set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$:-O3>") endif() -add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp source/Menus/InputMenu.cpp source/Menus/AudioDeviceMenu.cpp source/Menus/SeparatorMenu.cpp source/Menus/ColorCorrectionMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES}) +add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp source/Menus/InputMenu.cpp source/Menus/AudioDeviceMenu.cpp source/Menus/SeparatorMenu.cpp source/Menus/ColorCorrectionMenu.cpp source/Menus/Main3DMenu.cpp source/Menus/SecondScreen3DRelativePositionMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES}) if(NOT ("${EXTRA_DEPENDENCIES}" STREQUAL "")) diff --git a/include/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared_general.hpp b/include/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared_general.hpp index 7ffb8b6..d782ad6 100644 --- a/include/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared_general.hpp +++ b/include/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared_general.hpp @@ -5,9 +5,11 @@ #include #include "capture_structs.hpp" +uint64_t ftd3_get_capture_size(bool is_3d_enabled); uint64_t ftd3_get_capture_size(CaptureData* capture_data); std::string ftd3_get_serial(std::string serial_string, int &curr_serial_extra_id); void ftd3_insert_device(std::vector &devices_list, std::string serial_string, int &curr_serial_extra_id, uint32_t usb_speed, bool is_driver); void data_output_update(int inner_index, size_t read_data, CaptureData* capture_data, std::chrono::time_point &base_time); +bool ftd3_capture_3d_setup(CaptureData* capture_data, bool first_pass, bool& stored_3d_status); #endif diff --git a/include/Menus/Main3DMenu.hpp b/include/Menus/Main3DMenu.hpp new file mode 100644 index 0000000..e006d7b --- /dev/null +++ b/include/Menus/Main3DMenu.hpp @@ -0,0 +1,44 @@ +#ifndef __MAIN3DMENU_HPP +#define __MAIN3DMENU_HPP + +#include "OptionSelectionMenu.hpp" +#include + +#include "TextRectangle.hpp" +#include "sfml_gfx_structs.hpp" +#include "display_structs.hpp" +#include "capture_structs.hpp" + +enum Main3DMenuOutAction{ + MAIN_3D_MENU_NO_ACTION, + MAIN_3D_MENU_BACK, + MAIN_3D_MENU_REQUEST_3D_TOGGLE, + MAIN_3D_MENU_INTERLEAVED_TOGGLE, + MAIN_3D_MENU_SQUISH_TOP_TOGGLE, + MAIN_3D_MENU_SQUISH_BOTTOM_TOGGLE, + MAIN_3D_MENU_USB_SPEED_INFO, + MAIN_3D_MENU_DEVICE_INFO, + MAIN_3D_MENU_IMPLEMENTATION_INFO, + MAIN_3D_MENU_SECOND_SCREEN_POSITION_SETTINGS, +}; + +class Main3DMenu : public OptionSelectionMenu { +public: + Main3DMenu(bool font_load_success, sf::Font &text_font); + ~Main3DMenu(); + void prepare(float menu_scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info, DisplayData* display_data, CaptureStatus* status); + void insert_data(ScreenType stype); + Main3DMenuOutAction selected_index = Main3DMenuOutAction::MAIN_3D_MENU_NO_ACTION; + void reset_output_option(); +protected: + bool is_option_selectable(int index, int action); + bool is_option_inc_dec(int index); + void set_output_option(int index, int action); + int get_num_options(); + std::string get_string_option(int index, int action); + void class_setup(); +private: + int *options_indexes; + int num_enabled_options; +}; +#endif diff --git a/include/Menus/RelativePositionMenu.hpp b/include/Menus/RelativePositionMenu.hpp index ca69910..0560c40 100755 --- a/include/Menus/RelativePositionMenu.hpp +++ b/include/Menus/RelativePositionMenu.hpp @@ -18,6 +18,7 @@ enum RelPosMenuOutAction{ class RelativePositionMenu { public: + RelativePositionMenu(); RelativePositionMenu(bool font_load_success, sf::Font &text_font); ~RelativePositionMenu(); bool poll(SFEvent &event_data); @@ -29,7 +30,7 @@ public: void insert_data(); RelPosMenuOutAction selected_index = RelPosMenuOutAction::REL_POS_MENU_NO_ACTION; BottomRelativePosition selected_confirm_value = BOT_REL_POS_END; -private: +protected: struct RelPosMenuData { int option_selected = -1; int menu_width; @@ -39,7 +40,11 @@ private: }; RelPosMenuData future_data; TextRectangle **labels; + bool *selectable_labels; + int num_vertical_slices; + int num_elements_per_screen; + int num_elements_displayed_per_screen; int num_options_per_screen; int elements_start_id; int min_elements_text_scaling_factor; @@ -52,10 +57,23 @@ private: sf::Color menu_color; std::string title; - int num_elements_per_screen; + void initialize(bool font_load_success, sf::Font &text_font); + void prepare_options(); + void base_prepare(float menu_scaling_factor, int view_size_x, int view_size_y); + void prepare_text_slices(int x_multiplier, int x_divisor, int y_multiplier, int y_divisor, int index, float text_scaling_factor, bool center = false); + + virtual bool is_option_selectable(int index); + virtual void set_output_option(int index); + virtual std::string get_string_option(int index); + virtual void class_setup(); + virtual void option_slice_prepare(int i, int index, int num_vertical_slices, float text_scaling_factor); + virtual bool is_option_element(int option); + virtual bool is_option_left(int index); + virtual bool is_option_right(int index); + virtual bool is_option_above(int index); + virtual bool is_option_below(int index); +private: int num_title_back_x_elements; - int num_elements_displayed_per_screen; - int num_vertical_slices; int title_back_x_start_id; int back_x_id; int title_id; @@ -63,26 +81,16 @@ private: std::chrono::time_point last_action_time; const float action_timeout = 0.1; int option_selected = -1; - bool *selectable_labels; RelPosMenuData loaded_data; sf::RectangleShape menu_rectangle = sf::RectangleShape(sf::Vector2f(1, 1)); - - bool is_option_selectable(int index); - void set_output_option(int index); - std::string get_string_option(int index); - void class_setup(); - void prepare_options(); - void base_prepare(float menu_scaling_factor, int view_size_x, int view_size_y); void after_class_setup_connected_values(); - void prepare_text_slices(int x_multiplier, int x_divisor, int y_multiplier, int y_divisor, int index, float text_scaling_factor, bool center = false); bool can_execute_action(); void up_code(bool is_simple); void down_code(bool is_simple); void left_code(); void right_code(); void option_selection_handling(); - bool is_option_element(int option); void set_default_cursor_position(); void decrement_selected_option(bool is_simple); void increment_selected_option(bool is_simple); diff --git a/include/Menus/SecondScreen3DRelativePositionMenu.hpp b/include/Menus/SecondScreen3DRelativePositionMenu.hpp new file mode 100644 index 0000000..8bf3c21 --- /dev/null +++ b/include/Menus/SecondScreen3DRelativePositionMenu.hpp @@ -0,0 +1,48 @@ +#ifndef __SECOND_SCREEN_3D_RELPOSMENU_HPP +#define __SECOND_SCREEN_3D_RELPOSMENU_HPP + +#include +#include + +#include "TextRectangle.hpp" +#include "display_structs.hpp" +#include "event_structs.hpp" +#include "RelativePositionMenu.hpp" + +#define BACK_X_OUTPUT_OPTION -1 + +enum SecondScreen3DRelPosMenuOutAction{ + SECOND_SCREEN_3D_REL_POS_MENU_NO_ACTION, + SECOND_SCREEN_3D_REL_POS_MENU_BACK, + SECOND_SCREEN_3D_REL_POS_MENU_TOGGLE_MATCH, + SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM, +}; + +class SecondScreen3DRelativePositionMenu : public RelativePositionMenu { +public: + SecondScreen3DRelativePositionMenu(bool font_load_success, sf::Font &text_font); + ~SecondScreen3DRelativePositionMenu(); + std::chrono::time_point last_input_processed_time; + void reset_output_option(); + void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo* info); + void insert_data(ScreenType stype); + SecondScreen3DRelPosMenuOutAction selected_index = SecondScreen3DRelPosMenuOutAction::SECOND_SCREEN_3D_REL_POS_MENU_NO_ACTION; + SecondScreen3DRelativePosition selected_confirm_value = SECOND_SCREEN_3D_REL_POS_END; +protected: + bool is_option_selectable(int index); + void set_output_option(int index); + std::string get_string_option(int index); + void class_setup(); + + void option_slice_prepare(int i, int index, int num_vertical_slices, float text_scaling_factor); + bool is_option_element(int option); + bool is_option_left(int index); + bool is_option_right(int index); + bool is_option_above(int index); + bool is_option_below(int index); +private: + std::string setTextOptionBool(int index, bool value); + std::string get_false_option(int index); + int pos_y_subtractor; +}; +#endif diff --git a/include/Menus/VideoMenu.hpp b/include/Menus/VideoMenu.hpp index a5d9042..5ba6a90 100755 --- a/include/Menus/VideoMenu.hpp +++ b/include/Menus/VideoMenu.hpp @@ -41,6 +41,7 @@ enum VideoMenuOutAction{ VIDEO_MENU_CHANGE_TITLEBAR, VIDEO_MENU_VIDEO_EFFECTS_SETTINGS, VIDEO_MENU_SEPARATOR_SETTINGS, + VIDEO_MENU_3D_SETTINGS, }; class VideoMenu : public OptionSelectionMenu { diff --git a/include/devicecapture.hpp b/include/devicecapture.hpp index f0ff295..e798102 100755 --- a/include/devicecapture.hpp +++ b/include/devicecapture.hpp @@ -27,5 +27,7 @@ std::string get_name_of_device(CaptureStatus* capture_status, bool use_long = fa int get_usb_speed_of_device(CaptureStatus* capture_status); bool get_device_can_do_3d(CaptureStatus* capture_status); bool get_device_3d_implemented(CaptureStatus* capture_status); -bool get_3d_enabled(CaptureStatus* capture_status); +bool is_usb_speed_of_device_enough_3d(CaptureStatus* capture_status); +bool get_3d_enabled(CaptureStatus* capture_status, bool skip_requested_3d_check = false); +bool update_3d_enabled(CaptureStatus* capture_status); #endif diff --git a/include/display_structs.hpp b/include/display_structs.hpp index 1fdc99c..e7adf4e 100755 --- a/include/display_structs.hpp +++ b/include/display_structs.hpp @@ -24,8 +24,9 @@ enum ScreenType { TOP, BOTTOM, JOINT }; enum BottomRelativePosition { UNDER_TOP, LEFT_TOP, ABOVE_TOP, RIGHT_TOP, BOT_REL_POS_END }; +enum SecondScreen3DRelativePosition { UNDER_FIRST, LEFT_FIRST, ABOVE_FIRST, RIGHT_FIRST, SECOND_SCREEN_3D_REL_POS_END }; enum NonIntegerScalingModes { SMALLER_PRIORITY, INVERSE_PROPORTIONAL_PRIORITY, EQUAL_PRIORITY, PROPORTIONAL_PRIORITY, BIGGER_PRIORITY, END_NONINT_SCALE_MODES }; -enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE, MAIN_MENU_TYPE, VIDEO_MENU_TYPE, AUDIO_MENU_TYPE, CROP_MENU_TYPE, TOP_PAR_MENU_TYPE, BOTTOM_PAR_MENU_TYPE, ROTATION_MENU_TYPE, OFFSET_MENU_TYPE, BFI_MENU_TYPE, LOAD_MENU_TYPE, SAVE_MENU_TYPE, RESOLUTION_MENU_TYPE, EXTRA_MENU_TYPE, STATUS_MENU_TYPE, LICENSES_MENU_TYPE, RELATIVE_POS_MENU_TYPE, SHORTCUTS_MENU_TYPE, ACTION_SELECTION_MENU_TYPE, SCALING_RATIO_MENU_TYPE, ISN_MENU_TYPE, VIDEO_EFFECTS_MENU_TYPE, INPUT_MENU_TYPE, AUDIO_DEVICE_MENU_TYPE, SEPARATOR_MENU_TYPE, COLOR_CORRECTION_MENU_TYPE }; +enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE, MAIN_MENU_TYPE, VIDEO_MENU_TYPE, AUDIO_MENU_TYPE, CROP_MENU_TYPE, TOP_PAR_MENU_TYPE, BOTTOM_PAR_MENU_TYPE, ROTATION_MENU_TYPE, OFFSET_MENU_TYPE, BFI_MENU_TYPE, LOAD_MENU_TYPE, SAVE_MENU_TYPE, RESOLUTION_MENU_TYPE, EXTRA_MENU_TYPE, STATUS_MENU_TYPE, LICENSES_MENU_TYPE, RELATIVE_POS_MENU_TYPE, SHORTCUTS_MENU_TYPE, ACTION_SELECTION_MENU_TYPE, SCALING_RATIO_MENU_TYPE, ISN_MENU_TYPE, VIDEO_EFFECTS_MENU_TYPE, INPUT_MENU_TYPE, AUDIO_DEVICE_MENU_TYPE, SEPARATOR_MENU_TYPE, COLOR_CORRECTION_MENU_TYPE, MAIN_3D_MENU_TYPE, SECOND_SCREEN_RELATIVE_POS_MENU_TYPE }; enum InputColorspaceMode { FULL_COLORSPACE, DS_COLORSPACE, GBA_COLORSPACE, INPUT_COLORSPACE_END }; enum FrameBlendingMode { NO_FRAME_BLENDING, FULL_FRAME_BLENDING, DS_3D_BOTH_SCREENS_FRAME_BLENDING, FRAME_BLENDING_END }; @@ -44,6 +45,8 @@ struct ScreenInfo { double scaling; bool is_fullscreen; BottomRelativePosition bottom_pos; + SecondScreen3DRelativePosition second_screen_pos; + bool match_bottom_pos_and_second_screen_pos; float subscreen_offset, subscreen_attached_offset, total_offset_x, total_offset_y; int top_rotation, bot_rotation; bool show_mouse; @@ -76,6 +79,8 @@ struct ScreenInfo { InputColorspaceMode in_colorspace_bot; FrameBlendingMode frame_blending_top; FrameBlendingMode frame_blending_bot; + bool squish_3d_top; + bool squish_3d_bot; bool window_enabled; int initial_pos_x; int initial_pos_y; diff --git a/include/frontend.hpp b/include/frontend.hpp index 0abec4c..dff0daa 100755 --- a/include/frontend.hpp +++ b/include/frontend.hpp @@ -36,6 +36,8 @@ #include "AudioDeviceMenu.hpp" #include "SeparatorMenu.hpp" #include "ColorCorrectionMenu.hpp" +#include "Main3DMenu.hpp" +#include "SecondScreen3DRelativePositionMenu.hpp" #include "display_structs.hpp" #include "event_structs.hpp" #include "shaders_list.hpp" @@ -99,16 +101,20 @@ private: bool use_non_int_scaling; int rotation; const PARData *par; + bool divide_3d_par; }; bool created_proper_folder; CaptureStatus* capture_status; std::string win_title; sf::RenderWindow m_win; int m_width, m_height; + int m_width_no_manip, m_height_no_manip; int m_window_width, m_window_height; int m_prepare_load; int m_prepare_save; bool last_connected_status; + bool last_enabled_3d; + bool last_interleaved_3d; bool m_prepare_open; bool m_prepare_quit; bool m_scheduled_split; @@ -160,6 +166,8 @@ private: AudioDeviceMenu *audio_device_menu; SeparatorMenu *separator_menu; ColorCorrectionMenu *color_correction_menu; + Main3DMenu *main_3d_menu; + SecondScreen3DRelativePositionMenu *second_screen_3d_relpos_menu; std::vector possible_crops; std::vector possible_crops_ds; std::vector possible_crops_with_games; @@ -192,8 +200,8 @@ private: volatile bool is_thread_done; bool was_last_frame_null; - sf::RectangleShape m_in_rect_top, m_in_rect_bot; - out_rect_data m_out_rect_top, m_out_rect_bot; + sf::RectangleShape m_in_rect_top, m_in_rect_bot, m_in_rect_top_right; + out_rect_data m_out_rect_top, m_out_rect_bot, m_out_rect_top_right; ScreenType m_stype; const ShaderColorEmulationData* sent_shader_color_data; @@ -237,6 +245,9 @@ private: void fast_poll_change(); void padding_change(); void game_crop_enable_change(); + void request_3d_change(); + void interleaved_3d_change(); + void squish_3d_change(bool is_top); void audio_device_change(audio_output_device_data new_device_data); void is_nitro_capture_type_change(bool positive); void is_nitro_capture_speed_change(bool positive); @@ -264,6 +275,8 @@ private: void separator_windowed_multiplier_change(bool positive); void separator_fullscreen_multiplier_change(bool positive); void color_correction_value_change(int new_color_correction_value); + void second_screen_3d_pos_change(int new_second_screen_3d_pos); + void second_screen_3d_match_bottom_pos_change(); bool query_reset_request(); void reset_held_times(bool force = true); void poll_window(bool do_everything); @@ -278,16 +291,20 @@ private: int _choose_color_emulation_shader(bool is_top); int _choose_shader(PossibleShaderTypes shader_type, bool is_top); int choose_shader(PossibleShaderTypes shader_type, bool is_top); - void apply_shader_to_texture(out_rect_data &rect_data, PossibleShaderTypes shader_type, bool is_top); - bool apply_shaders_to_input(out_rect_data &rect_data, const sf::RectangleShape &final_in_rect, bool is_top); + void apply_shader_to_texture(sf::RectangleShape &rect_data, sf::RenderTexture &tex_data, PossibleShaderTypes shader_type, bool is_top); + bool apply_shaders_to_input(sf::RectangleShape &rect_data, sf::RenderTexture &tex_data, const sf::RectangleShape &final_in_rect, bool is_top); void pre_texture_conversion_processing(); - void post_texture_conversion_processing(out_rect_data &rect_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top, bool is_debug); + void post_texture_conversion_processing(sf::RectangleShape &rect_data, sf::RenderTexture &tex_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top, bool is_debug); void draw_rect_to_window(const sf::RectangleShape &out_rect, bool is_top); void window_bg_processing(); void display_data_to_window(bool actually_draw, bool is_debug = false); void window_render_call(); void set_position_screens(sf::Vector2f &curr_top_screen_size, sf::Vector2f &curr_bot_screen_size, int offset_x, int offset_y, int max_x, int max_y, int separator_size_x, int separator_size_y, bool do_work = true); float get_max_float_screen_multiplier(ResizingScreenData *own_screen, int width_limit, int height_limit, int other_rotation, bool is_two_screens_merged = false); + bool get_divide_3d_par(bool is_top, ScreenInfo* info); + sf::Vector2u get_3d_size_multiplier(ScreenInfo* info); + sf::Vector2u get_desk_mode_3d_multiplied(ScreenInfo* info); + sf::Vector2f get_3d_offset_out_rect(ScreenInfo* info, bool is_second_screen); int prepare_screen_ratio(ResizingScreenData *own_screen, int width_limit, int height_limit, int other_rotation); float get_ratio_compared_other_screen(ResizingScreenData *own_screen, ResizingScreenData* other_screen, float other_scaling); bool can_non_integerly_scale(); @@ -339,6 +356,8 @@ private: void setup_input_menu(bool reset_data = true); void setup_separator_menu(bool reset_data = true); void setup_color_correction_menu(bool reset_data = true); + void setup_main_3d_menu(bool reset_data = true); + void setup_second_screen_3d_relpos_menu(bool reset_data = true); void update_connection(); }; @@ -367,8 +386,9 @@ void reset_screen_info(ScreenInfo &info); bool load_screen_info(std::string key, std::string value, std::string base, ScreenInfo &info); std::string save_screen_info(std::string base, const ScreenInfo &info); const PARData* get_base_par(); -void get_par_size(int &width, int &height, float multiplier_factor, const PARData *correction_factor); -void get_par_size(float &width, float &height, float multiplier_factor, const PARData *correction_factor); +void get_par_size(int &width, int &height, float multiplier_factor, const PARData *correction_factor, bool divide_3d_par); +void get_par_size(float &width, float &height, float multiplier_factor, const PARData *correction_factor, bool divide_3d_par); +SecondScreen3DRelativePosition get_second_screen_pos(ScreenInfo* info, ScreenType stype); void update_output(FrontendData* frontend_data, double frame_time = 0.0, VideoOutputData *out_buf = NULL); void update_connected_3ds_ds(FrontendData* frontend_data, const CaptureDevice &old_cc_device, const CaptureDevice &new_cc_device); void update_connected_specific_settings(FrontendData* frontend_data, const CaptureDevice &cc_device); diff --git a/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_driver_acquisition.cpp b/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_driver_acquisition.cpp index 66d02fc..d9afe69 100644 --- a/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_driver_acquisition.cpp +++ b/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_driver_acquisition.cpp @@ -21,9 +21,44 @@ struct FTD3XXReceivedDataBuffer { ULONG read_buffer; }; +static bool wait_all_fast_capture_call_async_transfers(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data) { + void* handle = ((ftd3_device_device_handlers*)capture_data->handle)->driver_handle; + for(int inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS; ++inner_curr_in) { + FT_STATUS ftStatus = FT_GetOverlappedResult(handle, &received_buffer[inner_curr_in].overlap, &received_buffer[inner_curr_in].read_buffer, true); + if(FT_FAILED(ftStatus)) { + capture_error_print(true, capture_data, "Disconnected: USB error"); + return false; + } + } + return true; +} + +static bool fast_capture_call_init_async_transfers(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data, int fifo_channel, int &inner_curr_in, bool could_use_3d, bool stored_3d_status) { + void* handle = ((ftd3_device_device_handlers*)capture_data->handle)->driver_handle; + for(inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS - 1; ++inner_curr_in) { + CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(inner_curr_in); + uint8_t* buffer = (uint8_t*)&data_buf->capture_buf; + FT_STATUS ftStatus = FT_ASYNC_CALL(handle, fifo_channel, buffer, ftd3_get_capture_size(could_use_3d && stored_3d_status), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap); + if(ftStatus != FT_IO_PENDING) { + capture_error_print(true, capture_data, "Disconnected: Read failed"); + return false; + } + } + + inner_curr_in = FTD3_CONCURRENT_BUFFERS - 1; + return true; +} + static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data, int fifo_channel) { int inner_curr_in = 0; FT_STATUS ftStatus; + + bool could_use_3d = get_3d_enabled(&capture_data->status, true); + bool stored_3d_status = true; + bool result_3d_setup = ftd3_capture_3d_setup(capture_data, true, stored_3d_status); + if(!result_3d_setup) + return; + void* handle = ((ftd3_device_device_handlers*)capture_data->handle)->driver_handle; for (inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS; ++inner_curr_in) { ftStatus = FT_InitializeOverlapped(handle, &received_buffer[inner_curr_in].overlap); @@ -33,24 +68,29 @@ static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, Capture } } - for (inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS - 1; ++inner_curr_in) { - CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(inner_curr_in); - uint8_t* buffer = (uint8_t*)&data_buf->capture_buf; - ftStatus = FT_ASYNC_CALL(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap); - if(ftStatus != FT_IO_PENDING) { - capture_error_print(true, capture_data, "Disconnected: Read failed"); - return; - } - } - - inner_curr_in = FTD3_CONCURRENT_BUFFERS - 1; + if(!fast_capture_call_init_async_transfers(received_buffer, capture_data, fifo_channel, inner_curr_in, could_use_3d, stored_3d_status)) + return; auto clock_start = std::chrono::high_resolution_clock::now(); while (capture_data->status.connected && capture_data->status.running) { + if(could_use_3d && (stored_3d_status != capture_data->status.requested_3d)) { + if(!wait_all_fast_capture_call_async_transfers(received_buffer, capture_data)) + return; + + result_3d_setup = ftd3_capture_3d_setup(capture_data, false, stored_3d_status); + if(!result_3d_setup) + return; + + if(!fast_capture_call_init_async_transfers(received_buffer, capture_data, fifo_channel, inner_curr_in, could_use_3d, stored_3d_status)) + return; + + clock_start = std::chrono::high_resolution_clock::now(); + } + CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(inner_curr_in); uint8_t* buffer = (uint8_t*)&data_buf->capture_buf; - ftStatus = FT_ASYNC_CALL(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap); + ftStatus = FT_ASYNC_CALL(handle, fifo_channel, buffer, ftd3_get_capture_size(could_use_3d && stored_3d_status), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap); if(ftStatus != FT_IO_PENDING) { capture_error_print(true, capture_data, "Disconnected: Read failed"); return; @@ -71,15 +111,25 @@ static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, Capture static bool safe_capture_call(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data, int fifo_channel) { auto clock_start = std::chrono::high_resolution_clock::now(); void* handle = ((ftd3_device_device_handlers*)capture_data->handle)->driver_handle; + bool could_use_3d = get_3d_enabled(&capture_data->status, true); + bool stored_3d_status = true; + bool result_3d_setup = ftd3_capture_3d_setup(capture_data, true, stored_3d_status); + if(!result_3d_setup) + return true; while(capture_data->status.connected && capture_data->status.running) { + if(could_use_3d && (stored_3d_status != capture_data->status.requested_3d)) { + result_3d_setup = ftd3_capture_3d_setup(capture_data, false, stored_3d_status); + if(!result_3d_setup) + return true; + } CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(0); uint8_t* buffer = (uint8_t*)&data_buf->capture_buf; #ifdef _WIN32 - FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, NULL); + FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, buffer, ftd3_get_capture_size(could_use_3d && stored_3d_status), &received_buffer->read_buffer, NULL); #else - FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, buffer, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, 1000); + FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, buffer, ftd3_get_capture_size(could_use_3d && stored_3d_status), &received_buffer->read_buffer, 1000); #endif if(FT_FAILED(ftStatus)) { capture_error_print(true, capture_data, "Disconnected: Read failed"); diff --git a/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_libusb_acquisition.cpp b/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_libusb_acquisition.cpp index 08b4d20..b258018 100644 --- a/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_libusb_acquisition.cpp +++ b/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_libusb_acquisition.cpp @@ -22,6 +22,7 @@ struct FTD3LibusbCaptureReceivedData { bool in_use; + bool* pause_output; uint32_t index; int internal_index; CaptureData* capture_data; @@ -105,6 +106,9 @@ static void ftd3_libusb_read_frame_cb(void* user_data, int transfer_length, int } *ftd3_libusb_capture_recv_data->last_index = ftd3_libusb_capture_recv_data->index; + if(*ftd3_libusb_capture_recv_data->pause_output) + return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true); + data_output_update(ftd3_libusb_capture_recv_data->internal_index, transfer_length, ftd3_libusb_capture_recv_data->capture_data, *ftd3_libusb_capture_recv_data->clock_start); end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, false); } @@ -193,10 +197,34 @@ static void ftd3_libusb_capture_main_loop_processing(FTD3LibusbCaptureReceivedDa int index = 0; CaptureData* capture_data = ftd3_libusb_capture_recv_data[0].capture_data; + bool could_use_3d = get_3d_enabled(&capture_data->status, true); + bool stored_3d_status = true; + bool result_3d_setup = ftd3_capture_3d_setup(capture_data, true, stored_3d_status); + if(!result_3d_setup) + return; + for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) ftd3_libusb_read_frame_request(capture_data, ftd3_libusb_get_free_buffer(ftd3_libusb_capture_recv_data), index++, pipe); while(capture_data->status.connected && capture_data->status.running) { + if(could_use_3d && (stored_3d_status != capture_data->status.requested_3d)) { + *ftd3_libusb_capture_recv_data->pause_output = true; + wait_all_ftd3_libusb_buffers_free(ftd3_libusb_capture_recv_data); + if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0) { + capture_error_print(true, capture_data, "Disconnected: Read failed"); + return; + } + + result_3d_setup = ftd3_capture_3d_setup(capture_data, false, stored_3d_status); + if(!result_3d_setup) + return; + + *ftd3_libusb_capture_recv_data->pause_output = false; + for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) + ftd3_libusb_read_frame_request(capture_data, ftd3_libusb_get_free_buffer(ftd3_libusb_capture_recv_data), index++, pipe); + + *ftd3_libusb_capture_recv_data[0].clock_start = std::chrono::high_resolution_clock::now(); + } if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0) { capture_error_print(true, capture_data, "Disconnected: Read failed"); return; @@ -214,12 +242,14 @@ void ftd3_libusb_capture_main_loop(CaptureData* capture_data, int pipe) { uint32_t last_index = -1; int status = 0; + bool pause_output = false; SharedConsumerMutex is_buffer_free_shared_mutex(FTD3_CONCURRENT_BUFFERS); std::chrono::time_point clock_start = std::chrono::high_resolution_clock::now(); FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data = new FTD3LibusbCaptureReceivedData[FTD3_CONCURRENT_BUFFERS]; for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) { ftd3_libusb_capture_recv_data[i].in_use = false; ftd3_libusb_capture_recv_data[i].index = i; + ftd3_libusb_capture_recv_data[i].pause_output = &pause_output; ftd3_libusb_capture_recv_data[i].internal_index = i; ftd3_libusb_capture_recv_data[i].capture_data = capture_data; ftd3_libusb_capture_recv_data[i].last_index = &last_index; diff --git a/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared.cpp b/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared.cpp index b143bb5..a3f2958 100644 --- a/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared.cpp +++ b/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_shared.cpp @@ -54,14 +54,14 @@ uint64_t ftd3_get_video_in_size(CaptureData* capture_data) { return sizeof(RGB83DSVideoInputData_3D); } -static uint64_t ftd3_get_capture_size(CaptureStatus* capture_status) { - if(!get_3d_enabled(capture_status)) +uint64_t ftd3_get_capture_size(bool is_3d_enabled) { + if(!is_3d_enabled) return sizeof(FTD3_3DSCaptureReceived) & (~(EXTRA_DATA_BUFFER_FTD3XX_SIZE - 1)); return sizeof(FTD3_3DSCaptureReceived_3D) & (~(EXTRA_DATA_BUFFER_FTD3XX_SIZE - 1)); } uint64_t ftd3_get_capture_size(CaptureData* capture_data) { - return ftd3_get_capture_size(&capture_data->status); + return ftd3_get_capture_size(get_3d_enabled(&capture_data->status)); } static void preemptive_close_connection(CaptureData* capture_data) { @@ -180,8 +180,6 @@ bool connect_ftd3(bool print_failed, CaptureData* capture_data, CaptureDevice* d capture_error_print(print_failed, capture_data, "Second Create failed"); return false; } - - ftd3_device_device_handlers* handlers = (ftd3_device_device_handlers*)capture_data->handle; if(!reset_3ds_state(print_failed, capture_data)) return false; @@ -201,19 +199,47 @@ bool connect_ftd3(bool print_failed, CaptureData* capture_data, CaptureDevice* d if(!read_3ds_config_3d(print_failed, capture_data, device)) return false; - CaptureStatus tmp_status; - tmp_status.device = *device; - tmp_status.connected = true; - tmp_status.requested_3d = capture_data->status.requested_3d; - if(!get_3d_enabled(&tmp_status)) { - if(!set_3ds_state(print_failed, capture_data, 0x42)) - return false; + return true; +} +bool ftd3_capture_3d_setup(CaptureData* capture_data, bool first_pass, bool& stored_3d_status) { + CaptureStatus tmp_status; + tmp_status.device = capture_data->status.device; + tmp_status.connected = capture_data->status.connected; + tmp_status.requested_3d = capture_data->status.requested_3d; + + if(first_pass) + stored_3d_status = true; + + if((!first_pass) && ((stored_3d_status == tmp_status.requested_3d) || (!get_3d_enabled(&tmp_status, true)))) { + stored_3d_status = tmp_status.requested_3d; + return true; + } + + ftd3_device_device_handlers* handlers = (ftd3_device_device_handlers*)capture_data->handle; + bool print_failed = true; + + if(!first_pass) { + if(ftd3_is_error_compat(handlers, ftd3_abort_pipe_compat(handlers, BULK_IN))) { + capture_error_print(print_failed, capture_data, "Abort failed"); + preemptive_close_connection(capture_data); + return false; + } + } + + bool _3d_enabled_result = get_3d_enabled(&tmp_status); + bool update_state = stored_3d_status != _3d_enabled_result; + if(update_state) { + int state_to_set = 0x42; + if(_3d_enabled_result) + state_to_set = 0x43; + if(!set_3ds_state(print_failed, capture_data, state_to_set)) + return false; if(!set_3ds_state(print_failed, capture_data, 0x40)) return false; } - if(ftd3_is_error_compat(handlers, ftd3_set_stream_pipe_compat(handlers, BULK_IN, ftd3_get_capture_size(&tmp_status)))) { + if(ftd3_is_error_compat(handlers, ftd3_set_stream_pipe_compat(handlers, BULK_IN, ftd3_get_capture_size(_3d_enabled_result)))) { capture_error_print(print_failed, capture_data, "Stream failed"); preemptive_close_connection(capture_data); return false; @@ -226,16 +252,18 @@ bool connect_ftd3(bool print_failed, CaptureData* capture_data, CaptureDevice* d return false; } - if(ftd3_is_error_compat(handlers, ftd3_set_stream_pipe_compat(handlers, BULK_IN, ftd3_get_capture_size(&tmp_status)))) { + if(ftd3_is_error_compat(handlers, ftd3_set_stream_pipe_compat(handlers, BULK_IN, ftd3_get_capture_size(_3d_enabled_result)))) { capture_error_print(print_failed, capture_data, "Stream failed"); preemptive_close_connection(capture_data); return false; } } + stored_3d_status = tmp_status.requested_3d; return true; } void ftd3_capture_main_loop(CaptureData* capture_data) { + bool could_have_3d = get_3d_enabled(&capture_data->status, true); ftd3_main_loop_compat(capture_data, BULK_IN); } diff --git a/source/Menus/Main3DMenu.cpp b/source/Menus/Main3DMenu.cpp new file mode 100644 index 0000000..36f382d --- /dev/null +++ b/source/Menus/Main3DMenu.cpp @@ -0,0 +1,233 @@ +#include "Main3DMenu.hpp" +#include "devicecapture.hpp" + +#define NUM_TOTAL_MENU_OPTIONS (sizeof(pollable_options)/sizeof(pollable_options[0])) + +struct Main3DMenuOptionInfo { + const std::string base_name; + const std::string false_name; + const bool is_selectable; + const bool is_inc; + const std::string dec_str; + const std::string inc_str; + const Main3DMenuOutAction inc_out_action; + const Main3DMenuOutAction out_action; + const bool selectable_joint; + const bool selectable_top; + const bool selectable_bottom; +}; + +static const Main3DMenuOptionInfo main_3d_menu_device_option = { +.base_name = "", .false_name = "", .is_selectable = false, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = MAIN_3D_MENU_NO_ACTION, +.out_action = MAIN_3D_MENU_DEVICE_INFO, +.selectable_joint = true, .selectable_top = true, .selectable_bottom = true}; + +static const Main3DMenuOptionInfo main_3d_menu_usb_speed_option = { +.base_name = "", .false_name = "", .is_selectable = false, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = MAIN_3D_MENU_NO_ACTION, +.out_action = MAIN_3D_MENU_USB_SPEED_INFO, +.selectable_joint = true, .selectable_top = true, .selectable_bottom = true}; + +static const Main3DMenuOptionInfo main_3d_menu_implemented_option = { +.base_name = "", .false_name = "", .is_selectable = false, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = MAIN_3D_MENU_NO_ACTION, +.out_action = MAIN_3D_MENU_IMPLEMENTATION_INFO, +.selectable_joint = true, .selectable_top = true, .selectable_bottom = true}; + +static const Main3DMenuOptionInfo main_3d_menu_request_3d_option = { +.base_name = "Preference: 3D", .false_name = "Preference: 2D", .is_selectable = true, +.is_inc = true, .dec_str = "<", .inc_str = ">", .inc_out_action = MAIN_3D_MENU_REQUEST_3D_TOGGLE, +.out_action = MAIN_3D_MENU_REQUEST_3D_TOGGLE, +.selectable_joint = true, .selectable_top = true, .selectable_bottom = true}; + +static const Main3DMenuOptionInfo main_3d_menu_3d_interleaved_option = { +.base_name = "3D Style: Interleaved", .false_name = "3D Style: Separate", .is_selectable = true, +.is_inc = true, .dec_str = "<", .inc_str = ">", .inc_out_action = MAIN_3D_MENU_INTERLEAVED_TOGGLE, +.out_action = MAIN_3D_MENU_INTERLEAVED_TOGGLE, +.selectable_joint = true, .selectable_top = true, .selectable_bottom = true}; + +static const Main3DMenuOptionInfo main_3d_menu_squish_top_option = { +.base_name = "Stretch Top Screen", .false_name = "Squish Top Screen", .is_selectable = true, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = MAIN_3D_MENU_NO_ACTION, +.out_action = MAIN_3D_MENU_SQUISH_TOP_TOGGLE, +.selectable_joint = true, .selectable_top = false, .selectable_bottom = false}; + +static const Main3DMenuOptionInfo main_3d_menu_squish_bottom_option = { +.base_name = "Stretch Bottom Screen", .false_name = "Squish Bottom Screen", .is_selectable = true, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = MAIN_3D_MENU_NO_ACTION, +.out_action = MAIN_3D_MENU_SQUISH_BOTTOM_TOGGLE, +.selectable_joint = true, .selectable_top = false, .selectable_bottom = false}; + +static const Main3DMenuOptionInfo main_3d_menu_squish_mono_option = { +.base_name = "Stretch Screen", .false_name = "Squish Screen", .is_selectable = true, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = MAIN_3D_MENU_NO_ACTION, +.out_action = MAIN_3D_MENU_SQUISH_TOP_TOGGLE, +.selectable_joint = false, .selectable_top = true, .selectable_bottom = false}; + +static const Main3DMenuOptionInfo main_3d_menu_second_screen_position_settings_option = { +.base_name = "3D Screen Placement", .false_name = "", .is_selectable = true, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = MAIN_3D_MENU_NO_ACTION, +.out_action = MAIN_3D_MENU_SECOND_SCREEN_POSITION_SETTINGS, +.selectable_joint = true, .selectable_top = true, .selectable_bottom = false}; + +static const Main3DMenuOptionInfo* pollable_options[] = { +&main_3d_menu_device_option, +&main_3d_menu_usb_speed_option, +&main_3d_menu_implemented_option, +&main_3d_menu_request_3d_option, +&main_3d_menu_3d_interleaved_option, +&main_3d_menu_squish_top_option, +&main_3d_menu_squish_bottom_option, +&main_3d_menu_squish_mono_option, +&main_3d_menu_second_screen_position_settings_option, +}; + +Main3DMenu::Main3DMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ + this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; + this->initialize(font_load_success, text_font); + this->num_enabled_options = 0; +} + +Main3DMenu::~Main3DMenu() { + delete []this->options_indexes; +} + +void Main3DMenu::class_setup() { + this->num_options_per_screen = 5; + this->min_elements_text_scaling_factor = num_options_per_screen + 2; + this->width_factor_menu = 16; + this->width_divisor_menu = 9; + this->base_height_factor_menu = 12; + this->base_height_divisor_menu = 6; + this->min_text_size = 0.3; + this->max_width_slack = 1.1; + this->menu_color = sf::Color(30, 30, 60, 192); + this->title = "3D Settings"; + this->show_back_x = true; + this->show_x = false; + this->show_title = true; +} + +void Main3DMenu::insert_data(ScreenType stype) { + this->num_enabled_options = 0; + for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) { + if((stype == ScreenType::BOTTOM) && (!pollable_options[i]->selectable_bottom)) + continue; + if((stype == ScreenType::TOP) && (!pollable_options[i]->selectable_top)) + continue; + if((stype == ScreenType::JOINT) && (!pollable_options[i]->selectable_joint)) + continue; + this->options_indexes[this->num_enabled_options] = i; + this->num_enabled_options++; + } + this->prepare_options(); +} + +void Main3DMenu::reset_output_option() { + this->selected_index = Main3DMenuOutAction::MAIN_3D_MENU_NO_ACTION; +} + +void Main3DMenu::set_output_option(int index, int action) { + if(index == BACK_X_OUTPUT_OPTION) + this->selected_index = MAIN_3D_MENU_BACK; + else if((action == INC_ACTION) && this->is_option_inc_dec(index)) + this->selected_index = pollable_options[this->options_indexes[index]]->inc_out_action; + else + this->selected_index = pollable_options[this->options_indexes[index]]->out_action; +} + +int Main3DMenu::get_num_options() { + return this->num_enabled_options; +} + +std::string Main3DMenu::get_string_option(int index, int action) { + if((action == INC_ACTION) && this->is_option_inc_dec(index)) + return pollable_options[this->options_indexes[index]]->inc_str; + if((action == DEC_ACTION) && this->is_option_inc_dec(index)) + return pollable_options[this->options_indexes[index]]->dec_str; + if(action == FALSE_ACTION) + return pollable_options[this->options_indexes[index]]->false_name; + return pollable_options[this->options_indexes[index]]->base_name; +} + +bool Main3DMenu::is_option_selectable(int index, int action) { + return pollable_options[this->options_indexes[index]]->is_selectable; +} + +bool Main3DMenu::is_option_inc_dec(int index) { + return pollable_options[this->options_indexes[index]]->is_inc; +} + +static std::string get_device_connected_firmware_info(bool is_device_connected, bool is_device_3ds, bool is_firmware_3d) { + if(!is_device_connected) + return "No device connected"; + if(!is_device_3ds) + return "No 3DS connected"; + if(!is_firmware_3d) + return "FW: No 3D"; + return "FW: 3D"; +} + +static std::string get_usb_speed_3d_info(bool is_device_3ds, bool is_usb_speed_enough, int speed_device_connected) { + if(!is_device_3ds) + return ""; + if(!is_usb_speed_enough) + return "USB " + std::to_string(speed_device_connected) + ": Slow"; + return "USB " + std::to_string(speed_device_connected) + ": Ok"; +} + +static std::string get_implementation_info(bool is_device_3ds, bool is_implemented_3d) { + if(!is_device_3ds) + return ""; + if(!is_implemented_3d) + return "3D not implemented"; + return "3D implemented"; +} + +void Main3DMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info, DisplayData* display_data, CaptureStatus* status) { + int num_pages = this->get_num_pages(); + if(this->future_data.page >= num_pages) + this->future_data.page = num_pages - 1; + int start = this->future_data.page * this->num_options_per_screen; + bool is_device_connected = status->connected; + bool is_device_3ds = is_device_connected && status->device.is_3ds; + int speed_device_connected = get_usb_speed_of_device(status); + bool is_usb_speed_enough = is_device_3ds && is_usb_speed_of_device_enough_3d(status); + bool is_implemented_3d = is_device_3ds && get_device_3d_implemented(status); + bool is_firmware_3d = is_device_3ds && get_device_can_do_3d(status); + for(int i = 0; i < this->num_options_per_screen + 1; i++) { + int index = (i * this->single_option_multiplier) + this->elements_start_id; + if(!this->future_enabled_labels[index]) + continue; + int real_index = start + i; + int option_index = this->options_indexes[real_index]; + switch(pollable_options[option_index]->out_action) { + case MAIN_3D_MENU_DEVICE_INFO: + this->labels[index]->setText(get_device_connected_firmware_info(is_device_connected, is_device_3ds, is_firmware_3d)); + break; + case MAIN_3D_MENU_USB_SPEED_INFO: + this->labels[index]->setText(get_usb_speed_3d_info(is_device_3ds, is_usb_speed_enough, speed_device_connected)); + break; + case MAIN_3D_MENU_IMPLEMENTATION_INFO: + this->labels[index]->setText(get_implementation_info(is_device_3ds, is_implemented_3d)); + break; + case MAIN_3D_MENU_REQUEST_3D_TOGGLE: + this->labels[index]->setText(this->setTextOptionBool(real_index, status->requested_3d)); + break; + case MAIN_3D_MENU_INTERLEAVED_TOGGLE: + this->labels[index]->setText(this->setTextOptionBool(real_index, display_data->interleaved_3d)); + break; + case MAIN_3D_MENU_SQUISH_TOP_TOGGLE: + this->labels[index]->setText(this->setTextOptionBool(real_index, info->squish_3d_top)); + break; + case MAIN_3D_MENU_SQUISH_BOTTOM_TOGGLE: + this->labels[index]->setText(this->setTextOptionBool(real_index, info->squish_3d_bot)); + break; + default: + break; + } + } + + this->base_prepare(menu_scaling_factor, view_size_x, view_size_y); +} diff --git a/source/Menus/OptionSelectionMenu.cpp b/source/Menus/OptionSelectionMenu.cpp index e0dd483..5c36a8e 100755 --- a/source/Menus/OptionSelectionMenu.cpp +++ b/source/Menus/OptionSelectionMenu.cpp @@ -226,6 +226,7 @@ std::string OptionSelectionMenu::setTextOptionBool(int index, bool value) { return this->get_string_option(index, DEFAULT_ACTION); return this->get_string_option(index, FALSE_ACTION); } + std::string OptionSelectionMenu::setTextOptionFloat(int index, float value, int num_decimals) { std::string out = this->get_string_option(index, DEFAULT_ACTION) + ": " + get_float_str_decimals(value, num_decimals); return out; diff --git a/source/Menus/RelativePositionMenu.cpp b/source/Menus/RelativePositionMenu.cpp index fec56fe..25be698 100755 --- a/source/Menus/RelativePositionMenu.cpp +++ b/source/Menus/RelativePositionMenu.cpp @@ -9,43 +9,50 @@ struct RelativePositionMenuOptionInfo { const int position_x, position_y, multiplier_y; float text_factor_multiplier; const BottomRelativePosition out_action; + const int divisor_x; }; static const RelativePositionMenuOptionInfo above_option = { .base_name = "Above", .is_selectable = true, .position_x = 1, .position_y = 0, .multiplier_y = 1, .text_factor_multiplier = 1.0, -.out_action = UNDER_TOP}; +.out_action = UNDER_TOP, +.divisor_x = 3}; static const RelativePositionMenuOptionInfo left_option = { .base_name = "Left", .is_selectable = true, .position_x = 0, .position_y = 1, .multiplier_y = 1, .text_factor_multiplier = 1.0, -.out_action = RIGHT_TOP}; +.out_action = RIGHT_TOP, +.divisor_x = 3}; static const RelativePositionMenuOptionInfo right_option = { .base_name = "Right", .is_selectable = true, .position_x = 2, .position_y = 1, .multiplier_y = 1, .text_factor_multiplier = 1.0, -.out_action = LEFT_TOP}; +.out_action = LEFT_TOP, +.divisor_x = 3}; static const RelativePositionMenuOptionInfo below_option = { .base_name = "Below", .is_selectable = true, .position_x = 1, .position_y = 2, .multiplier_y = 1, .text_factor_multiplier = 1.0, -.out_action = ABOVE_TOP}; +.out_action = ABOVE_TOP, +.divisor_x = 3}; static const RelativePositionMenuOptionInfo desc_option = { .base_name = "Top Screen", .is_selectable = false, .position_x = 1, .position_y = 2, .multiplier_y = 2, .text_factor_multiplier = 0.95, -.out_action = BOT_REL_POS_END}; +.out_action = BOT_REL_POS_END, +.divisor_x = 3}; static const RelativePositionMenuOptionInfo desc2_option = { .base_name = "Position", .is_selectable = false, .position_x = 1, .position_y = 3, .multiplier_y = 2, .text_factor_multiplier = 0.95, -.out_action = BOT_REL_POS_END}; +.out_action = BOT_REL_POS_END, +.divisor_x = 3}; static const RelativePositionMenuOptionInfo* pollable_options[] = { &above_option, @@ -56,7 +63,21 @@ static const RelativePositionMenuOptionInfo* pollable_options[] = { &desc2_option, }; +RelativePositionMenu::RelativePositionMenu() { +} + RelativePositionMenu::RelativePositionMenu(bool font_load_success, sf::Font &text_font) { + this->initialize(font_load_success, text_font); +} + +RelativePositionMenu::~RelativePositionMenu() { + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) + delete this->labels[i]; + delete []this->labels; + delete []this->selectable_labels; +} + +void RelativePositionMenu::initialize(bool font_load_success, sf::Font &text_font) { this->class_setup(); this->after_class_setup_connected_values(); this->menu_rectangle.setFillColor(this->menu_color); @@ -80,16 +101,10 @@ RelativePositionMenu::RelativePositionMenu(bool font_load_success, sf::Font &tex this->selectable_labels[this->title_id] = false; } -RelativePositionMenu::~RelativePositionMenu() { - for(int i = 0; i < this->num_elements_displayed_per_screen; i++) - delete this->labels[i]; - delete []this->labels; - delete []this->selectable_labels; -} - void RelativePositionMenu::class_setup() { this->num_options_per_screen = NUM_TOTAL_MENU_OPTIONS; this->min_elements_text_scaling_factor = 4; + this->num_vertical_slices = 4; this->width_factor_menu = 16; this->width_divisor_menu = 9; this->base_height_factor_menu = 12; @@ -104,7 +119,6 @@ void RelativePositionMenu::after_class_setup_connected_values() { this->num_title_back_x_elements = 2; this->num_elements_per_screen = this->num_options_per_screen; this->num_elements_displayed_per_screen = num_title_back_x_elements + num_elements_per_screen; - this->num_vertical_slices = 4; this->title_back_x_start_id = 0; this->elements_start_id = num_title_back_x_elements + title_back_x_start_id; this->back_x_id = title_back_x_start_id + 1; @@ -145,6 +159,22 @@ void RelativePositionMenu::set_default_cursor_position() { } } +bool RelativePositionMenu::is_option_left(int index) { + return pollable_options[index]->out_action == LEFT_TOP; +} + +bool RelativePositionMenu::is_option_right(int index) { + return pollable_options[index]->out_action == RIGHT_TOP; +} + +bool RelativePositionMenu::is_option_above(int index) { + return pollable_options[index]->out_action == ABOVE_TOP; +} + +bool RelativePositionMenu::is_option_below(int index) { + return pollable_options[index]->out_action == UNDER_TOP; +} + void RelativePositionMenu::decrement_selected_option(bool is_simple) { if(this->future_data.option_selected < 0) { this->set_default_cursor_position(); @@ -152,7 +182,7 @@ void RelativePositionMenu::decrement_selected_option(bool is_simple) { } int elem_index = this->future_data.option_selected - this->elements_start_id; if(!is_simple) { - if(this->is_option_element(this->future_data.option_selected) && ((pollable_options[elem_index]->out_action == LEFT_TOP) || (pollable_options[elem_index]->out_action == ABOVE_TOP))) + if(this->is_option_element(this->future_data.option_selected) && (this->is_option_left(elem_index) || this->is_option_above(elem_index))) this->future_data.option_selected -= 1; } do { @@ -169,7 +199,7 @@ void RelativePositionMenu::increment_selected_option(bool is_simple) { } int elem_index = this->future_data.option_selected - this->elements_start_id; if(!is_simple) { - if(this->is_option_element(this->future_data.option_selected) && (pollable_options[elem_index]->out_action == RIGHT_TOP)) + if(this->is_option_element(this->future_data.option_selected) && this->is_option_right(elem_index)) this->future_data.option_selected += 1; } do { @@ -208,7 +238,7 @@ void RelativePositionMenu::prepare_options() { this->labels[this->back_x_id]->setShowText(true); this->labels[this->title_id]->setText(this->title); this->labels[this->title_id]->setShowText(true); - for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) { + for(int i = 0; i < this->num_options_per_screen; i++) { int label_start_index = i + this->elements_start_id; this->labels[label_start_index]->setText(this->get_string_option(i)); this->selectable_labels[label_start_index] = this->is_option_selectable(i); @@ -254,12 +284,12 @@ void RelativePositionMenu::down_code(bool is_simple) { void RelativePositionMenu::left_code() { if(!this->can_execute_action()) return; - if(this->is_option_element(this->future_data.option_selected) && (pollable_options[this->future_data.option_selected - this->elements_start_id]->out_action == RIGHT_TOP)) + if(this->is_option_element(this->future_data.option_selected) && this->is_option_right(this->future_data.option_selected - this->elements_start_id)) this->option_selection_handling(); else { this->future_data.option_selected -= 1; - for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) { - if(pollable_options[i]->out_action == RIGHT_TOP) { + for(int i = 0; i < this->num_options_per_screen; i++) { + if(this->is_option_right(i)) { this->future_data.option_selected = i + this->elements_start_id; break; } @@ -272,12 +302,12 @@ void RelativePositionMenu::right_code() { if(!this->can_execute_action()) return; int elem_index = this->future_data.option_selected - this->elements_start_id; - if(this->is_option_element(this->future_data.option_selected) && (pollable_options[this->future_data.option_selected - this->elements_start_id]->out_action == LEFT_TOP)) + if(this->is_option_element(this->future_data.option_selected) && this->is_option_left(this->future_data.option_selected - this->elements_start_id)) this->option_selection_handling(); else { this->future_data.option_selected -= 1; - for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) { - if(pollable_options[i]->out_action == LEFT_TOP) { + for(int i = 0; i < this->num_options_per_screen; i++) { + if(this->is_option_left(i)) { this->future_data.option_selected = i + this->elements_start_id; break; } @@ -427,7 +457,7 @@ void RelativePositionMenu::prepare_text_slices(int x_multiplier, int x_divisor, } void RelativePositionMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, BottomRelativePosition curr_bottom_pos) { - for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) { + for(int i = 0; i < this->num_options_per_screen; i++) { int index = i + this->elements_start_id; switch(pollable_options[i]->out_action) { case BOT_REL_POS_END: @@ -444,6 +474,10 @@ void RelativePositionMenu::prepare(float menu_scaling_factor, int view_size_x, i this->base_prepare(menu_scaling_factor, view_size_x, view_size_y); } +void RelativePositionMenu::option_slice_prepare(int i, int index, int num_vertical_slices, float text_scaling_factor) { + this->prepare_text_slices(pollable_options[i]->position_x, pollable_options[i]->divisor_x, pollable_options[i]->position_y + (1 * pollable_options[i]->multiplier_y), num_vertical_slices * pollable_options[i]->multiplier_y, index, text_scaling_factor * pollable_options[i]->text_factor_multiplier); +} + void RelativePositionMenu::base_prepare(float menu_scaling_factor, int view_size_x, int view_size_y) { const float base_height = (7 * BASE_PIXEL_FONT_HEIGHT * 11) / 9; int max_width = (view_size_x * 9) / 10; @@ -477,9 +511,9 @@ void RelativePositionMenu::base_prepare(float menu_scaling_factor, int view_size int top_divisor = 6; this->prepare_text_slices(0, 6, 0, this->num_vertical_slices, this->back_x_id, text_scaling_factor); this->prepare_text_slices(0, 1, 0, this->num_vertical_slices, this->title_id, text_scaling_factor); - for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) { + for(int i = 0; i < this->num_options_per_screen; i++) { int index = i + this->elements_start_id; - this->prepare_text_slices(pollable_options[i]->position_x, 3, pollable_options[i]->position_y + (1 * pollable_options[i]->multiplier_y), this->num_vertical_slices * pollable_options[i]->multiplier_y, index, text_scaling_factor * pollable_options[i]->text_factor_multiplier); + this->option_slice_prepare(i, index, this->num_vertical_slices, text_scaling_factor); } this->loaded_data = this->future_data; } diff --git a/source/Menus/SecondScreen3DRelativePositionMenu.cpp b/source/Menus/SecondScreen3DRelativePositionMenu.cpp new file mode 100644 index 0000000..307f47c --- /dev/null +++ b/source/Menus/SecondScreen3DRelativePositionMenu.cpp @@ -0,0 +1,197 @@ +#include "SecondScreen3DRelativePositionMenu.hpp" +#include "utils.hpp" + +#define NUM_TOTAL_MENU_OPTIONS (sizeof(pollable_options)/sizeof(pollable_options[0])) + +struct SecondScreen3DRelativePositionMenuOptionInfo { + const std::string base_name; + const std::string false_name; + const bool is_selectable; + const int position_x, position_y, multiplier_y; + float text_factor_multiplier; + const SecondScreen3DRelPosMenuOutAction out_action; + const SecondScreen3DRelativePosition out_position; + int divisor_x; +}; + +static const SecondScreen3DRelativePositionMenuOptionInfo above_option = { +.base_name = "Above", .false_name = "", +.is_selectable = true, +.position_x = 1, .position_y = 1, .multiplier_y = 1, +.text_factor_multiplier = 1.0, +.out_action = SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM, +.out_position = ABOVE_FIRST, +.divisor_x = 3}; + +static const SecondScreen3DRelativePositionMenuOptionInfo left_option = { +.base_name = "Left", .false_name = "", +.is_selectable = true, +.position_x = 0, .position_y = 2, .multiplier_y = 1, +.text_factor_multiplier = 1.0, +.out_action = SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM, +.out_position = LEFT_FIRST, +.divisor_x = 3}; + +static const SecondScreen3DRelativePositionMenuOptionInfo right_option = { +.base_name = "Right", .false_name = "", +.is_selectable = true, +.position_x = 2, .position_y = 2, .multiplier_y = 1, +.text_factor_multiplier = 1.0, +.out_action = SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM, +.out_position = RIGHT_FIRST, +.divisor_x = 3}; + +static const SecondScreen3DRelativePositionMenuOptionInfo below_option = { +.base_name = "Below", .false_name = "", +.is_selectable = true, +.position_x = 1, .position_y = 3, .multiplier_y = 1, +.text_factor_multiplier = 1.0, +.out_action = SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM, +.out_position = UNDER_FIRST, +.divisor_x = 3}; + +static const SecondScreen3DRelativePositionMenuOptionInfo desc_option = { +.base_name = "3D Screen", .false_name = "", +.is_selectable = false, +.position_x = 1, .position_y = 4, .multiplier_y = 2, +.text_factor_multiplier = 0.95, +.out_action = SECOND_SCREEN_3D_REL_POS_MENU_NO_ACTION, +.out_position = SECOND_SCREEN_3D_REL_POS_END, +.divisor_x = 3}; + +static const SecondScreen3DRelativePositionMenuOptionInfo desc2_option = { +.base_name = "Position", .false_name = "", +.is_selectable = false, +.position_x = 1, .position_y = 5, .multiplier_y = 2, +.text_factor_multiplier = 0.95, +.out_action = SECOND_SCREEN_3D_REL_POS_MENU_NO_ACTION, +.out_position = SECOND_SCREEN_3D_REL_POS_END, +.divisor_x = 3}; + +static const SecondScreen3DRelativePositionMenuOptionInfo match_option = { +.base_name = "Set Manual 3D Screen Pos.", .false_name = "Set Automatic 3D Screen Pos.", +.is_selectable = true, +.position_x = 0, .position_y = 0, .multiplier_y = 1, +.text_factor_multiplier = 1.0, +.out_action = SECOND_SCREEN_3D_REL_POS_MENU_TOGGLE_MATCH, +.out_position = SECOND_SCREEN_3D_REL_POS_END, +.divisor_x = 1}; + +static const SecondScreen3DRelativePositionMenuOptionInfo* pollable_options[] = { +&match_option, +&above_option, +&left_option, +&right_option, +&below_option, +&desc_option, +&desc2_option, +}; + +SecondScreen3DRelativePositionMenu::SecondScreen3DRelativePositionMenu(bool font_load_success, sf::Font &text_font) { + this->initialize(font_load_success, text_font); +} + +SecondScreen3DRelativePositionMenu::~SecondScreen3DRelativePositionMenu() { + for(int i = 0; i < this->num_elements_displayed_per_screen; i++) + delete this->labels[i]; + delete []this->labels; + delete []this->selectable_labels; +} + +void SecondScreen3DRelativePositionMenu::class_setup() { + this->num_options_per_screen = NUM_TOTAL_MENU_OPTIONS; + this->min_elements_text_scaling_factor = 4; + this->num_vertical_slices = 5; + this->pos_y_subtractor = 0; + this->width_factor_menu = 16; + this->width_divisor_menu = 9; + this->base_height_factor_menu = 12; + this->base_height_divisor_menu = 6; + this->min_text_size = 0.3; + this->max_width_slack = 1.1; + this->menu_color = sf::Color(30, 30, 60, 192); + this->title = "3D Screen Placement"; +} + +void SecondScreen3DRelativePositionMenu::insert_data(ScreenType stype) { + this->pos_y_subtractor = 0; + this->num_vertical_slices = 5; + this->prepare_options(); +} + +void SecondScreen3DRelativePositionMenu::reset_output_option() { + this->selected_index = SECOND_SCREEN_3D_REL_POS_MENU_NO_ACTION; +} + +void SecondScreen3DRelativePositionMenu::set_output_option(int index) { + if(index == BACK_X_OUTPUT_OPTION) + this->selected_index = SECOND_SCREEN_3D_REL_POS_MENU_BACK; + else { + this->selected_index = pollable_options[index]->out_action; + this->selected_confirm_value = pollable_options[index]->out_position; + } +} + +bool SecondScreen3DRelativePositionMenu::is_option_selectable(int index) { + return pollable_options[index]->is_selectable; +} + +std::string SecondScreen3DRelativePositionMenu::get_string_option(int index) { + return pollable_options[index]->base_name; +} + +std::string SecondScreen3DRelativePositionMenu::get_false_option(int index) { + return pollable_options[index]->false_name; +} + +void SecondScreen3DRelativePositionMenu::option_slice_prepare(int i, int index, int num_vertical_slices, float text_scaling_factor) { + this->prepare_text_slices(pollable_options[i]->position_x, pollable_options[i]->divisor_x, pollable_options[i]->position_y - this->pos_y_subtractor + (1 * pollable_options[i]->multiplier_y), num_vertical_slices * pollable_options[i]->multiplier_y, index, text_scaling_factor * pollable_options[i]->text_factor_multiplier); +} + +bool SecondScreen3DRelativePositionMenu::is_option_element(int option) { + return (option >= this->elements_start_id) && (option < (this->elements_start_id + this->num_elements_per_screen)); +} + +bool SecondScreen3DRelativePositionMenu::is_option_left(int index) { + return (pollable_options[index]->out_action == SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM) && (pollable_options[index]->out_position == RIGHT_FIRST); +} + +bool SecondScreen3DRelativePositionMenu::is_option_right(int index) { + return (pollable_options[index]->out_action == SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM) && (pollable_options[index]->out_position == LEFT_FIRST); +} + +bool SecondScreen3DRelativePositionMenu::is_option_above(int index) { + return (pollable_options[index]->out_action == SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM) && (pollable_options[index]->out_position == UNDER_FIRST); +} + +bool SecondScreen3DRelativePositionMenu::is_option_below(int index) { + return (pollable_options[index]->out_action == SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM) && (pollable_options[index]->out_position == ABOVE_FIRST); +} + +std::string SecondScreen3DRelativePositionMenu::setTextOptionBool(int index, bool value) { + if(value) + return this->get_string_option(index); + return this->get_false_option(index); +} + +void SecondScreen3DRelativePositionMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, ScreenInfo* info) { + SecondScreen3DRelativePosition curr_2nd_screen_3d_pos = info->second_screen_pos; + for(int i = 0; i < this->num_options_per_screen; i++) { + int index = i + this->elements_start_id; + switch(pollable_options[i]->out_action) { + case SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM: + if(pollable_options[i]->out_position == curr_2nd_screen_3d_pos) + this->labels[index]->setText("<" + this->get_string_option(i) + ">"); + else + this->labels[index]->setText(this->get_string_option(i)); + break; + case SECOND_SCREEN_3D_REL_POS_MENU_TOGGLE_MATCH: + this->labels[index]->setText(this->setTextOptionBool(i, info->match_bottom_pos_and_second_screen_pos)); + break; + default: + break; + } + } + + this->base_prepare(menu_scaling_factor, view_size_x, view_size_y); +} diff --git a/source/Menus/StatusMenu.cpp b/source/Menus/StatusMenu.cpp index c0a4b06..c71d325 100755 --- a/source/Menus/StatusMenu.cpp +++ b/source/Menus/StatusMenu.cpp @@ -71,7 +71,7 @@ StatusMenu::~StatusMenu() { void StatusMenu::class_setup() { this->num_options_per_screen = 6; - this->min_elements_text_scaling_factor = num_options_per_screen + 2; + this->min_elements_text_scaling_factor = num_options_per_screen + 1; this->width_factor_menu = 16; this->width_divisor_menu = 9; this->base_height_factor_menu = 12; diff --git a/source/Menus/VideoMenu.cpp b/source/Menus/VideoMenu.cpp index 2c79718..eef1462 100755 --- a/source/Menus/VideoMenu.cpp +++ b/source/Menus/VideoMenu.cpp @@ -195,12 +195,20 @@ static const VideoMenuOptionInfo separator_settings_option = { .is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = VIDEO_MENU_NO_ACTION, .out_action = VIDEO_MENU_SEPARATOR_SETTINGS}; +static const VideoMenuOptionInfo main_menu_3d_settings_option = { +.base_name = "3D Settings", .false_name = "", +.active_fullscreen = true, .active_windowed_screen = true, .requires_titlebar_possible = false, +.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true, +.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = VIDEO_MENU_NO_ACTION, +.out_action = VIDEO_MENU_3D_SETTINGS}; + static const VideoMenuOptionInfo* pollable_options[] = { &crop_option, &window_scaling_option, &allow_fill_scaling_option, &scaling_ratio_settings_option, &menu_scaling_option, +&main_menu_3d_settings_option, &bottom_screen_pos_option, &separator_settings_option, &vsync_option, diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index c9a9d64..41d4a2d 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -32,7 +32,7 @@ struct shader_and_data { static std::vector usable_shaders; -static bool is_size_valid(sf::Vector2f &size) { +static bool is_size_valid(sf::Vector2f size) { return (size.x > 0.0) && (size.y > 0.0); } @@ -61,6 +61,7 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp FPSArrayInit(&this->poll_fps); (void)this->in_tex.resize({MAX_IN_VIDEO_WIDTH * NUM_FRAMES_BLENDED, MAX_IN_VIDEO_HEIGHT}); this->m_in_rect_top.setTexture(&this->in_tex); + this->m_in_rect_top_right.setTexture(&this->in_tex); this->m_in_rect_bot.setTexture(&this->in_tex); this->display_data = display_data; this->shared_data = shared_data; @@ -80,6 +81,8 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp if(this->m_stype == ScreenType::BOTTOM) this->win_title += "_bot"; this->last_connected_status = false; + this->last_enabled_3d = false; + this->last_interleaved_3d = false; this->capture_status = capture_status; if(this->display_data->mono_app_mode && this->m_stype == ScreenType::JOINT) this->m_info.is_fullscreen = true; @@ -133,6 +136,10 @@ void WindowScreen::build() { this->m_out_rect_top.out_rect.setSize(top_screen_size); this->m_out_rect_top.out_rect.setTexture(&this->m_out_rect_top.out_tex.getTexture()); + (void)this->m_out_rect_top_right.out_tex.resize({(unsigned int)top_screen_size.x / 2, (unsigned int)top_screen_size.y}); + this->m_out_rect_top_right.out_rect.setSize(top_screen_size); + this->m_out_rect_top_right.out_rect.setTexture(&this->m_out_rect_top_right.out_tex.getTexture()); + (void)this->m_out_rect_bot.out_tex.resize({(unsigned int)bot_screen_size.x, (unsigned int)bot_screen_size.y}); this->m_out_rect_bot.out_rect.setSize(bot_screen_size); this->m_out_rect_bot.out_rect.setTexture(&this->m_out_rect_bot.out_tex.getTexture()); @@ -225,6 +232,17 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { } if(!should_be_open) this->m_info.is_fullscreen = false; + bool curr_enabled_3d = get_3d_enabled(this->capture_status); + if(this->last_enabled_3d != curr_enabled_3d) { + this->prepare_size_ratios(false, false); + this->future_operations.call_crop = true; + } + this->last_enabled_3d = curr_enabled_3d; + if(curr_enabled_3d && (this->last_interleaved_3d != this->display_data->interleaved_3d)) { + this->prepare_size_ratios(false, false); + this->future_operations.call_crop = true; + } + this->last_interleaved_3d = this->display_data->interleaved_3d; this->loaded_menu = this->curr_menu; loaded_operations = future_operations; if(this->loaded_operations.call_create) { @@ -367,6 +385,7 @@ void WindowScreen::print_notification_float(std::string base_text, float value, void WindowScreen::prepare_screen_rendering() { if(loaded_operations.call_blur) { this->m_out_rect_top.out_tex.setSmooth(this->loaded_info.is_blurred); + this->m_out_rect_top_right.out_tex.setSmooth(this->loaded_info.is_blurred); this->m_out_rect_bot.out_tex.setSmooth(this->loaded_info.is_blurred); } if(loaded_operations.call_crop) { @@ -639,22 +658,22 @@ int WindowScreen::choose_shader(PossibleShaderTypes shader_type, bool is_top) { return -1; } -void WindowScreen::apply_shader_to_texture(out_rect_data &rect_data, PossibleShaderTypes shader_type, bool is_top) { +void WindowScreen::apply_shader_to_texture(sf::RectangleShape &rect_data, sf::RenderTexture &tex_data, PossibleShaderTypes shader_type, bool is_top) { int chosen_shader = choose_shader(COLOR_PROCESSING_SHADER_TYPE, is_top); if(chosen_shader < 0) return; sf::RectangleShape in_rect; - in_rect.setTexture(&rect_data.out_tex.getTexture()); - const sf::IntRect texture_rect = rect_data.out_rect.getTextureRect(); + in_rect.setTexture(&tex_data.getTexture()); + const sf::IntRect texture_rect = rect_data.getTextureRect(); in_rect.setTextureRect(texture_rect); in_rect.setSize({(float)texture_rect.size.x, (float)texture_rect.size.y}); in_rect.setPosition({(float)texture_rect.position.x, (float)texture_rect.position.y}); in_rect.setRotation(sf::degrees(0)); in_rect.setOrigin({0, 0}); - rect_data.out_tex.draw(in_rect, &usable_shaders[chosen_shader].shader); + tex_data.draw(in_rect, &usable_shaders[chosen_shader].shader); } -bool WindowScreen::apply_shaders_to_input(out_rect_data &rect_data, const sf::RectangleShape &final_in_rect, bool is_top) { +bool WindowScreen::apply_shaders_to_input(sf::RectangleShape &rect_data, sf::RenderTexture &tex_data, const sf::RectangleShape &final_in_rect, bool is_top) { if(!sf::Shader::isAvailable()) return false; @@ -667,13 +686,13 @@ bool WindowScreen::apply_shaders_to_input(out_rect_data &rect_data, const sf::Re old_frame_pos_x = -1.0 / NUM_FRAMES_BLENDED; sf::Glsl::Vec2 old_pos = {old_frame_pos_x, 0.0}; usable_shaders[chosen_shader].shader.setUniform("old_frame_offset", old_pos); - rect_data.out_tex.draw(final_in_rect, &usable_shaders[chosen_shader].shader); + tex_data.draw(final_in_rect, &usable_shaders[chosen_shader].shader); - this->apply_shader_to_texture(rect_data, COLOR_PROCESSING_SHADER_TYPE, is_top); + this->apply_shader_to_texture(rect_data, tex_data, COLOR_PROCESSING_SHADER_TYPE, is_top); return true; } -void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top, bool is_debug) { +void WindowScreen::post_texture_conversion_processing(sf::RectangleShape &rect_data, sf::RenderTexture &tex_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top, bool is_debug) { if((is_top && this->m_stype == ScreenType::BOTTOM) || ((!is_top) && this->m_stype == ScreenType::TOP)) return; if(this->loaded_menu == CONNECT_MENU_TYPE) @@ -681,24 +700,24 @@ void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data, if(is_debug) { if(is_top) - rect_data.out_tex.clear(sf::Color::Red); + tex_data.clear(sf::Color::Red); else - rect_data.out_tex.clear(sf::Color::Blue); + tex_data.clear(sf::Color::Blue); } else { - rect_data.out_tex.clear(); + tex_data.clear(); sf::RectangleShape final_in_rect = in_rect; sf::IntRect text_coords_rect = final_in_rect.getTextureRect(); text_coords_rect.position.x += this->curr_frame_texture_pos * MAX_IN_VIDEO_WIDTH; final_in_rect.setTextureRect(text_coords_rect); if(this->capture_status->connected && actually_draw) { - bool use_default_shader = !(this->apply_shaders_to_input(rect_data, final_in_rect, is_top)); + bool use_default_shader = !(this->apply_shaders_to_input(rect_data, tex_data, final_in_rect, is_top)); if(use_default_shader) - rect_data.out_tex.draw(final_in_rect); + tex_data.draw(final_in_rect); //Place postprocessing effects here } } - rect_data.out_tex.display(); + tex_data.display(); } void WindowScreen::draw_rect_to_window(const sf::RectangleShape &out_rect, bool is_top) { @@ -723,18 +742,81 @@ void WindowScreen::window_bg_processing() { //Place BG processing here } +sf::Vector2u WindowScreen::get_3d_size_multiplier(ScreenInfo* info) { + if((!get_3d_enabled(this->capture_status)) || (this->display_data->interleaved_3d)) + return {1, 1}; + SecondScreen3DRelativePosition second_screen_pos = get_second_screen_pos(info, this->m_stype); + if((second_screen_pos == UNDER_FIRST) || (second_screen_pos == ABOVE_FIRST)) + return {1, 2}; + return {2, 1}; +} + +sf::Vector2u WindowScreen::get_desk_mode_3d_multiplied(ScreenInfo* info) { + if((!get_3d_enabled(this->capture_status)) || (this->display_data->interleaved_3d) || (this->m_stype == ScreenType::BOTTOM) || (info->top_scaling == 0)) + return curr_desk_mode.size; + return curr_desk_mode.size.componentWiseDiv(get_3d_size_multiplier(info)); +} + +sf::Vector2f WindowScreen::get_3d_offset_out_rect(ScreenInfo* info, bool is_second_screen) { + if((!get_3d_enabled(this->capture_status)) || (this->display_data->interleaved_3d)) + return {0, 0}; + float x_contribution = this->m_width_no_manip; + float y_contribution = this->m_height_no_manip; + if(info->is_fullscreen) { + sf::Vector2u curr_desk_mode_3d_size = get_desk_mode_3d_multiplied(info); + x_contribution = curr_desk_mode_3d_size.x; + y_contribution = curr_desk_mode_3d_size.y; + } + float offset_x_first_screen = 0; + float offset_y_first_screen = 0; + if((!info->is_fullscreen) && info->rounded_corners_fix) { + x_contribution -= LEFT_ROUNDED_PADDING; + y_contribution -= TOP_ROUNDED_PADDING; + } + SecondScreen3DRelativePosition second_screen_pos = get_second_screen_pos(info, this->m_stype); + if(second_screen_pos == ABOVE_FIRST) + offset_y_first_screen = y_contribution; + if(second_screen_pos == LEFT_FIRST) + offset_x_first_screen = x_contribution; + if(!is_second_screen) + return {offset_x_first_screen, offset_y_first_screen}; + if((second_screen_pos == UNDER_FIRST) || (second_screen_pos == ABOVE_FIRST)) + return {0, (-2 * offset_y_first_screen) + y_contribution}; + return {(-2 * offset_x_first_screen) + x_contribution, 0}; +} + void WindowScreen::display_data_to_window(bool actually_draw, bool is_debug) { this->draw_lock->lock(); - this->post_texture_conversion_processing(this->m_out_rect_top, this->m_in_rect_top, actually_draw, true, is_debug); - this->post_texture_conversion_processing(this->m_out_rect_bot, this->m_in_rect_bot, actually_draw, false, is_debug); + sf::RectangleShape out_rect_top = this->m_out_rect_top.out_rect; + sf::RectangleShape out_rect_top_right = this->m_out_rect_top_right.out_rect; + sf::RectangleShape out_rect_bot = this->m_out_rect_bot.out_rect; + sf::RectangleShape in_rect_top = this->m_in_rect_top; + sf::RectangleShape in_rect_top_right = this->m_in_rect_top_right; + sf::RectangleShape in_rect_bot = this->m_in_rect_bot; + this->post_texture_conversion_processing(out_rect_top, this->m_out_rect_top.out_tex, in_rect_top, actually_draw, true, is_debug); + this->post_texture_conversion_processing(out_rect_bot, this->m_out_rect_bot.out_tex, in_rect_bot, actually_draw, false, is_debug); + if(get_3d_enabled(this->capture_status) && (!this->display_data->interleaved_3d) && (this->m_stype != ScreenType::BOTTOM) && is_size_valid(out_rect_top.getSize())) { + out_rect_top_right.setTextureRect(out_rect_top.getTextureRect()); + this->post_texture_conversion_processing(out_rect_top_right, this->m_out_rect_top_right.out_tex, in_rect_top_right, actually_draw, true, is_debug); + } if(is_debug) this->m_win.clear(sf::Color::Green); else this->m_win.clear(); this->window_bg_processing(); - this->draw_rect_to_window(this->m_out_rect_top.out_rect, true); - this->draw_rect_to_window(this->m_out_rect_bot.out_rect, false); + this->draw_rect_to_window(out_rect_top, true); + this->draw_rect_to_window(out_rect_bot, false); + if(get_3d_enabled(this->capture_status) && (!this->display_data->interleaved_3d) && (this->m_stype != ScreenType::BOTTOM) && is_size_valid(out_rect_top.getSize())) { + sf::Vector2f offset_second_screen = get_3d_offset_out_rect(&this->loaded_info, true); + out_rect_top_right.setTextureRect(out_rect_top.getTextureRect()); + out_rect_top_right.setSize(out_rect_top.getSize()); + out_rect_top_right.setPosition(out_rect_top.getPosition() + offset_second_screen); + out_rect_top_right.setRotation(out_rect_top.getRotation()); + this->draw_rect_to_window(out_rect_top_right, true); + out_rect_bot.setPosition(out_rect_bot.getPosition() + offset_second_screen); + this->draw_rect_to_window(out_rect_bot, false); + } this->execute_menu_draws(); this->notification->draw(this->m_win); this->m_win.display(); @@ -895,8 +977,9 @@ float WindowScreen::get_max_float_screen_multiplier(ResizingScreenData *own_scre sf::Vector2f other_screen_size = sf::Vector2f(width_limit, height_limit); if((!is_size_valid(other_screen_size)) && is_two_screens_merged) other_screen_size = sf::Vector2f(1, 1); - int desk_height = curr_desk_mode.size.y - get_separator_size_y(own_screen->size, other_screen_size, 1.0, 1.0, this->m_stype, this->m_info.bottom_pos, this->m_info.separator_pixel_size, this->m_info.separator_fullscreen_multiplier, true); - int desk_width = curr_desk_mode.size.x - get_separator_size_x(own_screen->size, other_screen_size, 1.0, 1.0, this->m_stype, this->m_info.bottom_pos, this->m_info.separator_pixel_size, this->m_info.separator_fullscreen_multiplier, true); + sf::Vector2u curr_desk_mode_3d_size = get_desk_mode_3d_multiplied(&this->m_info); + int desk_height = curr_desk_mode_3d_size.y - get_separator_size_y(own_screen->size, other_screen_size, 1.0, 1.0, this->m_stype, this->m_info.bottom_pos, this->m_info.separator_pixel_size, this->m_info.separator_fullscreen_multiplier, true); + int desk_width = curr_desk_mode_3d_size.x - get_separator_size_x(own_screen->size, other_screen_size, 1.0, 1.0, this->m_stype, this->m_info.bottom_pos, this->m_info.separator_pixel_size, this->m_info.separator_fullscreen_multiplier, true); int height_max = desk_height; int width_max = desk_width; switch(this->m_info.bottom_pos) { @@ -914,7 +997,7 @@ float WindowScreen::get_max_float_screen_multiplier(ResizingScreenData *own_scre float own_width = own_screen->size.x; float own_height = own_screen->size.y; - get_par_size(own_width, own_height, 1.0, own_screen->par); + get_par_size(own_width, own_height, 1.0, own_screen->par, own_screen->divide_3d_par); if((own_screen->rotation / 10) % 2) std::swap(own_width, own_height); if((own_height == 0) || (own_width == 0)) @@ -933,7 +1016,7 @@ int WindowScreen::prepare_screen_ratio(ResizingScreenData *own_screen, int width float WindowScreen::get_ratio_compared_other_screen(ResizingScreenData *own_screen, ResizingScreenData* other_screen, float other_scaling) { int other_width = other_screen->size.x; int other_height = other_screen->size.y; - get_par_size(other_width, other_height, other_scaling, other_screen->par); + get_par_size(other_width, other_height, other_scaling, other_screen->par, other_screen->divide_3d_par); return prepare_screen_ratio(own_screen, other_width, other_height, other_screen->rotation); } @@ -978,7 +1061,7 @@ bool WindowScreen::can_non_integerly_scale() { void WindowScreen::rescale_nonint_subscreen(ResizingScreenData *main_screen_resize_data, ResizingScreenData *sub_screen_resize_data) { int new_width = main_screen_resize_data->size.x; int new_height = main_screen_resize_data->size.y; - get_par_size(new_width, new_height, *main_screen_resize_data->non_int_scaling, main_screen_resize_data->par); + get_par_size(new_width, new_height, *main_screen_resize_data->non_int_scaling, main_screen_resize_data->par, main_screen_resize_data->divide_3d_par); *sub_screen_resize_data->non_int_scaling = this->get_max_float_screen_multiplier(sub_screen_resize_data, new_width, new_height, main_screen_resize_data->rotation); if(!sub_screen_resize_data->use_non_int_scaling) *sub_screen_resize_data->non_int_scaling = static_cast(*sub_screen_resize_data->non_int_scaling); @@ -1044,8 +1127,8 @@ void WindowScreen::non_integer_scale_screens(ResizingScreenData *top_screen_resi int min_top_screen_height = top_screen_resize_data->size.y; int min_bot_screen_width = bot_screen_resize_data->size.x; int min_bot_screen_height = bot_screen_resize_data->size.y; - get_par_size(min_top_screen_width, min_top_screen_height, min_top_scaling, top_screen_resize_data->par); - get_par_size(min_bot_screen_width, min_bot_screen_height, min_bot_scaling, bot_screen_resize_data->par); + get_par_size(min_top_screen_width, min_top_screen_height, min_top_scaling, top_screen_resize_data->par, top_screen_resize_data->divide_3d_par); + get_par_size(min_bot_screen_width, min_bot_screen_height, min_bot_scaling, bot_screen_resize_data->par, bot_screen_resize_data->divide_3d_par); ResizingScreenData *bigger_screen_resize_data = top_screen_resize_data; ResizingScreenData *smaller_screen_resize_data = bot_screen_resize_data; @@ -1065,8 +1148,9 @@ void WindowScreen::non_integer_scale_screens(ResizingScreenData *top_screen_resi if((bot_screen_resize_data->rotation / 10) % 2) std::swap(min_bot_screen_width, min_bot_screen_height); - int free_width = curr_desk_mode.size.x - (min_bot_screen_width + min_top_screen_width); - int free_height = curr_desk_mode.size.y - (min_bot_screen_height + min_top_screen_height); + sf::Vector2u curr_desk_mode_3d_size = get_desk_mode_3d_multiplied(&this->m_info); + int free_width = curr_desk_mode_3d_size.x - (min_bot_screen_width + min_top_screen_width); + int free_height = curr_desk_mode_3d_size.y - (min_bot_screen_height + min_top_screen_height); switch(this->m_info.non_integer_mode) { case SMALLER_PRIORITY: @@ -1093,10 +1177,10 @@ void WindowScreen::merge_screens_data(ResizingScreenData* top_screen_resize_data // Due to PARs and rotations, this is a bit annoying, but whatever... float top_width = top_screen_resize_data->size.x; float top_height = top_screen_resize_data->size.y; - get_par_size(top_width, top_height, 1.0, top_screen_resize_data->par); + get_par_size(top_width, top_height, 1.0, top_screen_resize_data->par, top_screen_resize_data->divide_3d_par); float bot_width = bot_screen_resize_data->size.x; float bot_height = bot_screen_resize_data->size.y; - get_par_size(bot_width, bot_height, 1.0, bot_screen_resize_data->par); + get_par_size(bot_width, bot_height, 1.0, bot_screen_resize_data->par, bot_screen_resize_data->divide_3d_par); if((top_screen_resize_data->rotation / 10) % 2) std::swap(top_width, top_height); if((bot_screen_resize_data->rotation / 10) % 2) @@ -1132,7 +1216,7 @@ bool WindowScreen::prepare_screens_same_scaling_factor(ResizingScreenData* top_s return false; int scaling_merged = 1; float non_int_scaling_merged = 1.0; - ResizingScreenData merged_screen_resize_data = {.size = {}, .scaling = &scaling_merged, .non_int_scaling = &non_int_scaling_merged, .use_non_int_scaling = false, .rotation = 0, .par = NULL}; + ResizingScreenData merged_screen_resize_data = {.size = {}, .scaling = &scaling_merged, .non_int_scaling = &non_int_scaling_merged, .use_non_int_scaling = false, .rotation = 0, .par = NULL, .divide_3d_par = false}; merge_screens_data(top_screen_resize_data, bot_screen_resize_data, &merged_screen_resize_data, this->m_info.bottom_pos); non_int_scaling_merged = this->get_max_float_screen_multiplier(&merged_screen_resize_data, 0, 0, 0, true); scaling_merged = non_int_scaling_merged; @@ -1147,6 +1231,14 @@ bool WindowScreen::prepare_screens_same_scaling_factor(ResizingScreenData* top_s return true; } +bool WindowScreen::get_divide_3d_par(bool is_top, ScreenInfo* info) { + if(!get_3d_enabled(this->capture_status)) + return false; + if(!is_top) + return info->squish_3d_bot; + return info->squish_3d_top; +} + void WindowScreen::prepare_size_ratios(bool top_increase, bool bot_increase, bool cycle) { if(!this->m_info.is_fullscreen) return; @@ -1172,8 +1264,8 @@ void WindowScreen::prepare_size_ratios(bool top_increase, bool bot_increase, boo this->m_info.top_par = 0; if((this->m_info.bot_par >= this->possible_pars.size()) || (this->m_info.bot_par < 0)) this->m_info.bot_par = 0; - ResizingScreenData top_screen_resize_data = {.size = top_screen_size, .scaling = &this->m_info.top_scaling, .non_int_scaling = &this->m_info.non_integer_top_scaling, .use_non_int_scaling = this->m_info.use_non_integer_scaling_top, .rotation = this->m_info.top_rotation, .par = this->possible_pars[this->m_info.top_par]}; - ResizingScreenData bot_screen_resize_data = {.size = bot_screen_size, .scaling = &this->m_info.bot_scaling, .non_int_scaling = &this->m_info.non_integer_bot_scaling, .use_non_int_scaling = this->m_info.use_non_integer_scaling_bottom, .rotation = this->m_info.bot_rotation, .par = this->possible_pars[this->m_info.bot_par]}; + ResizingScreenData top_screen_resize_data = {.size = top_screen_size, .scaling = &this->m_info.top_scaling, .non_int_scaling = &this->m_info.non_integer_top_scaling, .use_non_int_scaling = this->m_info.use_non_integer_scaling_top, .rotation = this->m_info.top_rotation, .par = this->possible_pars[this->m_info.top_par], .divide_3d_par = get_divide_3d_par(true, &this->m_info)}; + ResizingScreenData bot_screen_resize_data = {.size = bot_screen_size, .scaling = &this->m_info.bot_scaling, .non_int_scaling = &this->m_info.non_integer_bot_scaling, .use_non_int_scaling = this->m_info.use_non_integer_scaling_bottom, .rotation = this->m_info.bot_rotation, .par = this->possible_pars[this->m_info.bot_par], .divide_3d_par = get_divide_3d_par(false, &this->m_info)}; bool processed = false; if(this->m_stype == ScreenType::JOINT && this->m_info.force_same_scaling) @@ -1208,7 +1300,8 @@ int WindowScreen::get_fullscreen_offset_x(int top_width, int top_height, int bot default: return 0; } - return (curr_desk_mode.size.x - offset_contribute) * this->loaded_info.total_offset_x; + sf::Vector2u curr_desk_mode_3d_size = get_desk_mode_3d_multiplied(&this->loaded_info); + return (curr_desk_mode_3d_size.x - offset_contribute) * this->loaded_info.total_offset_x; } int WindowScreen::get_fullscreen_offset_y(int top_width, int top_height, int bot_width, int bot_height, int separator_contribute) { @@ -1230,7 +1323,8 @@ int WindowScreen::get_fullscreen_offset_y(int top_width, int top_height, int bot default: return 0; } - return (curr_desk_mode.size.y - offset_contribute) * this->loaded_info.total_offset_y; + sf::Vector2u curr_desk_mode_3d_size = get_desk_mode_3d_multiplied(&this->loaded_info); + return (curr_desk_mode_3d_size.y - offset_contribute) * this->loaded_info.total_offset_y; } void WindowScreen::resize_window_and_out_rects(bool do_work) { @@ -1259,8 +1353,8 @@ void WindowScreen::resize_window_and_out_rects(bool do_work) { this->loaded_info.top_par = 0; if((this->loaded_info.bot_par >= this->possible_pars.size()) || (this->loaded_info.bot_par < 0)) this->loaded_info.bot_par = 0; - get_par_size(top_width, top_height, top_scaling, this->possible_pars[this->loaded_info.top_par]); - get_par_size(bot_width, bot_height, bot_scaling, this->possible_pars[this->loaded_info.bot_par]); + get_par_size(top_width, top_height, top_scaling, this->possible_pars[this->loaded_info.top_par], get_divide_3d_par(true, &this->loaded_info)); + get_par_size(bot_width, bot_height, bot_scaling, this->possible_pars[this->loaded_info.bot_par], get_divide_3d_par(false, &this->loaded_info)); if((!this->loaded_info.is_fullscreen) && this->loaded_info.rounded_corners_fix) { offset_y = TOP_ROUNDED_PADDING; @@ -1272,8 +1366,9 @@ void WindowScreen::resize_window_and_out_rects(bool do_work) { if(this->loaded_info.is_fullscreen) { offset_x = get_fullscreen_offset_x(top_width, top_height, bot_width, bot_height, separator_size_x); offset_y = get_fullscreen_offset_y(top_width, top_height, bot_width, bot_height, separator_size_y); - max_x = curr_desk_mode.size.x; - max_y = curr_desk_mode.size.y; + sf::Vector2u curr_desk_mode_3d_size = get_desk_mode_3d_multiplied(&this->loaded_info); + max_x = curr_desk_mode_3d_size.x; + max_y = curr_desk_mode_3d_size.y; } sf::Vector2f new_top_screen_size = {(float)top_width, (float)top_height}; sf::Vector2f new_bot_screen_size = {(float)bot_width, (float)bot_height}; @@ -1284,6 +1379,20 @@ void WindowScreen::resize_window_and_out_rects(bool do_work) { this->m_out_rect_bot.out_rect.setTextureRect(sf::IntRect({0, 0}, {(int)bot_screen_size.x, (int)bot_screen_size.y})); } this->set_position_screens(new_top_screen_size, new_bot_screen_size, offset_x, offset_y, max_x, max_y, separator_size_x, separator_size_y, do_work); + this->m_width_no_manip = this->m_width; + this->m_height_no_manip = this->m_height; + if(get_3d_enabled(this->capture_status) && (!this->display_data->interleaved_3d) && (this->m_stype != ScreenType::BOTTOM) && is_size_valid(this->m_out_rect_top.out_rect.getSize())) { + sf::Vector2f offset_first_screen = get_3d_offset_out_rect(&this->loaded_info, false); + this->m_out_rect_top.out_rect.setPosition(this->m_out_rect_top.out_rect.getPosition() + offset_first_screen); + this->m_out_rect_bot.out_rect.setPosition(this->m_out_rect_bot.out_rect.getPosition() + offset_first_screen); + if(!this->loaded_info.is_fullscreen) { + sf::Vector2f offset_to_apply = offset_first_screen; + if((offset_first_screen.x <= 0) && (offset_first_screen.y <= 0)) + offset_to_apply = get_3d_offset_out_rect(&this->loaded_info, true); + this->m_width += offset_to_apply.x; + this->m_height += offset_to_apply.y; + } + } if((!this->loaded_info.is_fullscreen) && this->loaded_info.rounded_corners_fix) { this->m_height += BOTTOM_ROUNDED_PADDING; this->m_width += RIGHT_ROUNDED_PADDING; @@ -1396,6 +1505,8 @@ sf::Vector2f WindowScreen::getShownScreenSize(bool is_top, ScreenInfo* info) { *crop_kind = 0; int width = (*crops)[*crop_kind]->top_width; int height = (*crops)[*crop_kind]->top_height; + if(get_3d_enabled(this->capture_status) && this->display_data->interleaved_3d) + width *= 2; if(!is_top) { width = (*crops)[*crop_kind]->bot_width; height = (*crops)[*crop_kind]->bot_height; @@ -1410,8 +1521,21 @@ void WindowScreen::crop() { sf::Vector2f top_screen_size = getShownScreenSize(true, &this->loaded_info); sf::Vector2f bot_screen_size = getShownScreenSize(false, &this->loaded_info); - this->resize_in_rect(this->m_in_rect_top, this->capture_status->device.top_screen_x + (*crops)[*crop_value]->top_x, this->capture_status->device.top_screen_y + (*crops)[*crop_value]->top_y, top_screen_size.x, top_screen_size.y); this->resize_in_rect(this->m_in_rect_bot, this->capture_status->device.bot_screen_x + (*crops)[*crop_value]->bot_x, this->capture_status->device.bot_screen_y + (*crops)[*crop_value]->bot_y, bot_screen_size.x, bot_screen_size.y); + if(get_3d_enabled(this->capture_status) && (!this->display_data->interleaved_3d)) { + int left_top_screen_x = this->capture_status->device.top_screen_x; + int left_top_screen_y = this->capture_status->device.top_screen_y; + int right_top_screen_x = this->capture_status->device.second_top_screen_x; + int right_top_screen_y = this->capture_status->device.second_top_screen_y; + if(!this->capture_status->device.is_second_top_screen_right) { + std::swap(left_top_screen_x, right_top_screen_x); + std::swap(left_top_screen_y, right_top_screen_y); + } + this->resize_in_rect(this->m_in_rect_top, left_top_screen_x + (*crops)[*crop_value]->top_x, left_top_screen_y + (*crops)[*crop_value]->top_y, top_screen_size.x, top_screen_size.y); + this->resize_in_rect(this->m_in_rect_top_right, right_top_screen_x + (*crops)[*crop_value]->top_x, right_top_screen_y + (*crops)[*crop_value]->top_y, top_screen_size.x, top_screen_size.y); + } + else + this->resize_in_rect(this->m_in_rect_top, this->capture_status->device.top_screen_x + (*crops)[*crop_value]->top_x, this->capture_status->device.top_screen_y + (*crops)[*crop_value]->top_y, top_screen_size.x, top_screen_size.y); this->loaded_operations.call_screen_settings_update = true; } diff --git a/source/WindowScreen_Menu.cpp b/source/WindowScreen_Menu.cpp index 1cc55ad..f1e7771 100755 --- a/source/WindowScreen_Menu.cpp +++ b/source/WindowScreen_Menu.cpp @@ -2,6 +2,7 @@ #include "frontend.hpp" #include "SFML/Audio/PlaybackDevice.hpp" +#include "devicecapture.hpp" #define FPS_WINDOW_SIZE 64 @@ -120,6 +121,8 @@ void WindowScreen::init_menus() { this->audio_device_menu = new AudioDeviceMenu(this->font_load_success, this->text_font); this->separator_menu = new SeparatorMenu(this->font_load_success, this->text_font); this->color_correction_menu = new ColorCorrectionMenu(this->font_load_success, this->text_font); + this->main_3d_menu = new Main3DMenu(this->font_load_success, this->text_font); + this->second_screen_3d_relpos_menu = new SecondScreen3DRelativePositionMenu(this->font_load_success, this->text_font); } void WindowScreen::destroy_menus() { @@ -147,6 +150,8 @@ void WindowScreen::destroy_menus() { delete this->audio_device_menu; delete this->separator_menu; delete this->color_correction_menu; + delete this->main_3d_menu; + delete this->second_screen_3d_relpos_menu; } void WindowScreen::set_close(int ret_val) { @@ -317,6 +322,35 @@ void WindowScreen::color_correction_value_change(int new_color_correction_value) this->print_notification(setting_name + this->possible_color_profiles[color_correction_index]->name); } +void WindowScreen::request_3d_change() { + bool updated = update_3d_enabled(this->capture_status); + if(updated) { + this->prepare_size_ratios(false, false); + this->future_operations.call_crop = true; + } +} + +void WindowScreen::interleaved_3d_change() { + this->display_data->interleaved_3d = !this->display_data->interleaved_3d; + bool updated = get_3d_enabled(this->capture_status); + if(updated) { + this->prepare_size_ratios(false, false); + this->future_operations.call_crop = true; + } +} + +void WindowScreen::squish_3d_change(bool is_top) { + if(is_top) + this->m_info.squish_3d_top = !this->m_info.squish_3d_top; + else + this->m_info.squish_3d_bot = !this->m_info.squish_3d_bot; + bool updated = get_3d_enabled(this->capture_status); + if(updated) { + this->prepare_size_ratios(false, false); + this->future_operations.call_screen_settings_update = true; + } +} + void WindowScreen::offset_change(float &value, float change) { if(change >= 1.0) return; @@ -422,8 +456,33 @@ void WindowScreen::input_toggle_change(bool &target) { void WindowScreen::bottom_pos_change(int new_bottom_pos) { BottomRelativePosition cast_new_bottom_pos = static_cast(new_bottom_pos % BottomRelativePosition::BOT_REL_POS_END); - if(cast_new_bottom_pos != this->m_info.bottom_pos) { - this->m_info.bottom_pos = cast_new_bottom_pos; + bool updated = cast_new_bottom_pos != this->m_info.bottom_pos; + this->m_info.bottom_pos = cast_new_bottom_pos; + if(updated) { + this->prepare_size_ratios(false, false); + this->future_operations.call_screen_settings_update = true; + } +} + +void WindowScreen::second_screen_3d_pos_change(int new_second_screen_3d_pos) { + SecondScreen3DRelativePosition cast_new_pos = static_cast(new_second_screen_3d_pos % SecondScreen3DRelativePosition::SECOND_SCREEN_3D_REL_POS_END); + SecondScreen3DRelativePosition prev_pos = get_second_screen_pos(&this->m_info, this->m_stype); + this->m_info.second_screen_pos = cast_new_pos; + SecondScreen3DRelativePosition curr_pos = get_second_screen_pos(&this->m_info, this->m_stype); + bool updated = get_3d_enabled(this->capture_status) && (prev_pos != curr_pos); + + if(updated) { + this->prepare_size_ratios(false, false); + this->future_operations.call_screen_settings_update = true; + } +} + +void WindowScreen::second_screen_3d_match_bottom_pos_change() { + SecondScreen3DRelativePosition prev_pos = get_second_screen_pos(&this->m_info, this->m_stype); + this->m_info.match_bottom_pos_and_second_screen_pos = !this->m_info.match_bottom_pos_and_second_screen_pos; + SecondScreen3DRelativePosition curr_pos = get_second_screen_pos(&this->m_info, this->m_stype); + bool updated = get_3d_enabled(this->capture_status) && (prev_pos != curr_pos); + if(updated) { this->prepare_size_ratios(false, false); this->future_operations.call_screen_settings_update = true; } @@ -1145,6 +1204,30 @@ void WindowScreen::setup_color_correction_menu(bool reset_data) { } } +void WindowScreen::setup_main_3d_menu(bool reset_data) { + if(!this->can_setup_menu()) + return; + if(this->curr_menu != MAIN_3D_MENU_TYPE) { + this->curr_menu = MAIN_3D_MENU_TYPE; + if(reset_data) + this->main_3d_menu->reset_data(); + this->main_3d_menu->insert_data(this->m_stype); + this->last_menu_change_time = std::chrono::high_resolution_clock::now(); + } +} + +void WindowScreen::setup_second_screen_3d_relpos_menu(bool reset_data) { + if(!this->can_setup_menu()) + return; + if(this->curr_menu != SECOND_SCREEN_RELATIVE_POS_MENU_TYPE) { + this->curr_menu = SECOND_SCREEN_RELATIVE_POS_MENU_TYPE; + if(reset_data) + this->second_screen_3d_relpos_menu->reset_data(); + this->second_screen_3d_relpos_menu->insert_data(this->m_stype); + this->last_menu_change_time = std::chrono::high_resolution_clock::now(); + } +} + void WindowScreen::update_save_menu() { if(this->curr_menu == SAVE_MENU_TYPE) { this->curr_menu = DEFAULT_MENU_TYPE; @@ -1692,6 +1775,9 @@ void WindowScreen::poll(bool do_everything) { case VIDEO_MENU_SEPARATOR_SETTINGS: this->setup_separator_menu(); break; + case VIDEO_MENU_3D_SETTINGS: + this->setup_main_3d_menu(); + break; default: break; } @@ -2229,6 +2315,60 @@ void WindowScreen::poll(bool do_everything) { continue; } break; + case MAIN_3D_MENU_TYPE: + if(this->main_3d_menu->poll(event_data)) { + switch(this->main_3d_menu->selected_index) { + case MAIN_3D_MENU_BACK: + this->setup_video_menu(false); + done = true; + break; + case MAIN_3D_MENU_NO_ACTION: + break; + case MAIN_3D_MENU_REQUEST_3D_TOGGLE: + this->request_3d_change(); + break; + case MAIN_3D_MENU_INTERLEAVED_TOGGLE: + this->interleaved_3d_change(); + break; + case MAIN_3D_MENU_SQUISH_TOP_TOGGLE: + this->squish_3d_change(true); + break; + case MAIN_3D_MENU_SQUISH_BOTTOM_TOGGLE: + this->squish_3d_change(false); + break; + case MAIN_3D_MENU_SECOND_SCREEN_POSITION_SETTINGS: + this->setup_second_screen_3d_relpos_menu(); + done = true; + break; + default: + break; + } + this->main_3d_menu->reset_output_option(); + continue; + } + break; + case SECOND_SCREEN_RELATIVE_POS_MENU_TYPE: + if(this->second_screen_3d_relpos_menu->poll(event_data)) { + switch(this->second_screen_3d_relpos_menu->selected_index) { + case SECOND_SCREEN_3D_REL_POS_MENU_BACK: + this->setup_main_3d_menu(false); + done = true; + break; + case SECOND_SCREEN_3D_REL_POS_MENU_NO_ACTION: + break; + case SECOND_SCREEN_3D_REL_POS_MENU_CONFIRM: + this->second_screen_3d_pos_change(this->second_screen_3d_relpos_menu->selected_confirm_value); + break; + case SECOND_SCREEN_3D_REL_POS_MENU_TOGGLE_MATCH: + this->second_screen_3d_match_bottom_pos_change(); + break; + default: + break; + } + this->second_screen_3d_relpos_menu->reset_output_option(); + continue; + } + break; default: break; } @@ -2511,6 +2651,12 @@ void WindowScreen::prepare_menu_draws(int view_size_x, int view_size_y) { case COLOR_CORRECTION_MENU_TYPE: this->color_correction_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, this->loaded_info.top_color_correction); break; + case MAIN_3D_MENU_TYPE: + this->main_3d_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, &this->loaded_info, this->display_data, this->capture_status); + break; + case SECOND_SCREEN_RELATIVE_POS_MENU_TYPE: + this->second_screen_3d_relpos_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, &this->loaded_info); + break; default: break; } @@ -2596,6 +2742,12 @@ void WindowScreen::execute_menu_draws() { case COLOR_CORRECTION_MENU_TYPE: this->color_correction_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win); break; + case MAIN_3D_MENU_TYPE: + this->main_3d_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win); + break; + case SECOND_SCREEN_RELATIVE_POS_MENU_TYPE: + this->second_screen_3d_relpos_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win); + break; default: break; } diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index 9396524..7c9e42e 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -615,6 +615,8 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, num_allowed_blanks--; else blank_out = true; + if(capture_data->status.cooldown_curr_in || (!capture_data->status.connected)) + blank_out = true; no_data_consecutive++; } } diff --git a/source/conversions.cpp b/source/conversions.cpp index f4f00e0..16e07af 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -69,38 +69,40 @@ static void ftd3_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_ } } else { + size_t last_line_index = ((IN_VIDEO_SIZE_3DS_3D - IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D) / (IN_VIDEO_WIDTH_3DS_3D * 3)) - 1; + size_t top_left_last_line_out_pos = 0; + size_t top_right_last_line_out_pos = 0; if(!interleaved_3d) { + // Optimize for speed for(int i = 0; i < (IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D / (IN_VIDEO_WIDTH_3DS_3D * 2)); i++) { convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, ((i * 2) + 0) * IN_VIDEO_WIDTH_3DS_3D, BOT_SIZE_3DS + TOP_SIZE_3DS + (i * IN_VIDEO_WIDTH_3DS_3D)); convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, ((i * 2) + 1) * IN_VIDEO_WIDTH_3DS_3D, BOT_SIZE_3DS + (i * IN_VIDEO_WIDTH_3DS_3D)); } - for(int i = 0; i < ((IN_VIDEO_SIZE_3DS_3D - IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D) / (IN_VIDEO_WIDTH_3DS_3D * 3)) - 1; i++) { + for(int i = 0; i < last_line_index; i++) { convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 0) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, BOT_SIZE_3DS + TOP_SIZE_3DS + (IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D / 2) + (i * IN_VIDEO_WIDTH_3DS_3D)); convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 1) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, BOT_SIZE_3DS + (IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D / 2) + (i * IN_VIDEO_WIDTH_3DS_3D)); convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 2) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, i * IN_VIDEO_WIDTH_3DS_3D); } - // For some weird reason, the last one is the opposite for bottom and - // second top screen - int i = ((IN_VIDEO_SIZE_3DS_3D - IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D) / (IN_VIDEO_WIDTH_3DS_3D * 3)) - 1; - convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 0) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, BOT_SIZE_3DS + TOP_SIZE_3DS + (IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D / 2) + (i * IN_VIDEO_WIDTH_3DS_3D)); - convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 2) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, BOT_SIZE_3DS + (IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D / 2) + (i * IN_VIDEO_WIDTH_3DS_3D)); - convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 1) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, i * IN_VIDEO_WIDTH_3DS_3D); + top_left_last_line_out_pos = BOT_SIZE_3DS + TOP_SIZE_3DS + (IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D / 2) + (last_line_index * IN_VIDEO_WIDTH_3DS_3D); + top_right_last_line_out_pos = BOT_SIZE_3DS + (IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D / 2) + (last_line_index * IN_VIDEO_WIDTH_3DS_3D); } else { + // Optimize for speed convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, 0, BOT_SIZE_3DS); - for(int i = 0; i < ((IN_VIDEO_SIZE_3DS_3D - IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D) / (IN_VIDEO_WIDTH_3DS_3D * 3)) - 1; i++) { + for(int i = 0; i < last_line_index; i++) { convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D * 2, (((i * 3) + 0) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, BOT_SIZE_3DS + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D + (i * IN_VIDEO_WIDTH_3DS_3D * 2)); convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 2) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, i * IN_VIDEO_WIDTH_3DS_3D); } - // For some weird reason, the last one is the opposite for bottom and - // second top screen - int i = ((IN_VIDEO_SIZE_3DS_3D - IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D) / (IN_VIDEO_WIDTH_3DS_3D * 3)) - 1; - convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 0) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, BOT_SIZE_3DS + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D + (i * IN_VIDEO_WIDTH_3DS_3D * 2)); - convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 2) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, BOT_SIZE_3DS + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D + (i * IN_VIDEO_WIDTH_3DS_3D * 2) + IN_VIDEO_WIDTH_3DS_3D); - convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 1) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, i * IN_VIDEO_WIDTH_3DS_3D); + top_left_last_line_out_pos = BOT_SIZE_3DS + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D + (last_line_index * IN_VIDEO_WIDTH_3DS_3D * 2); + top_right_last_line_out_pos = BOT_SIZE_3DS + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D + (last_line_index * IN_VIDEO_WIDTH_3DS_3D * 2) + IN_VIDEO_WIDTH_3DS_3D; } + // For some weird reason, the last one is the opposite for bottom and + // second top screen + convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((last_line_index * 3) + 0) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, top_left_last_line_out_pos); + convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((last_line_index * 3) + 2) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, top_right_last_line_out_pos); + convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((last_line_index * 3) + 1) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, last_line_index * IN_VIDEO_WIDTH_3DS_3D); } } diff --git a/source/devicecapture.cpp b/source/devicecapture.cpp index 7deede0..93f78a5 100755 --- a/source/devicecapture.cpp +++ b/source/devicecapture.cpp @@ -57,6 +57,10 @@ void capture_error_print(bool print_failed, CaptureData* capture_data, std::stri } void capture_error_print(bool print_failed, CaptureData* capture_data, std::string graphical_string, std::string detailed_string) { + if(capture_data->status.connected) { + capture_data->status.close_success = false; + capture_data->status.connected = false; + } if(print_failed) { capture_data->status.graphical_error_text = graphical_string; capture_data->status.detailed_error_text = detailed_string; @@ -70,12 +74,13 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten capture_data->status.close_success = false; return false; } - + if(!capture_data->status.close_success) { capture_error_print(print_failed, capture_data, "Previous device still closing..."); return false; } + capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM; // Device Listing std::vector devices_list; std::vector no_access_list; @@ -267,6 +272,16 @@ int get_usb_speed_of_device(CaptureStatus* capture_status) { return capture_status->device.usb_speed >> 8; } +bool is_usb_speed_of_device_enough_3d(CaptureStatus* capture_status) { + switch(capture_status->device.cc_type) { + default: + if(get_usb_speed_of_device(capture_status) < 3) + return false; + break; + } + return true; +} + bool get_device_can_do_3d(CaptureStatus* capture_status) { if(!capture_status->connected) return false; @@ -286,8 +301,8 @@ bool get_device_3d_implemented(CaptureStatus* capture_status) { } } -bool get_3d_enabled(CaptureStatus* capture_status) { - if(!capture_status->requested_3d) +bool get_3d_enabled(CaptureStatus* capture_status, bool skip_requested_3d_check) { + if((!skip_requested_3d_check) && (!capture_status->requested_3d)) return false; if(!capture_status->connected) return false; @@ -295,15 +310,19 @@ bool get_3d_enabled(CaptureStatus* capture_status) { return false; if(!get_device_3d_implemented(capture_status)) return false; - switch(capture_status->device.cc_type) { - default: - if(get_usb_speed_of_device(capture_status) < 3) - return false; - break; - } + if(!is_usb_speed_of_device_enough_3d(capture_status)) + return false; return true; } +bool update_3d_enabled(CaptureStatus* capture_status) { + bool would_3d_be_enabled = get_3d_enabled(capture_status, true); + if(would_3d_be_enabled && (capture_status->cooldown_curr_in < FIX_PARTIAL_FIRST_FRAME_NUM)) + capture_status->cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM; + capture_status->requested_3d = !capture_status->requested_3d; + return would_3d_be_enabled; +} + void capture_init() { #ifdef USE_DS_3DS_USB usb_ds_3ds_init(); diff --git a/source/frontend.cpp b/source/frontend.cpp index 0a7d8c5..205b3b7 100755 --- a/source/frontend.cpp +++ b/source/frontend.cpp @@ -573,6 +573,7 @@ void reset_screen_info(ScreenInfo &info) { info.scaling = DEFAULT_WINDOW_SCALING_VALUE; info.is_fullscreen = false; info.bottom_pos = UNDER_TOP; + info.second_screen_pos = RIGHT_FIRST; info.subscreen_offset = 0.5; info.subscreen_attached_offset = 0.0; info.total_offset_x = 0.5; @@ -616,6 +617,9 @@ void reset_screen_info(ScreenInfo &info) { info.separator_pixel_size = DEFAULT_SEP_SIZE; info.separator_windowed_multiplier = SEP_FOLLOW_SCALING_MULTIPLIER; info.separator_fullscreen_multiplier = DEFAULT_WINDOW_SCALING_VALUE; + info.squish_3d_top = false; + info.squish_3d_bot = false; + info.match_bottom_pos_and_second_screen_pos = false; } void override_set_data_to_screen_info(override_win_data &override_win, ScreenInfo &info) { @@ -854,7 +858,23 @@ bool load_screen_info(std::string key, std::string value, std::string base, Scre return true; } if(key == (base + "window_enabled")) { - info.window_enabled = frame_blending_sanitization(std::stoi(value)); + info.window_enabled = std::stoi(value); + return true; + } + if(key == (base + "second_screen_pos")) { + info.second_screen_pos = static_cast(std::stoi(value) % SecondScreen3DRelativePosition::SECOND_SCREEN_3D_REL_POS_END); + return true; + } + if(key == (base + "squish_3d_top")) { + info.squish_3d_top = std::stoi(value); + return true; + } + if(key == (base + "squish_3d_bot")) { + info.squish_3d_bot = std::stoi(value); + return true; + } + if(key == (base + "match_bottom_pos_and_second_screen_pos")) { + info.match_bottom_pos_and_second_screen_pos = std::stoi(value); return true; } return false; @@ -904,6 +924,10 @@ std::string save_screen_info(std::string base, const ScreenInfo &info) { out += base + "separator_pixel_size=" + std::to_string(info.separator_pixel_size) + "\n"; out += base + "separator_windowed_multiplier=" + std::to_string(info.separator_windowed_multiplier) + "\n"; out += base + "separator_fullscreen_multiplier=" + std::to_string(info.separator_fullscreen_multiplier) + "\n"; + out += base + "second_screen_pos=" + std::to_string(info.second_screen_pos) + "\n"; + out += base + "squish_3d_top=" + std::to_string(info.squish_3d_top) + "\n"; + out += base + "squish_3d_bot=" + std::to_string(info.squish_3d_bot) + "\n"; + out += base + "match_bottom_pos_and_second_screen_pos=" + std::to_string(info.match_bottom_pos_and_second_screen_pos) + "\n"; return out; } @@ -923,9 +947,12 @@ const PARData* get_base_par() { return basic_possible_pars[0]; } -void get_par_size(int &width, int &height, float multiplier_factor, const PARData *correction_factor) { +void get_par_size(int &width, int &height, float multiplier_factor, const PARData *correction_factor, bool divide_3d_par) { width *= multiplier_factor; height *= multiplier_factor; + float correction_factor_3d = 1.0; + if(divide_3d_par) + correction_factor_3d = 2.0; float correction_factor_divisor = correction_factor->width_multiplier; if(correction_factor->is_width_main) correction_factor_divisor = correction_factor->width_divisor; @@ -933,37 +960,64 @@ void get_par_size(int &width, int &height, float multiplier_factor, const PARDat if(correction_factor->is_fit) { if(correction_factor->is_width_main) width = ((height * correction_factor->width_multiplier) + correction_factor_approx_contribute) / correction_factor_divisor; - else + else { + width /= correction_factor_3d; height = ((width * correction_factor->width_divisor) + correction_factor_approx_contribute) / correction_factor_divisor; + } } else { if(correction_factor->is_width_main) width = ((width * correction_factor->width_multiplier) + correction_factor_approx_contribute) / correction_factor_divisor; else height = ((height * correction_factor->width_divisor) + correction_factor_approx_contribute) / correction_factor_divisor; + width /= correction_factor_3d; } } -void get_par_size(float &width, float &height, float multiplier_factor, const PARData *correction_factor) { +void get_par_size(float &width, float &height, float multiplier_factor, const PARData *correction_factor, bool divide_3d_par) { width *= multiplier_factor; height *= multiplier_factor; + float correction_factor_3d = 1.0; + if(divide_3d_par) + correction_factor_3d = 2.0; float correction_factor_divisor = correction_factor->width_multiplier; if(correction_factor->is_width_main) correction_factor_divisor = correction_factor->width_divisor; if(correction_factor->is_fit) { if(correction_factor->is_width_main) width = (height * correction_factor->width_multiplier) / correction_factor_divisor; - else + else { + width /= correction_factor_3d; height = (width * correction_factor->width_divisor) / correction_factor_divisor; + } } else { if(correction_factor->is_width_main) width = (width * correction_factor->width_multiplier) / correction_factor_divisor; else height = (height * correction_factor->width_divisor) / correction_factor_divisor; + width /= correction_factor_3d; } } +SecondScreen3DRelativePosition get_second_screen_pos(ScreenInfo* info, ScreenType stype) { + if(info->match_bottom_pos_and_second_screen_pos && (stype == ScreenType::JOINT)) { + switch(info->bottom_pos) { + case UNDER_TOP: + return RIGHT_FIRST; + case ABOVE_TOP: + return LEFT_FIRST; + case RIGHT_TOP: + return UNDER_FIRST; + case LEFT_TOP: + return ABOVE_FIRST; + default: + return RIGHT_FIRST; + } + } + return info->second_screen_pos; +} + JoystickDirection get_joystick_direction(uint32_t joystickId, sf::Joystick::Axis axis, float position) { bool is_horizontal = false; if((axis == sf::Joystick::Axis::Z) || (axis == sf::Joystick::Axis::R))