Implement Menu for adding Optimize serial keys
Some checks are pending
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux32 flags:32 name:Linux GCC 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux64 flags:64 name:Linux GCC x64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm32 flags:arm32 name:Linux GCC ARM 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm64 flags:arm64 name:Linux GCC ARM 64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:macos name:macOS Apple Silicon os:macos-14]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win32 flags:-A Win32 -DCMAKE_PARALLEL_MSVC=TRUE name:Windows VS2022 Win32 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win64 flags:-A x64 -DCMAKE_PARALLEL_MSVC=TRUE name:Windows VS2022 x64 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:winarm64 flags:-A ARM64 -DCMAKE_PARALLEL_MSVC=TRUE name:Windows VS2022 ARM os:windows-2022]) (push) Waiting to run
CD / Create Pi Mono Setup (push) Blocked by required conditions
CD / Publishing (push) Blocked by required conditions

This commit is contained in:
Lorenzooone 2025-11-07 02:27:23 +01:00
parent a6e4348066
commit 4ce35770ac
37 changed files with 1847 additions and 112 deletions

View File

@ -372,7 +372,7 @@ if(CYPRESS_NISETRO_SUPPORT)
add_compile_flag("USE_CYNI_USB")
endif()
if(OPTIMIZE_3DS_SUPPORT)
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_communications.cpp ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_acquisition.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_888_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_888_fpga_pl.cpp ${TOOLS_DATA_DIR}/adler_crc32_table_sp.cpp ${TOOLS_DATA_DIR}/optimize_key_to_byte_table.cpp)
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_communications.cpp ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_acquisition.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_888_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_888_fpga_pl.cpp ${TOOLS_DATA_DIR}/adler_crc32_table_sp.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_to_byte_table.cpp)
add_compile_flag("USE_CYPRESS_OPTIMIZE")
endif()
if(NEW_DS_LOOPY_SUPPORT)
@ -520,7 +520,7 @@ else()
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$<CONFIG:Release>:-O3;-funroll-loops>")
endif()
set(EXECUTABLE_SOURCE_FILES 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 source/Menus/USBConflictResolutionMenu.cpp source/Menus/Optimize3DSMenu.cpp source/libgpiod_compat.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
set(EXECUTABLE_SOURCE_FILES 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 source/Menus/USBConflictResolutionMenu.cpp source/Menus/Optimize3DSMenu.cpp source/Menus/OptimizeSerialKeyAddMenu.cpp source/libgpiod_compat.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_add_table.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_next_char_table.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_prev_char_table.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/font_mono_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
add_compile_flag("SFML_SYSTEM_ANDROID")
@ -570,6 +570,13 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/data/font.ttf ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/font_mono_ttf.cpp
COMMENT "Convert mono font to binary"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/data/font_mono.ttf ${TOOLS_DATA_DIR} font_mono_ttf font_mono_ttf
DEPENDS ${CMAKE_SOURCE_DIR}/data/font_mono.ttf ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp
COMMENT "Convert fw binary to C - FTD2 NDS 1"
@ -655,10 +662,31 @@ add_custom_command(
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/optimize_key_to_byte_table.cpp
OUTPUT ${TOOLS_DATA_DIR}/optimize_serial_key_to_byte_table.cpp
COMMENT "Convert table to C - Optimize Key to 5 bits"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/optimize_key_to_byte_table.bin ${TOOLS_DATA_DIR} optimize_key_to_byte_table optimize_key_to_byte_table
DEPENDS ${CMAKE_SOURCE_DIR}/bin/optimize_key_to_byte_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_to_byte_table.bin ${TOOLS_DATA_DIR} optimize_serial_key_to_byte_table optimize_serial_key_to_byte_table
DEPENDS ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_to_byte_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/optimize_serial_key_add_table.cpp
COMMENT "Convert table to C - Optimize Serial Key Alphabet"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_add_table.bin ${TOOLS_DATA_DIR} optimize_serial_key_add_table optimize_serial_key_add_table
DEPENDS ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_add_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/optimize_serial_key_next_char_table.cpp
COMMENT "Convert table to C - Optimize Serial Key next character"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_next_char_table.bin ${TOOLS_DATA_DIR} optimize_serial_key_next_char_table optimize_serial_key_next_char_table
DEPENDS ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_next_char_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/optimize_serial_key_prev_char_table.cpp
COMMENT "Convert table to C - Optimize Serial previous character"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_prev_char_table.bin ${TOOLS_DATA_DIR} optimize_serial_key_prev_char_table optimize_serial_key_prev_char_table
DEPENDS ${CMAKE_SOURCE_DIR}/bin/optimize_serial_key_prev_char_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
set(SHADERS_LIST "")

View File

@ -136,10 +136,12 @@ The current configuration can be saved to various extra profiles, creating the g
The name of profiles can be changed by altering the __name__ field in its file.
On Linux and MacOS, the profiles can be found at the "${HOME}/.config/cc3dsfs" folder. By default, "/home/<user_name>/.config/cc3dsfs".
On Linux and MacOS, by default the profiles can be found at the "${HOME}/.config/cc3dsfs" folder. Or "/home/<user_name>/.config/cc3dsfs".
On Windows, the profiles can be found in the ".config/cc3dsfs" folder inside the directory in which the program runs from.
The CC3DSFS\_CFG\_DIR environment variable can be used to specify a different target folder for cc3dsfs to store its data.
## Notes
- On Linux, you may need to include the udev USB access rules. You can use the .rules files available in the repository's usb\_rules directory, or define your own. For ease of use, releases come bundled with a script to do it named install\_usb\_rules.sh. It may require elevated permissions to execute properly. You may get a permission error if the rules are not installed.
- At startup, the audio may be unstable. It should fix itself, if you give it enough time.
@ -153,4 +155,5 @@ On Windows, the profiles can be found in the ".config/cc3dsfs" folder inside the
- When using the new 2024 Loopy DS Capture Card on Windows, the default driver (FTD2XX) adds one extra frame of latency. To remove that, consider switching to WinUSB as the driver. To change driver, download a software to install drivers like [Zadig](https://zadig.akeo.ie/), select the device in question and select WinUSB. Then install the driver and wait for it to finish. The application will now use WinUSB, with better latency (the serial shown in the Status menu will have an l where there previously was a d).
- There are multiple capture cards which use the same EZ-USB FX2LP board, creating a conflict. This means that when the user connects a device which uses the EZ-USB FX2LP board, they need to select one capture card among the possible ones. To avoid this extra step, the user can disable scanning for the conflicting capture cards they do not intend to use. The settings to do this are available under Extra Settings -> USB Conflict Resolution.
- MacOS does not allow running multiple instances of the same application, normally. If you want to run multiple instances of cc3dsfs on MacOS, open the terminal in the folder where cc3dsfs is and type `open -n cc3dsfs.app`.
- The CC3DSFS\_CFG\_DIR environment variable can be used to specify where cc3dsfs will store its data.
- To properly use the Optimize capture cards with cc3dsfs, a serial key is needed. This can be added via the _Optimize 3DS Settings_, under the _Add New Serial Key_ option. You can use CTRL+V in the textbox to copy the serial key, or insert it manually. To obtain the key, get your device ID (it can be copied from the _Optimize 3DS Settings_ menu) and type it in the [Official site](https://optimize.ath.cx/productkey_en.html). Using a keyboard to do this is suggested (but not required).
- Keys are saved under the keys folder inside the cc3dsfs config folder.

View File

@ -2,5 +2,8 @@
<resources>
<usb-device vendor-id="1027" product-id="24596" class="0" subclass="0" protocol="0" />
<usb-device vendor-id="1874" product-id="34323" class="0" subclass="0" protocol="0" />
<usb-device vendor-id="1204" product-id="34323" class="0" subclass="0" protocol="0" />
<usb-device vendor-id="1204" product-id="4100" class="0" subclass="0" protocol="0" />
</resources>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0123456789<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ABCDEFGHIJKLMNOPQRSTUVWXYZ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ABCDEFGHIJKLMNOPQRSTUVWXYZ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>123456789A<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>BCDEFGHIJKLMNOPQRSTUVWXYZ0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>BCDEFGHIJKLMNOPQRSTUVWXYZ0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Z012345678<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>9ABCDEFGHIJKLMNOPQRSTUVWXY<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>9ABCDEFGHIJKLMNOPQRSTUVWXY<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

BIN
data/font_mono.ttf Normal file

Binary file not shown.

View File

@ -1,6 +1,12 @@
#ifndef __CYPRESS_OPTIMIZE_3DS_ACQUISITION_HPP
#define __CYPRESS_OPTIMIZE_3DS_ACQUISITION_HPP
#define SERIAL_KEY_OPTIMIZE_NO_DASHES_SIZE 20
#define SERIAL_KEY_OPTIMIZE_DASHES_REPEATED_POS 4
// Not the last one, so -1
#define SERIAL_KEY_OPTIMIZE_DASHES_NUM ((SERIAL_KEY_OPTIMIZE_NO_DASHES_SIZE / SERIAL_KEY_OPTIMIZE_DASHES_REPEATED_POS) - 1)
#define SERIAL_KEY_OPTIMIZE_WITH_DASHES_SIZE (SERIAL_KEY_OPTIMIZE_NO_DASHES_SIZE + SERIAL_KEY_OPTIMIZE_DASHES_NUM)
#include <vector>
#include "utils.hpp"
#include "hw_defs.hpp"
@ -18,6 +24,7 @@ bool is_device_optimize_3ds(CaptureDevice* device);
bool is_device_optimize_o3ds(CaptureDevice* device);
bool is_device_optimize_n3ds(CaptureDevice* device);
bool cyop_is_key_for_device_id(CaptureDevice* device, std::string key);
KeySaveError add_key_to_file(std::string key, bool is_for_new_3ds);
void usb_cyop_device_init();
void usb_cyop_device_close();

View File

@ -47,6 +47,7 @@ int StartCaptureDma(cy_device_device_handlers* handlers, const cyop_device_usb_d
int capture_end(cy_device_device_handlers* handlers, const cyop_device_usb_device* device);
int ReadFrame(cy_device_device_handlers* handlers, uint8_t* buf, int length, const cyop_device_usb_device* device_desc);
int ReadFrameAsync(cy_device_device_handlers* handlers, uint8_t* buf, int length, const cyop_device_usb_device* device_desc, cy_async_callback_data* cb_data);
uint64_t get_device_id_from_key(std::string key, bool is_new_device);
bool check_key_matches_device_id(uint64_t device_id, std::string key, bool is_new_device);
bool check_key_matches_device_id(uint64_t device_id, std::string key, const cyop_device_usb_device* device);
bool check_key_valid(std::string key, bool is_new_device);

View File

@ -11,5 +11,7 @@ public:
virtual void draw(float scaling_factor, sf::RenderTarget &window) = 0;
virtual void reset_data(bool full_reset) = 0;
virtual void reset_output_option() = 0;
virtual void on_menu_unloaded() {};
bool is_inside_textbox = false;
};
#endif

View File

@ -14,6 +14,10 @@ enum Optimize3DSMenuOutAction{
OPTIMIZE3DS_MENU_BACK,
OPTIMIZE3DS_MENU_INPUT_VIDEO_FORMAT_INC,
OPTIMIZE3DS_MENU_INPUT_VIDEO_FORMAT_DEC,
OPTIMIZE3DS_MENU_INFO_DEVICE_ID,
OPTIMIZE3DS_MENU_COPY_DEVICE_ID,
OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY,
OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY_MENU,
};
class Optimize3DSMenu : public OptionSelectionMenu {
@ -30,6 +34,7 @@ protected:
void set_output_option(int index, int action);
size_t get_num_options();
std::string get_string_option(int index, int action);
float get_option_text_factor(int index);
void class_setup();
private:
int *options_indexes;

View File

@ -0,0 +1,127 @@
#ifndef __OPTIMIZESERIALKEYADDMENU_HPP
#define __OPTIMIZESERIALKEYADDMENU_HPP
#include <chrono>
#include "GenericMenu.hpp"
#include "TextRectangle.hpp"
#include "TextRectanglePool.hpp"
#include "display_structs.hpp"
#include "capture_structs.hpp"
#define BACK_X_OUTPUT_OPTION -1
enum OptimizeSerialKeyMenuOutAction{
OPTIMIZE_SERIAL_KEY_ADD_MENU_NO_ACTION,
OPTIMIZE_SERIAL_KEY_ADD_MENU_BACK,
OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_DEC,
OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INC,
OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INFO,
OPTIMIZE_SERIAL_KEY_ADD_MENU_SELECT_TEXTBOX,
OPTIMIZE_SERIAL_KEY_ADD_MENU_CONFIRM,
OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_PRINT,
OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_ABOVE_PRINT,
OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_BELOW_PRINT,
};
class OptimizeSerialKeyAddMenu : public GenericMenu {
public:
OptimizeSerialKeyAddMenu();
OptimizeSerialKeyAddMenu(TextRectanglePool* text_pool);
virtual ~OptimizeSerialKeyAddMenu();
bool poll(SFEvent &event_data);
void draw(float scaling_factor, sf::RenderTarget &window);
void reset_data(bool full_reset);
std::chrono::time_point<std::chrono::high_resolution_clock> last_input_processed_time;
void reset_output_option();
void on_menu_unloaded();
void prepare(float scaling_factor, int view_size_x, int view_size_y);
void insert_data(CaptureDevice* device);
std::string get_key();
OptimizeSerialKeyMenuOutAction selected_index = OptimizeSerialKeyMenuOutAction::OPTIMIZE_SERIAL_KEY_ADD_MENU_NO_ACTION;
bool key_for_new = false;
protected:
struct TextFieldInputFixedData {
int option_selected = -1;
int menu_width;
int menu_height;
int pos_x;
int pos_y;
};
TextFieldInputFixedData future_data;
TextRectangle **labels;
bool *selectable_labels;
int num_vertical_slices;
int num_elements_per_screen;
int num_elements_displayed_per_screen;
int num_options_per_screen;
int elements_start_id;
int min_elements_text_scaling_factor;
int width_factor_menu;
int width_divisor_menu;
int base_height_factor_menu;
int base_height_divisor_menu;
float min_text_size;
float max_width_slack;
sf::Color menu_color;
std::string title;
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 x_size, int y_size, int index, float text_scaling_factor, TextKind text_kind, TextPosKind pos_kind = POS_KIND_NORMAL, bool center = false);
TextRectangle* get_label_for_option(int option_num);
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();
virtual void option_slice_prepare(int i, int index, int num_vertical_slices, float text_scaling_factor);
virtual bool is_option_element(int option);
virtual bool is_option_left(int index);
virtual bool is_option_right(int index);
virtual bool is_selected_insert_text_option(int index);
virtual int get_next_option_selected_after_key_input();
virtual int get_option_selected_key_input();
virtual int get_option_print_key_input();
virtual bool add_to_key(uint32_t unicode);
virtual int get_pos_in_serial_key();
virtual int get_key_size();
virtual void key_update_char(bool increase);
virtual bool handle_click(int index, percentage_pos_text_t percentage, bool started_inside_textbox);
virtual void set_pos_special_label(int index);
private:
int num_title_back_x_elements;
int title_back_x_start_id;
int back_x_id;
int title_id;
int pos_key = 0;
std::string key = "WWWW-WWWW-WWWW-WWWW-WWWW";
const float cursor_blank_timeout = 0.2f;
std::chrono::time_point<std::chrono::high_resolution_clock> menu_time;
bool first_pass;
std::chrono::time_point<std::chrono::high_resolution_clock> last_action_time;
const float action_timeout = 0.1f;
TextFieldInputFixedData loaded_data;
sf::RectangleShape menu_rectangle = sf::RectangleShape(sf::Vector2f(1, 1));
void after_class_setup_connected_values();
bool can_execute_action();
void up_code(bool is_simple);
void down_code(bool is_simple);
void left_code();
void right_code();
void option_selection_handling();
void set_default_cursor_position();
void decrement_selected_option(bool is_simple);
void increment_selected_option(bool is_simple);
void quit_textbox(bool change_option_selected = true);
char get_key_update_char(bool increase);
std::string generate_key_print_string();
};
#endif

View File

@ -47,6 +47,7 @@ protected:
virtual size_t get_num_options();
virtual std::string get_string_option(int index, int action);
virtual void class_setup();
virtual float get_option_text_factor(int index) { return 1.0; }
int single_option_multiplier;

View File

@ -8,37 +8,61 @@
#define BASE_PIXEL_FONT_HEIGHT 24
enum TextKind {TEXT_KIND_NORMAL, TEXT_KIND_SELECTED, TEXT_KIND_SUCCESS, TEXT_KIND_WARNING, TEXT_KIND_ERROR, TEXT_KIND_OPAQUE_ERROR, TEXT_KIND_TITLE};
#define PERCENTAGE_POS_TEXT_ERROR (-1)
enum TextKind {TEXT_KIND_NORMAL, TEXT_KIND_SELECTED, TEXT_KIND_SUCCESS, TEXT_KIND_WARNING, TEXT_KIND_ERROR, TEXT_KIND_OPAQUE_ERROR, TEXT_KIND_TITLE, TEXT_KIND_TEXTBOX, TEXT_KIND_TEXTBOX_TRANSPARENT};
enum FontKind {FONT_KIND_NORMAL, FONT_KIND_MONO};
enum TextPosKind {POS_KIND_NORMAL, POS_KIND_PRIORITIZE_TOP_LEFT, POS_KIND_PRIORITIZE_BOTTOM_LEFT};
typedef sf::Vector2i percentage_pos_text_t;
typedef sf::Vector2i size_text_t;
typedef sf::Vector2i position_text_t;
class TextRectangle {
public:
TextRectangle(bool font_load_success, sf::Font &text_font);
TextRectangle(bool font_load_success, sf::Font *text_font, bool font_mono_load_success, sf::Font *text_font_mono);
~TextRectangle();
void setRectangleKind(TextKind kind);
void setTextFactor(float size_multiplier);
void setSize(int width, int height);
size_text_t getFinalSize();
size_text_t getFinalSizeNoMultipliers();
percentage_pos_text_t getCoordInRectanglePercentage(int coord_x, int coord_y);
bool isCoordInRectangle(int coord_x, int coord_y);
void setDuration(float on_seconds);
void setPosition(int pos_x, int pos_y);
void setPosition(int pos_x, int pos_y, TextPosKind kind=POS_KIND_NORMAL);
position_text_t getFinalPosition();
position_text_t getFinalPositionNoMultipliers();
void startTimer(bool do_start);
void setProportionalBox(bool proportional_box);
void setTightAndCentered(bool tight_and_centered);
void prepareRenderText();
void setText(std::string text);
void setShowText(bool show_text);
bool getShowText();
void draw(sf::RenderTarget &window);
void changeFont(FontKind new_font_kind);
void setLineSpacing(float new_line_spacing);
void setCharacterSpacing(float new_character_spacing);
void setLocked(bool new_locked);
// Only applies to text displayed with timer set to true
bool isTimerTextDone();
private:
out_rect_data text_rect;
sf::Text actual_text;
sf::Font *text_font;
sf::Font *text_font_mono;
bool font_load_success;
bool font_mono_load_success;
bool is_done_showing_text;
std::chrono::time_point<std::chrono::high_resolution_clock> clock_time_start;
int time_phase;
sf::Color curr_color;
const float base_time_slide_factor = 0.5;
const float base_pixel_slide_factor = 2.0;
int pos_x_center_contrib = 0;
int pos_y_center_contrib = 0;
struct TextData {
bool is_timed;
@ -47,13 +71,24 @@ private:
bool show_text;
bool render_text;
bool proportional_box;
bool tight_and_centered;
std::string printed_text;
float duration;
float font_pixel_height;
int width;
int height;
int stored_width;
int stored_height;
int pos_x;
int pos_y;
int stored_pos_x;
int stored_pos_y;
bool locked;
bool schedule_font_swap;
FontKind font_kind;
float line_spacing;
float character_spacing;
TextPosKind pos_kind;
};
TextData future_data;
@ -64,5 +99,8 @@ private:
void setTextWithLineWrapping(int x_limit = 0);
void updateText(int x_limit = 0);
void updateSlides(float* time_seconds);
float getNoBlurCharacterSpacing();
bool isFontLoaded(TextData &reference_data);
sf::Font* getFont(TextData &reference_data);
};
#endif

View File

@ -5,14 +5,16 @@
class TextRectanglePool {
public:
TextRectanglePool(bool font_load_success, sf::Font *text_font);
TextRectanglePool(bool font_load_success, sf::Font *text_font, bool font_mono_load_success, sf::Font *text_font_mono);
~TextRectanglePool();
void request_num_text_rectangles(int num_wanted_text_rectangles);
TextRectangle* get_text_rectangle(int index);
private:
bool font_load_success;
bool font_mono_load_success;
sf::Font *text_font;
sf::Font *text_font_mono;
int num_loaded_text_rectangles;
TextRectangle** text_rectangles_list;
};

View File

@ -328,6 +328,7 @@ struct CaptureStatus {
volatile bool reset_hardware = false;
bool requested_3d = false;
bool request_low_bw_format = true;
bool key_updated = false;
CaptureScreensType capture_type;
CaptureSpeedsType capture_speed;
int battery_percentage;

View File

@ -6,6 +6,8 @@
#include "capture_structs.hpp"
#include "frontend.hpp"
enum KeySaveError { KEY_SAVED, KEY_INVALID, KEY_ALREADY_PRESENT, KEY_SAVE_METHOD_NOT_FOUND };
struct no_access_recap_data {
no_access_recap_data(std::string name) : name(name), vid(-1), pid(-1) {}
no_access_recap_data(uint16_t vid, uint16_t pid) : name(""), vid(vid), pid(pid) {}
@ -26,6 +28,7 @@ void capture_warning_print(CaptureData* capture_data, std::string graphical_stri
uint64_t get_audio_n_samples(CaptureData* capture_data, CaptureDataSingleBuffer* data_buffer);
uint64_t get_video_in_size(CaptureData* capture_data, bool is_3d, InputVideoDataType video_data_type);
std::string get_device_id_string(CaptureStatus* capture_status);
std::string get_device_serial_key_string(CaptureStatus* capture_status);
std::string get_name_of_device(CaptureStatus* capture_status, bool use_long = false, bool want_real_serial = false);
int get_usb_speed_of_device(CaptureStatus* capture_status);
bool get_device_can_do_3d(CaptureStatus* capture_status);
@ -35,4 +38,6 @@ bool get_3d_enabled(CaptureStatus* capture_status, bool skip_requested_3d_check
bool update_3d_enabled(CaptureStatus* capture_status);
bool set_3d_enabled(CaptureStatus* capture_status, bool new_value);
float get_framerate_multiplier(CaptureStatus* capture_status);
KeySaveError save_cc_key(std::string key, CaptureConnectionType conn_type, bool differentiator);
void check_device_serial_key_update(CaptureStatus* capture_status, bool differentiator, std::string key);
#endif

View File

@ -26,7 +26,7 @@ enum ScreenType { TOP, BOTTOM, JOINT };
enum BottomRelativePosition { UNDER_TOP, LEFT_TOP, ABOVE_TOP, RIGHT_TOP, BOT_REL_POS_END };
enum SecondScreen3DRelativePosition { UNDER_FIRST, LEFT_FIRST, ABOVE_FIRST, RIGHT_FIRST, SECOND_SCREEN_3D_REL_POS_END };
enum NonIntegerScalingModes { SMALLER_PRIORITY, INVERSE_PROPORTIONAL_PRIORITY, EQUAL_PRIORITY, PROPORTIONAL_PRIORITY, BIGGER_PRIORITY, END_NONINT_SCALE_MODES };
enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE, MAIN_MENU_TYPE, VIDEO_MENU_TYPE, AUDIO_MENU_TYPE, CROP_MENU_TYPE, TOP_PAR_MENU_TYPE, BOTTOM_PAR_MENU_TYPE, ROTATION_MENU_TYPE, OFFSET_MENU_TYPE, BFI_MENU_TYPE, LOAD_MENU_TYPE, SAVE_MENU_TYPE, RESOLUTION_MENU_TYPE, EXTRA_MENU_TYPE, STATUS_MENU_TYPE, LICENSES_MENU_TYPE, RELATIVE_POS_MENU_TYPE, SHORTCUTS_MENU_TYPE, ACTION_SELECTION_MENU_TYPE, SCALING_RATIO_MENU_TYPE, ISN_MENU_TYPE, VIDEO_EFFECTS_MENU_TYPE, INPUT_MENU_TYPE, AUDIO_DEVICE_MENU_TYPE, SEPARATOR_MENU_TYPE, COLOR_CORRECTION_MENU_TYPE, MAIN_3D_MENU_TYPE, SECOND_SCREEN_RELATIVE_POS_MENU_TYPE, USB_CONFLICT_RESOLUTION_MENU_TYPE, OPTIMIZE_3DS_MENU_TYPE };
enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE, MAIN_MENU_TYPE, VIDEO_MENU_TYPE, AUDIO_MENU_TYPE, CROP_MENU_TYPE, TOP_PAR_MENU_TYPE, BOTTOM_PAR_MENU_TYPE, ROTATION_MENU_TYPE, OFFSET_MENU_TYPE, BFI_MENU_TYPE, LOAD_MENU_TYPE, SAVE_MENU_TYPE, RESOLUTION_MENU_TYPE, EXTRA_MENU_TYPE, STATUS_MENU_TYPE, LICENSES_MENU_TYPE, RELATIVE_POS_MENU_TYPE, SHORTCUTS_MENU_TYPE, ACTION_SELECTION_MENU_TYPE, SCALING_RATIO_MENU_TYPE, ISN_MENU_TYPE, VIDEO_EFFECTS_MENU_TYPE, INPUT_MENU_TYPE, AUDIO_DEVICE_MENU_TYPE, SEPARATOR_MENU_TYPE, COLOR_CORRECTION_MENU_TYPE, MAIN_3D_MENU_TYPE, SECOND_SCREEN_RELATIVE_POS_MENU_TYPE, USB_CONFLICT_RESOLUTION_MENU_TYPE, OPTIMIZE_3DS_MENU_TYPE, OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE };
enum InputColorspaceMode { FULL_COLORSPACE, DS_COLORSPACE, GBA_COLORSPACE, INPUT_COLORSPACE_END };
enum FrameBlendingMode { NO_FRAME_BLENDING, FULL_FRAME_BLENDING, DS_3D_BOTH_SCREENS_FRAME_BLENDING, FRAME_BLENDING_END };

View File

@ -10,7 +10,7 @@ enum JoystickAction {JOY_ACTION_NONE, JOY_ACTION_CONFIRM, JOY_ACTION_NEGATE, JOY
enum EventType {EVENT_NONE, EVENT_JOYSTICK_BTN_PRESSED, EVENT_JOYSTICK_BTN_RELEASED, EVENT_JOYSTICK_MOVED, EVENT_MOUSE_BTN_PRESSED, EVENT_MOUSE_MOVED, EVENT_KEY_PRESSED, EVENT_TEXT_ENTERED, EVENT_CLOSED, EVENT_KEY_RELEASED, EVENT_MOUSE_BTN_RELEASED};
struct SFEvent {
SFEvent(bool pressed, sf::Keyboard::Key code, bool poweroff_cmd = false, bool is_extra = false) : type(pressed ? EVENT_KEY_PRESSED : EVENT_KEY_RELEASED), code(code), poweroff_cmd(poweroff_cmd), is_extra(is_extra) {}
SFEvent(bool pressed, sf::Keyboard::Key code, bool alt, bool control, bool shift, bool system, bool poweroff_cmd = false, bool is_extra = false) : type(pressed ? EVENT_KEY_PRESSED : EVENT_KEY_RELEASED), code(code), alt(alt), control(control), shift(shift), system(system), poweroff_cmd(poweroff_cmd), is_extra(is_extra) {}
SFEvent(uint32_t unicode) : type(EVENT_TEXT_ENTERED), unicode(unicode) {}
SFEvent(bool pressed, uint32_t joystickId, uint32_t joy_button) : type(pressed ? EVENT_JOYSTICK_BTN_PRESSED : EVENT_MOUSE_BTN_RELEASED), joystickId(joystickId), joy_button(joy_button) {}
SFEvent(uint32_t joystickId, sf::Joystick::Axis axis, float position) : type(EVENT_JOYSTICK_MOVED), joystickId(joystickId), axis(axis), position(position) {}
@ -20,6 +20,10 @@ struct SFEvent {
EventType type;
sf::Keyboard::Key code;
bool alt;
bool control;
bool shift;
bool system;
uint32_t unicode;
uint32_t joystickId;
uint32_t joy_button;

View File

@ -41,6 +41,7 @@
#include "SecondScreen3DRelativePositionMenu.hpp"
#include "USBConflictResolutionMenu.hpp"
#include "Optimize3DSMenu.hpp"
#include "OptimizeSerialKeyAddMenu.hpp"
#include "display_structs.hpp"
#include "event_structs.hpp"
#include "shaders_list.hpp"
@ -198,6 +199,7 @@ private:
SecondScreen3DRelativePositionMenu *second_screen_3d_relpos_menu;
USBConflictResolutionMenu *usb_conflict_resolution_menu;
Optimize3DSMenu* optimize_3ds_menu;
OptimizeSerialKeyAddMenu* optimize_serial_key_add_menu;
std::vector<const CropData*> possible_crops;
std::vector<const CropData*> possible_crops_ds;
@ -230,6 +232,7 @@ private:
sf::Texture bot_in_tex;
sf::Font text_font;
sf::Font text_font_mono;
volatile bool main_thread_owns_window;
volatile bool is_window_factory_done;
@ -321,6 +324,7 @@ private:
void second_screen_3d_match_bottom_pos_change();
void devices_allowed_change(PossibleCaptureDevices device);
void input_video_data_format_request_change(bool positive);
bool add_new_cc_key(std::string key, CaptureConnectionType conn_type, bool discriminator);
bool query_reset_request();
void reset_held_times(bool force = true);
void poll_window(bool do_everything);
@ -410,7 +414,9 @@ private:
void setup_second_screen_3d_relpos_menu(bool reset_data = true);
void setup_usb_conflict_resolution_menu(bool reset_data = true);
void setup_optimize_3ds_menu(bool reset_data = true);
void setup_optimize_serial_key_add_menu(bool reset_data = true);
void update_connection();
bool has_menu_textbox();
};
struct FrontendData {

93
other licenses/OFL.txt Normal file
View File

@ -0,0 +1,93 @@
Copyright 2016 The Space Mono Project Authors (https://github.com/googlefonts/spacemono)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -13,6 +13,8 @@ The nisetro_ds* file was obtained from the source available software
NiseTro Preview (build 20100316), then edited for improved interoperability
and support for multiple concurrent connections.
The optimize* files were extracted from wireshark packets, then edited
for usage with a more generic driver, improved interoperability, and
support for multiple concurrent connections.
The optimize* files (minus the optimize_serial_key_* files) were extracted
from wireshark packets, then edited for usage with a more generic driver,
improved interoperability, and support for multiple concurrent connections.
Copyright of optimize* files (minus the optimize_serial_key_* files):
non-standard - Tanishige Ryu

View File

@ -10,6 +10,13 @@
#include <libusb.h>
#include <chrono>
#include <cstring>
#if (!defined(_MSC_VER)) || (_MSC_VER > 1916)
#include <filesystem>
#else
#include <experimental/filesystem>
#endif
#include <fstream>
#include <sstream>
// This code was developed by exclusively looking at Wireshark USB packet
// captures to learn the USB device's protocol.
@ -60,8 +67,8 @@ struct CypressOptimize3DSDeviceCaptureReceivedData {
static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status);
static int get_cypress_device_status(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data);
static void error_cypress_device_status(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, int error_val);
static std::string read_key_for_device_id_from_file(uint64_t device_id, const cyop_device_usb_device* usb_device_desc);
static void add_key_for_device_id_to_file(uint64_t device_id, std::string key, const cyop_device_usb_device* usb_device_desc);
static std::string read_key_for_device_id_from_file(uint64_t device_id, bool is_new_device);
static void add_key_for_device_id_to_file(uint64_t device_id, std::string key, bool is_new_device);
static cy_device_device_handlers* usb_find_by_serial_number(const cyop_device_usb_device* usb_device_desc, std::string wanted_serial_number, CaptureDevice* new_device) {
cy_device_device_handlers* final_handlers = NULL;
@ -714,6 +721,26 @@ static void cyop_key_missing_warning_message(CaptureData* capture_data) {
capture_warning_print(capture_data, "Key missing!\nClose to Timeout!\nReconfigured FPGA!", "Key missing! Close to Timeout! Reconfigured FPGA!");
}
static void cyop_key_check_and_interrogate_file(CaptureStatus* capture_status, const cyop_device_usb_device* usb_device_desc, uint64_t device_id, bool &is_key_valid, std::string &read_key) {
if(is_key_valid)
return;
// This can only happen during the first connection
is_key_valid = check_key_matches_device_id(device_id, read_key, usb_device_desc);
// This also can only happen during the first connection
if(is_key_valid)
add_key_for_device_id_to_file(device_id, read_key, usb_device_desc);
else {
read_key = read_key_for_device_id_from_file(device_id, usb_device_desc->is_new_device);
is_key_valid = check_key_matches_device_id(device_id, read_key, usb_device_desc->is_new_device);
}
capture_status->device.device_id = device_id;
capture_status->device.key = read_key;
capture_status->key_updated = false;
}
static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, InputVideoDataType &stored_video_data_type, bool &stored_is_3d, bool could_use_3d) {
cy_device_device_handlers* handlers = (cy_device_device_handlers*)capture_data->handle;
const cyop_device_usb_device* usb_device_desc = (const cyop_device_usb_device*)capture_data->status.device.descriptor;
@ -723,19 +750,13 @@ static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptim
bool force_capture_start_key = false;
int ret = capture_start(handlers, usb_device_desc, true, stored_video_data_type == OPTIMIZE_RGB888_FORMAT, device_id, read_key);
capture_data->status.title_check_id += 1;
capture_data->status.key_updated = false;
std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_capture_start = std::chrono::high_resolution_clock::now();
bool is_key_valid = check_key_matches_device_id(device_id, read_key, usb_device_desc);
if(is_key_valid)
add_key_for_device_id_to_file(device_id, read_key, usb_device_desc);
else {
read_key = read_key_for_device_id_from_file(device_id, usb_device_desc);
is_key_valid = check_key_matches_device_id(device_id, read_key, usb_device_desc);
}
capture_data->status.device.device_id = device_id;
capture_data->status.device.key = read_key;
bool is_key_valid = false;
cyop_key_check_and_interrogate_file(&capture_data->status, usb_device_desc, device_id, is_key_valid, read_key);
capture_data->status.device.video_data_type = stored_video_data_type;
if (ret < 0) {
capture_error_print(true, capture_data, "Capture Start: Failed");
return false;
@ -754,10 +775,11 @@ static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptim
bool has_recovered = false;
if(cause_error == LIBUSB_ERROR_TIMEOUT) {
force_capture_start_key = (!check_key_matches_device_id(device_id, read_key, usb_device_desc)) && key_missing_capture_start_again_check_time(clock_last_capture_start);
cyop_key_check_and_interrogate_file(&capture_data->status, usb_device_desc, device_id, is_key_valid, read_key);
int timeout_ret = restart_captures_cc_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, could_use_3d, force_capture_start_key, read_key, clock_last_capture_start);
if(timeout_ret >= 0) {
has_recovered = true;
if(force_capture_start_key)
if(force_capture_start_key && (!is_key_valid))
cyop_key_missing_warning_message(capture_data);
}
}
@ -769,15 +791,16 @@ static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptim
bool is_new_3d = could_use_3d && get_3d_enabled(&capture_data->status);
InputVideoDataType wanted_input_video_data_type = extract_wanted_input_video_data_type(capture_data);
force_capture_start_key = (!is_key_valid) && (!check_key_matches_device_id(device_id, read_key, usb_device_desc)) && key_missing_capture_start_again_check_time(clock_last_capture_start);
if((wanted_input_video_data_type != stored_video_data_type) || (is_new_3d != stored_is_3d) || force_capture_start_key) {
if((wanted_input_video_data_type != stored_video_data_type) || (is_new_3d != stored_is_3d) || force_capture_start_key || capture_data->status.key_updated) {
capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM + NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS;
wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data);
cyop_key_check_and_interrogate_file(&capture_data->status, usb_device_desc, device_id, is_key_valid, read_key);
ret = restart_captures_cc_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, could_use_3d, force_capture_start_key, read_key, clock_last_capture_start);
if(ret < 0) {
capture_error_print(true, capture_data, "Disconnected: Update mode error");
return false;
}
if(force_capture_start_key)
if(force_capture_start_key && (!is_key_valid))
cyop_key_missing_warning_message(capture_data);
}
if(!get_buffer_and_schedule_read(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, "Setup Read: Failed"))
@ -877,21 +900,18 @@ bool cyop_is_key_for_device(CaptureDevice* device, std::string key) {
return check_key_matches_device_id(device->device_id, key, (const cyop_device_usb_device*)device->descriptor);
}
static std::string get_keys_file_path(const cyop_device_usb_device* usb_device_desc) {
static std::string get_keys_file_path(bool is_new_device) {
std::string path = get_base_path_keys();
if(usb_device_desc->is_new_device)
if(is_new_device)
path += "optimize_new_3ds.txt";
else
path += "optimize_old_3ds.txt";
return path;
}
static std::string read_key_for_device_id_from_file(uint64_t device_id, const cyop_device_usb_device* usb_device_desc) {
if(usb_device_desc == NULL)
return "";
std::ifstream file(get_keys_file_path(usb_device_desc));
static std::string read_key_for_device_id_from_file(uint64_t device_id, bool is_new_device) {
std::ifstream file(get_keys_file_path(is_new_device));
std::string line;
std::string out_key = "";
@ -904,7 +924,7 @@ static std::string read_key_for_device_id_from_file(uint64_t device_id, const cy
std::string value;
if(!std::getline(kvp, value))
continue;
if(check_key_matches_device_id(device_id, value, usb_device_desc)) {
if(check_key_matches_device_id(device_id, value, is_new_device)) {
out_key = value;
break;
}
@ -918,21 +938,41 @@ static std::string read_key_for_device_id_from_file(uint64_t device_id, const cy
return out_key;
}
static void add_key_for_device_id_to_file(uint64_t device_id, std::string key, const cyop_device_usb_device* usb_device_desc) {
static void add_key_for_device_id_to_file(uint64_t device_id, std::string key, bool is_new_device) {
// This is fine for a limited amount of keys.
// It should be optimized if many keys need to be stored...
if(usb_device_desc == NULL)
return;
if(key == "")
return;
if(read_key_for_device_id_from_file(device_id, usb_device_desc) == key)
if(read_key_for_device_id_from_file(device_id, is_new_device) == key)
return;
std::ofstream file(get_keys_file_path(usb_device_desc), std::ios_base::app | std::ios_base::out);
std::ofstream file(get_keys_file_path(is_new_device), std::ios_base::app | std::ios_base::out);
file << key << std::endl;
file.close();
}
KeySaveError add_key_to_file(std::string key, bool is_for_new_3ds) {
uint64_t device_id = get_device_id_from_key(key, is_for_new_3ds);
if(device_id == 0)
return KEY_INVALID;
if(read_key_for_device_id_from_file(device_id, is_for_new_3ds) == key)
return KEY_ALREADY_PRESENT;
add_key_for_device_id_to_file(device_id, key, is_for_new_3ds);
return KEY_SAVED;
}
bool cyop_is_key_for_device_id(CaptureDevice* device, std::string key) {
if(device == NULL)
return false;
if(device->cc_type != CAPTURE_CONN_CYPRESS_OPTIMIZE)
return false;
if(device->device_id == 0)
return false;
if(key == "")
return false;
return check_key_matches_device_id(device->device_id, key, (const cyop_device_usb_device*)device->descriptor);
}
void usb_cyop_device_init() {
return usb_init();
}

View File

@ -2,6 +2,7 @@
#include "cypress_optimize_3ds_communications.hpp"
#include "cypress_shared_communications.hpp"
#include "cypress_optimize_3ds_acquisition_general.hpp"
#include "cypress_optimize_3ds_acquisition.hpp"
#include "usb_generic.hpp"
#include "optimize_new_3ds_fw.h"
@ -12,7 +13,7 @@
#include "optimize_old_3ds_565_fpga_pl.h"
#include "optimize_old_3ds_888_fpga_pl.h"
#include "optimize_key_to_byte_table.h"
#include "optimize_serial_key_to_byte_table.h"
// CRC32 table is a slightly edited crc32-adler.
// First entry all FFs instead of 00s.
@ -39,8 +40,8 @@
#define OPTIMIZE_NEW_3DS_WANTED_VALUE_BASE 0xFE00
#define OPTIMIZE_OLD_3DS_WANTED_VALUE_BASE 0xFD00
#define OPTIMIZE_NUM_KEY_CHARS 20
#define OPTIMIZE_NUM_KEY_CHARS_WITH_DASHES (OPTIMIZE_NUM_KEY_CHARS + 4)
#define OPTIMIZE_NUM_KEY_CHARS SERIAL_KEY_OPTIMIZE_NO_DASHES_SIZE
#define OPTIMIZE_NUM_KEY_CHARS_WITH_DASHES SERIAL_KEY_OPTIMIZE_WITH_DASHES_SIZE
#define OPTIMIZE_NUM_KEY_BYTES 12
#define OPTIMIZE_EEPROM_NEW_SIZE 0x80
@ -221,9 +222,9 @@ static bool key_to_key_bytes(uint8_t* in, uint8_t* out) {
for(size_t i = 0; i < OPTIMIZE_NUM_KEY_CHARS; i++) {
uint8_t character = in[i];
if(optimize_key_to_byte_table[character] == 0xFF)
if(optimize_serial_key_to_byte_table[character] == 0xFF)
return false;
value_converted |= optimize_key_to_byte_table[character] << converted_pos;
value_converted |= optimize_serial_key_to_byte_table[character] << converted_pos;
converted_pos += 5;
if(converted_pos >= 8) {
out[out_index++] = value_converted & 0xFF;
@ -686,12 +687,19 @@ static const uint8_t* get_start_capture_setup_key_buffer(const cyop_device_usb_d
return start_capture_setup_key_buffer_565_old;
}
bool check_key_matches_device_id(uint64_t device_id, std::string key, bool is_new_device) {
uint64_t get_device_id_from_key(std::string key, bool is_new_device) {
uint8_t key_bytes[OPTIMIZE_NUM_KEY_BYTES];
bool is_key_valid = key_to_data(key, key_bytes, is_new_device);
if(!is_key_valid)
return 0;
return read_be64(key_bytes);
}
bool check_key_matches_device_id(uint64_t device_id, std::string key, bool is_new_device) {
uint64_t device_id_read = get_device_id_from_key(key, is_new_device);
if(device_id_read == 0)
return false;
return device_id == read_be64(key_bytes);
return device_id == device_id_read;
}
bool check_key_matches_device_id(uint64_t device_id, std::string key, const cyop_device_usb_device* device) {

View File

@ -98,7 +98,7 @@ void ExtraButton::poll(std::queue<SFEvent> &events_queue) {
}
else
this->started = false;
events_queue.emplace(pressed, this->corresponding_key, this->is_power, true);
events_queue.emplace(pressed, this->corresponding_key, false, false, false, false, this->is_power, true);
}
std::string get_extra_button_name(sf::Keyboard::Key corresponding_key) {

View File

@ -91,6 +91,21 @@ static const LicenseMenuOptionInfo font_license_3_option = {
static const LicenseMenuOptionInfo font_license_4_option = {
.base_name = "open-font-license-official-text/"};
static const LicenseMenuOptionInfo font_mono_license_0_option = {
.base_name = "This software uses the font"};
static const LicenseMenuOptionInfo font_mono_license_1_option = {
.base_name = "SpaceMono-Regular."};
static const LicenseMenuOptionInfo font_mono_license_2_option = {
.base_name = "For its license, check:"};
static const LicenseMenuOptionInfo font_mono_license_3_option = {
.base_name = "openfontlicense.org/"};
static const LicenseMenuOptionInfo font_mono_license_4_option = {
.base_name = "open-font-license-official-text/"};
static const LicenseMenuOptionInfo isng_license_0_option = {
.base_name = "Portions of this software are"};
@ -158,6 +173,11 @@ static const LicenseMenuOptionInfo* pollable_options[] = {
&font_license_2_option,
&font_license_3_option,
&font_license_4_option,
&font_mono_license_0_option,
&font_mono_license_1_option,
&font_mono_license_2_option,
&font_mono_license_3_option,
&font_mono_license_4_option,
&cc3dsfs_license_0_option,
&cc3dsfs_license_1_option,
&cc3dsfs_license_2_option,

View File

@ -16,18 +16,48 @@ struct Optimize3DSMenuOptionInfo {
const Optimize3DSMenuOutAction out_action;
};
static const Optimize3DSMenuOptionInfo optimize_o3ds_hw_option = {
.base_name = "Hardware: Old 3DS", .false_name = "", .is_selectable = false,
static const Optimize3DSMenuOptionInfo optimize_o3ds_device_id_option = {
.base_name = "Old 3DS Device ID:", .false_name = "", .is_selectable = false,
.optimize_o3ds_valid = true, .optimize_n3ds_valid = false,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = OPTIMIZE3DS_MENU_NO_ACTION,
.out_action = OPTIMIZE3DS_MENU_NO_ACTION};
static const Optimize3DSMenuOptionInfo optimize_n3ds_hw_option = {
.base_name = "Hardware: New 3DS", .false_name = "", .is_selectable = false,
static const Optimize3DSMenuOptionInfo optimize_n3ds_device_id_option = {
.base_name = "New 3DS Device ID:", .false_name = "", .is_selectable = false,
.optimize_o3ds_valid = false, .optimize_n3ds_valid = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = OPTIMIZE3DS_MENU_NO_ACTION,
.out_action = OPTIMIZE3DS_MENU_NO_ACTION};
static const Optimize3DSMenuOptionInfo optimize_3ds_device_id_option = {
.base_name = "Device ID", .false_name = "", .is_selectable = false,
.optimize_o3ds_valid = true, .optimize_n3ds_valid = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = OPTIMIZE3DS_MENU_NO_ACTION,
.out_action = OPTIMIZE3DS_MENU_INFO_DEVICE_ID};
static const Optimize3DSMenuOptionInfo optimize_copy_3ds_device_id_option = {
.base_name = "Copy Device ID to clipboard", .false_name = "", .is_selectable = true,
.optimize_o3ds_valid = true, .optimize_n3ds_valid = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = OPTIMIZE3DS_MENU_NO_ACTION,
.out_action = OPTIMIZE3DS_MENU_COPY_DEVICE_ID};
static const Optimize3DSMenuOptionInfo optimize_serial_key_info_option = {
.base_name = "Serial Key:", .false_name = "", .is_selectable = false,
.optimize_o3ds_valid = true, .optimize_n3ds_valid = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = OPTIMIZE3DS_MENU_NO_ACTION,
.out_action = OPTIMIZE3DS_MENU_NO_ACTION};
static const Optimize3DSMenuOptionInfo optimize_serial_key_option = {
.base_name = "", .false_name = "", .is_selectable = false,
.optimize_o3ds_valid = true, .optimize_n3ds_valid = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = OPTIMIZE3DS_MENU_NO_ACTION,
.out_action = OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY};
static const Optimize3DSMenuOptionInfo optimize_serial_key_menu_option = {
.base_name = "Add New Serial Key", .false_name = "", .is_selectable = true,
.optimize_o3ds_valid = true, .optimize_n3ds_valid = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = OPTIMIZE3DS_MENU_NO_ACTION,
.out_action = OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY_MENU};
static const Optimize3DSMenuOptionInfo optimize_3ds_format_explanation_0 = {
.base_name = "Possible Data Types:", .false_name = "", .is_selectable = false,
.optimize_o3ds_valid = true, .optimize_n3ds_valid = true,
@ -65,8 +95,13 @@ static const Optimize3DSMenuOptionInfo optimize_3ds_change_format = {
.out_action = OPTIMIZE3DS_MENU_INPUT_VIDEO_FORMAT_DEC};
static const Optimize3DSMenuOptionInfo* pollable_options[] = {
//&optimize_o3ds_hw_option,
//&optimize_n3ds_hw_option,
//&optimize_o3ds_device_id_option,
//&optimize_n3ds_device_id_option,
&optimize_3ds_device_id_option,
&optimize_copy_3ds_device_id_option,
&optimize_serial_key_info_option,
&optimize_serial_key_option,
&optimize_serial_key_menu_option,
&optimize_3ds_format_explanation_0,
&optimize_3ds_format_explanation_1,
//&optimize_3ds_format_explanation_2,
@ -162,6 +197,17 @@ static std::string get_data_format_name(bool request_low_bw_format) {
return request_low_bw_format ? "RGB565" : "RGB888";
}
float Optimize3DSMenu::get_option_text_factor(int index) {
if(index <= 0)
return 1.0f;
if(index >= ((int)NUM_TOTAL_MENU_OPTIONS))
return 1.0f;
index = this->options_indexes[index];
if(pollable_options[index]->out_action == OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY)
return 0.85f;
return 1.0f;
}
void Optimize3DSMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, CaptureStatus* capture_status) {
int num_pages = this->get_num_pages();
if(this->future_data.page >= num_pages)
@ -177,6 +223,12 @@ void Optimize3DSMenu::prepare(float menu_scaling_factor, int view_size_x, int vi
case OPTIMIZE3DS_MENU_INPUT_VIDEO_FORMAT_DEC:
this->labels[index]->setText(this->setTextOptionString(real_index, get_data_format_name(capture_status->request_low_bw_format)));
break;
case OPTIMIZE3DS_MENU_INFO_DEVICE_ID:
this->labels[index]->setText(this->setTextOptionString(real_index, get_device_id_string(capture_status)));
break;
case OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY:
this->labels[index]->setText(get_device_serial_key_string(capture_status));
break;
default:
break;
}

View File

@ -0,0 +1,926 @@
#include "OptimizeSerialKeyAddMenu.hpp"
#include "utils.hpp"
#include "cypress_optimize_3ds_acquisition.hpp"
#include "optimize_serial_key_add_table.h"
#include "optimize_serial_key_next_char_table.h"
#include "optimize_serial_key_prev_char_table.h"
#include <cmath>
#define NUM_TOTAL_MENU_OPTIONS (sizeof(pollable_options)/sizeof(pollable_options[0]))
struct OptimizeSerialKeyAddMenuOptionInfo {
const std::string base_name;
const bool is_selectable;
const bool is_font_mono;
const bool is_color_transparent;
const int position_x, position_y, multiplier_y;
float text_factor_multiplier;
TextKind text_kind;
const int divisor_x, size_y, size_x;
TextPosKind pos_kind;
OptimizeSerialKeyMenuOutAction out_action;
};
static const OptimizeSerialKeyAddMenuOptionInfo desc_textbox_option = {
.base_name = "Select the textbox, then type the key", .is_selectable = false,
.is_font_mono = false,
.position_x = 0, .position_y = 0, .multiplier_y = 2,
.text_factor_multiplier = 0.8f, .text_kind = TEXT_KIND_NORMAL,
.divisor_x = 1, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_NO_ACTION};
static const OptimizeSerialKeyAddMenuOptionInfo desc2_textbox_option = {
.base_name = "via keyboard or use the key buttons.", .is_selectable = false,
.is_font_mono = false,
.position_x = 0, .position_y = 1, .multiplier_y = 2,
.text_factor_multiplier = 0.8f, .text_kind = TEXT_KIND_NORMAL,
.divisor_x = 1, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_NO_ACTION};
static const OptimizeSerialKeyAddMenuOptionInfo highlight_textbox_option = {
.base_name = "", .is_selectable = true,
.is_font_mono = true,
.position_x = 0, .position_y = 1, .multiplier_y = 1,
.text_factor_multiplier = 0.0f, .text_kind = TEXT_KIND_NORMAL,
.divisor_x = 1, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_SELECT_TEXTBOX};
static const OptimizeSerialKeyAddMenuOptionInfo textbox_option = {
.base_name = "\n____ ____ ____ ____ ____", .is_selectable = false,
.is_font_mono = true,
.position_x = 0, .position_y = 1, .multiplier_y = 1,
.text_factor_multiplier = 0.80f, .text_kind = TEXT_KIND_TEXTBOX,
.divisor_x = 1, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_PRINT};
static const OptimizeSerialKeyAddMenuOptionInfo textbox_button_above_option = {
.base_name = "", .is_selectable = false,
.is_font_mono = true,
.position_x = 0, .position_y = 0, .multiplier_y = 1,
.text_factor_multiplier = 0.80f, .text_kind = TEXT_KIND_TEXTBOX,
.divisor_x = 1, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_PRIORITIZE_BOTTOM_LEFT,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_ABOVE_PRINT};
static const OptimizeSerialKeyAddMenuOptionInfo textbox_button_below_option = {
.base_name = "", .is_selectable = false,
.is_font_mono = true,
.position_x = 1, .position_y = 0, .multiplier_y = 1,
.text_factor_multiplier = 0.80f, .text_kind = TEXT_KIND_TEXTBOX,
.divisor_x = 2, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_PRIORITIZE_TOP_LEFT,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_BELOW_PRINT};
static const OptimizeSerialKeyAddMenuOptionInfo left_option = {
.base_name = "<", .is_selectable = true,
.is_font_mono = false,
.position_x = 0, .position_y = 2, .multiplier_y = 1,
.text_factor_multiplier = 1.0f, .text_kind = TEXT_KIND_NORMAL,
.divisor_x = 6, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_DEC};
static const OptimizeSerialKeyAddMenuOptionInfo right_option = {
.base_name = ">", .is_selectable = true,
.is_font_mono = false,
.position_x = 5, .position_y = 2, .multiplier_y = 1,
.text_factor_multiplier = 1.0f, .text_kind = TEXT_KIND_NORMAL,
.divisor_x = 6, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INC};
static const OptimizeSerialKeyAddMenuOptionInfo target_file_option = {
.base_name = "Key for", .is_selectable = false,
.is_font_mono = false,
.position_x = 1, .position_y = 2, .multiplier_y = 1,
.text_factor_multiplier = 1.0f, .text_kind = TEXT_KIND_NORMAL,
.divisor_x = 6, .size_y = 1, .size_x = 4,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INFO};
static const OptimizeSerialKeyAddMenuOptionInfo add_key_option = {
.base_name = "Add key to list", .is_selectable = true,
.is_font_mono = false,
.position_x = 0, .position_y = 3, .multiplier_y = 1,
.text_factor_multiplier = 1.0f, .text_kind = TEXT_KIND_NORMAL,
.divisor_x = 1, .size_y = 1, .size_x = 1,
.pos_kind = POS_KIND_NORMAL,
.out_action = OPTIMIZE_SERIAL_KEY_ADD_MENU_CONFIRM};
static const OptimizeSerialKeyAddMenuOptionInfo* pollable_options[] = {
&desc_textbox_option,
&desc2_textbox_option,
&highlight_textbox_option,
&target_file_option,
&left_option,
&right_option,
&textbox_option,
&textbox_button_above_option,
&textbox_button_below_option,
&add_key_option,
};
OptimizeSerialKeyAddMenu::OptimizeSerialKeyAddMenu() {
}
OptimizeSerialKeyAddMenu::OptimizeSerialKeyAddMenu(TextRectanglePool* text_rectangle_pool) {
this->initialize(text_rectangle_pool);
}
OptimizeSerialKeyAddMenu::~OptimizeSerialKeyAddMenu() {
for(int i = 0; i < this->num_elements_displayed_per_screen; i++)
delete this->labels[i];
delete []this->labels;
delete []this->selectable_labels;
}
void OptimizeSerialKeyAddMenu::on_menu_unloaded() {
for(int i = 0; i < this->num_elements_displayed_per_screen; i++) {
this->labels[i]->changeFont(FONT_KIND_NORMAL);
this->labels[i]->setTightAndCentered(false);
this->labels[i]->setLineSpacing(1.0);
this->labels[i]->setCharacterSpacing(1.0);
this->labels[i]->setLocked(false);
}
sf::Keyboard::setVirtualKeyboardVisible(false);
}
void OptimizeSerialKeyAddMenu::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] = text_pool->get_text_rectangle(i);
this->labels[i]->setProportionalBox(false);
this->labels[i]->setText(std::to_string(i));
this->labels[i]->setShowText(true);
this->selectable_labels[i] = true;
}
this->future_data.menu_width = 1;
this->future_data.menu_height = 1;
this->future_data.pos_x = 0;
this->future_data.pos_y = 0;
this->last_action_time = std::chrono::high_resolution_clock::now();
this->last_input_processed_time = std::chrono::high_resolution_clock::now();
this->selectable_labels[this->back_x_id] = true;
this->selectable_labels[this->title_id] = false;
}
void OptimizeSerialKeyAddMenu::class_setup() {
this->num_options_per_screen = NUM_TOTAL_MENU_OPTIONS;
this->min_elements_text_scaling_factor = 4;
this->num_vertical_slices = 5;
this->width_factor_menu = 16;
this->width_divisor_menu = 9;
this->base_height_factor_menu = 12;
this->base_height_divisor_menu = 6;
this->min_text_size = 0.3f;
this->max_width_slack = 1.1f;
this->menu_color = sf::Color(30, 30, 60, 192);
this->title = "New Serial Key";
}
void OptimizeSerialKeyAddMenu::after_class_setup_connected_values() {
this->num_title_back_x_elements = 2;
this->num_elements_per_screen = this->num_options_per_screen;
this->num_elements_displayed_per_screen = num_title_back_x_elements + num_elements_per_screen;
this->title_back_x_start_id = 0;
this->elements_start_id = num_title_back_x_elements + title_back_x_start_id;
this->back_x_id = title_back_x_start_id + 1;
this->title_id = title_back_x_start_id;
}
bool OptimizeSerialKeyAddMenu::can_execute_action() {
this->last_input_processed_time = std::chrono::high_resolution_clock::now();
auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - this->last_action_time;
if(diff.count() > this->action_timeout)
return true;
return false;
}
void OptimizeSerialKeyAddMenu::insert_data(CaptureDevice* device) {
#ifdef USE_CYPRESS_OPTIMIZE
key_for_new = is_device_optimize_n3ds(device);
#endif
this->menu_time = std::chrono::high_resolution_clock::now();
this->is_inside_textbox = false;
this->first_pass = true;
this->prepare_options();
}
void OptimizeSerialKeyAddMenu::reset_data(bool full_reset) {
this->last_input_processed_time = std::chrono::high_resolution_clock::now();
if(full_reset) {
this->reset_output_option();
this->future_data.option_selected = -1;
}
}
bool OptimizeSerialKeyAddMenu::is_option_element(int option) {
return (option >= this->elements_start_id) && (option < (this->elements_start_id + this->num_elements_per_screen));
}
void OptimizeSerialKeyAddMenu::set_default_cursor_position() {
this->future_data.option_selected = this->elements_start_id;
while(!this->selectable_labels[this->future_data.option_selected]){
this->future_data.option_selected += 1;
if(this->future_data.option_selected >= this->num_elements_displayed_per_screen)
this->future_data.option_selected = 0;
if(this->future_data.option_selected == this->elements_start_id)
break;
}
}
// This is reversed, due to it being the position of the bottom screen.
// But we ask the user the position of the top screen.
bool OptimizeSerialKeyAddMenu::is_option_left(int index) {
return pollable_options[index]->out_action == OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_DEC;
}
bool OptimizeSerialKeyAddMenu::is_option_right(int index) {
return pollable_options[index]->out_action == OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INC;
}
void OptimizeSerialKeyAddMenu::decrement_selected_option(bool is_simple) {
if(this->future_data.option_selected < 0) {
this->set_default_cursor_position();
return;
}
int elem_index = this->future_data.option_selected - this->elements_start_id;
if(!is_simple) {
if(this->is_option_element(this->future_data.option_selected) && this->is_option_right(elem_index))
this->future_data.option_selected -= 1;
}
do {
this->future_data.option_selected -= 1;
if(this->future_data.option_selected < 0)
this->future_data.option_selected = this->num_elements_displayed_per_screen - 1;
} while(!this->selectable_labels[this->future_data.option_selected]);
}
void OptimizeSerialKeyAddMenu::increment_selected_option(bool is_simple) {
if(this->future_data.option_selected < 0){
this->set_default_cursor_position();
return;
}
int elem_index = this->future_data.option_selected - this->elements_start_id;
if(!is_simple) {
if(this->is_option_element(this->future_data.option_selected) && this->is_option_left(elem_index))
this->future_data.option_selected += 1;
}
do {
this->future_data.option_selected += 1;
if(this->future_data.option_selected >= this->num_elements_displayed_per_screen)
this->future_data.option_selected = 0;
} while(!this->selectable_labels[this->future_data.option_selected]);
}
void OptimizeSerialKeyAddMenu::reset_output_option() {
this->selected_index = OPTIMIZE_SERIAL_KEY_ADD_MENU_NO_ACTION;
}
void OptimizeSerialKeyAddMenu::set_output_option(int index) {
if(index == BACK_X_OUTPUT_OPTION)
this->selected_index = OPTIMIZE_SERIAL_KEY_ADD_MENU_BACK;
else {
if(pollable_options[index]->out_action == OPTIMIZE_SERIAL_KEY_ADD_MENU_SELECT_TEXTBOX) {
this->is_inside_textbox = !this->is_inside_textbox;
this->pos_key = 0;
if(this->is_inside_textbox)
sf::Keyboard::setVirtualKeyboardVisible(true);
else
sf::Keyboard::setVirtualKeyboardVisible(false);
}
else
this->selected_index = pollable_options[index]->out_action;
}
}
bool OptimizeSerialKeyAddMenu::is_option_drawable(int index) {
return true;
}
bool OptimizeSerialKeyAddMenu::is_option_selectable(int index) {
return pollable_options[index]->is_selectable;
}
std::string OptimizeSerialKeyAddMenu::get_string_option(int index) {
return pollable_options[index]->base_name;
}
bool OptimizeSerialKeyAddMenu::is_selected_insert_text_option(int index) {
if(index < 0)
return false;
if(index >= ((int)NUM_TOTAL_MENU_OPTIONS))
return false;
return pollable_options[index]->out_action == OPTIMIZE_SERIAL_KEY_ADD_MENU_SELECT_TEXTBOX;
}
static int get_option_index_of_action(OptimizeSerialKeyMenuOutAction action) {
for(size_t i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++)
if(pollable_options[i]->out_action == action)
return (int)i;
return NUM_TOTAL_MENU_OPTIONS - 1;
}
int OptimizeSerialKeyAddMenu::get_next_option_selected_after_key_input() {
return get_option_index_of_action(OPTIMIZE_SERIAL_KEY_ADD_MENU_CONFIRM);
}
int OptimizeSerialKeyAddMenu::get_option_selected_key_input() {
return get_option_index_of_action(OPTIMIZE_SERIAL_KEY_ADD_MENU_SELECT_TEXTBOX);
}
int OptimizeSerialKeyAddMenu::get_option_print_key_input() {
return get_option_index_of_action(OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_PRINT);
}
bool OptimizeSerialKeyAddMenu::handle_click(int index, percentage_pos_text_t percentage, bool started_inside_textbox) {
if(index < 0)
return false;
if(index >= ((int)NUM_TOTAL_MENU_OPTIONS))
return false;
bool retval = false;
int pos_click = 0;
switch(pollable_options[index]->out_action) {
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_PRINT:
pos_click = (percentage.x * SERIAL_KEY_OPTIMIZE_WITH_DASHES_SIZE) / 100;
if((pos_click % (SERIAL_KEY_OPTIMIZE_DASHES_REPEATED_POS + 1)) == SERIAL_KEY_OPTIMIZE_DASHES_REPEATED_POS)
pos_click += 1;
this->is_inside_textbox = true;
this->pos_key = pos_click - (pos_click / (SERIAL_KEY_OPTIMIZE_DASHES_REPEATED_POS + 1));
retval = true;
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_ABOVE_PRINT:
if(!started_inside_textbox)
break;
this->is_inside_textbox = true;
this->key_update_char(false);
retval = true;
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_BELOW_PRINT:
if(!started_inside_textbox)
break;
this->is_inside_textbox = true;
this->key_update_char(true);
retval = true;
break;
default:
break;
}
if((!started_inside_textbox) && this->is_inside_textbox)
sf::Keyboard::setVirtualKeyboardVisible(true);
return retval;
}
void OptimizeSerialKeyAddMenu::set_pos_special_label(int index) {
if(index < 0)
return;
if(index >= ((int)NUM_TOTAL_MENU_OPTIONS))
return;
TextRectangle* target = this->get_label_for_option(index);
if(target == NULL)
return;
TextRectangle* textbox = NULL;
size_text_t textbox_size;
position_text_t textbox_pos;
int pos_in_key = this->get_pos_in_serial_key();
int x_pos_key = 0;
int y_pos_contrib = 0;
switch(pollable_options[index]->out_action) {
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_ABOVE_PRINT:
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_BELOW_PRINT:
if(!this->is_inside_textbox)
break;
textbox = this->get_label_for_option(this->get_option_print_key_input());
if(textbox == NULL)
break;
textbox_size = textbox->getFinalSizeNoMultipliers();
textbox_pos = textbox->getFinalPositionNoMultipliers();
// For some reason, the 1.01 is needed to make this look right...
// Maybe because part of the space between 2 letters comes from the "next" letter?
x_pos_key = (int)std::round(((float)textbox_size.x * pos_in_key * 1.01) / SERIAL_KEY_OPTIMIZE_WITH_DASHES_SIZE);
if(pollable_options[index]->out_action == OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_BELOW_PRINT)
y_pos_contrib = textbox_size.y;
target->setPosition(textbox_pos.x + x_pos_key, textbox_pos.y + y_pos_contrib, pollable_options[index]->pos_kind);
break;
default:
break;
}
}
void OptimizeSerialKeyAddMenu::prepare_options() {
for(int i = 0; i < this->num_elements_displayed_per_screen; i++) {
this->labels[i]->setShowText(false);
}
this->labels[this->back_x_id]->setText("<--");
this->labels[this->back_x_id]->setShowText(true);
this->labels[this->title_id]->setText(this->title);
this->labels[this->title_id]->setShowText(true);
for(int i = 0; i < this->num_options_per_screen; i++) {
int label_start_index = i + this->elements_start_id;
this->labels[label_start_index]->setText(this->get_string_option(i));
this->selectable_labels[label_start_index] = this->is_option_selectable(i);
this->labels[label_start_index]->setShowText(true);
}
if(!this->selectable_labels[this->future_data.option_selected]) {
this->future_data.option_selected = -1;
}
}
void OptimizeSerialKeyAddMenu::option_selection_handling() {
if((this->future_data.option_selected == -1) || (!this->selectable_labels[this->future_data.option_selected])) {
this->future_data.option_selected = -1;
return;
}
if(!this->can_execute_action())
return;
if(this->future_data.option_selected == this->back_x_id) {
this->set_output_option(BACK_X_OUTPUT_OPTION);
this->last_action_time = std::chrono::high_resolution_clock::now();
}
else if(this->is_option_element(this->future_data.option_selected)) {
int elem_index = this->future_data.option_selected - this->elements_start_id;
this->set_output_option(elem_index);
this->last_action_time = std::chrono::high_resolution_clock::now();
}
}
void OptimizeSerialKeyAddMenu::up_code(bool is_simple) {
if(!this->can_execute_action())
return;
if(this->is_inside_textbox) {
this->key_update_char(false);
return;
}
this->decrement_selected_option(is_simple);
this->last_action_time = std::chrono::high_resolution_clock::now();
}
void OptimizeSerialKeyAddMenu::down_code(bool is_simple) {
if(!this->can_execute_action())
return;
if(this->is_inside_textbox) {
this->key_update_char(true);
return;
}
this->increment_selected_option(is_simple);
this->last_action_time = std::chrono::high_resolution_clock::now();
}
void OptimizeSerialKeyAddMenu::left_code() {
if(!this->can_execute_action())
return;
if(this->is_inside_textbox) {
this->pos_key -= 1;
if(this->pos_key < 0)
this->pos_key = 0;
return;
}
int elem_index = this->future_data.option_selected - this->elements_start_id;
if(this->is_option_element(this->future_data.option_selected) && this->is_option_left(elem_index))
this->option_selection_handling();
else {
this->future_data.option_selected -= 1;
for(int i = 0; i < this->num_options_per_screen; i++) {
if(this->is_option_left(i)) {
this->future_data.option_selected = i + this->elements_start_id;
break;
}
}
this->last_action_time = std::chrono::high_resolution_clock::now();
}
}
void OptimizeSerialKeyAddMenu::right_code() {
if(!this->can_execute_action())
return;
if(this->is_inside_textbox) {
this->pos_key += 1;
if(this->pos_key >= this->get_key_size())
this->pos_key = this->get_key_size() - 1;
return;
}
int elem_index = this->future_data.option_selected - this->elements_start_id;
if(this->is_option_element(this->future_data.option_selected) && this->is_option_right(elem_index))
this->option_selection_handling();
else {
this->future_data.option_selected -= 1;
for(int i = 0; i < this->num_options_per_screen; i++) {
if(this->is_option_right(i)) {
this->future_data.option_selected = i + this->elements_start_id;
break;
}
}
this->last_action_time = std::chrono::high_resolution_clock::now();
}
}
void OptimizeSerialKeyAddMenu::quit_textbox(bool change_option_selected) {
this->is_inside_textbox = false;
if(change_option_selected)
this->future_data.option_selected = this->get_next_option_selected_after_key_input() + this->elements_start_id;
}
int OptimizeSerialKeyAddMenu::get_pos_in_serial_key() {
return this->pos_key + (this->pos_key / SERIAL_KEY_OPTIMIZE_DASHES_REPEATED_POS);
}
bool OptimizeSerialKeyAddMenu::add_to_key(uint32_t unicode) {
int pos_in_serial_key = this->get_pos_in_serial_key();
if((unicode >= optimize_serial_key_add_table_len) || (optimize_serial_key_add_table[unicode] == 0xFF))
return false;
this->key[pos_in_serial_key] = (char)optimize_serial_key_add_table[unicode];
return true;
}
int OptimizeSerialKeyAddMenu::get_key_size() {
return SERIAL_KEY_OPTIMIZE_NO_DASHES_SIZE;
}
char OptimizeSerialKeyAddMenu::get_key_update_char(bool increase) {
int pos_in_serial_key = this->get_pos_in_serial_key();
uint8_t* char_table = optimize_serial_key_prev_char_table;
if(increase)
char_table = optimize_serial_key_next_char_table;
char base_character = this->key[pos_in_serial_key];
char target_character = '0';
if(char_table[(uint8_t)base_character] != 0xFF)
target_character = (char)char_table[(uint8_t)base_character];
return target_character;
}
void OptimizeSerialKeyAddMenu::key_update_char(bool increase) {
int pos_in_serial_key = this->get_pos_in_serial_key();
this->key[pos_in_serial_key] = this->get_key_update_char(increase);
}
bool OptimizeSerialKeyAddMenu::poll(SFEvent &event_data) {
bool consumed = true;
bool started_inside_textbox = this->is_inside_textbox;
bool is_paste_command = false;
sf::String pasted_string = "";
switch (event_data.type) {
case EVENT_TEXT_ENTERED:
if(!started_inside_textbox) {
consumed = false;
break;
}
if(!this->add_to_key(event_data.unicode)) {
consumed = false;
break;
}
this->pos_key += 1;
if(this->pos_key >= this->get_key_size())
this->quit_textbox();
break;
case EVENT_KEY_PRESSED:
switch (event_data.code) {
case sf::Keyboard::Key::Up:
this->up_code(false);
break;
case sf::Keyboard::Key::Down:
this->down_code(false);
break;
case sf::Keyboard::Key::PageUp:
this->up_code(true);
break;
case sf::Keyboard::Key::PageDown:
this->down_code(true);
break;
case sf::Keyboard::Key::Left:
this->left_code();
break;
case sf::Keyboard::Key::Right:
this->right_code();
break;
case sf::Keyboard::Key::Backspace:
if(started_inside_textbox)
this->left_code();
else
consumed = false;
break;
case sf::Keyboard::Key::V:
if(event_data.control)
is_paste_command = true;
#ifdef __APPLE__
if(event_data.system)
is_paste_command = true;
#endif
if(!is_paste_command) {
consumed = false;
break;
}
pasted_string = sf::Clipboard::getString();
for(size_t i = 0; i < pasted_string.getSize(); i++) {
if(!this->add_to_key(pasted_string[i]))
continue;
this->pos_key += 1;
if(this->pos_key >= this->get_key_size()) {
this->quit_textbox();
break;
}
}
break;
case sf::Keyboard::Key::Tab:
if(started_inside_textbox || this->is_selected_insert_text_option(this->future_data.option_selected - this->elements_start_id))
this->quit_textbox();
else
this->future_data.option_selected = this->get_option_selected_key_input() + this->elements_start_id;
break;
case sf::Keyboard::Key::Enter:
if(started_inside_textbox) {
if(event_data.is_extra) {
this->pos_key += 1;
if(this->pos_key >= this->get_key_size())
this->quit_textbox();
}
else
this->quit_textbox();
break;
}
this->option_selection_handling();
break;
default:
consumed = false;
break;
}
break;
case EVENT_MOUSE_MOVED:
this->future_data.option_selected = -1;
for(int i = 0; i < this->num_elements_displayed_per_screen; i++) {
if(!this->selectable_labels[i])
continue;
if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) {
this->future_data.option_selected = i;
this->last_input_processed_time = std::chrono::high_resolution_clock::now();
break;
}
}
break;
case EVENT_MOUSE_BTN_PRESSED:
if(started_inside_textbox) {
this->quit_textbox(false);
}
this->future_data.option_selected = -1;
consumed = false;
for(int i = 0; i < this->num_elements_displayed_per_screen; i++)
if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y))
if(this->handle_click(i - this->elements_start_id, this->labels[i]->getCoordInRectanglePercentage(event_data.mouse_x, event_data.mouse_y), started_inside_textbox)) {
consumed = true;
break;
}
if(consumed)
break;
consumed = true;
for(int i = 0; i < this->num_elements_displayed_per_screen; i++) {
if(!this->selectable_labels[i])
continue;
if(this->labels[i]->isCoordInRectangle(event_data.mouse_x, event_data.mouse_y)) {
this->future_data.option_selected = i;
break;
}
}
if(started_inside_textbox && (!this->is_inside_textbox))
sf::Keyboard::setVirtualKeyboardVisible(false);
if(this->future_data.option_selected == -1)
break;
if(event_data.mouse_button == sf::Mouse::Button::Left)
this->option_selection_handling();
break;
case EVENT_JOYSTICK_BTN_PRESSED:
switch(get_joystick_action(event_data.joystickId, event_data.joy_button)) {
case JOY_ACTION_CONFIRM:
if(started_inside_textbox) {
this->pos_key += 1;
if(this->pos_key >= this->get_key_size())
this->quit_textbox();
break;
}
this->option_selection_handling();
break;
case JOY_ACTION_NEGATE:
if(started_inside_textbox) {
this->pos_key += 1;
if(this->pos_key >= this->get_key_size())
this->quit_textbox();
break;
}
this->option_selection_handling();
break;
case JOY_ACTION_MENU:
if(started_inside_textbox) {
this->quit_textbox();
break;
}
consumed = false;
break;
default:
consumed = false;
break;
}
break;
case EVENT_JOYSTICK_MOVED:
switch(get_joystick_direction(event_data.joystickId, event_data.axis, event_data.position)) {
case JOY_DIR_UP:
this->up_code(false);
break;
case JOY_DIR_DOWN:
this->down_code(false);
break;
case JOY_DIR_LEFT:
this->left_code();
break;
case JOY_DIR_RIGHT:
this->right_code();
break;
default:
consumed = false;
break;
}
break;
default:
consumed = false;
break;
}
return consumed;
}
void OptimizeSerialKeyAddMenu::draw(float scaling_factor, sf::RenderTarget &window) {
const sf::Vector2f rect_size = this->menu_rectangle.getSize();
if((this->loaded_data.menu_width != rect_size.x) || (this->loaded_data.menu_height != rect_size.y)) {
this->menu_rectangle.setSize(sf::Vector2f((float)this->loaded_data.menu_width, (float)this->loaded_data.menu_height));
}
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++) {
if(this->is_option_drawable(i))
this->labels[i]->draw(window);
}
}
void OptimizeSerialKeyAddMenu::prepare_text_slices(int x_multiplier, int x_divisor, int y_multiplier, int y_divisor, int size_x, int size_y, int index, float text_scaling_factor, TextKind text_kind, TextPosKind pos_kind, bool center) {
this->labels[index]->setTextFactor(text_scaling_factor);
int x_base_pos = (this->future_data.menu_width * x_multiplier) / x_divisor;
int y_base_pos = (this->future_data.menu_height * y_multiplier) / y_divisor;
int x_size = (((this->future_data.menu_width * (x_multiplier + 1)) / x_divisor) - x_base_pos) * size_x;
int y_size = (((this->future_data.menu_height * (y_multiplier + 1)) / y_divisor) - y_base_pos) * size_y;
if(center)
x_size = ((this->future_data.menu_width * (x_divisor - x_multiplier)) / x_divisor) - x_base_pos;
this->labels[index]->setSize(x_size, y_size);
if(pos_kind == POS_KIND_NORMAL)
this->labels[index]->setPosition(this->future_data.pos_x + x_base_pos, this->future_data.pos_y + y_base_pos);
else
this->set_pos_special_label(index - this->elements_start_id);
if(this->is_inside_textbox && this->is_selected_insert_text_option(index - this->elements_start_id))
this->labels[index]->setRectangleKind(TEXT_KIND_SELECTED);
else {
if(index == this->future_data.option_selected)
this->labels[index]->setRectangleKind(TEXT_KIND_SELECTED);
else
this->labels[index]->setRectangleKind(text_kind);
}
this->labels[index]->prepareRenderText();
}
std::string OptimizeSerialKeyAddMenu::generate_key_print_string() {
std::string out_above_string = this->key;
std::string out_below_string = "____ ____ ____ ____ ____";
if(this->is_inside_textbox) {
auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - this->menu_time;
if(((int)std::round(diff.count() / cursor_blank_timeout)) & 1) {
out_above_string[this->get_pos_in_serial_key()] = ' ';
//out_below_string[this->get_pos_in_serial_key()] = ' ';
}
}
return out_above_string + "\n" + out_below_string;
}
TextRectangle* OptimizeSerialKeyAddMenu::get_label_for_option(int option_num) {
if(option_num < 0)
return NULL;
if(option_num >= this->num_options_per_screen)
return NULL;
return this->labels[option_num + this->elements_start_id];
}
void OptimizeSerialKeyAddMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y) {
for(int i = 0; i < this->num_options_per_screen; i++) {
int index = i + this->elements_start_id;
FontKind font_kind = FONT_KIND_NORMAL;
if(pollable_options[i]->is_font_mono)
font_kind = FONT_KIND_MONO;
this->labels[index]->changeFont(font_kind);
if((pollable_options[i]->out_action == OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_PRINT) && (!this->first_pass)) {
this->labels[index]->setLocked(true);
}
else
this->labels[index]->setLocked(false);
switch(pollable_options[i]->out_action) {
case OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INFO:
if(this->key_for_new)
this->labels[index]->setText(this->get_string_option(i) + ": New 3DS");
else
this->labels[index]->setText(this->get_string_option(i) + ": Old 3DS");
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_ABOVE_PRINT:
this->labels[index]->setTightAndCentered(true);
this->labels[index]->setLineSpacing(0.5f);
if(this->is_inside_textbox) {
if(!this->labels[index]->getShowText()) {
this->labels[index]->setLocked(false);
this->labels[index]->setShowText(true);
}
else
this->labels[index]->setLocked(true);
this->labels[index]->setText(std::string(1, this->get_key_update_char(false)) + "\n" + this->get_string_option(i));
}
else
this->labels[index]->setShowText(false);
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_BUTTON_BELOW_PRINT:
this->labels[index]->setTightAndCentered(true);
this->labels[index]->setLineSpacing(0.5f);
if(this->is_inside_textbox) {
if(!this->labels[index]->getShowText()) {
this->labels[index]->setLocked(false);
this->labels[index]->setShowText(true);
}
else
this->labels[index]->setLocked(true);
this->labels[index]->setText(this->get_string_option(i) + "\n" + std::string(1, this->get_key_update_char(true)));
}
else
this->labels[index]->setShowText(false);
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_PRINT:
this->labels[index]->setTightAndCentered(true);
this->labels[index]->setLineSpacing(0.0f);
this->labels[index]->setCharacterSpacing(1.4f);
this->labels[index]->setText(this->generate_key_print_string());
break;
default:
break;
}
}
this->first_pass = false;
this->base_prepare(menu_scaling_factor, view_size_x, view_size_y);
}
void OptimizeSerialKeyAddMenu::option_slice_prepare(int i, int index, int num_vertical_slices, float text_scaling_factor) {
this->prepare_text_slices(pollable_options[i]->position_x, pollable_options[i]->divisor_x, pollable_options[i]->position_y + (1 * pollable_options[i]->multiplier_y), num_vertical_slices * pollable_options[i]->multiplier_y, pollable_options[i]->size_x, pollable_options[i]->size_y, index, text_scaling_factor * pollable_options[i]->text_factor_multiplier, pollable_options[i]->text_kind, pollable_options[i]->pos_kind);
}
std::string OptimizeSerialKeyAddMenu::get_key() {
return this->key;
}
void OptimizeSerialKeyAddMenu::base_prepare(float menu_scaling_factor, int view_size_x, int view_size_y) {
const float base_height = (7 * BASE_PIXEL_FONT_HEIGHT * 11) / 9;
int max_width = (view_size_x * 9) / 10;
int max_height = (view_size_y * 9) / 10;
float max_width_corresponding_height = (max_width * this->width_divisor_menu * this->max_width_slack) / this->width_factor_menu;
float max_scaling_factor = max_height / base_height;
if(max_width_corresponding_height < max_height)
max_scaling_factor = max_width_corresponding_height / base_height;
float final_menu_scaling_factor = (menu_scaling_factor * this->base_height_factor_menu) / this->base_height_divisor_menu;
if(menu_scaling_factor > max_scaling_factor)
menu_scaling_factor = max_scaling_factor;
if(final_menu_scaling_factor > max_scaling_factor)
final_menu_scaling_factor = max_scaling_factor;
if(menu_scaling_factor < this->min_text_size)
menu_scaling_factor = this->min_text_size;
if(final_menu_scaling_factor < this->min_text_size)
final_menu_scaling_factor = this->min_text_size;
int num_elements_text_scaling_factor = this->num_vertical_slices;
if(num_elements_text_scaling_factor < this->min_elements_text_scaling_factor)
num_elements_text_scaling_factor = this->min_elements_text_scaling_factor;
float text_scaling_factor = (menu_scaling_factor * this->num_vertical_slices) / num_elements_text_scaling_factor;
this->future_data.menu_height = (int)(base_height * final_menu_scaling_factor);
this->future_data.menu_width = (this->future_data.menu_height * this->width_factor_menu) / this->width_divisor_menu;
if(this->future_data.menu_width > max_width)
this->future_data.menu_width = max_width;
this->future_data.pos_x = (view_size_x - this->future_data.menu_width) / 2;
this->future_data.pos_y = (view_size_y - this->future_data.menu_height) / 2;
this->prepare_text_slices(0, 6, 0, this->num_vertical_slices, 1, 1, this->back_x_id, text_scaling_factor, TEXT_KIND_NORMAL);
this->prepare_text_slices(0, 1, 0, this->num_vertical_slices, 1, 1, this->title_id, text_scaling_factor, TEXT_KIND_TITLE);
for(int i = 0; i < this->num_options_per_screen; i++) {
int index = i + this->elements_start_id;
this->option_slice_prepare(i, index, this->num_vertical_slices, text_scaling_factor);
}
this->loaded_data = this->future_data;
}

View File

@ -494,7 +494,9 @@ void OptionSelectionMenu::draw(float scaling_factor, sf::RenderTarget &window) {
}
void OptionSelectionMenu::prepare_text_slices(int x_multiplier, int x_divisor, int y_multiplier, int y_divisor, int index, float text_scaling_factor, bool center) {
this->labels[index]->setTextFactor(text_scaling_factor);
int elem_index = index - this->elements_start_id;
int start = this->num_options_per_screen * this->future_data.page;
this->labels[index]->setTextFactor(text_scaling_factor * this->get_option_text_factor((elem_index / this->single_option_multiplier) + start));
int x_base_pos = (this->future_data.menu_width * x_multiplier) / x_divisor;
int y_base_pos = (this->future_data.menu_height * y_multiplier) / y_divisor;
int x_size = ((this->future_data.menu_width * (x_multiplier + 1)) / x_divisor) - x_base_pos;

View File

@ -1,28 +1,56 @@
#include "TextRectangle.hpp"
#include <cmath>
TextRectangle::TextRectangle(bool font_load_success, sf::Font &text_font) : actual_text(text_font) {
#define TEXT_RECTANGLE_POS_APPROX 1.02
TextRectangle::TextRectangle(bool font_load_success, sf::Font *text_font, bool font_mono_load_success, sf::Font *text_font_mono) : actual_text(*text_font) {
this->reset_data(this->future_data);
this->text_font = text_font;
this->text_font_mono = text_font_mono;
this->font_load_success = font_load_success;
this->font_mono_load_success = font_mono_load_success;
this->is_done_showing_text = true;
this->setRealSize(1, 1, false);
this->text_rect.out_rect.setTexture(&this->text_rect.out_tex.getTexture());
if(this->font_load_success)
this->actual_text.setFont(text_font);
this->actual_text.setFont(*this->text_font);
this->time_phase = 0;
this->reset_data(this->future_data);
this->loaded_data.font_kind = this->future_data.font_kind;
}
TextRectangle::~TextRectangle() {
}
void TextRectangle::changeFont(FontKind new_font_kind) {
if(this->future_data.font_kind != new_font_kind) {
this->future_data.render_text = true;
this->future_data.schedule_font_swap = true;
}
this->future_data.font_kind = new_font_kind;
}
void TextRectangle::setSize(int width, int height) {
if((height == this->future_data.height) && (width == this->future_data.width))
return;
this->future_data.width = width;
this->future_data.height = height;
this->future_data.locked = false;
this->future_data.render_text = true;
}
size_text_t TextRectangle::getFinalSize() {
return size_text_t({this->future_data.stored_width, this->future_data.stored_height});
}
size_text_t TextRectangle::getFinalSizeNoMultipliers() {
size_text_t size = this->getFinalSize();
if(this->future_data.tight_and_centered)
size.x = (int)(size.x / TEXT_RECTANGLE_POS_APPROX);
return size;
}
void TextRectangle::setRectangleKind(TextKind kind) {
if(this->future_data.kind != kind) {
this->future_data.render_text = true;
@ -35,6 +63,7 @@ void TextRectangle::setTextFactor(float size_multiplier) {
if(this->future_data.font_pixel_height == new_pixel_height)
return;
this->future_data.font_pixel_height = new_pixel_height;
this->future_data.locked = false;
this->future_data.render_text = true;
}
@ -42,23 +71,88 @@ void TextRectangle::setDuration(float on_seconds) {
this->future_data.duration = on_seconds;
}
void TextRectangle::setPosition(int pos_x, int pos_y) {
void TextRectangle::setLineSpacing(float new_line_spacing) {
if(this->future_data.line_spacing != new_line_spacing)
this->future_data.render_text = true;
this->future_data.line_spacing = new_line_spacing;
}
void TextRectangle::setCharacterSpacing(float new_character_spacing) {
if(this->future_data.character_spacing != new_character_spacing)
this->future_data.render_text = true;
this->future_data.character_spacing = new_character_spacing;
}
void TextRectangle::setPosition(int pos_x, int pos_y, TextPosKind kind) {
if((pos_x == this->future_data.pos_x) && (pos_y == this->future_data.pos_y) && (kind == this->future_data.pos_kind))
return;
if(kind != POS_KIND_NORMAL)
this->future_data.render_text = true;
this->future_data.pos_x = pos_x;
this->future_data.pos_y = pos_y;
this->future_data.pos_kind = kind;
this->future_data.locked = false;
}
position_text_t TextRectangle::getFinalPosition() {
return position_text_t({this->future_data.stored_pos_x, this->future_data.stored_pos_y});
}
position_text_t TextRectangle::getFinalPositionNoMultipliers() {
position_text_t pos = this->getFinalPosition();
size_text_t full_size = this->getFinalSize();
size_text_t base_size = this->getFinalSizeNoMultipliers();
pos.x += (full_size.x - base_size.x) / 2;
pos.y += (full_size.y - base_size.y) / 2;
return pos;
}
void TextRectangle::setLocked(bool new_locked) {
this->future_data.locked = new_locked;
}
percentage_pos_text_t TextRectangle::getCoordInRectanglePercentage(int coord_x, int coord_y) {
percentage_pos_text_t percentage;
percentage.x = PERCENTAGE_POS_TEXT_ERROR;
percentage.y = PERCENTAGE_POS_TEXT_ERROR;
if(!(this->isFontLoaded(this->future_data) && this->future_data.show_text))
return percentage;
int left = this->future_data.stored_pos_x;
int right = left + this->future_data.stored_width;
int up = this->future_data.stored_pos_y;
int down = up + this->future_data.stored_height;
if(coord_x < left)
return percentage;
if(coord_y < up)
return percentage;
if(coord_x >= right)
return percentage;
if(coord_y >= down)
return percentage;
percentage.x = ((coord_x - left) * 100) / (right - left);
percentage.y = ((coord_y - up) * 100) / (down - up);
return percentage;
}
bool TextRectangle::isCoordInRectangle(int coord_x, int coord_y) {
if(!(font_load_success && this->future_data.show_text))
return false;
if(coord_x < this->future_data.pos_x)
return false;
if(coord_y < this->future_data.pos_y)
return false;
if(coord_x >= this->future_data.pos_x + this->future_data.width)
return false;
if(coord_y >= this->future_data.pos_y + this->future_data.height)
return false;
return true;
percentage_pos_text_t result = this->getCoordInRectanglePercentage(coord_x, coord_y);
return (result.x != PERCENTAGE_POS_TEXT_ERROR) && (result.y != PERCENTAGE_POS_TEXT_ERROR);
}
bool TextRectangle::isFontLoaded(TextData &reference_data) {
if(reference_data.font_kind == FONT_KIND_NORMAL)
return this->font_load_success;
if(reference_data.font_kind == FONT_KIND_MONO)
return this->font_mono_load_success;
return false;
}
sf::Font* TextRectangle::getFont(TextData &reference_data) {
if(reference_data.font_kind == FONT_KIND_NORMAL)
return this->text_font;
if(reference_data.font_kind == FONT_KIND_MONO)
return this->text_font_mono;
return NULL;
}
void TextRectangle::startTimer(bool do_start) {
@ -73,14 +167,22 @@ void TextRectangle::setProportionalBox(bool proportional_box) {
this->future_data.proportional_box = proportional_box;
}
void TextRectangle::prepareRenderText() {
if(this->future_data.proportional_box) {
this->future_data.width = this->loaded_data.width;
this->future_data.height = this->loaded_data.height;
void TextRectangle::setTightAndCentered(bool tight_and_centered) {
if(this->future_data.tight_and_centered != tight_and_centered) {
this->future_data.render_text = true;
}
this->future_data.tight_and_centered = tight_and_centered;
}
void TextRectangle::prepareRenderText() {
this->future_data.stored_width = this->loaded_data.stored_width;
this->future_data.stored_height = this->loaded_data.stored_height;
this->future_data.stored_pos_x = this->loaded_data.stored_pos_x;
this->future_data.stored_pos_y = this->loaded_data.stored_pos_y;
this->loaded_data = this->future_data;
this->future_data.render_text = false;
this->future_data.start_timer = false;
this->future_data.schedule_font_swap = false;
}
void TextRectangle::setText(std::string text) {
@ -97,13 +199,33 @@ void TextRectangle::setShowText(bool show_text) {
this->future_data.render_text = true;
}
bool TextRectangle::getShowText() {
return this->future_data.show_text;
}
void TextRectangle::draw(sf::RenderTarget &window) {
if(this->loaded_data.schedule_font_swap && this->isFontLoaded(this->loaded_data)) {
this->actual_text.setFont(*this->getFont(this->loaded_data));
}
if(this->loaded_data.render_text) {
this->updateText((int)window.getView().getSize().x);
}
if(font_load_success && this->loaded_data.show_text && (!this->is_done_showing_text)) {
if(this->isFontLoaded(this->loaded_data) && this->loaded_data.show_text && (!this->is_done_showing_text)) {
if(this->loaded_data.locked) {
this->loaded_data.width = this->loaded_data.stored_width;
this->loaded_data.height = this->loaded_data.stored_height;
this->loaded_data.pos_x = this->loaded_data.stored_pos_x;
this->loaded_data.pos_y = this->loaded_data.stored_pos_y;
this->pos_x_center_contrib = 0;
this->pos_y_center_contrib = 0;
}
this->loaded_data.pos_x += this->pos_x_center_contrib;
this->loaded_data.pos_y += this->pos_y_center_contrib;
this->text_rect.out_rect.setPosition({(float)this->loaded_data.pos_x, (float)this->loaded_data.pos_y});
if(this->loaded_data.is_timed) {
if(this->loaded_data.stored_height != 0)
this->loaded_data.height = this->loaded_data.stored_height;
float time_seconds[3];
this->updateSlides(time_seconds);
if(this->loaded_data.start_timer) {
@ -125,7 +247,8 @@ void TextRectangle::draw(sf::RenderTarget &window) {
rect_curr_height = -this->loaded_data.height + ((int)(factor * this->loaded_data.height));
else if(this->time_phase == 2)
rect_curr_height = ((int)(factor * this->loaded_data.height)) * -1;
this->text_rect.out_rect.setPosition({(float)this->loaded_data.pos_x, (float)this->loaded_data.pos_y + rect_curr_height});
this->loaded_data.pos_y += rect_curr_height;
this->text_rect.out_rect.setPosition({(float)this->loaded_data.pos_x, (float)this->loaded_data.pos_y});
if(factor >= 1) {
this->time_phase++;
@ -134,6 +257,10 @@ void TextRectangle::draw(sf::RenderTarget &window) {
if(this->time_phase >= 3)
this->is_done_showing_text = true;
}
this->loaded_data.stored_pos_x = this->loaded_data.pos_x;
this->loaded_data.stored_pos_y = this->loaded_data.pos_y;
this->loaded_data.stored_width = this->loaded_data.width;
this->loaded_data.stored_height = this->loaded_data.height;
window.draw(this->text_rect.out_rect);
}
}
@ -145,6 +272,7 @@ void TextRectangle::reset_data(TextData &data) {
data.show_text = false;
data.render_text = false;
data.proportional_box = true;
data.tight_and_centered = false;
data.printed_text = "Sample Text";
data.duration = 2.5;
data.font_pixel_height = BASE_PIXEL_FONT_HEIGHT;
@ -152,6 +280,16 @@ void TextRectangle::reset_data(TextData &data) {
data.height = 1;
data.pos_x = 0;
data.pos_y = 0;
data.font_kind = FONT_KIND_NORMAL;
data.schedule_font_swap = false;
data.line_spacing = 1.0;
data.character_spacing = 1.0;
data.stored_width = data.width;
data.stored_height = data.height;
data.stored_pos_x = data.pos_x;
data.stored_pos_y = data.pos_y;
data.locked = false;
data.pos_kind = POS_KIND_NORMAL;
}
static sf::String convert_to_utf8(const std::string &str) {
@ -196,6 +334,8 @@ void TextRectangle::setTextWithLineWrapping(int x_limit) {
void TextRectangle::setRealSize(int width, int height, bool check_previous) {
this->loaded_data.width = width;
this->loaded_data.height = height;
this->pos_x_center_contrib = 0;
this->pos_y_center_contrib = 0;
if(check_previous) {
if((height == this->text_rect.out_rect.getSize().y) && (width == this->text_rect.out_rect.getSize().x))
return;
@ -205,37 +345,89 @@ void TextRectangle::setRealSize(int width, int height, bool check_previous) {
this->text_rect.out_rect.setTextureRect(sf::IntRect({0, 0}, {this->loaded_data.width, this->loaded_data.height}));
}
float TextRectangle::getNoBlurCharacterSpacing() {
const float whitespaceWidth = this->getFont(this->loaded_data)->getGlyph(U' ', this->actual_text.getCharacterSize(), false).advance;
float pixels_letter_spacing = (float)round((whitespaceWidth / 3.0f) * (this->loaded_data.character_spacing - 1.0));
return (float)((pixels_letter_spacing / (whitespaceWidth / 3.0f)) + 1.0);
}
void TextRectangle::updateText(int x_limit) {
// set the character size
this->actual_text.setCharacterSize((unsigned int)this->loaded_data.font_pixel_height); // in pixels, not points!
// set the color
this->actual_text.setFillColor(sf::Color::White);
// set the text style
//this->actual_text.setStyle(sf::Text::Bold);
this->actual_text.setPosition({0, 0});
this->setTextWithLineWrapping(x_limit);
sf::FloatRect globalBounds;
if(this->loaded_data.proportional_box) {
globalBounds = this->actual_text.getGlobalBounds();
int new_width = this->loaded_data.width;
int new_height = this->loaded_data.height;
int bounds_width = (int)(globalBounds.size.x + (globalBounds.position.x * 2));
int bounds_height = (int)(globalBounds.size.y + (globalBounds.position.y * 2));
if(new_width < bounds_width)
new_width = bounds_width;
if(new_height < bounds_height)
new_height = bounds_height;
this->setRealSize(new_width, new_height);
this->actual_text.setPosition({(float)((int)(5 * (((float)this->loaded_data.font_pixel_height) / BASE_PIXEL_FONT_HEIGHT))), 0});
globalBounds = this->actual_text.getGlobalBounds();
this->setRealSize((int)(globalBounds.size.x + (globalBounds.position.x * 2)), (int)(globalBounds.size.y + (globalBounds.position.y * 2)));
if(!this->loaded_data.locked) {
// set the character size
this->actual_text.setCharacterSize((unsigned int)this->loaded_data.font_pixel_height); // in pixels, not points!
// set the text style
//this->actual_text.setStyle(sf::Text::Bold);
this->actual_text.setPosition({0, 0});
this->setTextWithLineWrapping(x_limit);
sf::FloatRect globalBounds;
this->actual_text.setLineSpacing(this->loaded_data.line_spacing);
this->actual_text.setLetterSpacing(this->getNoBlurCharacterSpacing());
if(this->loaded_data.tight_and_centered) {
globalBounds = this->actual_text.getGlobalBounds();
int new_width = this->loaded_data.width;
int new_height = this->loaded_data.height;
int base_width = (int)(globalBounds.size.x + (globalBounds.position.x * 2));
int bounds_width = (int)(base_width * TEXT_RECTANGLE_POS_APPROX);
int base_height = (int)(globalBounds.size.y + (globalBounds.position.y * 2));
int bounds_height = base_height;
if(new_width < bounds_width) {
bounds_width = new_width;
base_width = new_width;
}
if(new_height < bounds_height) {
bounds_height = new_height;
base_height = new_width;
}
this->setRealSize(bounds_width, bounds_height);
switch(this->loaded_data.pos_kind) {
case POS_KIND_NORMAL:
this->actual_text.setPosition({(float)((int)((this->loaded_data.width - (globalBounds.size.x + (globalBounds.position.x * 2))) / 2)), (float)((int)((this->loaded_data.height - (globalBounds.size.y + (globalBounds.position.y * 2))) / 2))});
this->pos_x_center_contrib = (new_width - this->loaded_data.width) / 2;
this->pos_y_center_contrib = (new_height - this->loaded_data.height) / 2;
break;
case POS_KIND_PRIORITIZE_TOP_LEFT:
this->actual_text.setPosition({0, 0});
this->pos_x_center_contrib = (base_width - this->loaded_data.width) / 2;
this->pos_y_center_contrib = 0;
break;
case POS_KIND_PRIORITIZE_BOTTOM_LEFT:
this->actual_text.setPosition({0, 0});
this->pos_x_center_contrib = (base_width - this->loaded_data.width) / 2;
this->pos_y_center_contrib = -this->loaded_data.height;
break;
default:
break;
}
}
else if(this->loaded_data.proportional_box) {
globalBounds = this->actual_text.getGlobalBounds();
int new_width = this->loaded_data.width;
int new_height = this->loaded_data.height;
int bounds_width = (int)(globalBounds.size.x + (globalBounds.position.x * 2));
int bounds_height = (int)(globalBounds.size.y + (globalBounds.position.y * 2));
if(new_width < bounds_width)
new_width = bounds_width;
if(new_height < bounds_height)
new_height = bounds_height;
this->setRealSize(new_width, new_height);
this->actual_text.setPosition({(float)((int)(5 * (((float)this->loaded_data.font_pixel_height) / BASE_PIXEL_FONT_HEIGHT))), 0});
globalBounds = this->actual_text.getGlobalBounds();
this->setRealSize((int)(globalBounds.size.x + (globalBounds.position.x * 2)), (int)(globalBounds.size.y + (globalBounds.position.y * 2)));
}
else {
this->setRealSize(this->loaded_data.width, this->loaded_data.height);
this->actual_text.setPosition({0, 0});
globalBounds = this->actual_text.getGlobalBounds();
this->actual_text.setPosition({(float)((int)((this->loaded_data.width - (globalBounds.size.x + (globalBounds.position.x * 2))) / 2)), (float)((int)((this->loaded_data.height - (globalBounds.size.y + (globalBounds.position.y * 2))) / 2))});
}
}
else {
this->setRealSize(this->loaded_data.width, this->loaded_data.height);
sf::Vector2f old_actual_text_pos = this->actual_text.getPosition();
this->actual_text.setPosition({0, 0});
globalBounds = this->actual_text.getGlobalBounds();
this->actual_text.setPosition({(float)((int)((this->loaded_data.width - (globalBounds.size.x + (globalBounds.position.x * 2))) / 2)), (float)((int)((this->loaded_data.height - (globalBounds.size.y + (globalBounds.position.y * 2))) / 2))});
this->setTextWithLineWrapping(x_limit);
this->actual_text.setPosition(old_actual_text_pos);
}
sf::Color color_text = sf::Color(255, 255, 255, 255);
switch(this->loaded_data.kind) {
case TEXT_KIND_NORMAL:
this->curr_color = sf::Color(40, 40, 80, 192);
@ -255,12 +447,21 @@ void TextRectangle::updateText(int x_limit) {
case TEXT_KIND_OPAQUE_ERROR:
this->curr_color = sf::Color(160, 60, 60, 192);
break;
case TEXT_KIND_TEXTBOX:
this->curr_color = sf::Color(255, 255, 255, 255);
color_text = sf::Color(0, 0, 0, 255);
break;
case TEXT_KIND_TEXTBOX_TRANSPARENT:
this->curr_color = sf::Color(255, 255, 255, 0);
color_text = sf::Color(0, 0, 0, 255);
break;
case TEXT_KIND_TITLE:
this->curr_color = sf::Color(30, 30, 60, 0);
break;
default:
break;
}
this->actual_text.setFillColor(color_text);
this->text_rect.out_tex.clear(this->curr_color);
this->text_rect.out_tex.draw(this->actual_text);
this->text_rect.out_tex.display();

View File

@ -1,9 +1,11 @@
#include "TextRectangle.hpp"
#include "TextRectanglePool.hpp"
TextRectanglePool::TextRectanglePool(bool font_load_success, sf::Font *text_font) {
TextRectanglePool::TextRectanglePool(bool font_load_success, sf::Font *text_font, bool font_mono_load_success, sf::Font *text_font_mono) {
this->font_load_success = font_load_success;
this->text_font = text_font;
this->font_mono_load_success = font_mono_load_success;
this->text_font_mono = text_font_mono;
this->num_loaded_text_rectangles = 0;
this->text_rectangles_list = NULL;
}
@ -30,7 +32,7 @@ void TextRectanglePool::request_num_text_rectangles(int num_wanted_text_rectangl
// 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);
new_text_rectangle_ptrs[i] = new TextRectangle(this->font_load_success, this->text_font, this->font_mono_load_success, this->text_font_mono);
}
if(this->num_loaded_text_rectangles > 0)

View File

@ -5,6 +5,7 @@
#include <cstring>
#include <cmath>
#include "font_ttf.h"
#include "font_mono_ttf.h"
#include "shaders_list.hpp"
#include "devicecapture.hpp"
#include <conversions.hpp>
@ -55,8 +56,9 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp
this->ret_val = 0;
reset_screen_info(this->m_info);
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);
bool font_mono_load_success = this->text_font_mono.openFromMemory(font_mono_ttf, font_mono_ttf_len);
this->notification = new TextRectangle(font_load_success, &this->text_font, font_mono_load_success, &this->text_font_mono);
this->text_rectangle_pool = new TextRectanglePool(font_load_success, &this->text_font, font_mono_load_success, &this->text_font_mono);
this->init_menus();
FPSArrayInit(&this->in_fps);
FPSArrayInit(&this->draw_fps);

View File

@ -126,6 +126,7 @@ void WindowScreen::init_menus() {
this->second_screen_3d_relpos_menu = new SecondScreen3DRelativePositionMenu(this->text_rectangle_pool);
this->usb_conflict_resolution_menu = new USBConflictResolutionMenu(this->text_rectangle_pool);
this->optimize_3ds_menu = new Optimize3DSMenu(this->text_rectangle_pool);
this->optimize_serial_key_add_menu = new OptimizeSerialKeyAddMenu(this->text_rectangle_pool);
}
void WindowScreen::destroy_menus() {
@ -157,6 +158,7 @@ void WindowScreen::destroy_menus() {
delete this->second_screen_3d_relpos_menu;
delete this->usb_conflict_resolution_menu;
delete this->optimize_3ds_menu;
delete this->optimize_serial_key_add_menu;
}
void WindowScreen::set_close(int ret_val) {
@ -599,6 +601,29 @@ void WindowScreen::input_video_data_format_request_change(bool positive) {
this->last_data_format_change_time = curr_time;
}
bool WindowScreen::add_new_cc_key(std::string key, CaptureConnectionType conn_type, bool discriminator) {
bool ret = false;
KeySaveError save_error = save_cc_key(key, conn_type, discriminator);
switch(save_error) {
case KEY_SAVE_METHOD_NOT_FOUND:
this->print_notification("Key saving method missing", TEXT_KIND_ERROR);
break;
case KEY_INVALID:
this->print_notification("Key invalid", TEXT_KIND_ERROR);
break;
case KEY_ALREADY_PRESENT:
this->print_notification("Key already present", TEXT_KIND_WARNING);
break;
case KEY_SAVED:
this->print_notification("Key saved successfully");
ret = true;
break;
default:
break;
}
return ret;
}
bool WindowScreen::can_execute_cmd(const WindowCommand* window_cmd, bool is_extra, bool is_always) {
if((!window_cmd->usable_always) && is_always)
return false;
@ -741,6 +766,10 @@ bool WindowScreen::common_poll(SFEvent &event_data) {
break;
case EVENT_TEXT_ENTERED:
if(this->has_menu_textbox()) {
consumed = false;
break;
}
switch(event_data.unicode) {
case 's':
this->execute_cmd(WINDOW_COMMAND_SPLIT);
@ -863,6 +892,8 @@ bool WindowScreen::can_setup_menu() {
}
void WindowScreen::switch_to_menu(CurrMenuType new_menu_type, GenericMenu* new_menu, bool reset_data, bool update_last_menu_change_time) {
if((this->curr_menu != new_menu_type) && (this->curr_menu_ptr != NULL))
this->curr_menu_ptr->on_menu_unloaded();
this->curr_menu = new_menu_type;
this->curr_menu_ptr = new_menu;
if(this->curr_menu_ptr != NULL)
@ -1206,6 +1237,15 @@ void WindowScreen::setup_optimize_3ds_menu(bool reset_data) {
}
}
void WindowScreen::setup_optimize_serial_key_add_menu(bool reset_data) {
if(!this->can_setup_menu())
return;
if(this->curr_menu != OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE) {
this->switch_to_menu(OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE, this->optimize_serial_key_add_menu, reset_data);
this->optimize_serial_key_add_menu->insert_data(&this->capture_status->device);
}
}
void WindowScreen::update_save_menu() {
if(this->curr_menu == SAVE_MENU_TYPE) {
this->curr_menu = DEFAULT_MENU_TYPE;
@ -1213,6 +1253,12 @@ void WindowScreen::update_save_menu() {
}
}
bool WindowScreen::has_menu_textbox() {
if(this->loaded_menu_ptr == NULL)
return false;
return this->loaded_menu_ptr->is_inside_textbox;
}
bool WindowScreen::no_menu_poll(SFEvent &event_data) {
bool consumed = true;
switch(event_data.type) {
@ -1286,6 +1332,10 @@ bool WindowScreen::main_poll(SFEvent &event_data) {
bool consumed = true;
switch(event_data.type) {
case EVENT_TEXT_ENTERED:
if(this->has_menu_textbox()) {
consumed = false;
break;
}
switch(event_data.unicode) {
case 'c':
this->execute_cmd(WINDOW_COMMAND_CROP);
@ -2302,6 +2352,17 @@ void WindowScreen::poll(bool do_everything) {
break;
case OPTIMIZE3DS_MENU_NO_ACTION:
break;
case OPTIMIZE3DS_MENU_INFO_DEVICE_ID:
break;
case OPTIMIZE3DS_MENU_COPY_DEVICE_ID:
sf::Clipboard::setString(get_device_id_string(this->capture_status));
this->print_notification("Device ID copied!");
break;
case OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY:
break;
case OPTIMIZE3DS_MENU_OPTIMIZE_SERIAL_KEY_MENU:
this->setup_optimize_serial_key_add_menu();
break;
case OPTIMIZE3DS_MENU_INPUT_VIDEO_FORMAT_INC:
this->input_video_data_format_request_change(true);
break;
@ -2313,6 +2374,37 @@ void WindowScreen::poll(bool do_everything) {
}
this->loaded_menu_ptr->reset_output_option();
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE:
switch(this->optimize_serial_key_add_menu->selected_index) {
case OPTIMIZE_SERIAL_KEY_ADD_MENU_BACK:
this->setup_optimize_3ds_menu(false);
done = true;
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_NO_ACTION:
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_CONFIRM:
if(add_new_cc_key(this->optimize_serial_key_add_menu->get_key(), CAPTURE_CONN_CYPRESS_OPTIMIZE, this->optimize_serial_key_add_menu->key_for_new)) {
check_device_serial_key_update(this->capture_status, this->optimize_serial_key_add_menu->key_for_new, this->optimize_serial_key_add_menu->get_key());
this->setup_optimize_3ds_menu(false);
done = true;
}
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_DEC:
this->optimize_serial_key_add_menu->key_for_new = !this->optimize_serial_key_add_menu->key_for_new;
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INC:
this->optimize_serial_key_add_menu->key_for_new = !this->optimize_serial_key_add_menu->key_for_new;
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_TARGET_INFO:
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_SELECT_TEXTBOX:
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_KEY_PRINT:
break;
default:
break;
}
this->loaded_menu_ptr->reset_output_option();
break;
default:
break;
@ -2342,6 +2434,10 @@ void WindowScreen::update_capture_specific_settings() {
}
if(this->curr_menu == ISN_MENU_TYPE)
this->setup_no_menu();
if(this->curr_menu == OPTIMIZE_3DS_MENU_TYPE)
this->setup_no_menu();
if(this->curr_menu == OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE)
this->setup_no_menu();
}
int WindowScreen::load_data() {
@ -2427,11 +2523,11 @@ void WindowScreen::poll_window(bool do_everything) {
events_queue.emplace(EVENT_CLOSED);
else if(const auto* keyPressed = event->getIf<sf::Event::KeyPressed>()) {
if(this->shared_data->input_data.enable_keyboard_input)
events_queue.emplace(true, keyPressed->code);
events_queue.emplace(true, keyPressed->code, keyPressed->alt, keyPressed->control, keyPressed->shift, keyPressed->system);
}
else if(const auto* keyReleased = event->getIf<sf::Event::KeyReleased>()) {
if(this->shared_data->input_data.enable_keyboard_input)
events_queue.emplace(false, keyReleased->code);
events_queue.emplace(false, keyReleased->code, keyReleased->alt, keyReleased->control, keyReleased->shift, keyReleased->system);
}
else if(const auto* textEntered = event->getIf<sf::Event::TextEntered>()) {
if(this->shared_data->input_data.enable_keyboard_input)
@ -2605,6 +2701,9 @@ void WindowScreen::prepare_menu_draws(int view_size_x, int view_size_y) {
case OPTIMIZE_3DS_MENU_TYPE:
this->optimize_3ds_menu->prepare(menu_scaling_factor, view_size_x, view_size_y, this->capture_status);
break;
case OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE:
this->optimize_serial_key_add_menu->prepare(menu_scaling_factor, view_size_x, view_size_y);
break;
default:
break;
}

View File

@ -12,6 +12,7 @@
#include <iostream>
#define CONNECTION_NO_DEVICE_SELECTED (-1)
#define NO_SERIAL_KEY_STR "No Serial Key"
static bool poll_connection_window_screen(WindowScreen *screen, int &chosen_index) {
screen->poll();
@ -308,6 +309,37 @@ std::string get_device_id_string(CaptureStatus* capture_status) {
return "";
}
std::string get_device_serial_key_string(CaptureStatus* capture_status) {
if(!capture_status->connected)
return NO_SERIAL_KEY_STR;
if(capture_status->device.device_id == 0)
return NO_SERIAL_KEY_STR;
if(capture_status->device.key == "")
return NO_SERIAL_KEY_STR;
return capture_status->device.key;
}
void check_device_serial_key_update(CaptureStatus* capture_status, bool differentiator, std::string key) {
if(get_device_serial_key_string(capture_status) != NO_SERIAL_KEY_STR)
return;
if(capture_status->key_updated)
return;
switch(capture_status->device.cc_type) {
case CAPTURE_CONN_CYPRESS_OPTIMIZE:
#ifdef USE_CYPRESS_OPTIMIZE
if(differentiator != is_device_optimize_n3ds(&capture_status->device))
break;
if(cyop_is_key_for_device_id(&capture_status->device, key))
capture_status->key_updated = true;
#endif
break;
default:
break;
}
}
std::string get_name_of_device(CaptureStatus* capture_status, bool use_long, bool want_real_serial) {
if(!capture_status->connected)
return "Not connected";
@ -397,6 +429,22 @@ float get_framerate_multiplier(CaptureStatus* capture_status) {
return 0.5;
}
KeySaveError save_cc_key(std::string key, CaptureConnectionType conn_type, bool differentiator) {
KeySaveError error = KEY_SAVE_METHOD_NOT_FOUND;
switch(conn_type) {
case CAPTURE_CONN_CYPRESS_OPTIMIZE:
#ifdef USE_CYPRESS_OPTIMIZE
error = add_key_to_file(key, differentiator);
#endif
break;
default:
break;
}
return error;
}
void capture_init() {
#ifdef USE_DS_3DS_USB
usb_ds_3ds_init();

View File

@ -1131,7 +1131,7 @@ void update_connected_3ds_ds(FrontendData* frontend_data, const CaptureDevice &o
}
void update_connected_specific_settings(FrontendData* frontend_data, const CaptureDevice &cc_device) {
if(cc_device.cc_type == CAPTURE_CONN_IS_NITRO) {
if((cc_device.cc_type == CAPTURE_CONN_IS_NITRO) || (cc_device.cc_type == CAPTURE_CONN_CYPRESS_OPTIMIZE)) {
frontend_data->top_screen->update_capture_specific_settings();
frontend_data->bot_screen->update_capture_specific_settings();
frontend_data->joint_screen->update_capture_specific_settings();

View File

@ -9,7 +9,11 @@
#include <iostream>
#include <fstream>
#include <sstream>
#if (!defined(_MSC_VER)) || (_MSC_VER > 1916)
#include <filesystem>
#else
#include <experimental/filesystem>
#endif
#include <mutex>
#include <condition_variable>
#include <chrono>