diff --git a/.github/workflows/cd_main.yml b/.github/workflows/cd_main.yml index 5a226fd..aaba876 100644 --- a/.github/workflows/cd_main.yml +++ b/.github/workflows/cd_main.yml @@ -16,9 +16,9 @@ jobs: fail-fast: false matrix: platform: - - { name: Windows VS2022 x64, os: windows-2022, flags: -A x64, artifact_name: win64} - - { name: Windows VS2022 ARM, os: windows-2022, flags: -A ARM64, artifact_name: winarm64} - - { name: Windows VS2022 Win32, os: windows-2022, flags: -A Win32, artifact_name: win32} + - { name: Windows VS2022 x64, os: windows-2022, flags: -A x64 -DCMAKE_PARALLEL_MSVC=TRUE, artifact_name: win64} + - { name: Windows VS2022 ARM, os: windows-2022, flags: -A ARM64 -DCMAKE_PARALLEL_MSVC=TRUE, artifact_name: winarm64} + - { name: Windows VS2022 Win32, os: windows-2022, flags: -A Win32 -DCMAKE_PARALLEL_MSVC=TRUE, artifact_name: win32} - { name: Linux GCC x64, os: ubuntu-latest, flags: 64, artifact_name: linux64} - { name: Linux GCC 32, os: ubuntu-latest, flags: 32, artifact_name: linux32} - { name: Linux GCC ARM 64, os: ubuntu-latest, flags: arm64, artifact_name: linuxarm64} diff --git a/CMakeLists.txt b/CMakeLists.txt index ea48e0b..df5e123 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,25 @@ cmake_minimum_required(VERSION 3.16) set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "Build archs for Mac OS X" FORCE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") +set(CMAKE_PARALLEL_MSVC FALSE CACHE BOOL "Enables parallel compilation with MSVC") + +#Workaround due to cmake parallel being broken, and needing to set these +#flags before the project is defined... +if(${CMAKE_PARALLEL_MSVC}) + message("Parallel build MSVC configuration") + set(CMAKE_C_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} /MP") + set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /MP") +endif() + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) set(TARGET_LANGUAGES CXX C) project(cc3dsfs VERSION 1.0.0 LANGUAGES ${TARGET_LANGUAGES}) include(ExternalProject) +if((${CMAKE_PARALLEL_MSVC}) AND (NOT (MSVC))) + message(FATAL_ERROR "Parallel build option specific to MSVC used with wrong compiler!") +endif() + set(N3DSXL_LOOPY_SUPPORT 1) set(NEW_DS_LOOPY_SUPPORT 1) set(IS_DEVICES_SUPPORT 1) @@ -57,6 +71,7 @@ else() list(APPEND EXTRA_CXX_FLAGS "-Wno-ignored-qualifiers") list(APPEND EXTRA_CXX_FLAGS "-Wno-missing-field-initializers") endif() + set(RASPBERRY_PI_COMPILATION FALSE CACHE BOOL "Option for compiling the Raspberry Pi GPIO library in") set(SFML_BUILD_NETWORK FALSE) set(EXTRA_LIBRARIES "") @@ -532,7 +547,7 @@ else() set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$:-O3;-funroll-loops>") 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 source/Menus/Main3DMenu.cpp source/Menus/SecondScreen3DRelativePositionMenu.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/TextRectanglePool.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 "")) add_dependencies(${OUTPUT_NAME} ${EXTRA_DEPENDENCIES}) diff --git a/include/Menus/ActionSelectionMenu.hpp b/include/Menus/ActionSelectionMenu.hpp index cd98a6b..c4b0a61 100755 --- a/include/Menus/ActionSelectionMenu.hpp +++ b/include/Menus/ActionSelectionMenu.hpp @@ -14,7 +14,7 @@ class ActionSelectionMenu : public OptionSelectionMenu { public: - ActionSelectionMenu(bool font_load_success, sf::Font &text_font); + ActionSelectionMenu(TextRectanglePool* text_pool); ~ActionSelectionMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, PossibleWindowCommands curr_cmd); void insert_data(std::vector &possible_actions); diff --git a/include/Menus/AudioDeviceMenu.hpp b/include/Menus/AudioDeviceMenu.hpp index 42ea2f4..d7fd5e4 100644 --- a/include/Menus/AudioDeviceMenu.hpp +++ b/include/Menus/AudioDeviceMenu.hpp @@ -14,7 +14,7 @@ class AudioDeviceMenu : public OptionSelectionMenu { public: - AudioDeviceMenu(bool font_load_success, sf::Font &text_font); + AudioDeviceMenu(TextRectanglePool* text_pool); ~AudioDeviceMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, const audio_output_device_data curr_device_data); void insert_data(std::vector* possible_devices); diff --git a/include/Menus/AudioMenu.hpp b/include/Menus/AudioMenu.hpp index 2aabdf3..163760e 100755 --- a/include/Menus/AudioMenu.hpp +++ b/include/Menus/AudioMenu.hpp @@ -26,7 +26,7 @@ enum AudioMenuOutAction{ class AudioMenu : public OptionSelectionMenu { public: - AudioMenu(bool font_load_success, sf::Font &text_font); + AudioMenu(TextRectanglePool* text_pool); ~AudioMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, AudioData *audio_data); void insert_data(); diff --git a/include/Menus/BFIMenu.hpp b/include/Menus/BFIMenu.hpp index c5dfcf1..9c25565 100755 --- a/include/Menus/BFIMenu.hpp +++ b/include/Menus/BFIMenu.hpp @@ -20,7 +20,7 @@ enum BFIMenuOutAction{ class BFIMenu : public OptionSelectionMenu { public: - BFIMenu(bool font_load_success, sf::Font &text_font); + BFIMenu(TextRectanglePool* text_pool); ~BFIMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info); void insert_data(); diff --git a/include/Menus/ColorCorrectionMenu.hpp b/include/Menus/ColorCorrectionMenu.hpp index bace70f..9732905 100644 --- a/include/Menus/ColorCorrectionMenu.hpp +++ b/include/Menus/ColorCorrectionMenu.hpp @@ -13,7 +13,7 @@ class ColorCorrectionMenu : public OptionSelectionMenu { public: - ColorCorrectionMenu(bool font_load_success, sf::Font &text_font); + ColorCorrectionMenu(TextRectanglePool* text_pool); ~ColorCorrectionMenu(); void setup_title(std::string added_name); void prepare(float scaling_factor, int view_size_x, int view_size_y, int current_crop); diff --git a/include/Menus/ConnectionMenu.hpp b/include/Menus/ConnectionMenu.hpp index f29a404..f6a0509 100755 --- a/include/Menus/ConnectionMenu.hpp +++ b/include/Menus/ConnectionMenu.hpp @@ -9,7 +9,7 @@ class ConnectionMenu : public OptionSelectionMenu { public: - ConnectionMenu(bool font_load_success, sf::Font &text_font); + ConnectionMenu(TextRectanglePool* text_pool); ~ConnectionMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y); void insert_data(std::vector *devices_list); diff --git a/include/Menus/CropMenu.hpp b/include/Menus/CropMenu.hpp index 17ed836..82e3744 100755 --- a/include/Menus/CropMenu.hpp +++ b/include/Menus/CropMenu.hpp @@ -13,7 +13,7 @@ class CropMenu : public OptionSelectionMenu { public: - CropMenu(bool font_load_success, sf::Font &text_font); + CropMenu(TextRectanglePool* text_pool); ~CropMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, int current_crop); void insert_data(std::vector* possible_crops); diff --git a/include/Menus/ExtraSettingsMenu.hpp b/include/Menus/ExtraSettingsMenu.hpp index 9749b66..c4673f4 100755 --- a/include/Menus/ExtraSettingsMenu.hpp +++ b/include/Menus/ExtraSettingsMenu.hpp @@ -18,7 +18,7 @@ enum ExtraSettingsMenuOutAction{ class ExtraSettingsMenu : public OptionSelectionMenu { public: - ExtraSettingsMenu(bool font_load_success, sf::Font &text_font); + ExtraSettingsMenu(TextRectanglePool* text_pool); ~ExtraSettingsMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y); void insert_data(ScreenType s_type, bool is_fullscreen); diff --git a/include/Menus/FileConfigMenu.hpp b/include/Menus/FileConfigMenu.hpp index e659c6b..992ccbe 100755 --- a/include/Menus/FileConfigMenu.hpp +++ b/include/Menus/FileConfigMenu.hpp @@ -18,7 +18,7 @@ struct FileData { class FileConfigMenu : public OptionSelectionMenu { public: - FileConfigMenu(bool font_load_success, sf::Font &text_font); + FileConfigMenu(TextRectanglePool* text_pool); ~FileConfigMenu(); void setup_title(std::string added_name); void prepare(float scaling_factor, int view_size_x, int view_size_y); diff --git a/include/Menus/ISNitroMenu.hpp b/include/Menus/ISNitroMenu.hpp index d805c89..7b17574 100644 --- a/include/Menus/ISNitroMenu.hpp +++ b/include/Menus/ISNitroMenu.hpp @@ -25,7 +25,7 @@ enum ISNitroMenuOutAction{ class ISNitroMenu : public OptionSelectionMenu { public: - ISNitroMenu(bool font_load_success, sf::Font &text_font); + ISNitroMenu(TextRectanglePool* text_pool); ~ISNitroMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, CaptureStatus* capture_status); void insert_data(CaptureDevice* device); diff --git a/include/Menus/InputMenu.hpp b/include/Menus/InputMenu.hpp index c8ace16..1e130e3 100644 --- a/include/Menus/InputMenu.hpp +++ b/include/Menus/InputMenu.hpp @@ -21,7 +21,7 @@ enum InputMenuOutAction{ class InputMenu : public OptionSelectionMenu { public: - InputMenu(bool font_load_success, sf::Font &text_font); + InputMenu(TextRectanglePool* text_pool); ~InputMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, InputData* input_data); void insert_data(bool enabled_shortcuts, bool enabled_extra_buttons); diff --git a/include/Menus/LicenseMenu.hpp b/include/Menus/LicenseMenu.hpp index 50a55e2..89785e0 100755 --- a/include/Menus/LicenseMenu.hpp +++ b/include/Menus/LicenseMenu.hpp @@ -15,7 +15,7 @@ enum LicenseMenuOutAction{ class LicenseMenu : public OptionSelectionMenu { public: - LicenseMenu(bool font_load_success, sf::Font &text_font); + LicenseMenu(TextRectanglePool* text_pool); ~LicenseMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y); void insert_data(); diff --git a/include/Menus/Main3DMenu.hpp b/include/Menus/Main3DMenu.hpp index 9cec1dc..225818b 100644 --- a/include/Menus/Main3DMenu.hpp +++ b/include/Menus/Main3DMenu.hpp @@ -24,7 +24,7 @@ enum Main3DMenuOutAction{ class Main3DMenu : public OptionSelectionMenu { public: - Main3DMenu(bool font_load_success, sf::Font &text_font); + Main3DMenu(TextRectanglePool* text_pool); ~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); diff --git a/include/Menus/MainMenu.hpp b/include/Menus/MainMenu.hpp index 8990321..abd02e6 100755 --- a/include/Menus/MainMenu.hpp +++ b/include/Menus/MainMenu.hpp @@ -32,7 +32,7 @@ enum MainMenuOutAction{ class MainMenu : public OptionSelectionMenu { public: - MainMenu(bool font_load_success, sf::Font &text_font); + MainMenu(TextRectanglePool* text_pool); ~MainMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, bool connected); void insert_data(ScreenType s_type, bool is_fullscreen, bool mono_app_mode, CaptureDevice* device, bool connected); diff --git a/include/Menus/OffsetMenu.hpp b/include/Menus/OffsetMenu.hpp index 5eafad1..815f202 100755 --- a/include/Menus/OffsetMenu.hpp +++ b/include/Menus/OffsetMenu.hpp @@ -23,7 +23,7 @@ enum OffsetMenuOutAction{ class OffsetMenu : public OptionSelectionMenu { public: - OffsetMenu(bool font_load_success, sf::Font &text_font); + OffsetMenu(TextRectanglePool* text_pool); ~OffsetMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info); void insert_data(); diff --git a/include/Menus/OptionSelectionMenu.hpp b/include/Menus/OptionSelectionMenu.hpp index c8f91a7..8c8831d 100755 --- a/include/Menus/OptionSelectionMenu.hpp +++ b/include/Menus/OptionSelectionMenu.hpp @@ -5,6 +5,7 @@ #include #include "TextRectangle.hpp" +#include "TextRectanglePool.hpp" #include "event_structs.hpp" #define BACK_X_OUTPUT_OPTION -1 @@ -50,7 +51,7 @@ protected: int single_option_multiplier; int get_num_pages(); - void initialize(bool font_load_success, sf::Font &text_font); + void initialize(TextRectanglePool* text_pool); void prepare_options(); void base_prepare(float menu_scaling_factor, int view_size_x, int view_size_y); std::string setTextOptionInt(int index, int value); diff --git a/include/Menus/PARMenu.hpp b/include/Menus/PARMenu.hpp index 049813c..5509060 100755 --- a/include/Menus/PARMenu.hpp +++ b/include/Menus/PARMenu.hpp @@ -13,7 +13,7 @@ class PARMenu : public OptionSelectionMenu { public: - PARMenu(bool font_load_success, sf::Font &text_font); + PARMenu(TextRectanglePool* text_pool); ~PARMenu(); void setup_title(std::string added_name); void prepare(float scaling_factor, int view_size_x, int view_size_y, int current_crop); diff --git a/include/Menus/RelativePositionMenu.hpp b/include/Menus/RelativePositionMenu.hpp index b1b585c..3e2fedf 100755 --- a/include/Menus/RelativePositionMenu.hpp +++ b/include/Menus/RelativePositionMenu.hpp @@ -5,6 +5,7 @@ #include #include "TextRectangle.hpp" +#include "TextRectanglePool.hpp" #include "display_structs.hpp" #include "event_structs.hpp" @@ -19,7 +20,7 @@ enum RelPosMenuOutAction{ class RelativePositionMenu { public: RelativePositionMenu(); - RelativePositionMenu(bool font_load_success, sf::Font &text_font); + RelativePositionMenu(TextRectanglePool* text_pool); virtual ~RelativePositionMenu(); bool poll(SFEvent &event_data); void draw(float scaling_factor, sf::RenderTarget &window); @@ -57,12 +58,13 @@ protected: sf::Color menu_color; std::string title; - void initialize(bool font_load_success, sf::Font &text_font); + void initialize(TextRectanglePool* text_pool); 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 bool is_option_drawable(int index); virtual void set_output_option(int index); virtual std::string get_string_option(int index); virtual void class_setup(); diff --git a/include/Menus/ResolutionMenu.hpp b/include/Menus/ResolutionMenu.hpp index 3af13f9..d96e1c6 100755 --- a/include/Menus/ResolutionMenu.hpp +++ b/include/Menus/ResolutionMenu.hpp @@ -13,7 +13,7 @@ class ResolutionMenu : public OptionSelectionMenu { public: - ResolutionMenu(bool font_load_success, sf::Font &text_font); + ResolutionMenu(TextRectanglePool* text_pool); ~ResolutionMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, int fullscreen_mode_width, int fullscreen_mode_height); void insert_data(std::vector* possible_resolutions, const sf::VideoMode &desktop_resolution); diff --git a/include/Menus/RotationMenu.hpp b/include/Menus/RotationMenu.hpp index cd30cbb..a0ecaad 100755 --- a/include/Menus/RotationMenu.hpp +++ b/include/Menus/RotationMenu.hpp @@ -21,7 +21,7 @@ enum RotationMenuOutAction{ class RotationMenu : public OptionSelectionMenu { public: - RotationMenu(bool font_load_success, sf::Font &text_font); + RotationMenu(TextRectanglePool* text_pool); ~RotationMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info); void insert_data(); diff --git a/include/Menus/ScalingRatioMenu.hpp b/include/Menus/ScalingRatioMenu.hpp index e48ede7..ed3198d 100755 --- a/include/Menus/ScalingRatioMenu.hpp +++ b/include/Menus/ScalingRatioMenu.hpp @@ -22,7 +22,7 @@ enum ScalingRatioMenuOutAction{ class ScalingRatioMenu : public OptionSelectionMenu { public: - ScalingRatioMenu(bool font_load_success, sf::Font &text_font); + ScalingRatioMenu(TextRectanglePool* text_pool); ~ScalingRatioMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info); void insert_data(); diff --git a/include/Menus/SecondScreen3DRelativePositionMenu.hpp b/include/Menus/SecondScreen3DRelativePositionMenu.hpp index 276a368..387345a 100644 --- a/include/Menus/SecondScreen3DRelativePositionMenu.hpp +++ b/include/Menus/SecondScreen3DRelativePositionMenu.hpp @@ -20,7 +20,7 @@ enum SecondScreen3DRelPosMenuOutAction{ class SecondScreen3DRelativePositionMenu : public RelativePositionMenu { public: - SecondScreen3DRelativePositionMenu(bool font_load_success, sf::Font &text_font); + SecondScreen3DRelativePositionMenu(TextRectanglePool* text_pool); ~SecondScreen3DRelativePositionMenu(); std::chrono::time_point last_input_processed_time; void reset_output_option(); @@ -29,6 +29,7 @@ public: 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_drawable(int index); bool is_option_selectable(int index); void set_output_option(int index); std::string get_string_option(int index); diff --git a/include/Menus/SeparatorMenu.hpp b/include/Menus/SeparatorMenu.hpp index 7ea059c..e93fac3 100644 --- a/include/Menus/SeparatorMenu.hpp +++ b/include/Menus/SeparatorMenu.hpp @@ -23,7 +23,7 @@ enum SeparatorMenuOutAction{ class SeparatorMenu : public OptionSelectionMenu { public: - SeparatorMenu(bool font_load_success, sf::Font &text_font); + SeparatorMenu(TextRectanglePool* text_pool); ~SeparatorMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info); void insert_data(bool is_fullscreen); diff --git a/include/Menus/ShortcutMenu.hpp b/include/Menus/ShortcutMenu.hpp index 9063587..148eba0 100755 --- a/include/Menus/ShortcutMenu.hpp +++ b/include/Menus/ShortcutMenu.hpp @@ -13,7 +13,7 @@ class ShortcutMenu : public OptionSelectionMenu { public: - ShortcutMenu(bool font_load_success, sf::Font &text_font); + ShortcutMenu(TextRectanglePool* text_pool); ~ShortcutMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y); void insert_data(std::vector &shortcut_names); diff --git a/include/Menus/StatusMenu.hpp b/include/Menus/StatusMenu.hpp index 80bdb34..2c522a8 100755 --- a/include/Menus/StatusMenu.hpp +++ b/include/Menus/StatusMenu.hpp @@ -16,7 +16,7 @@ enum StatusMenuOutAction{ class StatusMenu : public OptionSelectionMenu { public: - StatusMenu(bool font_load_success, sf::Font &text_font); + StatusMenu(TextRectanglePool* text_pool); ~StatusMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, double in_fps, double poll_fps, double draw_fps, CaptureStatus* capture_status); void insert_data(); diff --git a/include/Menus/VideoEffectsMenu.hpp b/include/Menus/VideoEffectsMenu.hpp index 6b72e7c..fbcc5a4 100644 --- a/include/Menus/VideoEffectsMenu.hpp +++ b/include/Menus/VideoEffectsMenu.hpp @@ -20,7 +20,7 @@ enum VideoEffectsMenuOutAction{ class VideoEffectsMenu : public OptionSelectionMenu { public: - VideoEffectsMenu(bool font_load_success, sf::Font &text_font); + VideoEffectsMenu(TextRectanglePool* text_pool); ~VideoEffectsMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info); void insert_data(); diff --git a/include/Menus/VideoMenu.hpp b/include/Menus/VideoMenu.hpp index 15354a9..b99d6b0 100755 --- a/include/Menus/VideoMenu.hpp +++ b/include/Menus/VideoMenu.hpp @@ -46,7 +46,7 @@ enum VideoMenuOutAction{ class VideoMenu : public OptionSelectionMenu { public: - VideoMenu(bool font_load_success, sf::Font &text_font); + VideoMenu(TextRectanglePool* text_pool); ~VideoMenu(); void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info, ScreenType screen_type); void insert_data(ScreenType s_type, bool is_fullscreen, bool can_have_titlebar); diff --git a/include/TextRectanglePool.hpp b/include/TextRectanglePool.hpp new file mode 100644 index 0000000..2594175 --- /dev/null +++ b/include/TextRectanglePool.hpp @@ -0,0 +1,20 @@ +#ifndef __TEXTRECTANGLEPOOL_HPP +#define __TEXTRECTANGLEPOOL_HPP + +#include "TextRectangle.hpp" + +class TextRectanglePool { +public: + TextRectanglePool(bool font_load_success, sf::Font *text_font); + ~TextRectanglePool(); + void request_num_text_rectangles(int num_wanted_text_rectangles); + TextRectangle* get_text_rectangle(int index); + +private: + bool font_load_success; + sf::Font *text_font; + int num_loaded_text_rectangles; + TextRectangle** text_rectangles_list; +}; + +#endif diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index 98598ca..e7706b0 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -46,17 +46,18 @@ struct PACKED RGB83DSVideoInputData_3D { uint8_t screen_data[IN_VIDEO_SIZE_3DS_3D][3]; }; -#define OLD_DS_PIXEL_B_BITS 5 -#define OLD_DS_PIXEL_G_BITS 6 #define OLD_DS_PIXEL_R_BITS 5 +#define OLD_DS_PIXEL_G_BITS 6 +#define OLD_DS_PIXEL_B_BITS 5 -struct PACKED USBOldDSPixelData { - uint16_t b : OLD_DS_PIXEL_B_BITS; - uint16_t g : OLD_DS_PIXEL_G_BITS; +// The internal order needs to be reversed... This is so confusing... +struct PACKED ALIGNED(2) USBOldDSPixelData { uint16_t r : OLD_DS_PIXEL_R_BITS; + uint16_t g : OLD_DS_PIXEL_G_BITS; + uint16_t b : OLD_DS_PIXEL_B_BITS; }; -struct PACKED USBOldDSVideoInputData { +struct PACKED ALIGNED(2) USBOldDSVideoInputData { USBOldDSPixelData screen_data[IN_VIDEO_SIZE_DS]; }; @@ -64,10 +65,11 @@ struct PACKED USBOldDSVideoInputData { #define OPTIMIZE_3DS_PIXEL_G_BITS 6 #define OPTIMIZE_3DS_PIXEL_B_BITS 5 -struct PACKED USB5653DSOptimizePixelData { - uint16_t r : OPTIMIZE_3DS_PIXEL_R_BITS; - uint16_t g : OPTIMIZE_3DS_PIXEL_G_BITS; +// The internal order needs to be reversed... This is so confusing... +struct PACKED ALIGNED(2) USB5653DSOptimizePixelData { uint16_t b : OPTIMIZE_3DS_PIXEL_B_BITS; + uint16_t g : OPTIMIZE_3DS_PIXEL_G_BITS; + uint16_t r : OPTIMIZE_3DS_PIXEL_R_BITS; }; struct PACKED USB8883DSOptimizePixelData { @@ -100,22 +102,22 @@ struct PACKED USB3DSOptimizeHeaderSoundData { USB3DSOptimizeSingleSoundData samples[2]; }; -struct PACKED USB5653DSOptimizeInputColumnData { +struct PACKED ALIGNED(16) USB5653DSOptimizeInputColumnData { USB3DSOptimizeHeaderSoundData header_sound; USB5653DSOptimizePixelData pixel[HEIGHT_3DS][2]; }; -struct PACKED USB5653DSOptimizeInputColumnData3D { +struct PACKED ALIGNED(16) USB5653DSOptimizeInputColumnData3D { USB3DSOptimizeHeaderSoundData header_sound; USB5653DSOptimizePixelData pixel[HEIGHT_3DS][3]; }; -struct PACKED USB8883DSOptimizeInputColumnData { +struct PACKED ALIGNED(16) USB8883DSOptimizeInputColumnData { USB3DSOptimizeHeaderSoundData header_sound; USB8883DSOptimizePixelData pixel[HEIGHT_3DS][2]; }; -struct PACKED USB8883DSOptimizeInputColumnData3D { +struct PACKED ALIGNED(16) USB8883DSOptimizeInputColumnData3D { USB3DSOptimizeHeaderSoundData header_sound; USB8883DSOptimizePixelData pixel[HEIGHT_3DS][3]; }; @@ -124,7 +126,7 @@ struct PACKED ISNitroEmulatorVideoInputData { uint8_t screen_data[IN_VIDEO_SIZE_DS][3]; }; -struct PACKED ISTWLCaptureVideoInputData { +struct PACKED ALIGNED(2) ISTWLCaptureVideoInputData { USBOldDSPixelData screen_data[IN_VIDEO_SIZE_DS]; uint8_t bit_6_rb_screen_data[(IN_VIDEO_SIZE_DS >> 3) * 2]; }; diff --git a/include/conversions.hpp b/include/conversions.hpp index bbb9215..97d36fa 100755 --- a/include/conversions.hpp +++ b/include/conversions.hpp @@ -6,4 +6,6 @@ bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status, bool interleaved_3d); bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, uint16_t &last_buffer_index, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status); +void manualConvertOutputToRGB(VideoOutputData* src, VideoOutputData* dst, size_t pos_x_data, size_t pos_y_data, size_t width, size_t height, InputVideoDataType video_data_type); + #endif diff --git a/include/display_structs.hpp b/include/display_structs.hpp index e7adf4e..9c46cdd 100755 --- a/include/display_structs.hpp +++ b/include/display_structs.hpp @@ -111,10 +111,59 @@ struct SharedData { InputData input_data; }; -struct ALIGNED(8) VideoOutputData { - uint8_t screen_data[MAX_IN_VIDEO_SIZE][3]; +#pragma pack(push, 1) + +// The internal order needs to be reversed... This is so confusing... +struct PACKED ALIGNED(2) VideoPixelRGB16 { + uint16_t b : 5; + uint16_t g : 6; + uint16_t r : 5; }; +// The internal order needs to be reversed... This is so confusing... +struct PACKED ALIGNED(2) VideoPixelBGR16 { + uint16_t r : 5; + uint16_t g : 6; + uint16_t b : 5; +}; + +struct PACKED VideoPixelRGB { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +struct PACKED VideoPixelBGR { + uint8_t b; + uint8_t g; + uint8_t r; +}; + +struct PACKED ALIGNED(16) VideoOutputDataRGB16 { + VideoPixelRGB16 screen_data[MAX_IN_VIDEO_SIZE]; +}; + +struct PACKED ALIGNED(16) VideoOutputDataBGR16 { + VideoPixelBGR16 screen_data[MAX_IN_VIDEO_SIZE]; +}; + +struct PACKED ALIGNED(16) VideoOutputDataRGB { + VideoPixelRGB screen_data[MAX_IN_VIDEO_SIZE]; +}; + +struct PACKED ALIGNED(16) VideoOutputDataBGR { + VideoPixelBGR screen_data[MAX_IN_VIDEO_SIZE]; +}; + +union PACKED ALIGNED(16) VideoOutputData { + VideoOutputDataRGB16 rgb16_video_output_data; + VideoOutputDataBGR16 bgr16_video_output_data; + VideoOutputDataRGB rgb_video_output_data; + VideoOutputDataBGR bgr_video_output_data; +}; + +#pragma pack(pop) + struct CropData { int top_width; int top_height; diff --git a/include/frontend.hpp b/include/frontend.hpp index ced955b..b4c2b1c 100755 --- a/include/frontend.hpp +++ b/include/frontend.hpp @@ -11,6 +11,7 @@ #include "audio_data.hpp" #include "capture_structs.hpp" #include "TextRectangle.hpp" +#include "TextRectanglePool.hpp" #include "sfml_gfx_structs.hpp" #include "ConnectionMenu.hpp" #include "MainMenu.hpp" @@ -52,11 +53,19 @@ struct FPSArray { int index; }; +struct OutTextData { + std::string full_text; + std::string small_text; + std::string preamble_name = NAME; + bool consumed = true; + TextKind kind; +}; + class WindowScreen { public: ScreenInfo m_info; - WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool created_proper_folder); + WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool created_proper_folder, bool disable_frame_blending); ~WindowScreen(); void build(); @@ -76,6 +85,7 @@ public: void update_save_menu(); void print_notification(std::string text, TextKind kind = TEXT_KIND_NORMAL); + void process_own_out_text_data(bool print_to_notification = true); int load_data(); int save_data(); bool open_capture(); @@ -103,6 +113,9 @@ private: const PARData *par; bool divide_3d_par; }; + OutTextData own_out_text_data; + InputVideoDataType last_update_texture_data_type; + bool use_texture_software_based_conv; bool created_proper_folder; CaptureStatus* capture_status; std::string win_title; @@ -119,7 +132,6 @@ private: bool m_prepare_quit; bool m_scheduled_split; int ret_val; - bool font_load_success; double frame_time; DisplayData* display_data; SharedData* shared_data; @@ -190,7 +202,12 @@ private: std::chrono::time_point last_menu_change_time; int curr_frame_texture_pos = 0; - sf::Texture in_tex; + int num_frames_to_blend; + sf::Texture full_in_tex; + bool shared_texture_available; + sf::Texture top_l_in_tex; + sf::Texture top_r_in_tex; + sf::Texture bot_in_tex; sf::Font text_font; @@ -212,6 +229,7 @@ private: sf::VideoMode curr_desk_mode; TextRectangle* notification; + TextRectanglePool* text_rectangle_pool; ConsumerMutex display_lock; ConsumerMutex *draw_lock; @@ -230,6 +248,10 @@ private: void free_ownership_of_window(bool is_main_thread); void resize_in_rect(sf::RectangleShape &in_rect, int start_x, int start_y, int width, int height); + int get_pos_x_screen_inside_data(bool is_top, bool is_second = false); + int get_pos_y_screen_inside_data(bool is_top, bool is_second = false); + int get_pos_x_screen_inside_in_tex(bool is_top, bool is_second = false); + int get_pos_y_screen_inside_in_tex(bool is_top, bool is_second = false); int get_screen_corner_modifier_x(int rotation, int width); int get_screen_corner_modifier_y(int rotation, int height); void print_notification_on_off(std::string base_text, bool value); @@ -286,6 +308,10 @@ private: void prepare_screen_rendering(); bool window_needs_work(); void window_factory(bool is_main_thread); + void opengl_error_out(std::string error_base, std::string error_str); + void opengl_error_check(std::string error_base); + bool single_update_texture(unsigned int m_texture, InputVideoDataType video_data_type, size_t pos_x_data, size_t pos_y_data, size_t width, size_t height, bool manually_converted); + void execute_single_update_texture(bool &manually_converted, bool do_full, bool is_top = false, bool is_second = false); void update_texture(); int _choose_base_input_shader(bool is_top); int _choose_color_emulation_shader(bool is_top); @@ -371,32 +397,44 @@ struct FrontendData { bool reload; }; +void ConsumeOutText(OutTextData &out_text_data, bool update_consumed = true); +void UpdateOutText(OutTextData &out_text_data, std::string full_text, std::string small_text, TextKind kind); + void FPSArrayInit(FPSArray *array); void FPSArrayDestroy(FPSArray *array); void FPSArrayInsertElement(FPSArray *array, double frame_time); + void insert_basic_crops(std::vector &crop_vector, ScreenType s_type, bool is_ds, bool allow_game_specific); void insert_basic_pars(std::vector &par_vector); void insert_basic_color_profiles(std::vector &color_profiles_vector); + void reset_display_data(DisplayData *display_data); void reset_input_data(InputData* input_data); void reset_shared_data(SharedData* shared_data); void reset_fullscreen_info(ScreenInfo &info); + void sanitize_enabled_info(ScreenInfo &top_bot_info, ScreenInfo &top_info, ScreenInfo &bot_info); void override_set_data_to_screen_info(override_win_data &override_win, ScreenInfo &info); 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, 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); + void screen_display_thread(WindowScreen *screen); + std::string get_name_non_int_mode(NonIntegerScalingModes input); std::string get_name_frame_blending_mode(FrameBlendingMode input); std::string get_name_input_colorspace_mode(InputColorspaceMode input); bool is_input_data_valid(InputData* input_data, bool consider_buttons); void default_sleep(float wanted_ms = -1); + #endif diff --git a/include/hw_defs.hpp b/include/hw_defs.hpp index bcd2839..a592f36 100755 --- a/include/hw_defs.hpp +++ b/include/hw_defs.hpp @@ -70,6 +70,13 @@ #define MAX_IN_VIDEO_SIZE (MAX_IN_VIDEO_WIDTH * MAX_IN_VIDEO_HEIGHT) #define MAX_IN_VIDEO_BPP_SIZE IN_VIDEO_BPP_SIZE_3DS +#define MAX_IN_VIDEO_WIDTH_TOP IN_VIDEO_WIDTH_DS +#define MAX_IN_VIDEO_HEIGHT_TOP (TOP_WIDTH_3DS + TOP_WIDTH_3DS) +#define MAX_IN_VIDEO_WIDTH_SINGLE_TOP IN_VIDEO_WIDTH_DS +#define MAX_IN_VIDEO_HEIGHT_SINGLE_TOP TOP_WIDTH_3DS +#define MAX_IN_VIDEO_WIDTH_BOTTOM IN_VIDEO_WIDTH_DS +#define MAX_IN_VIDEO_HEIGHT_BOTTOM BOT_WIDTH_3DS + // 1096 is the value when things are ideal. However, it can actually happen that the transfer isn't 100% on time. // When that happens, a bit more audio data may get transfered. It's a ton on O3DS when Windows underprioritizes USB... // In general, it should be less than * 2, but you never know. For now, go for safety at x16... diff --git a/source/Menus/ActionSelectionMenu.cpp b/source/Menus/ActionSelectionMenu.cpp index 372d3bc..d025463 100755 --- a/source/Menus/ActionSelectionMenu.cpp +++ b/source/Menus/ActionSelectionMenu.cpp @@ -1,7 +1,7 @@ #include "ActionSelectionMenu.hpp" -ActionSelectionMenu::ActionSelectionMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +ActionSelectionMenu::ActionSelectionMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } ActionSelectionMenu::~ActionSelectionMenu() { diff --git a/source/Menus/AudioDeviceMenu.cpp b/source/Menus/AudioDeviceMenu.cpp index 9219862..c652669 100644 --- a/source/Menus/AudioDeviceMenu.cpp +++ b/source/Menus/AudioDeviceMenu.cpp @@ -1,7 +1,7 @@ #include "AudioDeviceMenu.hpp" -AudioDeviceMenu::AudioDeviceMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +AudioDeviceMenu::AudioDeviceMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } AudioDeviceMenu::~AudioDeviceMenu() { diff --git a/source/Menus/AudioMenu.cpp b/source/Menus/AudioMenu.cpp index a6c3266..bfed111 100755 --- a/source/Menus/AudioMenu.cpp +++ b/source/Menus/AudioMenu.cpp @@ -60,9 +60,9 @@ static const AudioMenuOptionInfo* pollable_options[] = { &audio_restart_option, }; -AudioMenu::AudioMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +AudioMenu::AudioMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/BFIMenu.cpp b/source/Menus/BFIMenu.cpp index 380f997..3f72b2d 100755 --- a/source/Menus/BFIMenu.cpp +++ b/source/Menus/BFIMenu.cpp @@ -46,9 +46,9 @@ static const BFIMenuOptionInfo* pollable_options[] = { &bfi_amount_option, }; -BFIMenu::BFIMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +BFIMenu::BFIMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/ColorCorrectionMenu.cpp b/source/Menus/ColorCorrectionMenu.cpp index 8fcaedf..f3afbc8 100644 --- a/source/Menus/ColorCorrectionMenu.cpp +++ b/source/Menus/ColorCorrectionMenu.cpp @@ -1,7 +1,7 @@ #include "ColorCorrectionMenu.hpp" -ColorCorrectionMenu::ColorCorrectionMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +ColorCorrectionMenu::ColorCorrectionMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } ColorCorrectionMenu::~ColorCorrectionMenu() { diff --git a/source/Menus/ConnectionMenu.cpp b/source/Menus/ConnectionMenu.cpp index 6b12cb7..db8290e 100755 --- a/source/Menus/ConnectionMenu.cpp +++ b/source/Menus/ConnectionMenu.cpp @@ -1,7 +1,7 @@ #include "ConnectionMenu.hpp" -ConnectionMenu::ConnectionMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +ConnectionMenu::ConnectionMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } ConnectionMenu::~ConnectionMenu() { diff --git a/source/Menus/CropMenu.cpp b/source/Menus/CropMenu.cpp index de8d9d7..1155bcf 100755 --- a/source/Menus/CropMenu.cpp +++ b/source/Menus/CropMenu.cpp @@ -1,7 +1,7 @@ #include "CropMenu.hpp" -CropMenu::CropMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +CropMenu::CropMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } CropMenu::~CropMenu() { diff --git a/source/Menus/ExtraSettingsMenu.cpp b/source/Menus/ExtraSettingsMenu.cpp index 32fa180..b9cf894 100755 --- a/source/Menus/ExtraSettingsMenu.cpp +++ b/source/Menus/ExtraSettingsMenu.cpp @@ -58,9 +58,9 @@ static const ExtraSettingsMenuOptionInfo* pollable_options[] = { &quit_option, }; -ExtraSettingsMenu::ExtraSettingsMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +ExtraSettingsMenu::ExtraSettingsMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/FileConfigMenu.cpp b/source/Menus/FileConfigMenu.cpp index 924f7f1..01172fa 100755 --- a/source/Menus/FileConfigMenu.cpp +++ b/source/Menus/FileConfigMenu.cpp @@ -1,7 +1,7 @@ #include "FileConfigMenu.hpp" -FileConfigMenu::FileConfigMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +FileConfigMenu::FileConfigMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } FileConfigMenu::~FileConfigMenu() { diff --git a/source/Menus/ISNitroMenu.cpp b/source/Menus/ISNitroMenu.cpp index a94be44..f557b87 100644 --- a/source/Menus/ISNitroMenu.cpp +++ b/source/Menus/ISNitroMenu.cpp @@ -69,9 +69,9 @@ static const ISNitroMenuOptionInfo* pollable_options[] = { &is_nitro_reset_option, }; -ISNitroMenu::ISNitroMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +ISNitroMenu::ISNitroMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/InputMenu.cpp b/source/Menus/InputMenu.cpp index a31eaf7..5e542d4 100644 --- a/source/Menus/InputMenu.cpp +++ b/source/Menus/InputMenu.cpp @@ -41,9 +41,9 @@ static const InputMenuOptionInfo* pollable_options[] = { &input_menu_toggle_buttons_option, }; -InputMenu::InputMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +InputMenu::InputMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/LicenseMenu.cpp b/source/Menus/LicenseMenu.cpp index 329ee19..a55a3d9 100755 --- a/source/Menus/LicenseMenu.cpp +++ b/source/Menus/LicenseMenu.cpp @@ -165,9 +165,9 @@ static const LicenseMenuOptionInfo* pollable_options[] = { &cc3dsfs_license_4_option, }; -LicenseMenu::LicenseMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +LicenseMenu::LicenseMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/Main3DMenu.cpp b/source/Menus/Main3DMenu.cpp index 39b1dcc..9596a79 100644 --- a/source/Menus/Main3DMenu.cpp +++ b/source/Menus/Main3DMenu.cpp @@ -83,9 +83,9 @@ static const Main3DMenuOptionInfo* pollable_options[] = { &main_3d_menu_second_screen_position_settings_option, }; -Main3DMenu::Main3DMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +Main3DMenu::Main3DMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/MainMenu.cpp b/source/Menus/MainMenu.cpp index dfaa6ea..1c498f9 100755 --- a/source/Menus/MainMenu.cpp +++ b/source/Menus/MainMenu.cpp @@ -166,9 +166,9 @@ static const MainMenuOptionInfo* pollable_options[] = { &shutdown_option, }; -MainMenu::MainMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +MainMenu::MainMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/OffsetMenu.cpp b/source/Menus/OffsetMenu.cpp index b5698d3..9e481d8 100755 --- a/source/Menus/OffsetMenu.cpp +++ b/source/Menus/OffsetMenu.cpp @@ -38,9 +38,9 @@ static const OffsetMenuOptionInfo* pollable_options[] = { &canvas_y_pos_option, }; -OffsetMenu::OffsetMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +OffsetMenu::OffsetMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/OptionSelectionMenu.cpp b/source/Menus/OptionSelectionMenu.cpp index e79cb36..272d9e5 100755 --- a/source/Menus/OptionSelectionMenu.cpp +++ b/source/Menus/OptionSelectionMenu.cpp @@ -5,25 +5,24 @@ OptionSelectionMenu::OptionSelectionMenu() { } OptionSelectionMenu::~OptionSelectionMenu() { - for(int i = 0; i < this->num_elements_displayed_per_screen; i++) - delete this->labels[i]; delete []this->labels; delete []this->selectable_labels; delete []this->future_enabled_labels; delete []this->loaded_enabled_labels; } -void OptionSelectionMenu::initialize(bool font_load_success, sf::Font &text_font) { +void OptionSelectionMenu::initialize(TextRectanglePool* text_pool) { this->class_setup(); this->after_class_setup_connected_values(); this->menu_rectangle.setFillColor(this->menu_color); this->menu_rectangle.setPosition({1, 1}); + text_pool->request_num_text_rectangles(this->num_elements_displayed_per_screen); this->labels = new TextRectangle*[this->num_elements_displayed_per_screen]; this->selectable_labels = new bool[this->num_elements_displayed_per_screen]; this->future_enabled_labels = new bool[this->num_elements_displayed_per_screen]; this->loaded_enabled_labels = new bool[this->num_elements_displayed_per_screen]; for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { - this->labels[i] = new TextRectangle(font_load_success, text_font); + this->labels[i] = text_pool->get_text_rectangle(i); this->labels[i]->setProportionalBox(false); this->labels[i]->setText(std::to_string(i)); this->labels[i]->setShowText(true); diff --git a/source/Menus/PARMenu.cpp b/source/Menus/PARMenu.cpp index 2234d31..fde806b 100755 --- a/source/Menus/PARMenu.cpp +++ b/source/Menus/PARMenu.cpp @@ -1,7 +1,7 @@ #include "PARMenu.hpp" -PARMenu::PARMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +PARMenu::PARMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } PARMenu::~PARMenu() { diff --git a/source/Menus/RelativePositionMenu.cpp b/source/Menus/RelativePositionMenu.cpp index 9db6510..9f21da2 100755 --- a/source/Menus/RelativePositionMenu.cpp +++ b/source/Menus/RelativePositionMenu.cpp @@ -66,8 +66,8 @@ static const RelativePositionMenuOptionInfo* pollable_options[] = { RelativePositionMenu::RelativePositionMenu() { } -RelativePositionMenu::RelativePositionMenu(bool font_load_success, sf::Font &text_font) { - this->initialize(font_load_success, text_font); +RelativePositionMenu::RelativePositionMenu(TextRectanglePool* text_rectangle_pool) { + this->initialize(text_rectangle_pool); } RelativePositionMenu::~RelativePositionMenu() { @@ -77,15 +77,16 @@ RelativePositionMenu::~RelativePositionMenu() { delete []this->selectable_labels; } -void RelativePositionMenu::initialize(bool font_load_success, sf::Font &text_font) { +void RelativePositionMenu::initialize(TextRectanglePool* text_pool) { this->class_setup(); this->after_class_setup_connected_values(); this->menu_rectangle.setFillColor(this->menu_color); this->menu_rectangle.setPosition({1, 1}); + text_pool->request_num_text_rectangles(this->num_elements_displayed_per_screen); this->labels = new TextRectangle*[this->num_elements_displayed_per_screen]; this->selectable_labels = new bool[this->num_elements_displayed_per_screen]; for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { - this->labels[i] = new TextRectangle(font_load_success, text_font); + this->labels[i] = text_pool->get_text_rectangle(i); this->labels[i]->setProportionalBox(false); this->labels[i]->setText(std::to_string(i)); this->labels[i]->setShowText(true); @@ -224,6 +225,10 @@ void RelativePositionMenu::set_output_option(int index) { } } +bool RelativePositionMenu::is_option_drawable(int index) { + return true; +} + bool RelativePositionMenu::is_option_selectable(int index) { return pollable_options[index]->is_selectable; } @@ -428,7 +433,8 @@ void RelativePositionMenu::draw(float scaling_factor, sf::RenderTarget &window) this->menu_rectangle.setPosition({(float)this->loaded_data.pos_x, (float)this->loaded_data.pos_y}); window.draw(this->menu_rectangle); for(int i = 0; i < this->num_elements_displayed_per_screen; i++) { - this->labels[i]->draw(window); + if(this->is_option_drawable(i)) + this->labels[i]->draw(window); } } diff --git a/source/Menus/ResolutionMenu.cpp b/source/Menus/ResolutionMenu.cpp index 06a2be7..f578fb3 100755 --- a/source/Menus/ResolutionMenu.cpp +++ b/source/Menus/ResolutionMenu.cpp @@ -1,7 +1,7 @@ #include "ResolutionMenu.hpp" -ResolutionMenu::ResolutionMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +ResolutionMenu::ResolutionMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } ResolutionMenu::~ResolutionMenu() { diff --git a/source/Menus/RotationMenu.cpp b/source/Menus/RotationMenu.cpp index 2094917..2632cc4 100755 --- a/source/Menus/RotationMenu.cpp +++ b/source/Menus/RotationMenu.cpp @@ -32,9 +32,9 @@ static const RotationMenuOptionInfo* pollable_options[] = { &both_rotation_option, }; -RotationMenu::RotationMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +RotationMenu::RotationMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/ScalingRatioMenu.cpp b/source/Menus/ScalingRatioMenu.cpp index 39a1501..30c141c 100755 --- a/source/Menus/ScalingRatioMenu.cpp +++ b/source/Menus/ScalingRatioMenu.cpp @@ -46,9 +46,9 @@ static const ScalingRatioMenuOptionInfo* pollable_options[] = { &force_same_scaling_option, }; -ScalingRatioMenu::ScalingRatioMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +ScalingRatioMenu::ScalingRatioMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/SecondScreen3DRelativePositionMenu.cpp b/source/Menus/SecondScreen3DRelativePositionMenu.cpp index 5d6f3a6..d43327f 100644 --- a/source/Menus/SecondScreen3DRelativePositionMenu.cpp +++ b/source/Menus/SecondScreen3DRelativePositionMenu.cpp @@ -88,8 +88,8 @@ static const SecondScreen3DRelativePositionMenuOptionInfo* pollable_options[] = &desc2_option, }; -SecondScreen3DRelativePositionMenu::SecondScreen3DRelativePositionMenu(bool font_load_success, sf::Font &text_font) { - this->initialize(font_load_success, text_font); +SecondScreen3DRelativePositionMenu::SecondScreen3DRelativePositionMenu(TextRectanglePool* text_rectangle_pool) { + this->initialize(text_rectangle_pool); } SecondScreen3DRelativePositionMenu::~SecondScreen3DRelativePositionMenu() { @@ -138,6 +138,14 @@ void SecondScreen3DRelativePositionMenu::set_output_option(int index) { } } +bool SecondScreen3DRelativePositionMenu::is_option_drawable(int index) { + if(index < this->elements_start_id) + return true; + if((this->stype != ScreenType::JOINT) && (!pollable_options[index - this->elements_start_id]->exists_non_joint)) + return false; + return true; +} + bool SecondScreen3DRelativePositionMenu::is_option_selectable(int index) { if((this->stype != ScreenType::JOINT) && (!pollable_options[index]->exists_non_joint)) return false; diff --git a/source/Menus/SeparatorMenu.cpp b/source/Menus/SeparatorMenu.cpp index 63c7100..5bb1586 100644 --- a/source/Menus/SeparatorMenu.cpp +++ b/source/Menus/SeparatorMenu.cpp @@ -44,9 +44,9 @@ static const SeparatorMenuOptionInfo* pollable_options[] = { &separator_fullscreen_mul_change_option, }; -SeparatorMenu::SeparatorMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +SeparatorMenu::SeparatorMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/ShortcutMenu.cpp b/source/Menus/ShortcutMenu.cpp index 440366a..aa85495 100755 --- a/source/Menus/ShortcutMenu.cpp +++ b/source/Menus/ShortcutMenu.cpp @@ -1,7 +1,7 @@ #include "ShortcutMenu.hpp" -ShortcutMenu::ShortcutMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ - this->initialize(font_load_success, text_font); +ShortcutMenu::ShortcutMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ + this->initialize(text_rectangle_pool); } ShortcutMenu::~ShortcutMenu() { diff --git a/source/Menus/StatusMenu.cpp b/source/Menus/StatusMenu.cpp index e581e95..e58530d 100755 --- a/source/Menus/StatusMenu.cpp +++ b/source/Menus/StatusMenu.cpp @@ -57,9 +57,9 @@ static const StatusMenuOptionInfo* pollable_options[] = { &status_fps_draw_option, }; -StatusMenu::StatusMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +StatusMenu::StatusMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; this->last_update_time = std::chrono::high_resolution_clock::now(); this->do_update = true; diff --git a/source/Menus/VideoEffectsMenu.cpp b/source/Menus/VideoEffectsMenu.cpp index 2c56eba..ddd9294 100644 --- a/source/Menus/VideoEffectsMenu.cpp +++ b/source/Menus/VideoEffectsMenu.cpp @@ -35,9 +35,9 @@ static const VideoEffectsMenuOptionInfo* pollable_options[] = { &color_correction_menu_option, }; -VideoEffectsMenu::VideoEffectsMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +VideoEffectsMenu::VideoEffectsMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/Menus/VideoMenu.cpp b/source/Menus/VideoMenu.cpp index c6f8694..4ba71ec 100755 --- a/source/Menus/VideoMenu.cpp +++ b/source/Menus/VideoMenu.cpp @@ -231,9 +231,9 @@ static const VideoMenuOptionInfo* pollable_options[] = { &bfi_settings_option, }; -VideoMenu::VideoMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){ +VideoMenu::VideoMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){ this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS]; - this->initialize(font_load_success, text_font); + this->initialize(text_rectangle_pool); this->num_enabled_options = 0; } diff --git a/source/TextRectanglePool.cpp b/source/TextRectanglePool.cpp new file mode 100644 index 0000000..72bb635 --- /dev/null +++ b/source/TextRectanglePool.cpp @@ -0,0 +1,48 @@ +#include "TextRectangle.hpp" +#include "TextRectanglePool.hpp" + +TextRectanglePool::TextRectanglePool(bool font_load_success, sf::Font *text_font) { + this->font_load_success = font_load_success; + this->text_font = text_font; + this->num_loaded_text_rectangles = 0; + this->text_rectangles_list = NULL; +} + +TextRectanglePool::~TextRectanglePool() { + if(this->num_loaded_text_rectangles > 0) { + for(int i = 0; i < this->num_loaded_text_rectangles; i++) + delete this->text_rectangles_list[i]; + delete []this->text_rectangles_list; + } + this->num_loaded_text_rectangles = 0; +} + +void TextRectanglePool::request_num_text_rectangles(int num_wanted_text_rectangles) { + if(this->num_loaded_text_rectangles > num_wanted_text_rectangles) + return; + + TextRectangle** new_text_rectangle_ptrs = new TextRectangle*[num_wanted_text_rectangles]; + + // Copy other TextRectangles to new list + for(int i = 0; i < this->num_loaded_text_rectangles; i++) { + new_text_rectangle_ptrs[i] = this->text_rectangles_list[i]; + } + + // Create new TextRectangles + for(int i = this->num_loaded_text_rectangles; i < num_wanted_text_rectangles; i++) { + new_text_rectangle_ptrs[i] = new TextRectangle(this->font_load_success, *this->text_font); + } + + if(this->num_loaded_text_rectangles > 0) + delete []this->text_rectangles_list; + + this->text_rectangles_list = new_text_rectangle_ptrs; + this->num_loaded_text_rectangles = num_wanted_text_rectangles; +} + +TextRectangle* TextRectanglePool::get_text_rectangle(int index) { + if((this->num_loaded_text_rectangles <= index) || (index < 0)) + return NULL; + + return this->text_rectangles_list[index]; +} diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index fa7af02..cacb6aa 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -7,6 +7,7 @@ #include "font_ttf.h" #include "shaders_list.hpp" #include "devicecapture.hpp" +#include #define LEFT_ROUNDED_PADDING 5 #define RIGHT_ROUNDED_PADDING 5 @@ -36,7 +37,7 @@ static bool is_size_valid(sf::Vector2f size) { return (size.x > 0.0) && (size.y > 0.0); } -WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool created_proper_folder) { +WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool created_proper_folder, bool disable_frame_blending) { this->draw_lock = draw_lock; this->m_stype = stype; insert_basic_crops(this->possible_crops, this->m_stype, false, false); @@ -53,16 +54,60 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp this->m_scheduled_split = false; this->ret_val = 0; reset_screen_info(this->m_info); - this->font_load_success = this->text_font.openFromMemory(font_ttf, font_ttf_len); - this->notification = new TextRectangle(this->font_load_success, this->text_font); + bool font_load_success = this->text_font.openFromMemory(font_ttf, font_ttf_len); + this->notification = new TextRectangle(font_load_success, this->text_font); + this->text_rectangle_pool = new TextRectanglePool(font_load_success, &this->text_font); this->init_menus(); FPSArrayInit(&this->in_fps); FPSArrayInit(&this->draw_fps); 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->last_update_texture_data_type = VIDEO_DATA_RGB; + this->use_texture_software_based_conv = false; + this->num_frames_to_blend = NUM_FRAMES_BLENDED; + if(disable_frame_blending) + this->num_frames_to_blend = 1; + const size_t top_width = MAX_IN_VIDEO_WIDTH_TOP * this->num_frames_to_blend; + const size_t top_height = MAX_IN_VIDEO_HEIGHT_TOP; + const size_t top_single_width = MAX_IN_VIDEO_WIDTH_SINGLE_TOP * this->num_frames_to_blend; + const size_t top_single_height = MAX_IN_VIDEO_HEIGHT_SINGLE_TOP; + const size_t bottom_width = MAX_IN_VIDEO_WIDTH_BOTTOM * this->num_frames_to_blend; + const size_t bottom_height = MAX_IN_VIDEO_HEIGHT_BOTTOM; + size_t full_width = MAX_IN_VIDEO_WIDTH * this->num_frames_to_blend; + size_t full_height = MAX_IN_VIDEO_HEIGHT; + if(this->m_stype == ScreenType::TOP) { + full_width = top_width; + full_height = top_height; + } + if(this->m_stype == ScreenType::BOTTOM) { + full_width = bottom_width; + full_height = bottom_height; + } + this->shared_texture_available = this->full_in_tex.resize({(unsigned int)full_width, (unsigned int)full_height}); + if(this->shared_texture_available) { + this->m_in_rect_top.setTexture(&this->full_in_tex); + this->m_in_rect_top_right.setTexture(&this->full_in_tex); + this->m_in_rect_bot.setTexture(&this->full_in_tex); + } + else { + if((this->m_stype == ScreenType::TOP) || (this->m_stype == ScreenType::JOINT)) { + full_width = top_width; + full_height = top_height; + (void)this->top_l_in_tex.resize({ (unsigned int)top_single_width, (unsigned int)top_single_height }); + (void)this->top_r_in_tex.resize({ (unsigned int)top_single_width, (unsigned int)top_single_height }); + this->m_in_rect_top.setTexture(&this->top_l_in_tex); + this->m_in_rect_top_right.setTexture(&this->top_r_in_tex); + } + else { + this->m_in_rect_top.setTexture(&this->bot_in_tex); + this->m_in_rect_top_right.setTexture(&this->bot_in_tex); + } + if((this->m_stype == ScreenType::BOTTOM) || (this->m_stype == ScreenType::JOINT)) { + (void)this->bot_in_tex.resize({ (unsigned int)bottom_width, (unsigned int)bottom_height }); + this->m_in_rect_bot.setTexture(&this->bot_in_tex); + } + else + this->m_in_rect_bot.setTexture(&this->top_l_in_tex); + } this->display_data = display_data; this->shared_data = shared_data; this->audio_data = audio_data; @@ -76,10 +121,16 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp this->done_display = true; this->saved_buf = new VideoOutputData; this->win_title = NAME; - if(this->m_stype == ScreenType::TOP) + if(this->m_stype == ScreenType::TOP) { this->win_title += "_top"; - if(this->m_stype == ScreenType::BOTTOM) + this->own_out_text_data.preamble_name += " top window"; + } + if(this->m_stype == ScreenType::BOTTOM) { this->win_title += "_bot"; + this->own_out_text_data.preamble_name += " bottom window"; + } + if(this->m_stype == ScreenType::JOINT) + this->own_out_text_data.preamble_name += " joint window"; this->last_connected_status = false; this->last_enabled_3d = false; this->last_interleaved_3d = false; @@ -114,6 +165,7 @@ WindowScreen::~WindowScreen() { delete this->saved_buf; delete this->notification; this->destroy_menus(); + delete this->text_rectangle_pool; FPSArrayDestroy(&this->in_fps); FPSArrayDestroy(&this->draw_fps); FPSArrayDestroy(&this->poll_fps); @@ -250,7 +302,7 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { this->last_poll_time = std::chrono::high_resolution_clock::now(); } if(this->m_win.isOpen() || this->loaded_operations.call_create) { - this->curr_frame_texture_pos = (this->curr_frame_texture_pos + 1) % NUM_FRAMES_BLENDED; + this->curr_frame_texture_pos = (this->curr_frame_texture_pos + 1) % this->num_frames_to_blend; auto curr_time = std::chrono::high_resolution_clock::now(); const std::chrono::duration diff = curr_time - this->last_draw_time; FPSArrayInsertElement(&draw_fps, diff.count()); @@ -330,6 +382,14 @@ void WindowScreen::free_ownership_of_window(bool is_main_thread) { } } +static bool is_vertically_rotated(int rotation) { + return (rotation / 10) % 2; +} + +static bool is_negatively_rotated(int rotation) { + return ((rotation / 10) % 4) >= 2; +} + void WindowScreen::resize_in_rect(sf::RectangleShape &in_rect, int start_x, int start_y, int width, int height) { int target_x = start_x; int target_y = start_y; @@ -337,7 +397,7 @@ void WindowScreen::resize_in_rect(sf::RectangleShape &in_rect, int start_x, int int target_height = height; int target_rotation = -1 * this->capture_status->device.base_rotation; - if((this->capture_status->device.base_rotation / 10) % 2) { + if(is_vertically_rotated(this->capture_status->device.base_rotation)) { std::swap(target_x, target_y); std::swap(target_width, target_height); } @@ -486,8 +546,8 @@ std::string WindowScreen::_title_factory() { if(this->capture_status->connected) title += " - " + get_name_of_device(this->capture_status); return title; -} - + } + sf::String WindowScreen::title_factory() { std::string title = this->_title_factory(); return sf::String::fromUtf8(title.begin(), title.end()); @@ -506,32 +566,171 @@ sf::String WindowScreen::title_factory() { #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #endif -void WindowScreen::update_texture() { - unsigned int m_texture = this->in_tex.getNativeHandle(); - if (this->saved_buf && m_texture) - { - // Copy pixels from the given array to the texture - glBindTexture(GL_TEXTURE_2D, m_texture); - GLenum format = GL_RGB; - GLenum type = GL_UNSIGNED_BYTE; - if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR) - format = GL_BGR; - if(this->capture_status->device.video_data_type == VIDEO_DATA_RGB16) - type = GL_UNSIGNED_SHORT_5_6_5; - if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR16) - type = GL_UNSIGNED_SHORT_5_6_5_REV; - size_t width = this->capture_status->device.width; - size_t height = this->capture_status->device.height; - if(get_3d_enabled(this->capture_status)) { - width = this->capture_status->device.width_3d; - height = this->capture_status->device.height_3d; - } - glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(this->curr_frame_texture_pos * MAX_IN_VIDEO_WIDTH), static_cast(0), static_cast(width), static_cast(height), format, type, this->saved_buf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +void WindowScreen::opengl_error_out(std::string error_base, std::string error_str) { + UpdateOutText(this->own_out_text_data, error_base + ": " + error_str, error_base, TEXT_KIND_ERROR); +} - // Force an OpenGL flush, so that the texture data will appear updated - // in all contexts immediately (solves problems in multi-threaded apps) - glFlush(); +void WindowScreen::opengl_error_check(std::string error_base) { + GLenum glCheckInternalError = glGetError(); + while (glCheckInternalError != GL_NO_ERROR) { + // Do error processing here... Simply logging it for now + this->opengl_error_out(error_base, std::to_string(glCheckInternalError)); + glCheckInternalError = glGetError(); + } +} + +bool WindowScreen::single_update_texture(unsigned int m_texture, InputVideoDataType video_data_type, size_t pos_x_data, size_t pos_y_data, size_t width, size_t height, bool manually_converted) { + if(!(this->saved_buf && m_texture)) + return false; + + this->opengl_error_check("Previous OpenGL Error"); + // Copy pixels from the given array to the texture + glBindTexture(GL_TEXTURE_2D, m_texture); + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; + size_t format_size = sizeof(VideoPixelRGB); + + if(!manually_converted) { + if(video_data_type == VIDEO_DATA_BGR) { + format = GL_BGR; + format_size = sizeof(VideoPixelBGR); + } + if(video_data_type == VIDEO_DATA_RGB16) { + type = GL_UNSIGNED_SHORT_5_6_5; + format_size = sizeof(VideoPixelRGB16); + } + if(video_data_type == VIDEO_DATA_BGR16) { + type = GL_UNSIGNED_SHORT_5_6_5_REV; + format_size = sizeof(VideoPixelBGR16); + } + } + + this->opengl_error_check("BindTexture OpenGL Error"); + glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(this->curr_frame_texture_pos * MAX_IN_VIDEO_WIDTH), static_cast(0), static_cast(width), static_cast(height), format, type, ((uint8_t*)this->saved_buf) + (pos_y_data * width * format_size)); + GLenum glCheckInternalError = glGetError(); + while (glCheckInternalError != GL_NO_ERROR) { + bool processed = false; + if(glCheckInternalError == GL_INVALID_ENUM) { + if((format != GL_RGB) || (type != GL_UNSIGNED_BYTE)) { + UpdateOutText(this->own_out_text_data, "Switching to software-based texture updating", "", TEXT_KIND_NORMAL); + this->last_update_texture_data_type = video_data_type; + this->use_texture_software_based_conv = true; + return true; + } + } + if(!processed) { + // Do error processing here... Simply logging it for now + this->opengl_error_out("SubImage2D OpenGL Error", std::to_string(glCheckInternalError)); + processed = true; + } + glCheckInternalError = glGetError(); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + this->opengl_error_check("TexParameteri OpenGL Error"); + + // Force an OpenGL flush, so that the texture data will appear updated + // in all contexts immediately (solves problems in multi-threaded apps) + glFlush(); + return false; +} + +void WindowScreen::execute_single_update_texture(bool &manually_converted, bool do_full, bool is_top, bool is_second) { + InputVideoDataType video_data_type = this->capture_status->device.video_data_type; + size_t top_width = TOP_WIDTH_3DS; + size_t top_height = HEIGHT_3DS; + size_t single_top_width = TOP_WIDTH_3DS; + size_t single_top_height = HEIGHT_3DS; + size_t bot_width = BOT_WIDTH_3DS; + size_t bot_height = HEIGHT_3DS; + if(!this->capture_status->device.is_3ds) { + top_width = WIDTH_DS; + top_height = HEIGHT_DS; + single_top_width = WIDTH_DS; + single_top_height = HEIGHT_DS; + bot_width = WIDTH_DS; + bot_height = HEIGHT_DS; + } + if(get_3d_enabled(this->capture_status)) + top_width *= 2; + + if(is_vertically_rotated(this->capture_status->device.base_rotation)) { + std::swap(top_width, top_height); + std::swap(single_top_width, single_top_height); + std::swap(bot_width, bot_height); + } + size_t full_width = std::max(top_width, bot_width); + size_t full_height = top_height + bot_height; + size_t width = full_width; + size_t height = full_height; + size_t pos_x_data = 0; + size_t pos_y_data = 0; + if(this->m_stype == ScreenType::TOP) { + full_height = top_height; + height = full_height; + pos_x_data = this->get_pos_x_screen_inside_data(true); + pos_y_data = this->get_pos_y_screen_inside_data(true); + } + if(this->m_stype == ScreenType::BOTTOM) { + full_height = bot_height; + height = full_height; + pos_x_data = this->get_pos_x_screen_inside_data(false); + pos_y_data = this->get_pos_y_screen_inside_data(false); + } + size_t pos_x_conv = pos_x_data; + size_t pos_y_conv = pos_y_data; + + sf::Texture* target_texture = &this->full_in_tex; + if(!do_full) { + if(is_top) { + height = single_top_height; + pos_x_data = this->get_pos_x_screen_inside_data(true, is_second); + pos_y_data = this->get_pos_y_screen_inside_data(true, is_second); + sf::Texture* top_l_texture = &this->top_l_in_tex; + sf::Texture* top_r_texture = &this->top_r_in_tex; + if(get_3d_enabled(this->capture_status) && (!this->display_data->interleaved_3d)) { + if(!this->capture_status->device.is_second_top_screen_right) + std::swap(top_l_texture, top_r_texture); + } + target_texture = top_l_texture; + if(is_second) + target_texture = top_r_texture; + } + else { + height = bot_height; + pos_x_data = this->get_pos_x_screen_inside_data(false); + pos_y_data = this->get_pos_y_screen_inside_data(false); + target_texture = &this->bot_in_tex; + } + } + + if(is_vertically_rotated(this->capture_status->device.base_rotation)) + std::swap(pos_x_data, pos_y_data); + + unsigned int m_texture = target_texture->getNativeHandle(); + bool retry = true; + while(retry) { + bool software_based_conv = manually_converted || (this->use_texture_software_based_conv && (video_data_type == this->last_update_texture_data_type)); + if(software_based_conv) { + if(!manually_converted) + manualConvertOutputToRGB(this->saved_buf, this->saved_buf, pos_x_conv, pos_y_conv, full_width, full_height, video_data_type); + manually_converted = true; + } + retry = this->single_update_texture(m_texture, video_data_type, pos_x_data, pos_y_data, width, height, manually_converted); + } +} + +void WindowScreen::update_texture() { + bool manually_converted = false; + if(this->shared_texture_available) + this->execute_single_update_texture(manually_converted, true); + else { + if((this->m_stype == ScreenType::TOP) || (this->m_stype == ScreenType::JOINT)) { + this->execute_single_update_texture(manually_converted, false, true); + if(get_3d_enabled(this->capture_status)) + this->execute_single_update_texture(manually_converted, false, true, true); + } + if((this->m_stype == ScreenType::BOTTOM) || (this->m_stype == ScreenType::JOINT)) + this->execute_single_update_texture(manually_converted, false, false); } } @@ -692,9 +891,9 @@ bool WindowScreen::apply_shaders_to_input(sf::RectangleShape &rect_data, sf::Ren if(chosen_shader < 0) return false; - float old_frame_pos_x = ((float)(NUM_FRAMES_BLENDED - 1)) / NUM_FRAMES_BLENDED; + float old_frame_pos_x = ((float)(this->num_frames_to_blend - 1)) / this->num_frames_to_blend; if(this->curr_frame_texture_pos > 0) - old_frame_pos_x = -1.0 / NUM_FRAMES_BLENDED; + old_frame_pos_x = -1.0f / this->num_frames_to_blend; sf::Glsl::Vec2 old_pos = {old_frame_pos_x, 0.0}; usable_shaders[chosen_shader].shader.setUniform("old_frame_offset", old_pos); to_process_tex_data->draw(final_in_rect, &usable_shaders[chosen_shader].shader); @@ -811,7 +1010,8 @@ void WindowScreen::display_data_to_window(bool actually_draw, bool is_debug) { this->m_out_rect_bot.to_process_tex = &this->m_out_rect_bot.out_tex; this->m_out_rect_bot.to_backup_tex = &this->m_out_rect_bot.backup_tex; this->post_texture_conversion_processing(out_rect_bot, this->m_out_rect_bot.to_process_tex, this->m_out_rect_bot.to_backup_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())) { + bool has_to_do_top_right_screen = get_3d_enabled(this->capture_status) && ((!this->display_data->interleaved_3d) || (!this->shared_texture_available)) && (this->m_stype != ScreenType::BOTTOM) && is_size_valid(out_rect_top.getSize()); + if(has_to_do_top_right_screen) { out_rect_top_right.setTextureRect(out_rect_top.getTextureRect()); this->m_out_rect_top_right.to_process_tex = &this->m_out_rect_top_right.out_tex; this->m_out_rect_top_right.to_backup_tex = &this->m_out_rect_top_right.backup_tex; @@ -823,17 +1023,38 @@ void WindowScreen::display_data_to_window(bool actually_draw, bool is_debug) { else this->m_win.clear(); this->window_bg_processing(); + bool needs_to_glue_textures_3d = has_to_do_top_right_screen && this->display_data->interleaved_3d && (!this->shared_texture_available); + if(needs_to_glue_textures_3d) { + float x_divisor = 2.0f; + float y_divisor = 1.0f; + out_rect_top.setSize({out_rect_top.getSize().x / x_divisor, out_rect_top.getSize().y / y_divisor}); + sf::IntRect texture_rect_top = out_rect_top.getTextureRect(); + texture_rect_top.size.x /= (int)x_divisor; + texture_rect_top.size.y /= (int)y_divisor; + out_rect_top.setTextureRect(texture_rect_top); + } 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())) { + if(has_to_do_top_right_screen) { sf::Vector2f offset_second_screen = get_3d_offset_out_rect(&this->loaded_info, true); + if(needs_to_glue_textures_3d) { + float base_multiplier = 1.0f; + if(is_negatively_rotated(this->loaded_info.top_rotation)) + base_multiplier = -1.0f; + if(is_vertically_rotated(this->loaded_info.top_rotation)) + offset_second_screen = {0, base_multiplier * out_rect_top.getSize().x / 1.0f}; + else + offset_second_screen = {base_multiplier * out_rect_top.getSize().x / 1.0f, 0}; + } 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); + if(!needs_to_glue_textures_3d) { + 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); @@ -913,9 +1134,9 @@ void WindowScreen::set_position_screens(sf::Vector2f &curr_top_screen_size, sf:: int bot_screen_width = (int)curr_bot_screen_size.x; int bot_screen_height = (int)curr_bot_screen_size.y; - if((this->loaded_info.top_rotation / 10) % 2) + if(is_vertically_rotated(this->loaded_info.top_rotation)) std::swap(top_screen_width, top_screen_height); - if((this->loaded_info.bot_rotation / 10) % 2) + if(is_vertically_rotated(this->loaded_info.bot_rotation)) std::swap(bot_screen_width, bot_screen_height); if(this->m_stype == ScreenType::TOP) @@ -986,7 +1207,7 @@ float WindowScreen::get_max_float_screen_multiplier(ResizingScreenData *own_scre if(!is_size_valid(own_screen->size)) return 0; - if((other_rotation / 10) % 2) + if(is_vertically_rotated(other_rotation)) std::swap(width_limit, height_limit); sf::Vector2f other_screen_size = sf::Vector2f((float)width_limit, (float)height_limit); if((!is_size_valid(other_screen_size)) && is_two_screens_merged) @@ -1012,7 +1233,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, own_screen->divide_3d_par); - if((own_screen->rotation / 10) % 2) + if(is_vertically_rotated(own_screen->rotation)) std::swap(own_width, own_height); if((own_height == 0) || (own_width == 0)) return 0; @@ -1157,9 +1378,9 @@ void WindowScreen::non_integer_scale_screens(ResizingScreenData *top_screen_resi std::swap(min_bigger_screen_height, min_smaller_screen_height); } - if((top_screen_resize_data->rotation / 10) % 2) + if(is_vertically_rotated(top_screen_resize_data->rotation)) std::swap(min_top_screen_width, min_top_screen_height); - if((bot_screen_resize_data->rotation / 10) % 2) + if(is_vertically_rotated(bot_screen_resize_data->rotation)) std::swap(min_bot_screen_width, min_bot_screen_height); sf::Vector2u curr_desk_mode_3d_size = get_desk_mode_3d_multiplied(&this->m_info); @@ -1195,9 +1416,9 @@ void WindowScreen::merge_screens_data(ResizingScreenData* top_screen_resize_data 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, bot_screen_resize_data->divide_3d_par); - if((top_screen_resize_data->rotation / 10) % 2) + if(is_vertically_rotated(top_screen_resize_data->rotation)) std::swap(top_width, top_height); - if((bot_screen_resize_data->rotation / 10) % 2) + if(is_vertically_rotated(bot_screen_resize_data->rotation)) std::swap(bot_width, bot_height); float final_width = std::max(top_width, bot_width); float final_height = std::max(top_height, bot_height); @@ -1296,9 +1517,9 @@ void WindowScreen::prepare_size_ratios(bool top_increase, bool bot_increase, boo } int WindowScreen::get_fullscreen_offset_x(int top_width, int top_height, int bot_width, int bot_height, int separator_contribute) { - if((this->loaded_info.top_rotation / 10) % 2) + if(is_vertically_rotated(this->loaded_info.top_rotation)) std::swap(top_width, top_height); - if((this->loaded_info.bot_rotation / 10) % 2) + if(is_vertically_rotated(this->loaded_info.bot_rotation)) std::swap(bot_width, bot_height); int greatest_width = std::max(top_width, bot_width); int offset_contribute = 0; @@ -1319,9 +1540,9 @@ int WindowScreen::get_fullscreen_offset_x(int top_width, int top_height, int bot } int WindowScreen::get_fullscreen_offset_y(int top_width, int top_height, int bot_width, int bot_height, int separator_contribute) { - if((this->loaded_info.top_rotation / 10) % 2) + if(is_vertically_rotated(this->loaded_info.top_rotation)) std::swap(top_width, top_height); - if((this->loaded_info.bot_rotation / 10) % 2) + if(is_vertically_rotated(this->loaded_info.bot_rotation)) std::swap(bot_width, bot_height); int greatest_height = std::max(top_height, bot_height); int offset_contribute = 0; @@ -1528,6 +1749,46 @@ sf::Vector2f WindowScreen::getShownScreenSize(bool is_top, ScreenInfo* info) { return {(float)width, (float)height}; } +int WindowScreen::get_pos_x_screen_inside_data(bool is_top, bool is_second) { + if(!is_top) + return this->capture_status->device.bot_screen_x; + if(!is_second) + return this->capture_status->device.top_screen_x; + return this->capture_status->device.second_top_screen_x; +} + +int WindowScreen::get_pos_y_screen_inside_data(bool is_top, bool is_second) { + if(!is_top) + return this->capture_status->device.bot_screen_y; + if(!is_second) + return this->capture_status->device.top_screen_y; + return this->capture_status->device.second_top_screen_y; +} + +int WindowScreen::get_pos_x_screen_inside_in_tex(bool is_top, bool is_second) { + if(!this->shared_texture_available) + return 0; + if(is_vertically_rotated(this->capture_status->device.base_rotation)) { + if(this->m_stype == ScreenType::TOP) + return this->get_pos_x_screen_inside_data(is_top, is_second) - this->get_pos_x_screen_inside_data(is_top, false); + if(this->m_stype == ScreenType::BOTTOM) + return 0; + } + return this->get_pos_x_screen_inside_data(is_top, is_second); +} + +int WindowScreen::get_pos_y_screen_inside_in_tex(bool is_top, bool is_second) { + if(!this->shared_texture_available) + return 0; + if(!is_vertically_rotated(this->capture_status->device.base_rotation)) { + if(this->m_stype == ScreenType::TOP) + return this->get_pos_y_screen_inside_data(is_top, is_second) - this->get_pos_y_screen_inside_data(is_top, false); + if(this->m_stype == ScreenType::BOTTOM) + return 0; + } + return this->get_pos_y_screen_inside_data(is_top, is_second); +} + void WindowScreen::crop() { std::vector *crops = this->get_crop_data_vector(&this->loaded_info); int *crop_value = this->get_crop_index_ptr(&this->loaded_info); @@ -1535,12 +1796,12 @@ 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_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, (int)bot_screen_size.x, (int)bot_screen_size.y); + this->resize_in_rect(this->m_in_rect_bot, this->get_pos_x_screen_inside_in_tex(false) + (*crops)[*crop_value]->bot_x, this->get_pos_y_screen_inside_in_tex(false) + (*crops)[*crop_value]->bot_y, (int)bot_screen_size.x, (int)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; + int left_top_screen_x = this->get_pos_x_screen_inside_in_tex(true, false); + int left_top_screen_y = this->get_pos_y_screen_inside_in_tex(true, false); + int right_top_screen_x = this->get_pos_x_screen_inside_in_tex(true, true); + int right_top_screen_y = this->get_pos_y_screen_inside_in_tex(true, true); 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); @@ -1549,10 +1810,19 @@ void WindowScreen::crop() { 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, (int)top_screen_size.x, (int)top_screen_size.y); } else { - float x_multiplier = 1.0; - if(get_3d_enabled(this->capture_status) && this->display_data->interleaved_3d) - x_multiplier = 2.0; - this->resize_in_rect(this->m_in_rect_top, (int)(this->capture_status->device.top_screen_x + ((*crops)[*crop_value]->top_x * x_multiplier)), this->capture_status->device.top_screen_y + (*crops)[*crop_value]->top_y, (int)top_screen_size.x, (int)top_screen_size.y); + bool is_3d_interleaved = get_3d_enabled(this->capture_status) && this->display_data->interleaved_3d; + float x_multiplier = 1.0f; + if(is_3d_interleaved) + x_multiplier = 2.0f; + int starting_in_rect_x = (int)(this->get_pos_x_screen_inside_in_tex(true) + ((*crops)[*crop_value]->top_x * x_multiplier)); + int starting_in_rect_y = (int)(this->get_pos_y_screen_inside_in_tex(true) + (*crops)[*crop_value]->top_y); + if(is_3d_interleaved && (!this->shared_texture_available)) + top_screen_size.x /= 2.0f; + this->resize_in_rect(this->m_in_rect_top, starting_in_rect_x, starting_in_rect_y, (int)top_screen_size.x, (int)top_screen_size.y); + if(is_3d_interleaved && (!this->shared_texture_available)) { + int second_screen_x_starting_pos = std::max(0, ((int)((*crops)[*crop_value]->top_x * x_multiplier)) - TOP_WIDTH_3DS); + this->resize_in_rect(this->m_in_rect_top_right, second_screen_x_starting_pos, starting_in_rect_y, (int)top_screen_size.x, (int)top_screen_size.y); + } } this->loaded_operations.call_screen_settings_update = true; } @@ -1574,3 +1844,12 @@ void WindowScreen::setWinSize(bool is_main_thread) { this->draw_lock->unlock(); } } + +void WindowScreen::process_own_out_text_data(bool print_to_notification) { + if(!this->own_out_text_data.consumed) { + ConsumeOutText(this->own_out_text_data, false); + if(print_to_notification) + this->print_notification(this->own_out_text_data.small_text, this->own_out_text_data.kind); + this->own_out_text_data.consumed = true; + } +} diff --git a/source/WindowScreen_Menu.cpp b/source/WindowScreen_Menu.cpp index 054c510..b5a20c9 100755 --- a/source/WindowScreen_Menu.cpp +++ b/source/WindowScreen_Menu.cpp @@ -97,32 +97,32 @@ static double FPSArrayGetAverage(FPSArray *array) { void WindowScreen::init_menus() { this->last_menu_change_time = std::chrono::high_resolution_clock::now(); - this->connection_menu = new ConnectionMenu(this->font_load_success, this->text_font); - this->main_menu = new MainMenu(this->font_load_success, this->text_font); - this->video_menu = new VideoMenu(this->font_load_success, this->text_font); - this->crop_menu = new CropMenu(this->font_load_success, this->text_font); - this->par_menu = new PARMenu(this->font_load_success, this->text_font); - this->offset_menu = new OffsetMenu(this->font_load_success, this->text_font); - this->rotation_menu = new RotationMenu(this->font_load_success, this->text_font); - this->audio_menu = new AudioMenu(this->font_load_success, this->text_font); - this->bfi_menu = new BFIMenu(this->font_load_success, this->text_font); - this->relpos_menu = new RelativePositionMenu(this->font_load_success, this->text_font); - this->resolution_menu = new ResolutionMenu(this->font_load_success, this->text_font); - this->fileconfig_menu = new FileConfigMenu(this->font_load_success, this->text_font); - this->extra_menu = new ExtraSettingsMenu(this->font_load_success, this->text_font); - this->status_menu = new StatusMenu(this->font_load_success, this->text_font); - this->license_menu = new LicenseMenu(this->font_load_success, this->text_font); - this->shortcut_menu = new ShortcutMenu(this->font_load_success, this->text_font); - this->action_selection_menu = new ActionSelectionMenu(this->font_load_success, this->text_font); - this->scaling_ratio_menu = new ScalingRatioMenu(this->font_load_success, this->text_font); - this->is_nitro_menu = new ISNitroMenu(this->font_load_success, this->text_font); - this->video_effects_menu = new VideoEffectsMenu(this->font_load_success, this->text_font); - this->input_menu = new InputMenu(this->font_load_success, this->text_font); - 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); + this->connection_menu = new ConnectionMenu(this->text_rectangle_pool); + this->main_menu = new MainMenu(this->text_rectangle_pool); + this->video_menu = new VideoMenu(this->text_rectangle_pool); + this->crop_menu = new CropMenu(this->text_rectangle_pool); + this->par_menu = new PARMenu(this->text_rectangle_pool); + this->offset_menu = new OffsetMenu(this->text_rectangle_pool); + this->rotation_menu = new RotationMenu(this->text_rectangle_pool); + this->audio_menu = new AudioMenu(this->text_rectangle_pool); + this->bfi_menu = new BFIMenu(this->text_rectangle_pool); + this->relpos_menu = new RelativePositionMenu(this->text_rectangle_pool); + this->resolution_menu = new ResolutionMenu(this->text_rectangle_pool); + this->fileconfig_menu = new FileConfigMenu(this->text_rectangle_pool); + this->extra_menu = new ExtraSettingsMenu(this->text_rectangle_pool); + this->status_menu = new StatusMenu(this->text_rectangle_pool); + this->license_menu = new LicenseMenu(this->text_rectangle_pool); + this->shortcut_menu = new ShortcutMenu(this->text_rectangle_pool); + this->action_selection_menu = new ActionSelectionMenu(this->text_rectangle_pool); + this->scaling_ratio_menu = new ScalingRatioMenu(this->text_rectangle_pool); + this->is_nitro_menu = new ISNitroMenu(this->text_rectangle_pool); + this->video_effects_menu = new VideoEffectsMenu(this->text_rectangle_pool); + this->input_menu = new InputMenu(this->text_rectangle_pool); + this->audio_device_menu = new AudioDeviceMenu(this->text_rectangle_pool); + this->separator_menu = new SeparatorMenu(this->text_rectangle_pool); + this->color_correction_menu = new ColorCorrectionMenu(this->text_rectangle_pool); + this->main_3d_menu = new Main3DMenu(this->text_rectangle_pool); + this->second_screen_3d_relpos_menu = new SecondScreen3DRelativePositionMenu(this->text_rectangle_pool); } void WindowScreen::destroy_menus() { diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index 309bd15..8afbf4b 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -29,17 +29,11 @@ #define NO_DATA_CONSECUTIVE_THRESHOLD 4 #define TIME_AUDIO_DEVICE_CHECK 0.25 -struct OutTextData { - std::string full_text; - std::string small_text; - bool consumed; - TextKind kind; -}; - struct override_all_data { override_win_data override_top_bot_data; override_win_data override_top_data; override_win_data override_bot_data; + bool disable_frame_blending = false; bool no_audio = false; int volume = DEFAULT_NO_VOLUME_VALUE; bool always_prevent_mouse_showing = false; @@ -51,20 +45,6 @@ struct override_all_data { bool quit_on_first_connection_failure = false; }; -static void ConsoleOutText(std::string full_text) { - if(full_text != "") - std::cout << "[" << NAME << "] " << full_text << std::endl; -} - -static void UpdateOutText(OutTextData &out_text_data, std::string full_text, std::string small_text, TextKind kind) { - if(!out_text_data.consumed) - ConsoleOutText(out_text_data.full_text); - out_text_data.full_text = full_text; - out_text_data.small_text = small_text; - out_text_data.kind = kind; - out_text_data.consumed = false; -} - static void SuccessConnectionOutTextGenerator(OutTextData &out_text_data, CaptureData* capture_data) { if(capture_data->status.connected) UpdateOutText(out_text_data, "Connected to " + capture_data->status.device.name + " - " + capture_data->status.device.serial_number, "Connected", TEXT_KIND_SUCCESS); @@ -528,7 +508,6 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, bool skip_io = false; int num_allowed_blanks = MAX_ALLOWED_BLANKS; OutTextData out_text_data; - out_text_data.consumed = true; int ret_val = 0; int poll_timeout = 0; const bool endianness = is_big_endian(); @@ -537,9 +516,9 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, memset(out_buf, 0, sizeof(VideoOutputData)); draw_lock.unlock(); - WindowScreen *top_screen = new WindowScreen(ScreenType::TOP, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder); - WindowScreen *bot_screen = new WindowScreen(ScreenType::BOTTOM, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder); - WindowScreen *joint_screen = new WindowScreen(ScreenType::JOINT, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder); + WindowScreen *top_screen = new WindowScreen(ScreenType::TOP, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder, override_data.disable_frame_blending); + WindowScreen *bot_screen = new WindowScreen(ScreenType::BOTTOM, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder, override_data.disable_frame_blending); + WindowScreen *joint_screen = new WindowScreen(ScreenType::JOINT, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder, override_data.disable_frame_blending); frontend_data.top_screen = top_screen; frontend_data.bot_screen = bot_screen; frontend_data.joint_screen = joint_screen; @@ -696,8 +675,11 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, capture_data->status.new_error_text = false; } + top_screen->process_own_out_text_data(); + bot_screen->process_own_out_text_data(); + joint_screen->process_own_out_text_data(); if((!out_text_data.consumed) && (!frontend_data.reload)) { - ConsoleOutText(out_text_data.full_text); + ConsumeOutText(out_text_data, false); top_screen->print_notification(out_text_data.small_text, out_text_data.kind); bot_screen->print_notification(out_text_data.small_text, out_text_data.kind); joint_screen->print_notification(out_text_data.small_text, out_text_data.kind); @@ -719,10 +701,10 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, save_layout_file(override_data.loaded_profile, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, false, created_proper_folder); - if(!out_text_data.consumed) { - ConsoleOutText(out_text_data.full_text); - out_text_data.consumed = true; - } + top_screen->process_own_out_text_data(false); + bot_screen->process_own_out_text_data(false); + joint_screen->process_own_out_text_data(false); + ConsumeOutText(out_text_data); delete out_buf; return ret_val; @@ -801,6 +783,8 @@ int main(int argc, char **argv) { continue; if(parse_existence_arg(i, argv, override_data.recovery_mode, true, "--recovery_mode")) continue; + if(parse_existence_arg(i, argv, override_data.disable_frame_blending, true, "--no_frame_blend")) + continue; if(parse_int_arg(i, argc, argv, override_data.override_top_bot_data.pos_x, "--pos_x_both")) continue; if(parse_int_arg(i, argc, argv, override_data.override_top_bot_data.pos_y, "--pos_y_both")) @@ -852,41 +836,43 @@ int main(int argc, char **argv) { continue; #endif std::cout << "Help:" << std::endl; - std::cout << " --mono_app Enables special mode for when only this application" << std::endl; - std::cout << " should run on the system. Disabled by default." << std::endl; - std::cout << " --recovery_mode Resets to the defaults." << std::endl; - std::cout << " --pos_x_both Set default x position for the window with both screens." << std::endl; - std::cout << " --pos_y_both Set default y position for the window with both screens." << std::endl; - std::cout << " --scaling_both Overrides the scale factor for the window with both screens." << std::endl; - std::cout << " --enabled_both Overrides the presence of the window with both screens." << std::endl; - std::cout << " 1 On, 0 Off." << std::endl; - std::cout << " --pos_x_top Set default x position for the top screen's window." << std::endl; - std::cout << " --pos_y_top Set default y position for the top screen's window." << std::endl; - std::cout << " --scaling_top Overrides the top screen window's scale factor." << std::endl; - std::cout << " --enabled_top Overrides the presence of the top screen's window." << std::endl; - std::cout << " 1 On, 0 Off." << std::endl; - std::cout << " --pos_x_bot Set default x position for the bottom screen's window." << std::endl; - std::cout << " --pos_y_bot Set default y position for the bottom screen's window." << std::endl; - std::cout << " --scaling_bot Overrides the bottom screen window's scale factor." << std::endl; - std::cout << " --enabled_bot Overrides the presence of the bottom screen's window." << std::endl; - std::cout << " 1 On, 0 Off." << std::endl; - std::cout << " --volume Overrides the saved volume for the audio. 0 - 200" << std::endl; - std::cout << " --no_audio Disables audio output and processing completely." << std::endl; - std::cout << " --no_cursor Prevents the mouse cursor from showing, unless moved." << std::endl; - std::cout << " --auto_connect Automatically connects to the first available device," << std::endl; - std::cout << " even if multiple are present." << std::endl; - std::cout << " --failure_close Automatically closes the software if the first connection" << std::endl; - std::cout << " doesn't succeed." << std::endl; - std::cout << " --auto_close Automatically closes the software on disconnect." << std::endl; - std::cout << " --profile Loads the profile with the specified ID at startup" << std::endl; - std::cout << " instead of the default one. When the program closes," << std::endl; - std::cout << " the data is also saved to the specified profile." << std::endl; + std::cout << " --mono_app Enables special mode for when only this application" << std::endl; + std::cout << " should run on the system. Disabled by default." << std::endl; + std::cout << " --recovery_mode Resets to the defaults." << std::endl; + std::cout << " --pos_x_both Set default x position for the window with both screens." << std::endl; + std::cout << " --pos_y_both Set default y position for the window with both screens." << std::endl; + std::cout << " --scaling_both Overrides the scale factor for the window with both screens." << std::endl; + std::cout << " --enabled_both Overrides the presence of the window with both screens." << std::endl; + std::cout << " 1 On, 0 Off." << std::endl; + std::cout << " --pos_x_top Set default x position for the top screen's window." << std::endl; + std::cout << " --pos_y_top Set default y position for the top screen's window." << std::endl; + std::cout << " --scaling_top Overrides the top screen window's scale factor." << std::endl; + std::cout << " --enabled_top Overrides the presence of the top screen's window." << std::endl; + std::cout << " 1 On, 0 Off." << std::endl; + std::cout << " --pos_x_bot Set default x position for the bottom screen's window." << std::endl; + std::cout << " --pos_y_bot Set default y position for the bottom screen's window." << std::endl; + std::cout << " --scaling_bot Overrides the bottom screen window's scale factor." << std::endl; + std::cout << " --enabled_bot Overrides the presence of the bottom screen's window." << std::endl; + std::cout << " 1 On, 0 Off." << std::endl; + std::cout << " --no_frame_blend Disables support for frame blending shader." << std::endl; + std::cout << " May improve compatibility with lower end hardware." << std::endl; + std::cout << " --volume Overrides the saved volume for the audio. 0 - 200" << std::endl; + std::cout << " --no_audio Disables audio output and processing completely." << std::endl; + std::cout << " --no_cursor Prevents the mouse cursor from showing, unless moved." << std::endl; + std::cout << " --auto_connect Automatically connects to the first available device," << std::endl; + std::cout << " even if multiple are present." << std::endl; + std::cout << " --failure_close Automatically closes the software if the first connection" << std::endl; + std::cout << " doesn't succeed." << std::endl; + std::cout << " --auto_close Automatically closes the software on disconnect." << std::endl; + std::cout << " --profile Loads the profile with the specified ID at startup" << std::endl; + std::cout << " instead of the default one. When the program closes," << std::endl; + std::cout << " the data is also saved to the specified profile." << std::endl; #ifdef RASPI - std::cout << " --pi_select ID Specifies ID for the select GPIO button." << std::endl; - std::cout << " --pi_menu ID Specifies ID for the menu GPIO button." << std::endl; - std::cout << " --pi_enter ID Specifies ID for the enter GPIO button." << std::endl; - std::cout << " --pi_power ID Specifies ID for the poweroff GPIO button." << std::endl; - std::cout << " --pi_pud_down Sets the pull-up GPIO mode to down. Default is up." << std::endl; + std::cout << " --pi_select ID Specifies ID for the select GPIO button." << std::endl; + std::cout << " --pi_menu ID Specifies ID for the menu GPIO button." << std::endl; + std::cout << " --pi_enter ID Specifies ID for the enter GPIO button." << std::endl; + std::cout << " --pi_power ID Specifies ID for the poweroff GPIO button." << std::endl; + std::cout << " --pi_pud_down Sets the pull-up GPIO mode to down. Default is up." << std::endl; #endif return 0; } diff --git a/source/conversions.cpp b/source/conversions.cpp index 1b0c458..a53a16f 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -340,11 +340,11 @@ static inline void usb_rgb888convertInterleaveU163DVideoToOutputDirectOptMonoBot static inline void convertVideoToOutputChunk(RGB83DSVideoInputData *p_in, VideoOutputData *p_out, size_t iters, size_t start_in, size_t start_out) { - memcpy(&p_out->screen_data[start_out], &p_in->screen_data[start_in], iters * 3); + memcpy(&p_out->rgb_video_output_data.screen_data[start_out], &p_in->screen_data[start_in], iters * sizeof(VideoPixelRGB)); } static inline void convertVideoToOutputChunk_3D(RGB83DSVideoInputData_3D *p_in, VideoOutputData *p_out, size_t iters, size_t start_in, size_t start_out) { - memcpy(&p_out->screen_data[start_out], &p_in->screen_data[start_in], iters * 3); + memcpy(&p_out->rgb_video_output_data.screen_data[start_out], &p_in->screen_data[start_in], iters * sizeof(VideoPixelRGB)); } static void expand_2d_to_3d_convertVideoToOutput(uint8_t *out_screen_data, size_t pixels_size, bool interleaved_3d, bool requested_3d) { @@ -368,7 +368,7 @@ static void ftd3_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_ convertVideoToOutputChunk(&p_in->ftd3_received.video_in, p_out, IN_VIDEO_WIDTH_3DS, (((i * 2) + 0) * IN_VIDEO_WIDTH_3DS) + IN_VIDEO_NO_BOTTOM_SIZE_3DS, i * IN_VIDEO_WIDTH_3DS); convertVideoToOutputChunk(&p_in->ftd3_received.video_in, p_out, IN_VIDEO_WIDTH_3DS, (((i * 2) + 1) * IN_VIDEO_WIDTH_3DS) + IN_VIDEO_NO_BOTTOM_SIZE_3DS, BOT_SIZE_3DS + IN_VIDEO_NO_BOTTOM_SIZE_3DS + (i * IN_VIDEO_WIDTH_3DS)); } - expand_2d_to_3d_convertVideoToOutput((uint8_t*)p_out->screen_data, 3, interleaved_3d, requested_3d); + expand_2d_to_3d_convertVideoToOutput((uint8_t*)p_out->rgb_video_output_data.screen_data, sizeof(VideoPixelRGB), interleaved_3d, requested_3d); } 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; @@ -410,10 +410,10 @@ static void ftd3_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_ static inline void usb_oldDSconvertVideoToOutputHalfLineDirectOptLE(USBOldDSCaptureReceived *p_in, VideoOutputData *p_out, int input_halfline, int output_halfline) { //de-interleave pixels - const int pixels_size = 2; + const int pixels_size = sizeof(VideoPixelBGR16); const int num_halflines = 2; const size_t ptr_out_size = sizeof(deinterleaved_rgb565_pixels); - deinterleaved_rgb565_pixels* out_ptr_top = (deinterleaved_rgb565_pixels*)p_out->screen_data; + deinterleaved_rgb565_pixels* out_ptr_top = (deinterleaved_rgb565_pixels*)p_out->bgr16_video_output_data.screen_data; deinterleaved_rgb565_pixels* out_ptr_bottom = out_ptr_top + ((WIDTH_DS * HEIGHT_DS * pixels_size) / ptr_out_size); interleaved_rgb565_pixels* in_ptr = (interleaved_rgb565_pixels*)p_in->video_in.screen_data; const uint32_t halfline_iters = WIDTH_DS / num_halflines; @@ -422,10 +422,10 @@ static inline void usb_oldDSconvertVideoToOutputHalfLineDirectOptLE(USBOldDSCapt static inline void usb_oldDSconvertVideoToOutputHalfLineDirectOptBE(USBOldDSCaptureReceived *p_in, VideoOutputData *p_out, int input_halfline, int output_halfline) { //de-interleave pixels - const int pixels_size = 2; + const int pixels_size = sizeof(VideoPixelBGR16); const int num_halflines = 2; const size_t ptr_out_size = sizeof(deinterleaved_rgb565_pixels); - deinterleaved_rgb565_pixels* out_ptr_top = (deinterleaved_rgb565_pixels*)p_out->screen_data; + deinterleaved_rgb565_pixels* out_ptr_top = (deinterleaved_rgb565_pixels*)p_out->bgr16_video_output_data.screen_data; deinterleaved_rgb565_pixels* out_ptr_bottom = out_ptr_top + ((WIDTH_DS * HEIGHT_DS * pixels_size) / ptr_out_size); interleaved_rgb565_pixels* in_ptr = (interleaved_rgb565_pixels*)p_in->video_in.screen_data; const uint32_t halfline_iters = WIDTH_DS / num_halflines; @@ -442,12 +442,12 @@ static inline bool usb_OptimizeHasExtraHeaderSoundData(USB3DSOptimizeHeaderSound static inline void usb_3DS565OptimizeconvertVideoToOutputLineDirectOptLE(USB5653DSOptimizeCaptureReceived *p_in, VideoOutputData *p_out, uint16_t column) { //de-interleave pixels - const int pixels_size = 2; + const int pixels_size = sizeof(VideoPixelRGB16); const size_t column_start_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2) + 2; const size_t column_pre_last_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2); const size_t column_last_bot_pos = TOP_WIDTH_3DS; const size_t ptr_out_size = sizeof(deinterleaved_rgb565_pixels); - deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->screen_data; + deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->rgb16_video_output_data.screen_data; deinterleaved_rgb565_pixels* out_ptr_top = out_ptr_bottom + ((BOT_SIZE_3DS * pixels_size) / ptr_out_size); interleaved_rgb565_pixels* in_ptr = (interleaved_rgb565_pixels*)p_in->bottom_only_column; if(column < column_last_bot_pos) @@ -471,12 +471,12 @@ static inline void usb_3DS565OptimizeconvertVideoToOutputLineDirectOptLE(USB5653 static inline void usb_3DS565OptimizeconvertVideoToOutputLineDirectOptBE(USB5653DSOptimizeCaptureReceived *p_in, VideoOutputData *p_out, uint16_t column) { //de-interleave pixels - const int pixels_size = 2; + const int pixels_size = sizeof(VideoPixelRGB16); const size_t column_start_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2) + 2; const size_t column_pre_last_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2); const size_t column_last_bot_pos = TOP_WIDTH_3DS; const size_t ptr_out_size = sizeof(deinterleaved_rgb565_pixels); - deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->screen_data; + deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->rgb16_video_output_data.screen_data; deinterleaved_rgb565_pixels* out_ptr_top = out_ptr_bottom + ((BOT_SIZE_3DS * pixels_size) / ptr_out_size); interleaved_rgb565_pixels* in_ptr = (interleaved_rgb565_pixels*)p_in->bottom_only_column; if(column < column_last_bot_pos) @@ -500,12 +500,12 @@ static inline void usb_3DS565OptimizeconvertVideoToOutputLineDirectOptBE(USB5653 static inline void usb_3DS565Optimizeconvert3DVideoToOutputLineDirectOptLE(USB5653DSOptimizeCaptureReceived_3D *p_in, VideoOutputData *p_out, uint16_t column, bool interleaved_3d) { //de-interleave pixels - const int pixels_size = 2; + const int pixels_size = sizeof(VideoPixelRGB16); const size_t column_start_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2) + 2; const size_t column_pre_last_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2); const size_t column_last_bot_pos = TOP_WIDTH_3DS; const size_t ptr_out_size = sizeof(deinterleaved_rgb565_pixels); - deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->screen_data; + deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->rgb16_video_output_data.screen_data; deinterleaved_rgb565_pixels* out_ptr_top_l = out_ptr_bottom + ((BOT_SIZE_3DS * pixels_size) / ptr_out_size); deinterleaved_rgb565_pixels* out_ptr_top_r = out_ptr_bottom + (((TOP_SIZE_3DS + BOT_SIZE_3DS) * pixels_size) / ptr_out_size); interleaved_3d_rgb565_pixels* in_ptr = (interleaved_3d_rgb565_pixels*)p_in->bottom_only_column; @@ -536,12 +536,12 @@ static inline void usb_3DS565Optimizeconvert3DVideoToOutputLineDirectOptLE(USB56 static inline void usb_3DS565Optimizeconvert3DVideoToOutputLineDirectOptBE(USB5653DSOptimizeCaptureReceived_3D *p_in, VideoOutputData *p_out, uint16_t column, bool interleaved_3d) { //de-interleave pixels - const int pixels_size = 2; + const int pixels_size = sizeof(VideoPixelRGB16); const size_t column_start_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2) + 2; const size_t column_pre_last_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2); const size_t column_last_bot_pos = TOP_WIDTH_3DS; const size_t ptr_out_size = sizeof(deinterleaved_rgb565_pixels); - deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->screen_data; + deinterleaved_rgb565_pixels* out_ptr_bottom = (deinterleaved_rgb565_pixels*)p_out->rgb16_video_output_data.screen_data; deinterleaved_rgb565_pixels* out_ptr_top_l = out_ptr_bottom + ((BOT_SIZE_3DS * pixels_size) / ptr_out_size); deinterleaved_rgb565_pixels* out_ptr_top_r = out_ptr_bottom + (((TOP_SIZE_3DS + BOT_SIZE_3DS) * pixels_size) / ptr_out_size); interleaved_3d_rgb565_pixels* in_ptr = (interleaved_3d_rgb565_pixels*)p_in->bottom_only_column; @@ -572,12 +572,12 @@ static inline void usb_3DS565Optimizeconvert3DVideoToOutputLineDirectOptBE(USB56 static inline void usb_3DS888OptimizeconvertVideoToOutputLineDirectOpt(USB8883DSOptimizeCaptureReceived *p_in, VideoOutputData *p_out, uint16_t column) { //de-interleave pixels - const int pixels_size = 3; + const int pixels_size = sizeof(VideoPixelRGB); const size_t column_start_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2) + 2; const size_t column_pre_last_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2); const size_t column_last_bot_pos = TOP_WIDTH_3DS; const size_t ptr_out_size = sizeof(deinterleaved_rgb888_u16_pixels); - deinterleaved_rgb888_u16_pixels* out_ptr_bottom = (deinterleaved_rgb888_u16_pixels*)p_out->screen_data; + deinterleaved_rgb888_u16_pixels* out_ptr_bottom = (deinterleaved_rgb888_u16_pixels*)p_out->rgb_video_output_data.screen_data; deinterleaved_rgb888_u16_pixels* out_ptr_top = out_ptr_bottom + ((BOT_SIZE_3DS * pixels_size) / ptr_out_size); interleaved_rgb888_u16_pixels* in_ptr = (interleaved_rgb888_u16_pixels*)p_in->bottom_only_column; if(column < column_last_bot_pos) @@ -601,12 +601,12 @@ static inline void usb_3DS888OptimizeconvertVideoToOutputLineDirectOpt(USB8883DS static inline void usb_3DS888Optimizeconvert3DVideoToOutputLineDirectOpt(USB8883DSOptimizeCaptureReceived_3D *p_in, VideoOutputData *p_out, uint16_t column, bool interleaved_3d) { //de-interleave pixels - const int pixels_size = 3; + const int pixels_size = sizeof(VideoPixelRGB); const size_t column_start_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2) + 2; const size_t column_pre_last_bot_pos = (SCREEN_WIDTH_FIRST_PIXEL_BOTTOM_3DS * 2); const size_t column_last_bot_pos = TOP_WIDTH_3DS; const size_t ptr_out_size = sizeof(deinterleaved_rgb888_u16_pixels); - deinterleaved_rgb888_u16_pixels* out_ptr_bottom = (deinterleaved_rgb888_u16_pixels*)p_out->screen_data; + deinterleaved_rgb888_u16_pixels* out_ptr_bottom = (deinterleaved_rgb888_u16_pixels*)p_out->rgb_video_output_data.screen_data; deinterleaved_rgb888_u16_pixels* out_ptr_top_l = out_ptr_bottom + ((BOT_SIZE_3DS * pixels_size) / ptr_out_size); deinterleaved_rgb888_u16_pixels* out_ptr_top_r = out_ptr_bottom + (((TOP_SIZE_3DS + BOT_SIZE_3DS) * pixels_size) / ptr_out_size); interleaved_3d_rgb888_u16_pixels* in_ptr = (interleaved_3d_rgb888_u16_pixels*)p_in->bottom_only_column; @@ -638,12 +638,12 @@ static inline void usb_3DS888Optimizeconvert3DVideoToOutputLineDirectOpt(USB8883 static void usb_oldDSconvertVideoToOutput(USBOldDSCaptureReceived *p_in, VideoOutputData *p_out, const bool is_big_endian) { #ifndef SIMPLE_DS_FRAME_SKIP if(!p_in->frameinfo.valid) { //LCD was off - memset(p_out->screen_data, 0, WIDTH_DS * (2 * HEIGHT_DS) * sizeof(uint16_t)); + memset(p_out->bgr16_video_output_data.screen_data, 0, WIDTH_DS * (2 * HEIGHT_DS) * sizeof(uint16_t)); return; } // Handle first line being off, if needed - memset(p_out->screen_data, 0, WIDTH_DS * sizeof(uint16_t)); + memset(p_out->bgr16_video_output_data.screen_data, 0, WIDTH_DS * sizeof(uint16_t)); if(!is_big_endian) { int input_halfline = 0; @@ -656,7 +656,7 @@ static void usb_oldDSconvertVideoToOutput(USBOldDSCaptureReceived *p_in, VideoOu if(p_in->frameinfo.half_line_flags[(i >> 3)] & (1 << (i & 7))) usb_oldDSconvertVideoToOutputHalfLineDirectOptLE(p_in, p_out, input_halfline++, i); else { // deal with missing half-line - uint16_t* out_ptr_top = (uint16_t*)&p_out->screen_data; + uint16_t* out_ptr_top = (uint16_t*)&p_out->bgr16_video_output_data.screen_data; uint16_t* out_ptr_bottom = out_ptr_top + (WIDTH_DS * HEIGHT_DS); memcpy(&out_ptr_top[i * (WIDTH_DS / 2)], &out_ptr_top[(i - 2) * (WIDTH_DS / 2)], (WIDTH_DS / 2) * sizeof(uint16_t)); memcpy(&out_ptr_bottom[i * (WIDTH_DS / 2)], &out_ptr_bottom[(i - 2) * (WIDTH_DS / 2)], (WIDTH_DS / 2) * sizeof(uint16_t)); @@ -674,7 +674,7 @@ static void usb_oldDSconvertVideoToOutput(USBOldDSCaptureReceived *p_in, VideoOu if(p_in->frameinfo.half_line_flags[(i >> 3)] & (1 << (i & 7))) usb_oldDSconvertVideoToOutputHalfLineDirectOptBE(p_in, p_out, input_halfline++, i); else { // deal with missing half-line - uint16_t* out_ptr_top = (uint16_t*)&p_out->screen_data; + uint16_t* out_ptr_top = (uint16_t*)&p_out->bgr16_video_output_data.screen_data; uint16_t* out_ptr_bottom = out_ptr_top + (WIDTH_DS * HEIGHT_DS); memcpy(&out_ptr_top[i * (WIDTH_DS / 2)], &out_ptr_top[(i - 2) * (WIDTH_DS / 2)], (WIDTH_DS / 2) * sizeof(uint16_t)); memcpy(&out_ptr_bottom[i * (WIDTH_DS / 2)], &out_ptr_bottom[(i - 2) * (WIDTH_DS / 2)], (WIDTH_DS / 2) * sizeof(uint16_t)); @@ -696,7 +696,7 @@ static void ftd2_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_ } static void usb_3DSconvertVideoToOutput(USB3DSCaptureReceived *p_in, VideoOutputData *p_out) { - memcpy(p_out->screen_data, p_in->video_in.screen_data, IN_VIDEO_HEIGHT_3DS * IN_VIDEO_WIDTH_3DS * 3); + memcpy(p_out->rgb_video_output_data.screen_data, p_in->video_in.screen_data, IN_VIDEO_HEIGHT_3DS * IN_VIDEO_WIDTH_3DS * 3); } static void usb_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureDevice* capture_device, bool enabled_3d, const bool is_big_endian, bool interleaved_3d, bool requested_3d) { @@ -712,6 +712,10 @@ inline static uint8_t to_8_bit_6(uint8_t data) { return (data << 2) | (data >> 4); } +inline static uint8_t to_8_bit_5(uint8_t data) { + return (data << 3) | (data >> 2); +} + inline static void to_8_bit_6(uint8_t* out, uint8_t* in) { out[0] = to_8_bit_6(in[0]); out[1] = to_8_bit_6(in[1]); @@ -720,9 +724,9 @@ inline static void to_8_bit_6(uint8_t* out, uint8_t* in) { static void usb_cypress_nisetro_ds_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out) { int pos_top = 0; - int pos_bottom = WIDTH_DS * HEIGHT_DS * 3; + int pos_bottom = WIDTH_DS * HEIGHT_DS * sizeof(VideoPixelRGB); uint8_t* data_in = (uint8_t*)p_in->cypress_nisetro_capture_received.video_in.screen_data; - uint8_t* data_out = (uint8_t*)p_out->screen_data; + uint8_t* data_out = (uint8_t*)p_out->rgb_video_output_data.screen_data; for(size_t i = 0; i < sizeof(CypressNisetroDSCaptureReceived); i++) { uint8_t conv = to_8_bit_6(data_in[i]); if(data_in[i] & 0x40) @@ -741,7 +745,7 @@ static void usb_3ds_optimize_convertVideoToOutput(CaptureReceived *p_in, VideoOu else for(int i = 0; i < (TOP_WIDTH_3DS + 1); i++) usb_3DS565OptimizeconvertVideoToOutputLineDirectOptBE(&p_in->cypress_optimize_received_565, p_out, i); - expand_2d_to_3d_convertVideoToOutput((uint8_t*)p_out->screen_data, 2, interleaved_3d, requested_3d); + expand_2d_to_3d_convertVideoToOutput((uint8_t*)p_out->rgb16_video_output_data.screen_data, sizeof(VideoPixelRGB16), interleaved_3d, requested_3d); } else { if(!is_big_endian) @@ -756,7 +760,7 @@ static void usb_3ds_optimize_convertVideoToOutput(CaptureReceived *p_in, VideoOu if(!enabled_3d) { for(int i = 0; i < (TOP_WIDTH_3DS + 1); i++) usb_3DS888OptimizeconvertVideoToOutputLineDirectOpt(&p_in->cypress_optimize_received_888, p_out, i); - expand_2d_to_3d_convertVideoToOutput((uint8_t*)p_out->screen_data, 3, interleaved_3d, requested_3d); + expand_2d_to_3d_convertVideoToOutput((uint8_t*)p_out->rgb_video_output_data.screen_data, sizeof(VideoPixelRGB), interleaved_3d, requested_3d); } else { for(int i = 0; i < (TOP_WIDTH_3DS + 1); i++) @@ -779,8 +783,8 @@ static void usb_is_device_convertVideoToOutput(CaptureReceived *p_in, VideoOutpu out_clear_pos = 0; } if((capture_type == CAPTURE_SCREENS_BOTTOM) || (capture_type == CAPTURE_SCREENS_TOP)) - memset(p_out->screen_data[out_clear_pos], 0, (size_t)(num_pixels * 3)); - memcpy(p_out->screen_data[out_start_pos], p_in->is_nitro_capture_received.video_in.screen_data, (size_t)(num_pixels * 3)); + memset((uint8_t*)&p_out->bgr_video_output_data.screen_data[out_clear_pos], 0, (size_t)(num_pixels * sizeof(VideoPixelBGR))); + memcpy((uint8_t*)&p_out->bgr_video_output_data.screen_data[out_start_pos], p_in->is_nitro_capture_received.video_in.screen_data, (size_t)(num_pixels * sizeof(VideoPixelBGR))); return; } ISTWLCaptureVideoInputData* data = &p_in->is_twl_capture_received.video_capture_in.video_in; @@ -807,7 +811,7 @@ static void usb_is_device_convertVideoToOutput(CaptureReceived *p_in, VideoOutpu pixels[3][1] = data_16_bit[index].fourth_g; pixels[3][2] = (data_16_bit[index].fourth_b << 1) | (data_2_bit[index].fourth_b); for(int k = 0; k < num_pixels_struct; k++) - to_8_bit_6(p_out->screen_data[out_pos + (u * num_pixels_struct) + k], pixels[k]); + to_8_bit_6((uint8_t*)&p_out->rgb_video_output_data.screen_data[out_pos + (u * num_pixels_struct) + k], pixels[k]); } } } @@ -1010,3 +1014,64 @@ bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, uint16_t &la p_out[i] = (base_ptr[(i * 2) + 1] << 8) | base_ptr[i * 2]; return true; } + +static void convert_rgb16_to_rgb(VideoOutputData* src, VideoOutputData* dst, size_t pos_x_data, size_t pos_y_data, size_t width, size_t height) { + for (size_t i = 0; i < height; i++) { + for (size_t j = 0; j < width; j++) { + size_t pixel = ((height - 1 - i) * width) + (width - 1 - j) + pos_x_data + (pos_y_data * width); + uint8_t r = to_8_bit_5(src->rgb16_video_output_data.screen_data[pixel].r); + uint8_t g = to_8_bit_6(src->rgb16_video_output_data.screen_data[pixel].g); + uint8_t b = to_8_bit_5(src->rgb16_video_output_data.screen_data[pixel].b); + dst->rgb_video_output_data.screen_data[pixel].r = r; + dst->rgb_video_output_data.screen_data[pixel].g = g; + dst->rgb_video_output_data.screen_data[pixel].b = b; + } + } +} + +static void convert_bgr_to_rgb(VideoOutputData* src, VideoOutputData* dst, size_t pos_x_data, size_t pos_y_data, size_t width, size_t height) { + for (size_t i = 0; i < height; i++) { + for (size_t j = 0; j < width; j++) { + size_t pixel = ((height - 1 - i) * width) + (width - 1 - j) + pos_x_data + (pos_y_data * width); + uint8_t r = src->bgr_video_output_data.screen_data[pixel].r; + uint8_t g = src->bgr_video_output_data.screen_data[pixel].g; + uint8_t b = src->bgr_video_output_data.screen_data[pixel].b; + dst->rgb_video_output_data.screen_data[pixel].r = r; + dst->rgb_video_output_data.screen_data[pixel].g = g; + dst->rgb_video_output_data.screen_data[pixel].b = b; + } + } +} + +static void convert_bgr16_to_rgb(VideoOutputData* src, VideoOutputData* dst, size_t pos_x_data, size_t pos_y_data, size_t width, size_t height) { + uint16_t* data_16_ptr = (uint16_t*)src; + for (size_t i = 0; i < height; i++) { + for (size_t j = 0; j < width; j++) { + size_t pixel = ((height - 1 - i) * width) + (width - 1 - j) + pos_x_data + (pos_y_data * width); + uint8_t r = to_8_bit_5(src->bgr16_video_output_data.screen_data[pixel].r); + uint8_t g = to_8_bit_6(src->bgr16_video_output_data.screen_data[pixel].g); + uint8_t b = to_8_bit_5(src->bgr16_video_output_data.screen_data[pixel].b); + dst->rgb_video_output_data.screen_data[pixel].r = r; + dst->rgb_video_output_data.screen_data[pixel].g = g; + dst->rgb_video_output_data.screen_data[pixel].b = b; + } + } +} + +void manualConvertOutputToRGB(VideoOutputData* src, VideoOutputData* dst, size_t pos_x_data, size_t pos_y_data, size_t width, size_t height, InputVideoDataType video_data_type) { + switch (video_data_type) { + case VIDEO_DATA_RGB: + break; + case VIDEO_DATA_RGB16: + convert_rgb16_to_rgb(src, dst, pos_x_data, pos_y_data, width, height); + break; + case VIDEO_DATA_BGR: + convert_bgr_to_rgb(src, dst, pos_x_data, pos_y_data, width, height); + break; + case VIDEO_DATA_BGR16: + convert_bgr16_to_rgb(src, dst, pos_x_data, pos_y_data, width, height); + break; + default: + break; + } +} diff --git a/source/frontend.cpp b/source/frontend.cpp index a47adfa..fddf41d 100755 --- a/source/frontend.cpp +++ b/source/frontend.cpp @@ -1,6 +1,7 @@ #include "frontend.hpp" #include #include +#include #include const CropData default_3ds_crop = { @@ -1177,3 +1178,24 @@ std::string get_name_input_colorspace_mode(InputColorspaceMode input) { } return output; } + +static void ConsoleOutText(std::string full_text, std::string preamble_name) { + if(full_text != "") + std::cout << "[" << preamble_name << "] " << full_text << std::endl; +} + +void ConsumeOutText(OutTextData &out_text_data, bool update_consumed) { + if(!out_text_data.consumed) + ConsoleOutText(out_text_data.full_text, out_text_data.preamble_name); + if(update_consumed) + out_text_data.consumed = true; +} + +void UpdateOutText(OutTextData &out_text_data, std::string full_text, std::string small_text, TextKind kind) { + if(!out_text_data.consumed) + ConsumeOutText(out_text_data); + out_text_data.full_text = full_text; + out_text_data.small_text = small_text; + out_text_data.kind = kind; + out_text_data.consumed = false; +}