diff --git a/CMakeLists.txt b/CMakeLists.txt index ebd2cc8..ccd8dd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,7 @@ file(MAKE_DIRECTORY ${TOOLS_DATA_DIR}) set(OUTPUT_NAME cc3dsfs) add_custom_target(CMakeBin2C) -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/3dscapture.cpp source/conversions.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp) +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/3dscapture.cpp source/conversions.cpp source/ConnectionMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp) target_link_libraries(${OUTPUT_NAME} PRIVATE sfml-graphics sfml-audio sfml-window sfml-system ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB}) target_link_directories(${OUTPUT_NAME} PRIVATE ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}) target_include_directories(${OUTPUT_NAME} PRIVATE ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include) diff --git a/include/3dscapture.hpp b/include/3dscapture.hpp index 8993454..a8ce720 100755 --- a/include/3dscapture.hpp +++ b/include/3dscapture.hpp @@ -15,9 +15,6 @@ #define FT_ASYNC_CALL FT_ReadPipeAsync #endif -#define REAL_SERIAL_NUMBER_SIZE 16 -#define SERIAL_NUMBER_SIZE (REAL_SERIAL_NUMBER_SIZE+1) - // Max value (Due to support of old FTD3XX versions...) #define NUM_CONCURRENT_DATA_BUFFERS 8 diff --git a/include/ConnectionMenu.hpp b/include/ConnectionMenu.hpp new file mode 100755 index 0000000..ba08fd7 --- /dev/null +++ b/include/ConnectionMenu.hpp @@ -0,0 +1,53 @@ +#ifndef __CONNECTIONMENU_HPP +#define __CONNECTIONMENU_HPP + +#include +#include + +#include "TextRectangle.hpp" +#include "capture_structs.hpp" +#include "sfml_gfx_structs.hpp" + +#define CONNECTION_NUM_ELEMENTS_PER_SCREEN 4 +#define CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN (CONNECTION_NUM_ELEMENTS_PER_SCREEN + 3) + +class ConnectionMenu { +public: + ConnectionMenu(bool font_load_success, sf::Font &text_font); + ~ConnectionMenu(); + bool poll(SFEvent &event_data); + void draw(float scaling_factor, sf::RenderTarget &window); + void prepare(float scaling_factor, int view_size_x, int view_size_y); + void insert_data(DevicesList *devices_list); + int selected_index = -1; +private: + struct ConnectionMenuData { + int page = 0; + int option_selected = -1; + bool enabled_labels[CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN]; + int menu_width; + int menu_height; + int pos_x; + int pos_y; + }; + std::chrono::time_point last_action_time; + const float action_timeout = 0.1; + int loaded_page = 0; + int option_selected = -1; + TextRectangle *labels[CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN]; + bool selectable_labels[CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN]; + ConnectionMenuData future_data; + ConnectionMenuData loaded_data; + DevicesList *devices_list; + + bool can_execute_action(); + void up_code(); + void down_code(); + void left_code(); + void right_code(); + void prepare_options(); + void option_selection_handling(); + void decrement_selected_option(); + void increment_selected_option(); +}; +#endif diff --git a/include/TextRectangle.hpp b/include/TextRectangle.hpp new file mode 100755 index 0000000..d19b578 --- /dev/null +++ b/include/TextRectangle.hpp @@ -0,0 +1,70 @@ +#ifndef __TEXTRECTANGLE_HPP +#define __TEXTRECTANGLE_HPP + +#include + +#include +#include "sfml_gfx_structs.hpp" + +#define BASE_PIXEL_FONT_HEIGHT 24 + +enum TextKind {TEXT_KIND_NORMAL, TEXT_KIND_SELECTED, TEXT_KIND_SUCCESS, TEXT_KIND_WARNING, TEXT_KIND_ERROR}; + +class TextRectangle { +public: + TextRectangle(bool font_load_success, sf::Font &text_font); + ~TextRectangle(); + void setRectangleKind(TextKind kind); + void setTextFactor(float size_multiplier); + void setSize(int width, int height); + bool isCoordInRectangle(int coord_x, int coord_y); + void setDuration(float on_seconds); + void setPosition(int pos_x, int pos_y); + void startTimer(bool do_start); + void setProportionalBox(bool proportional_box); + void prepareRenderText(); + void setText(std::string text); + void setShowText(bool show_text); + void draw(sf::RenderTarget &window); + +private: + out_rect_data text_rect; + sf::Text actual_text; + bool font_load_success; + bool is_done_showing_text; + std::chrono::time_point clock_time_start; + int time_phase; + sf::Color *base_bg_color; + sf::Color *selected_bg_color; + sf::Color *success_bg_color; + sf::Color *warning_bg_color; + sf::Color *error_bg_color; + const float base_time_slide_factor = 0.5; + const float base_pixel_slide_factor = 2.0; + + struct TextData { + bool is_timed; + bool start_timer; + TextKind kind; + bool show_text; + bool render_text; + bool proportional_box; + std::string printed_text; + float duration; + float font_pixel_height; + int width; + int height; + int pos_x; + int pos_y; + }; + + TextData future_data; + TextData loaded_data; + + void setRealSize(int width, int height); + void reset_data(TextData &data); + void setTextWithLineWrapping(int x_limit = 0); + void updateText(int x_limit = 0); + void updateSlides(float* time_seconds); +}; +#endif diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index bfcfb5c..16585e1 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -5,6 +5,9 @@ #include "hw_defs.hpp" #include +#define REAL_SERIAL_NUMBER_SIZE 16 +#define SERIAL_NUMBER_SIZE (REAL_SERIAL_NUMBER_SIZE+1) + #define MAX_SAMPLES_IN 1096 #define FIX_PARTIAL_FIRST_FRAME_NUM 3 diff --git a/include/frontend.hpp b/include/frontend.hpp index 890f6cb..da8bcd7 100755 --- a/include/frontend.hpp +++ b/include/frontend.hpp @@ -10,6 +10,9 @@ #include "audio_data.hpp" #include "capture_structs.hpp" #include "hw_defs.hpp" +#include "TextRectangle.hpp" +#include "sfml_gfx_structs.hpp" +#include "ConnectionMenu.hpp" enum Crop { DEFAULT_3DS, SPECIAL_DS, SCALED_DS, NATIVE_DS, SCALED_GBA, NATIVE_GBA, SCALED_GB, NATIVE_GB, NATIVE_SNES, NATIVE_NES, CROP_END }; enum BottomRelativePosition { UNDER_TOP, LEFT_TOP, ABOVE_TOP, RIGHT_TOP, BOT_REL_POS_END }; @@ -46,84 +49,10 @@ struct PACKED VideoOutputData { #pragma pack(pop) -struct SFEvent { - SFEvent(sf::Event::EventType type, sf::Keyboard::Key code, uint32_t unicode, uint32_t joystickId, uint32_t joy_button, sf::Joystick::Axis axis, float position, sf::Mouse::Button mouse_button, int mouse_x, int mouse_y) : type(type), code(code), unicode(unicode), joystickId(joystickId), joy_button(joy_button), axis(axis), position(position), mouse_button(mouse_button), mouse_x(mouse_x), mouse_y(mouse_y) {} - - sf::Event::EventType type; - sf::Keyboard::Key code; - uint32_t unicode; - uint32_t joystickId; - uint32_t joy_button; - sf::Joystick::Axis axis; - float position; - sf::Mouse::Button mouse_button; - int mouse_x; - int mouse_y; -}; - -struct out_rect_data { - sf::RectangleShape out_rect; - sf::RenderTexture out_tex; -}; - 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); -enum TextKind {TEXT_KIND_NORMAL, TEXT_KIND_SELECTED, TEXT_KIND_SUCCESS, TEXT_KIND_WARNING, TEXT_KIND_ERROR}; - -class TextRectangle { -public: - TextRectangle(bool font_load_success, sf::Font &text_font); - ~TextRectangle(); - void setSize(int width, int height); - void setRectangleKind(TextKind kind); - void setTextFactor(float size_multiplier); - void setDuration(float on_seconds); - void startTimer(bool do_start); - void setProportionalBox(bool proportional_box); - void prepareRenderText(); - void setText(std::string text); - void setShowText(bool show_text); - void draw(sf::RenderTarget &window); - -private: - out_rect_data text_rect; - sf::Text actual_text; - int width, height; - bool font_load_success; - bool is_done_showing_text; - std::chrono::time_point clock_time_start; - int time_phase; - sf::Color *base_bg_color; - sf::Color *selected_bg_color; - sf::Color *success_bg_color; - sf::Color *warning_bg_color; - sf::Color *error_bg_color; - const float base_time_slide_factor = 0.5; - const float base_pixel_slide_factor = 2.0; - - struct TextData { - bool is_timed; - bool start_timer; - TextKind kind; - bool show_text; - bool render_text; - bool proportional_box; - std::string printed_text; - float duration; - float font_pixel_height; - }; - - TextData future_data; - TextData loaded_data; - - void reset_data(TextData &data); - void setTextWithLineWrapping(int x_limit = 0); - void updateText(int x_limit = 0); - void updateSlides(float* time_seconds); -}; - class WindowScreen { public: enum ScreenType { TOP, BOTTOM, JOINT }; @@ -141,6 +70,9 @@ public: void end(); void after_thread_join(); void draw(double frame_time, VideoOutputData* out_buf); + void setup_connection_menu(DevicesList *devices_list); + int check_connection_menu_result(); + void end_connection_menu(); void print_notification(std::string text, TextKind kind = TEXT_KIND_NORMAL); int load_data(); @@ -165,17 +97,19 @@ private: int m_prepare_save; bool m_prepare_open; bool m_prepare_quit; + bool font_load_success; double frame_time; DisplayData* display_data; AudioData* audio_data; std::mutex* events_access; std::chrono::time_point last_mouse_action_time; const float mouse_timeout = 5.0f; + CurrMenuType loaded_menu; + ConnectionMenu *connection_menu; sf::Texture in_tex; sf::Font text_font; - bool font_load_success; volatile bool main_thread_owns_window; volatile bool is_window_factory_done; @@ -220,13 +154,13 @@ private: void display_data_to_window(bool actually_draw); void window_render_call(); int apply_offset_algo(int offset_contribute, OffsetAlgorithm chosen_algo); - 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); + 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, bool do_work = true); int prepare_screen_ratio(sf::Vector2f &screen_size, int own_rotation, int width_limit, int height_limit, int other_rotation); void calc_scaling_resize_screens(sf::Vector2f &own_screen_size, sf::Vector2f &other_screen_size, int &own_scaling, int &other_scaling, int own_rotation, int other_rotation, bool increase, bool mantain, bool set_to_zero); void prepare_size_ratios(bool top_increase, bool bot_increase); int get_fullscreen_offset_x(int top_width, int top_height, int bot_width, int bot_height); int get_fullscreen_offset_y(int top_width, int top_height, int bot_width, int bot_height); - void resize_window_and_out_rects(); + void resize_window_and_out_rects(bool do_work = true); void create_window(bool re_prepare_size); void update_view_size(); void open(); @@ -245,6 +179,7 @@ struct FrontendData { bool reload; }; +void default_sleep(); void update_output(FrontendData* frontend_data, double frame_time = 0, VideoOutputData *out_buf = NULL); void screen_display_thread(WindowScreen *screen, CaptureStatus* capture_status); #endif diff --git a/include/sfml_gfx_structs.hpp b/include/sfml_gfx_structs.hpp new file mode 100755 index 0000000..6f49c77 --- /dev/null +++ b/include/sfml_gfx_structs.hpp @@ -0,0 +1,34 @@ +#ifndef __SFML_GFX_STRUCTS_HPP +#define __SFML_GFX_STRUCTS_HPP + +#include +#include + +enum JoystickDirection {JOY_DIR_NONE, JOY_DIR_UP, JOY_DIR_DOWN, JOY_DIR_LEFT, JOY_DIR_RIGHT}; +enum JoystickAction {JOY_ACTION_NONE, JOY_ACTION_CONFIRM, JOY_ACTION_NEGATE}; + +struct out_rect_data { + sf::RectangleShape out_rect; + sf::RenderTexture out_tex; +}; + +struct SFEvent { + SFEvent(sf::Event::EventType type, sf::Keyboard::Key code, uint32_t unicode, uint32_t joystickId, uint32_t joy_button, sf::Joystick::Axis axis, float position, sf::Mouse::Button mouse_button, int mouse_x, int mouse_y) : type(type), code(code), unicode(unicode), joystickId(joystickId), joy_button(joy_button), axis(axis), position(position), mouse_button(mouse_button), mouse_x(mouse_x), mouse_y(mouse_y) {} + + sf::Event::EventType type; + sf::Keyboard::Key code; + uint32_t unicode; + uint32_t joystickId; + uint32_t joy_button; + sf::Joystick::Axis axis; + float position; + sf::Mouse::Button mouse_button; + int mouse_x; + int mouse_y; +}; + +void joystick_axis_poll(std::queue &events_queue); +JoystickDirection get_joystick_direction(uint32_t joystickId, sf::Joystick::Axis axis, float position); +JoystickAction get_joystick_action(uint32_t joystickId, uint32_t joy_button); + +#endif diff --git a/source/3dscapture.cpp b/source/3dscapture.cpp index 1b2d89d..ddf2cc3 100755 --- a/source/3dscapture.cpp +++ b/source/3dscapture.cpp @@ -50,10 +50,43 @@ static void list_devices(DevicesList &devices_list) { } } -static int choose_device(DevicesList &devices_list, FrontendData* frontend_data) { - if(devices_list.numValidDevices == 1) +static bool poll_connection_window_screen(WindowScreen *screen, int &chosen_index) { + screen->poll(); + if(screen->check_connection_menu_result() != -1) { + chosen_index = screen->check_connection_menu_result(); + return true; + } + if(screen->close_capture()) { + return true; + } + return false; +} + +static int choose_device(DevicesList *devices_list, FrontendData* frontend_data) { + if(devices_list->numValidDevices == 1) return 0; - return 0; + int chosen_index = -1; + frontend_data->top_screen->setup_connection_menu(devices_list); + frontend_data->bot_screen->setup_connection_menu(devices_list); + frontend_data->joint_screen->setup_connection_menu(devices_list); + bool done = false; + while(!done) { + update_output(frontend_data); + done = poll_connection_window_screen(frontend_data->top_screen, chosen_index); + if(done) + break; + done = poll_connection_window_screen(frontend_data->bot_screen, chosen_index); + if(done) + break; + done = poll_connection_window_screen(frontend_data->joint_screen, chosen_index); + if(done) + break; + default_sleep(); + } + frontend_data->top_screen->end_connection_menu(); + frontend_data->bot_screen->end_connection_menu(); + frontend_data->joint_screen->end_connection_menu(); + return chosen_index; } static void preemptive_close_connection(CaptureData* capture_data) { @@ -89,7 +122,7 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten return false; } - int chosen_device = choose_device(devices_list, frontend_data); + int chosen_device = choose_device(&devices_list, frontend_data); if(chosen_device == -1) { if(print_failed) { capture_data->status.error_text = "No device was selected"; diff --git a/source/ConnectionMenu.cpp b/source/ConnectionMenu.cpp new file mode 100755 index 0000000..a6038a7 --- /dev/null +++ b/source/ConnectionMenu.cpp @@ -0,0 +1,348 @@ +#include "ConnectionMenu.hpp" + +#define CONNECTION_PREV_PAGE_ID (CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - 3) +#define CONNECTION_INFO_PAGES_ID (CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - 2) +#define CONNECTION_NEXT_PAGE_ID (CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - 1) + +ConnectionMenu::ConnectionMenu(bool font_load_success, sf::Font &text_font) { + for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { + this->labels[i] = new TextRectangle(font_load_success, text_font); + this->labels[i]->setProportionalBox(false); + this->labels[i]->setText(std::to_string(i)); + this->labels[i]->setShowText(true); + this->selectable_labels[i] = true; + this->future_data.enabled_labels[i] = true; + } + this->last_action_time = std::chrono::high_resolution_clock::now(); + this->selectable_labels[CONNECTION_INFO_PAGES_ID] = false; +} + +ConnectionMenu::~ConnectionMenu() { + for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) + delete this->labels[i]; +} + +bool ConnectionMenu::can_execute_action() { + auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - this->last_action_time; + if(diff.count() > this->action_timeout) + return true; + return false; +} + +void ConnectionMenu::insert_data(DevicesList *devices_list) { + this->selected_index = -1; + this->future_data.option_selected = -1; + this->future_data.page = 0; + this->devices_list = devices_list; + this->prepare_options(); +} + +void ConnectionMenu::decrement_selected_option() { + do { + this->future_data.option_selected -= 1; + if(this->future_data.option_selected <= 0) { + this->future_data.option_selected = 0; + return; + } + if(this->future_data.option_selected >= CONNECTION_NUM_ELEMENTS_PER_SCREEN) { + this->future_data.option_selected = CONNECTION_NUM_ELEMENTS_PER_SCREEN - 1; + } + } while(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])); +} + +void ConnectionMenu::increment_selected_option() { + int starting_value = this->future_data.option_selected; + if(starting_value < 0){ + this->future_data.option_selected = 0; + return; + } + do { + this->future_data.option_selected += 1; + if(this->future_data.option_selected >= CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN) { + this->future_data.option_selected = starting_value; + return; + } + } while(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])); +} + +void ConnectionMenu::prepare_options() { + int num_pages = 1 + ((this->devices_list->numValidDevices - 1) / CONNECTION_NUM_ELEMENTS_PER_SCREEN); + if(this->future_data.page >= num_pages) + this->future_data.page = num_pages - 1; + int start = this->future_data.page * CONNECTION_NUM_ELEMENTS_PER_SCREEN; + int total_elements = this->devices_list->numValidDevices - start; + if(total_elements > CONNECTION_NUM_ELEMENTS_PER_SCREEN) + total_elements = CONNECTION_NUM_ELEMENTS_PER_SCREEN; + for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { + this->future_data.enabled_labels[i] = false; + this->labels[i]->setShowText(false); + } + for(int i = 0; i < total_elements; i++) { + this->future_data.enabled_labels[i] = true; + this->labels[i]->setText(std::string(&this->devices_list->serialNumbers[SERIAL_NUMBER_SIZE * (i + start)])); + this->labels[i]->setShowText(true); + } + if(num_pages > 1) { + this->future_data.enabled_labels[CONNECTION_INFO_PAGES_ID] = true; + this->labels[CONNECTION_INFO_PAGES_ID]->setText(std::to_string(this->future_data.page + 1) + "/" + std::to_string(num_pages)); + this->labels[CONNECTION_INFO_PAGES_ID]->setShowText(true); + if(this->future_data.page > 0) { + this->future_data.enabled_labels[CONNECTION_PREV_PAGE_ID] = true; + this->labels[CONNECTION_PREV_PAGE_ID]->setText("<"); + this->labels[CONNECTION_PREV_PAGE_ID]->setShowText(true); + } + if(this->future_data.page < (num_pages - 1)) { + this->future_data.enabled_labels[CONNECTION_NEXT_PAGE_ID] = true; + this->labels[CONNECTION_NEXT_PAGE_ID]->setText(">"); + this->labels[CONNECTION_NEXT_PAGE_ID]->setShowText(true); + } + } + if(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])) { + this->future_data.option_selected = -1; + } +} + +void ConnectionMenu::option_selection_handling() { + int old_loaded_page = this->future_data.page; + if(!(this->selectable_labels[this->future_data.option_selected] && this->future_data.enabled_labels[this->future_data.option_selected])) { + this->future_data.option_selected = -1; + return; + } + if(!this->can_execute_action()) + return; + if(this->future_data.option_selected < CONNECTION_NUM_ELEMENTS_PER_SCREEN) { + this->selected_index = this->future_data.option_selected + (CONNECTION_NUM_ELEMENTS_PER_SCREEN * this->future_data.page); + this->last_action_time = std::chrono::high_resolution_clock::now(); + } + else if((this->future_data.option_selected == CONNECTION_PREV_PAGE_ID) && this->future_data.page > 0) + this->future_data.page--; + else if((this->future_data.option_selected == CONNECTION_NEXT_PAGE_ID) && this->future_data.page < ((this->devices_list->numValidDevices - 1) / CONNECTION_NUM_ELEMENTS_PER_SCREEN)) + this->future_data.page++; + if(old_loaded_page != this->future_data.page) { + this->prepare_options(); + this->last_action_time = std::chrono::high_resolution_clock::now(); + } +} + +void ConnectionMenu::up_code() { + if(!this->can_execute_action()) + return; + this->decrement_selected_option(); + this->last_action_time = std::chrono::high_resolution_clock::now(); +} + +void ConnectionMenu::down_code() { + if(!this->can_execute_action()) + return; + this->increment_selected_option(); + this->last_action_time = std::chrono::high_resolution_clock::now(); +} + +void ConnectionMenu::left_code() { + if(!this->can_execute_action()) + return; + if(this->selectable_labels[CONNECTION_PREV_PAGE_ID] && this->future_data.enabled_labels[CONNECTION_PREV_PAGE_ID]) { + if(this->future_data.option_selected == CONNECTION_PREV_PAGE_ID) + this->option_selection_handling(); + else { + this->future_data.option_selected = CONNECTION_PREV_PAGE_ID; + this->last_action_time = std::chrono::high_resolution_clock::now(); + } + } +} + +void ConnectionMenu::right_code() { + if(!this->can_execute_action()) + return; + if(this->selectable_labels[CONNECTION_NEXT_PAGE_ID] && this->future_data.enabled_labels[CONNECTION_NEXT_PAGE_ID]) { + if(this->future_data.option_selected == CONNECTION_NEXT_PAGE_ID) + this->option_selection_handling(); + else { + this->future_data.option_selected = CONNECTION_NEXT_PAGE_ID; + this->last_action_time = std::chrono::high_resolution_clock::now(); + } + } +} + +bool ConnectionMenu::poll(SFEvent &event_data) { + bool consumed = true; + switch (event_data.type) { + case sf::Event::TextEntered: + switch (event_data.unicode) { + default: + consumed = false; + break; + } + + break; + + case sf::Event::KeyPressed: + switch (event_data.code) { + case sf::Keyboard::Up: + this->up_code(); + break; + case sf::Keyboard::Down: + this->down_code(); + break; + case sf::Keyboard::PageUp: + this->up_code(); + break; + case sf::Keyboard::PageDown: + this->down_code(); + break; + case sf::Keyboard::Left: + this->left_code(); + break; + case sf::Keyboard::Right: + this->right_code(); + break; + case sf::Keyboard::Enter: + this->option_selection_handling(); + break; + default: + consumed = false; + break; + } + + break; + case sf::Event::MouseMoved: + this->future_data.option_selected = -1; + for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { + if(!(this->selectable_labels[i] && this->future_data.enabled_labels[i])) + continue; + if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) { + this->future_data.option_selected = i; + break; + } + } + break; + case sf::Event::MouseButtonPressed: + this->future_data.option_selected = -1; + for(int i = 0; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { + if(!(this->selectable_labels[i] && this->future_data.enabled_labels[i])) + continue; + if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) { + this->future_data.option_selected = i; + break; + } + } + if(this->future_data.option_selected == -1) + break; + if(event_data.mouse_button == sf::Mouse::Left) + this->option_selection_handling(); + break; + case sf::Event::JoystickButtonPressed: + switch(get_joystick_action(event_data.joystickId, event_data.joy_button)) { + case JOY_ACTION_CONFIRM: + this->option_selection_handling(); + break; + case JOY_ACTION_NEGATE: + this->option_selection_handling(); + break; + default: + consumed = false; + break; + } + break; + case sf::Event::JoystickMoved: + switch(get_joystick_direction(event_data.joystickId, event_data.axis, event_data.position)) { + case JOY_DIR_UP: + this->up_code(); + break; + case JOY_DIR_DOWN: + this->down_code(); + break; + case JOY_DIR_LEFT: + this->left_code(); + break; + case JOY_DIR_RIGHT: + this->right_code(); + break; + default: + consumed = false; + break; + } + break; + default: + consumed = false; + break; + } + return consumed; +} + +void ConnectionMenu::draw(float scaling_factor, sf::RenderTarget &window) { + sf::RectangleShape menu_rectangle(sf::Vector2f(this->loaded_data.menu_width, this->loaded_data.menu_height)); + menu_rectangle.setFillColor(sf::Color(30, 30, 60, 192)); + menu_rectangle.setPosition(this->loaded_data.pos_x, this->loaded_data.pos_y); + window.draw(menu_rectangle); + for(int i = 0; i < CONNECTION_NUM_ELEMENTS_PER_SCREEN; i++) { + if(this->loaded_data.enabled_labels[i]) + this->labels[i]->draw(window); + } + for(int i = CONNECTION_NUM_ELEMENTS_PER_SCREEN; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { + if(this->loaded_data.enabled_labels[i]) + this->labels[i]->draw(window); + } +} + +void ConnectionMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y) { + int num_elements = 1; + for(int i = 1; i < CONNECTION_NUM_ELEMENTS_PER_SCREEN; i++) + if(this->future_data.enabled_labels[i]) + num_elements++; + bool has_bottom = false; + for(int i = CONNECTION_NUM_ELEMENTS_PER_SCREEN; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) + if(this->future_data.enabled_labels[i]) + has_bottom = true; + if(has_bottom) + num_elements += 1; + const float base_height = ((CONNECTION_NUM_ELEMENTS_PER_SCREEN + 1) * (BASE_PIXEL_FONT_HEIGHT * 8)) / 6; + int max_width = (view_size_x * 9) / 10; + int max_height = (view_size_y * 9) / 10; + float max_scaling_factor = max_height / base_height; + if(menu_scaling_factor > max_scaling_factor) + menu_scaling_factor = max_scaling_factor; + if(menu_scaling_factor < 0.3) + menu_scaling_factor = 0.3; + int num_elements_text_scaling_factor = num_elements; + if(num_elements_text_scaling_factor < 3) + num_elements_text_scaling_factor = 3; + float text_scaling_factor = (menu_scaling_factor * (CONNECTION_NUM_ELEMENTS_PER_SCREEN + 1)) / num_elements_text_scaling_factor; + int menu_height = base_height * menu_scaling_factor; + int menu_width = (menu_height * 16) / 9; + if(menu_width > max_width) + menu_width = max_width; + int pos_x = (view_size_x - menu_width) / 2; + int pos_y = (view_size_y - menu_height) / 2; + int slice_y_size = menu_height / num_elements; + int slice_x_size = menu_width / (CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - CONNECTION_NUM_ELEMENTS_PER_SCREEN); + for(int i = 0; i < CONNECTION_NUM_ELEMENTS_PER_SCREEN; i++) { + if(!this->future_data.enabled_labels[i]) + continue; + this->labels[i]->setTextFactor(text_scaling_factor); + this->labels[i]->setSize(menu_width, slice_y_size); + this->labels[i]->setPosition(pos_x, pos_y + (slice_y_size * i)); + if(i == this->future_data.option_selected) + this->labels[i]->setRectangleKind(TEXT_KIND_SELECTED); + else + this->labels[i]->setRectangleKind(TEXT_KIND_NORMAL); + this->labels[i]->prepareRenderText(); + } + for(int i = CONNECTION_NUM_ELEMENTS_PER_SCREEN; i < CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN; i++) { + if(!this->future_data.enabled_labels[i]) + continue; + this->labels[i]->setTextFactor(text_scaling_factor); + int x_size = slice_x_size; + if(i == (CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - 1)) + x_size = menu_width - (slice_x_size * (CONNECTION_NUM_ELEMENTS_DISPLAYED_PER_SCREEN - CONNECTION_NUM_ELEMENTS_PER_SCREEN - 1)); + this->labels[i]->setSize(x_size, menu_height - (slice_y_size * (num_elements - 1))); + this->labels[i]->setPosition(pos_x + (slice_x_size * (i - CONNECTION_NUM_ELEMENTS_PER_SCREEN)), pos_y + (slice_y_size * (num_elements - 1))); + if(i == this->future_data.option_selected) + this->labels[i]->setRectangleKind(TEXT_KIND_SELECTED); + else + this->labels[i]->setRectangleKind(TEXT_KIND_NORMAL); + this->labels[i]->prepareRenderText(); + } + this->loaded_data = this->future_data; +} diff --git a/source/TextRectangle.cpp b/source/TextRectangle.cpp index 098c3f4..a864d45 100755 --- a/source/TextRectangle.cpp +++ b/source/TextRectangle.cpp @@ -1,6 +1,4 @@ -#include "frontend.hpp" - -#define BASE_PIXEL_FONT_HEIGHT 24 +#include "TextRectangle.hpp" TextRectangle::TextRectangle(bool font_load_success, sf::Font &text_font) { this->font_load_success = font_load_success; @@ -26,11 +24,11 @@ TextRectangle::~TextRectangle() { } void TextRectangle::setSize(int width, int height) { - this->width = width; - this->height = height; - this->text_rect.out_rect.setSize(sf::Vector2f(this->width, this->height)); - this->text_rect.out_tex.create(this->width, this->height); - this->text_rect.out_rect.setTextureRect(sf::IntRect(0, 0, this->width, this->height)); + if((height == this->future_data.height) && (width == this->future_data.width)) + return; + this->future_data.width = width; + this->future_data.height = height; + this->future_data.render_text = true; } void TextRectangle::setRectangleKind(TextKind kind) { @@ -42,13 +40,35 @@ void TextRectangle::setRectangleKind(TextKind kind) { void TextRectangle::setTextFactor(float size_multiplier) { int new_pixel_height = BASE_PIXEL_FONT_HEIGHT * size_multiplier; + if(this->future_data.font_pixel_height == new_pixel_height) + return; this->future_data.font_pixel_height = new_pixel_height; + this->future_data.render_text = true; } void TextRectangle::setDuration(float on_seconds) { this->future_data.duration = on_seconds; } +void TextRectangle::setPosition(int pos_x, int pos_y) { + this->future_data.pos_x = pos_x; + this->future_data.pos_y = pos_y; +} + +bool TextRectangle::isCoordInRectangle(int coord_x, int coord_y) { + if(!(font_load_success && this->future_data.show_text && (!this->is_done_showing_text))) + return false; + if(coord_x < this->future_data.pos_x) + return false; + if(coord_y < this->future_data.pos_y) + return false; + if(coord_x >= this->future_data.pos_x + this->future_data.width) + return false; + if(coord_y >= this->future_data.pos_y + this->future_data.height) + return false; + return true; +} + void TextRectangle::startTimer(bool do_start) { this->future_data.start_timer = do_start; this->future_data.is_timed = do_start; @@ -62,6 +82,10 @@ void TextRectangle::setProportionalBox(bool proportional_box) { } void TextRectangle::prepareRenderText() { + if(this->loaded_data.proportional_box) { + this->future_data.width = this->loaded_data.width; + this->future_data.height = this->loaded_data.height; + } this->loaded_data = this->future_data; this->future_data.render_text = false; this->future_data.start_timer = false; @@ -83,6 +107,7 @@ void TextRectangle::draw(sf::RenderTarget &window) { this->updateText(window.getView().getSize().x); } if(font_load_success && this->loaded_data.show_text && (!this->is_done_showing_text)) { + this->text_rect.out_rect.setPosition(this->loaded_data.pos_x, this->loaded_data.pos_y); if(this->loaded_data.is_timed) { float time_seconds[3]; this->updateSlides(time_seconds); @@ -102,10 +127,10 @@ void TextRectangle::draw(sf::RenderTarget &window) { int rect_curr_height = 0; if(this->time_phase == 0) - rect_curr_height = -this->height + ((int)(factor * this->height)); + rect_curr_height = -this->loaded_data.height + ((int)(factor * this->loaded_data.height)); else if(this->time_phase == 2) - rect_curr_height = ((int)(factor * this->height)) * -1; - this->text_rect.out_rect.setPosition(0, rect_curr_height); + rect_curr_height = ((int)(factor * this->loaded_data.height)) * -1; + this->text_rect.out_rect.setPosition(this->loaded_data.pos_x, this->loaded_data.pos_y + rect_curr_height); if(factor >= 1) { this->time_phase++; @@ -128,6 +153,8 @@ void TextRectangle::reset_data(TextData &data) { data.printed_text = "Sample Text"; data.duration = 2.5; data.font_pixel_height = BASE_PIXEL_FONT_HEIGHT; + data.pos_x = 0; + data.pos_y = 0; } void TextRectangle::setTextWithLineWrapping(int x_limit) { @@ -165,6 +192,16 @@ void TextRectangle::setTextWithLineWrapping(int x_limit) { this->actual_text.setString(new_text); } +void TextRectangle::setRealSize(int width, int height) { + this->loaded_data.width = width; + this->loaded_data.height = height; + if((height == this->text_rect.out_rect.getSize().y) && (width == this->text_rect.out_rect.getSize().x)) + return; + this->text_rect.out_rect.setSize(sf::Vector2f(this->loaded_data.width, this->loaded_data.height)); + this->text_rect.out_tex.create(this->loaded_data.width, this->loaded_data.height); + this->text_rect.out_rect.setTextureRect(sf::IntRect(0, 0, this->loaded_data.width, this->loaded_data.height)); +} + void TextRectangle::updateText(int x_limit) { // set the character size this->actual_text.setCharacterSize(this->loaded_data.font_pixel_height); // in pixels, not points! @@ -173,26 +210,27 @@ void TextRectangle::updateText(int x_limit) { // set the text style //this->actual_text.setStyle(sf::Text::Bold); this->setTextWithLineWrapping(x_limit); - sf::FloatRect globalBounds = this->actual_text.getGlobalBounds(); - int new_width = this->width; - int new_height = this->height; - int bounds_width = globalBounds.width + (globalBounds.left * 2); - int bounds_height = globalBounds.height + (globalBounds.top * 2); - if(new_width < bounds_width) - new_width = bounds_width; - if(new_height < bounds_height) - new_height = bounds_height; - if((new_width != this->width) || (new_height != this->height)) - this->setSize(new_width, new_height); + sf::FloatRect globalBounds; if(this->loaded_data.proportional_box) { + globalBounds = this->actual_text.getGlobalBounds(); + int new_width = this->loaded_data.width; + int new_height = this->loaded_data.height; + int bounds_width = globalBounds.width + (globalBounds.left * 2); + int bounds_height = globalBounds.height + (globalBounds.top * 2); + if(new_width < bounds_width) + new_width = bounds_width; + if(new_height < bounds_height) + new_height = bounds_height; + this->setRealSize(new_width, new_height); this->actual_text.setPosition((int)(5 * (((float)this->loaded_data.font_pixel_height) / BASE_PIXEL_FONT_HEIGHT)), 0); globalBounds = this->actual_text.getGlobalBounds(); - this->setSize(globalBounds.width + (globalBounds.left * 2), globalBounds.height + (globalBounds.top * 2)); + this->setRealSize(globalBounds.width + (globalBounds.left * 2), globalBounds.height + (globalBounds.top * 2)); } else { + this->setRealSize(this->loaded_data.width, this->loaded_data.height); this->actual_text.setPosition(0, 0); globalBounds = this->actual_text.getGlobalBounds(); - this->actual_text.setPosition((new_width - (globalBounds.width + (globalBounds.left * 4))) / 2, (new_height - (globalBounds.height + (globalBounds.top * 4))) / 2); + this->actual_text.setPosition((int)((this->loaded_data.width - (globalBounds.width + (globalBounds.left * 2))) / 2), (int)((this->loaded_data.height - (globalBounds.height + (globalBounds.top * 2))) / 2)); } sf::Color *used_color = this->base_bg_color; switch(this->loaded_data.kind) { @@ -219,7 +257,7 @@ void TextRectangle::updateText(int x_limit) { } void TextRectangle::updateSlides(float* time_seconds) { - time_seconds[0] = base_time_slide_factor * (this->height / (loaded_data.font_pixel_height * base_pixel_slide_factor)); + time_seconds[0] = base_time_slide_factor * (this->loaded_data.height / (loaded_data.font_pixel_height * base_pixel_slide_factor)); time_seconds[1] = loaded_data.duration; - time_seconds[2] = base_time_slide_factor * (this->height / (loaded_data.font_pixel_height * base_pixel_slide_factor)); + time_seconds[2] = base_time_slide_factor * (this->loaded_data.height / (loaded_data.font_pixel_height * base_pixel_slide_factor)); } diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index 01016ec..111f0b3 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -26,6 +26,7 @@ WindowScreen::WindowScreen(WindowScreen::ScreenType stype, DisplayData* display_ reset_screen_info(this->m_info); this->font_load_success = this->text_font.loadFromMemory(font_ttf, font_ttf_len); this->notification = new TextRectangle(this->font_load_success, this->text_font); + this->connection_menu = new ConnectionMenu(this->font_load_success, this->text_font); this->in_tex.create(IN_VIDEO_WIDTH, IN_VIDEO_HEIGHT); this->m_in_rect_top.setTexture(&this->in_tex); this->m_in_rect_bot.setTexture(&this->in_tex); @@ -43,7 +44,8 @@ WindowScreen::WindowScreen(WindowScreen::ScreenType stype, DisplayData* display_ WindowScreen::~WindowScreen() { delete this->saved_buf; - this->saved_buf = NULL; + delete this->notification; + delete this->connection_menu; } void WindowScreen::build() { @@ -383,6 +385,8 @@ bool WindowScreen::main_poll(SFEvent &event_data) { } void WindowScreen::poll() { + if(this->close_capture()) + return; if(this->m_info.is_fullscreen && this->m_info.show_mouse) { auto curr_time = std::chrono::high_resolution_clock::now(); const std::chrono::duration diff = curr_time - this->last_mouse_action_time; @@ -393,14 +397,22 @@ void WindowScreen::poll() { while(!events_queue.empty()) { SFEvent event_data = events_queue.front(); events_queue.pop(); - if(this->common_poll(event_data)) + if(this->common_poll(event_data)) { + if(this->close_capture()) + return; continue; - switch(this->display_data->curr_menu) { + } + switch(this->loaded_menu) { case DEFAULT_MENU_TYPE: if(this->main_poll(event_data)) continue; break; case CONNECT_MENU_TYPE: + if(this->connection_menu->poll(event_data)) { + if(this->check_connection_menu_result() != -1) + return; + continue; + } break; default: break; @@ -468,6 +480,7 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { else this->open(); } + this->loaded_menu = this->display_data->curr_menu; loaded_operations = future_operations; if(this->m_win.isOpen() || this->loaded_operations.call_create) { WindowScreen::reset_operations(future_operations); @@ -480,6 +493,15 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { this->notification->prepareRenderText(); this->frame_time = frame_time; this->scheduled_work_on_window = this->window_needs_work(); + if(this->loaded_menu == CONNECT_MENU_TYPE) { + int view_size_x = this->m_window_width; + int view_size_y = this->m_window_height; + if(!this->loaded_info.is_fullscreen) { + view_size_x = this->m_width; + view_size_y = this->m_height; + } + this->connection_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y); + } this->is_window_factory_done = false; this->is_thread_done = false; this->done_display = false; @@ -493,6 +515,19 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { } } +void WindowScreen::setup_connection_menu(DevicesList *devices_list) { + this->display_data->curr_menu = CONNECT_MENU_TYPE; + this->connection_menu->insert_data(devices_list); +} + +int WindowScreen::check_connection_menu_result() { + return this->connection_menu->selected_index; +} + +void WindowScreen::end_connection_menu() { + this->display_data->curr_menu = DEFAULT_MENU_TYPE; +} + void WindowScreen::print_notification(std::string text, TextKind kind) { this->notification->setText(text); this->notification->setRectangleKind(kind); @@ -611,8 +646,10 @@ void WindowScreen::poll_window() { mouse_x = event.mouseMove.x; mouse_y = event.mouseMove.y; } - events_queue.emplace(event.type, event.key.code, event.text.unicode, joystickId, event.joystickButton.button, event.joystickMove.axis, event.joystickMove.position, event.mouseButton.button, mouse_x, mouse_y); + events_queue.emplace(event.type, event.key.code, event.text.unicode, joystickId, event.joystickButton.button, event.joystickMove.axis, 0.0, event.mouseButton.button, mouse_x, mouse_y); } + if(this->m_win.hasFocus()) + joystick_axis_poll(this->events_queue); this->events_access->unlock(); } } @@ -690,6 +727,8 @@ void WindowScreen::window_factory(bool is_main_thread) { } void WindowScreen::pre_texture_conversion_processing() { + if(this->loaded_menu != DEFAULT_MENU_TYPE) + return; //Place preprocessing window-specific effects here this->in_tex.update((uint8_t*)this->saved_buf, IN_VIDEO_WIDTH, IN_VIDEO_HEIGHT, 0, 0); } @@ -697,6 +736,8 @@ void WindowScreen::pre_texture_conversion_processing() { void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top) { if((is_top && this->m_stype == WindowScreen::ScreenType::BOTTOM) || ((!is_top) && this->m_stype == WindowScreen::ScreenType::TOP)) return; + if(this->loaded_menu != DEFAULT_MENU_TYPE) + return; rect_data.out_tex.clear(); if(actually_draw) { @@ -716,10 +757,19 @@ void WindowScreen::display_data_to_window(bool actually_draw) { this->m_win.clear(); this->window_bg_processing(); - if(this->m_stype != WindowScreen::ScreenType::BOTTOM) - this->m_win.draw(this->m_out_rect_top.out_rect); - if(this->m_stype != WindowScreen::ScreenType::TOP) - this->m_win.draw(this->m_out_rect_bot.out_rect); + switch(this->loaded_menu) { + case DEFAULT_MENU_TYPE: + if(this->m_stype != WindowScreen::ScreenType::BOTTOM) + this->m_win.draw(this->m_out_rect_top.out_rect); + if(this->m_stype != WindowScreen::ScreenType::TOP) + this->m_win.draw(this->m_out_rect_bot.out_rect); + break; + case CONNECT_MENU_TYPE: + this->connection_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win); + break; + default: + break; + } this->notification->draw(this->m_win); this->m_win.display(); } @@ -752,7 +802,7 @@ int WindowScreen::apply_offset_algo(int offset_contribute, OffsetAlgorithm chose } } -void WindowScreen::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) { +void WindowScreen::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, bool do_work) { int top_screen_x = 0, top_screen_y = 0; int bot_screen_x = 0, bot_screen_y = 0; int top_screen_width = curr_top_screen_size.x; @@ -815,8 +865,10 @@ void WindowScreen::set_position_screens(sf::Vector2f &curr_top_screen_size, sf:: break; } } - this->m_out_rect_top.out_rect.setPosition(top_screen_x + offset_x + get_screen_corner_modifier_x(this->loaded_info.top_rotation, top_screen_width), top_screen_y + offset_y + get_screen_corner_modifier_y(this->loaded_info.top_rotation, top_screen_height)); - this->m_out_rect_bot.out_rect.setPosition(bot_screen_x + offset_x + get_screen_corner_modifier_x(this->loaded_info.bot_rotation, bot_screen_width), bot_screen_y + offset_y + get_screen_corner_modifier_y(this->loaded_info.bot_rotation, bot_screen_height)); + if(do_work) { + this->m_out_rect_top.out_rect.setPosition(top_screen_x + offset_x + get_screen_corner_modifier_x(this->loaded_info.top_rotation, top_screen_width), top_screen_y + offset_y + get_screen_corner_modifier_y(this->loaded_info.top_rotation, top_screen_height)); + this->m_out_rect_bot.out_rect.setPosition(bot_screen_x + offset_x + get_screen_corner_modifier_x(this->loaded_info.bot_rotation, bot_screen_width), bot_screen_y + offset_y + get_screen_corner_modifier_y(this->loaded_info.bot_rotation, bot_screen_height)); + } int top_end_x = top_screen_x + offset_x + top_screen_width; int top_end_y = top_screen_y + offset_y + top_screen_height; @@ -960,7 +1012,7 @@ int WindowScreen::get_fullscreen_offset_y(int top_width, int top_height, int bot return apply_offset_algo(curr_desk_mode.height - offset_contribute, this->loaded_info.total_offset_algorithm_y); } -void WindowScreen::resize_window_and_out_rects() { +void WindowScreen::resize_window_and_out_rects(bool do_work) { sf::Vector2f top_screen_size = getShownScreenSize(true, this->loaded_info.crop_kind); sf::Vector2f bot_screen_size = getShownScreenSize(false, this->loaded_info.crop_kind); int top_height = this->loaded_info.scaling * top_screen_size.y; @@ -984,11 +1036,13 @@ void WindowScreen::resize_window_and_out_rects() { } sf::Vector2f new_top_screen_size = sf::Vector2f(top_width, top_height); sf::Vector2f new_bot_screen_size = sf::Vector2f(bot_width, bot_height); - this->m_out_rect_top.out_rect.setSize(new_top_screen_size); - this->m_out_rect_top.out_rect.setTextureRect(sf::IntRect(0, 0, top_screen_size.x, top_screen_size.y)); - this->m_out_rect_bot.out_rect.setSize(new_bot_screen_size); - this->m_out_rect_bot.out_rect.setTextureRect(sf::IntRect(0, 0, bot_screen_size.x, bot_screen_size.y)); - this->set_position_screens(new_top_screen_size, new_bot_screen_size, offset_x, offset_y, max_x, max_y); + if(do_work) { + this->m_out_rect_top.out_rect.setSize(new_top_screen_size); + this->m_out_rect_top.out_rect.setTextureRect(sf::IntRect(0, 0, top_screen_size.x, top_screen_size.y)); + this->m_out_rect_bot.out_rect.setSize(new_bot_screen_size); + this->m_out_rect_bot.out_rect.setTextureRect(sf::IntRect(0, 0, bot_screen_size.x, bot_screen_size.y)); + } + this->set_position_screens(new_top_screen_size, new_bot_screen_size, offset_x, offset_y, max_x, max_y, do_work); } void WindowScreen::create_window(bool re_prepare_size) { diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index ca93f0a..04d56f9 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -179,7 +179,7 @@ void soundCall(AudioData *audio_data, CaptureData* capture_data) { else { audio.stop_audio(); audio.stop(); - sf::sleep(sf::milliseconds(1000/USB_CHECKS_PER_SECOND)); + default_sleep(); } } @@ -282,7 +282,7 @@ void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data) { num_elements_fps_array++; if(num_elements_fps_array >= (2 * FPS_WINDOW_SIZE)) num_elements_fps_array -= FPS_WINDOW_SIZE; - sf::sleep(sf::milliseconds(1000/USB_CHECKS_PER_SECOND)); + default_sleep(); } int available_fps = FPS_WINDOW_SIZE; diff --git a/source/frontend.cpp b/source/frontend.cpp index 3428f22..d80744e 100755 --- a/source/frontend.cpp +++ b/source/frontend.cpp @@ -1,4 +1,5 @@ #include "frontend.hpp" +#include void reset_screen_info(ScreenInfo &info) { info.is_blurred = false; @@ -139,6 +140,55 @@ std::string save_screen_info(std::string base, const ScreenInfo &info) { return out; } +void joystick_axis_poll(std::queue &events_queue) { + for(int i = 0; i < sf::Joystick::Count; i++) { + if(!sf::Joystick::isConnected(i)) + continue; + for(int j = 0; j < sf::Joystick::AxisCount; j++) { + sf::Joystick::Axis axis = sf::Joystick::Axis(sf::Joystick::Axis::X + j); + if(sf::Joystick::hasAxis(i, axis)) + events_queue.emplace(sf::Event::JoystickMoved, sf::Keyboard::Backspace, 0, i, 0, axis, sf::Joystick::getAxisPosition(i, axis), sf::Mouse::Left, 0, 0); + } + } +} + +JoystickDirection get_joystick_direction(uint32_t joystickId, sf::Joystick::Axis axis, float position) { + bool is_horizontal = false; + if((axis == sf::Joystick::Z) || (axis == sf::Joystick::R)) + return JOY_DIR_NONE; + if((axis == sf::Joystick::X) || (axis == sf::Joystick::U) || (axis == sf::Joystick::PovX)) + is_horizontal = true; + int direction = 0; + if(position >= 90.0) + direction = 1; + if(position <= -90.0) + direction = -1; + if(direction == 0) + return JOY_DIR_NONE; + if(direction > 0) { + if(is_horizontal) + return JOY_DIR_RIGHT; + return JOY_DIR_DOWN; + } + if(is_horizontal) + return JOY_DIR_LEFT; + return JOY_DIR_UP; +} + +JoystickAction get_joystick_action(uint32_t joystickId, uint32_t joy_button) { + sf::Joystick::Identification joystick_data = sf::Joystick::getIdentification(joystickId); + std::cout << std::string(joystick_data.name) << ": " << joystick_data.vendorId << " - " << joystick_data.productId << std::endl; + if((joy_button == 0) || (joy_button == 1)) + return JOY_ACTION_CONFIRM; + if((joy_button == 2) || (joy_button == 3)) + return JOY_ACTION_NEGATE; + return JOY_ACTION_NONE; +} + +void default_sleep() { + sf::sleep(sf::milliseconds(1000/USB_CHECKS_PER_SECOND)); +} + void update_output(FrontendData* frontend_data, double frame_time, VideoOutputData *out_buf) { if(frontend_data->reload) { frontend_data->top_screen->reload();