Implement RPi basic version-special code

This commit is contained in:
Lorenzooone 2024-06-02 06:20:49 +02:00
parent d5765338f2
commit f572c42bbb
17 changed files with 353 additions and 89 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ cc3dsfs
cc3dsfs.exe
*.conf
*.a
*.zip
ftd3xx/
presets/
build/

18
CMakeLists.txt Normal file → Executable file
View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(cc3dsfs VERSION 0.0.0 LANGUAGES CXX)
project(cc3dsfs VERSION 1.0.0 LANGUAGES CXX)
include(ExternalProject)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
@ -7,8 +7,15 @@ option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
set(CMAKE_HOST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING "Host Compiler")
set(WINDOWS_FTD3XX_USE_SHARED_LIB 0)
set(FETCHCONTENT_QUIET FALSE)
set(EXTRA_LINUX_CXX_FLAGS "-DXLIB_BASED 1" CACHE STRING "Extra Linux CXX flags")
set(EXTRA_CXX_FLAGS "")
set(RASPBERRY_PI_COMPILATION FALSE CACHE BOOL "Option for compiling the Raspberry Pi GPIO library in")
set(SFML_BUILD_NETWORK FALSE)
set(EXTRA_LIBRARIES "")
if (RASPBERRY_PI_COMPILATION)
set(EXTRA_LIBRARIES "pigpiod_if2")
set(EXTRA_CXX_FLAGS "${EXTRA_CXX_FLAGS}-DRASPI 1 ")
endif()
# Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24:
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
@ -50,6 +57,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
set(FTD3XX_MOUNTED_FOLDER /Volumes/${FTD3XX_VOL})
set(FTD3XX_SUBFOLDER macos)
else()
set(EXTRA_CXX_FLAGS "${EXTRA_CXX_FLAGS}-DXLIB_BASED 1 ")
set(FTD3XX_BUILD_COMMAND ${CMAKE_SOURCE_DIR}/linux_setup_ftd3xx.sh)
set(FTD3XX_URL_TIME 2023/03)
set(FTD3XX_VER 1.0.5)
@ -132,13 +140,13 @@ file(MAKE_DIRECTORY ${TOOLS_DATA_DIR})
set(OUTPUT_NAME cc3dsfs)
add_executable(CMakeBin2C tools/bin2c.cpp)
add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/3dscapture.cpp source/conversions.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 ${TOOLS_DATA_DIR}/font_ttf.cpp)
add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/3dscapture.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 ${TOOLS_DATA_DIR}/font_ttf.cpp)
add_dependencies(${OUTPUT_NAME} FTD3XX_BUILD_PROJECT CMakeBin2C)
target_link_libraries(${OUTPUT_NAME} PRIVATE sfml-graphics sfml-audio sfml-window sfml-system ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB})
target_link_libraries(${OUTPUT_NAME} PRIVATE sfml-graphics sfml-audio sfml-window sfml-system ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB} ${EXTRA_LIBRARIES})
target_link_directories(${OUTPUT_NAME} PRIVATE ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER})
target_include_directories(${OUTPUT_NAME} PRIVATE ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/Menus)
target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_20)
target_compile_options(${OUTPUT_NAME} PRIVATE ${EXTRA_LINUX_CXX_FLAGS})
target_compile_options(${OUTPUT_NAME} PRIVATE ${EXTRA_CXX_FLAGS})
target_compile_features(CMakeBin2C PRIVATE cxx_std_17)
add_custom_command(

4
README.md Normal file → Executable file
View File

@ -122,4 +122,8 @@ The name of profiles can be changed by altering the __name__ field in its file.
- USB Hubs can be the cause of connection issues. If you're having problems, try checking whether the 3DS connects fine or not without any other devices connected.
- Fullscreen mode on MacOS may mistake the screen for being bigger than what it really is. Changing the resolution to the proper one of the screen in the _Resolution Settings_ under Video Settings will fix the issue.
- Current font in use: OFL Sorts Mill Goudy TT
- When compiling on a Raspberry Pi, to enable usage of GPIO, use:
```
cmake -B build -DRASPBERRY_PI_COMPILATION=TRUE ; cmake --build build --config Release
```

28
include/ExtraButtons.hpp Executable file
View File

@ -0,0 +1,28 @@
#ifndef __EXTRABUTTONS_HPP
#define __EXTRABUTTONS_HPP
#include <chrono>
#include "sfml_gfx_structs.hpp"
class ExtraButton {
public:
void initialize(int pi_value, int id, sf::Keyboard::Key corresponding_key, bool is_power, float first_re_press_time, float later_re_press_time);
int get_pi_value();
void poll(std::queue<SFEvent> &events_queue);
private:
bool initialized = false;
int id;
sf::Keyboard::Key corresponding_key;
bool is_power;
int pi_value;
bool started;
bool after_first;
float first_re_press_time;
float later_re_press_time;
std::chrono::time_point<std::chrono::high_resolution_clock> last_press_time;
bool is_time_valid;
bool is_pressed();
bool is_valid();
};
#endif

View File

@ -26,6 +26,7 @@ public:
void reset_output_option();
protected:
void set_output_option(int index, int action);
bool is_option_selectable(int index, int action);
int get_num_options();
std::string get_string_option(int index, int action);
void class_setup();

View File

@ -30,7 +30,7 @@ public:
MainMenu(bool font_load_success, sf::Font &text_font);
~MainMenu();
void prepare(float scaling_factor, int view_size_x, int view_size_y, bool connected);
void insert_data(ScreenType s_type, bool is_fullscreen);
void insert_data(ScreenType s_type, bool is_fullscreen, bool mono_app_mode);
MainMenuOutAction selected_index = MainMenuOutAction::MAIN_MENU_NO_ACTION;
void reset_output_option();
protected:

View File

@ -34,6 +34,7 @@ struct ScreenInfo {
struct DisplayData {
bool split;
bool mono_app_mode;
};
#pragma pack(push, 1)

View File

@ -131,6 +131,9 @@ private:
std::chrono::time_point<std::chrono::high_resolution_clock> last_draw_time;
FPSArray poll_fps;
std::chrono::time_point<std::chrono::high_resolution_clock> last_poll_time;
bool triggered_poweroff;
std::chrono::time_point<std::chrono::high_resolution_clock> last_poweroff_time;
const float poweroff_timeout = 30.0;
sf::Texture in_tex;

View File

@ -13,7 +13,7 @@ struct out_rect_data {
};
struct SFEvent {
SFEvent(sf::Event::EventType type, sf::Keyboard::Key code, uint32_t unicode, uint32_t joystickId, uint32_t joy_button, sf::Joystick::Axis axis, float position, sf::Mouse::Button mouse_button, int mouse_x, int mouse_y) : type(type), code(code), unicode(unicode), joystickId(joystickId), joy_button(joy_button), axis(axis), position(position), mouse_button(mouse_button), mouse_x(mouse_x), mouse_y(mouse_y) {}
SFEvent(sf::Event::EventType type, sf::Keyboard::Key code, uint32_t unicode, uint32_t joystickId, uint32_t joy_button, sf::Joystick::Axis axis, float position, sf::Mouse::Button mouse_button, int mouse_x, int mouse_y, bool poweroff_cmd) : type(type), code(code), unicode(unicode), joystickId(joystickId), joy_button(joy_button), axis(axis), position(position), mouse_button(mouse_button), mouse_x(mouse_x), mouse_y(mouse_y), poweroff_cmd(poweroff_cmd) {}
sf::Event::EventType type;
sf::Keyboard::Key code;
@ -25,10 +25,14 @@ struct SFEvent {
sf::Mouse::Button mouse_button;
int mouse_x;
int mouse_y;
bool poweroff_cmd;
};
void joystick_axis_poll(std::queue<SFEvent> &events_queue);
JoystickDirection get_joystick_direction(uint32_t joystickId, sf::Joystick::Axis axis, float position);
JoystickAction get_joystick_action(uint32_t joystickId, uint32_t joy_button);
void init_extra_buttons_poll(int page_up_id, int page_down_id, int enter_id, int power_id);
void end_extra_buttons_poll();
void extra_buttons_poll(std::queue<SFEvent> &events_queue);
#endif

97
source/ExtraButtons.cpp Executable file
View File

@ -0,0 +1,97 @@
#include "ExtraButtons.hpp"
#ifdef RASPI
#include <pigpiod_if2.h>
#endif
static ExtraButton pi_page_up, pi_page_down, pi_enter, pi_power;
void ExtraButton::initialize(int pi_value, int id, sf::Keyboard::Key corresponding_key, bool is_power, float first_re_press_time, float later_re_press_time) {
this->pi_value = pi_value;
this->id = id;
this->is_power = is_power;
this->corresponding_key = corresponding_key;
this->started = false;
this->initialized = true;
this->is_time_valid = false;
this->last_press_time = std::chrono::high_resolution_clock::now();
this->first_re_press_time = first_re_press_time;
this->later_re_press_time = later_re_press_time;
#ifdef RASPI
set_mode(this->pi_value, this->id, PI_INPUT);
set_pull_up_down(this->pi_value, this->id, PI_PUD_UP);
#endif
}
int ExtraButton::get_pi_value() {
if(!this->initialized)
return -1;
return this->pi_value;
}
bool ExtraButton::is_pressed() {
#ifdef RASPI
return gpio_read(this->pi_value, this->id) == 0;
#else
return false;
#endif
}
bool ExtraButton::is_valid() {
return this->initialized && (this->id >= 0) && (this->pi_value >= 0);
}
void ExtraButton::poll(std::queue<SFEvent> &events_queue) {
if(!this->is_valid())
return;
sf::Event::EventType event_kind = sf::Event::KeyReleased;
if(this->is_pressed())
event_kind = sf::Event::KeyPressed;
if(event_kind == sf::Event::KeyPressed) {
auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - this->last_press_time;
float press_frequency_limit = this->first_re_press_time;
if((!this->started) || this->after_first)
press_frequency_limit = this->later_re_press_time;
// Do this regardless, even if it was previously released.
// This allows being more "lenient" with bad hw connections...
if(this->is_time_valid && (diff.count() < press_frequency_limit))
return;
this->is_time_valid = true;
this->last_press_time = curr_time;
if(!this->started) {
this->started = true;
this->after_first = false;
}
else
this->after_first = true;
}
else
this->started = false;
events_queue.emplace(event_kind, this->corresponding_key, 0, 0, 0, sf::Joystick::Axis::X, 0, sf::Mouse::Left, 0, 0, this->is_power);
}
void init_extra_buttons_poll(int page_up_id, int page_down_id, int enter_id, int power_id) {
int pi_value = -1;
#ifdef RASPI
pi_value = pigpio_start(NULL, NULL);
#endif
pi_page_up.initialize(pi_value, page_up_id, sf::Keyboard::PageUp, false, 0.5, 0.03);
pi_page_down.initialize(pi_value, page_down_id, sf::Keyboard::PageDown, false, 0.5, 0.03);
pi_enter.initialize(pi_value, enter_id, sf::Keyboard::Enter, false, 0.5, 0.075);
pi_power.initialize(pi_value, power_id, sf::Keyboard::Escape, true, 30.0, 30.0);
}
void end_extra_buttons_poll() {
#ifdef RASPI
int pi_value = pi_page_up.get_pi_value();
if(pi_value >= 0)
pigpio_stop(pi_value);
#endif
}
void extra_buttons_poll(std::queue<SFEvent> &events_queue) {
pi_page_down.poll(events_queue);
pi_page_up.poll(events_queue);
pi_enter.poll(events_queue);
pi_power.poll(events_queue);
}

View File

@ -4,6 +4,7 @@
struct ExtraSettingsMenuOptionInfo {
const std::string base_name;
const bool is_selectable;
const bool active_fullscreen;
const bool active_windowed_screen;
const bool active_joint_screen;
@ -12,37 +13,44 @@ struct ExtraSettingsMenuOptionInfo {
const ExtraSettingsMenuOutAction out_action;
};
static const ExtraSettingsMenuOptionInfo warning_option = {
.base_name = "Advanced users only!", .is_selectable = false,
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.out_action = EXTRA_SETTINGS_MENU_NO_ACTION};
static const ExtraSettingsMenuOptionInfo windowed_option = {
.base_name = "Windowed Mode",
.base_name = "Windowed Mode", .is_selectable = true,
.active_fullscreen = true, .active_windowed_screen = false,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.out_action = EXTRA_SETTINGS_MENU_FULLSCREEN};
static const ExtraSettingsMenuOptionInfo fullscreen_option = {
.base_name = "Fullscreen Mode",
.base_name = "Fullscreen Mode", .is_selectable = true,
.active_fullscreen = false, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.out_action = EXTRA_SETTINGS_MENU_FULLSCREEN};
static const ExtraSettingsMenuOptionInfo join_screens_option = {
.base_name = "Join Screens",
.base_name = "Join Screens", .is_selectable = true,
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = false, .active_top_screen = true, .active_bottom_screen = true,
.out_action = EXTRA_SETTINGS_MENU_SPLIT};
static const ExtraSettingsMenuOptionInfo split_screens_option = {
.base_name = "Split Screens",
.base_name = "Split Screens", .is_selectable = true,
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = false, .active_bottom_screen = false,
.out_action = EXTRA_SETTINGS_MENU_SPLIT};
static const ExtraSettingsMenuOptionInfo quit_option = {
.base_name = "Quit Application",
.base_name = "Quit Application", .is_selectable = true,
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.out_action = EXTRA_SETTINGS_MENU_QUIT_APPLICATION};
static const ExtraSettingsMenuOptionInfo* pollable_options[] = {
&warning_option,
&windowed_option,
&fullscreen_option,
&join_screens_option,
@ -72,7 +80,7 @@ void ExtraSettingsMenu::class_setup() {
this->menu_color = sf::Color(30, 30, 60, 192);
this->title = "Extra Settings";
this->show_back_x = true;
this->show_x = true;
this->show_x = false;
this->show_title = true;
}
@ -109,6 +117,10 @@ void ExtraSettingsMenu::set_output_option(int index, int action) {
this->selected_index = pollable_options[this->options_indexes[index]]->out_action;
}
bool ExtraSettingsMenu::is_option_selectable(int index, int action) {
return pollable_options[this->options_indexes[index]]->is_selectable;
}
int ExtraSettingsMenu::get_num_options() {
return this->num_enabled_options;
}

View File

@ -2,14 +2,6 @@
#define NUM_TOTAL_MENU_OPTIONS (sizeof(pollable_options)/sizeof(pollable_options[0]))
#define OPTION_WINDOWED true
#define OPTION_FULLSCREEN true
#define OPTION_JOIN true
#define OPTION_SPLIT true
#define OPTION_EXTRA false
#define OPTION_QUIT true
#define OPTION_SHUTDOWN false
struct MainMenuOptionInfo {
const std::string base_name;
const std::string false_name;
@ -18,6 +10,8 @@ struct MainMenuOptionInfo {
const bool active_joint_screen;
const bool active_top_screen;
const bool active_bottom_screen;
const bool enabled_normal_mode;
const bool enabled_mono_mode;
const MainMenuOutAction out_action;
};
@ -25,84 +19,91 @@ static const MainMenuOptionInfo connect_option = {
.base_name = "Disconnect", .false_name = "Connect",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true,
.out_action = MAIN_MENU_OPEN};
static const MainMenuOptionInfo windowed_option = {
.base_name = "Windowed Mode", .false_name = "",
.active_fullscreen = OPTION_WINDOWED, .active_windowed_screen = false,
.active_fullscreen = true, .active_windowed_screen = false,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = false,
.out_action = MAIN_MENU_FULLSCREEN};
static const MainMenuOptionInfo fullscreen_option = {
.base_name = "Fullscreen Mode", .false_name = "",
.active_fullscreen = false, .active_windowed_screen = OPTION_FULLSCREEN,
.active_fullscreen = false, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = false,
.out_action = MAIN_MENU_FULLSCREEN};
static const MainMenuOptionInfo join_screens_option = {
.base_name = "Join Screens", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = false, .active_top_screen = OPTION_JOIN, .active_bottom_screen = OPTION_JOIN,
.active_joint_screen = false, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = false,
.out_action = MAIN_MENU_SPLIT};
static const MainMenuOptionInfo split_screens_option = {
.base_name = "Split Screens", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = OPTION_SPLIT, .active_top_screen = false, .active_bottom_screen = false,
.active_joint_screen = true, .active_top_screen = false, .active_bottom_screen = false,
.enabled_normal_mode = true, .enabled_mono_mode = false,
.out_action = MAIN_MENU_SPLIT};
static const MainMenuOptionInfo video_settings_option = {
.base_name = "Video Settings", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true,
.out_action = MAIN_MENU_VIDEO_SETTINGS};
static const MainMenuOptionInfo quit_option = {
.base_name = "Quit Application", .false_name = "",
.active_fullscreen = OPTION_QUIT, .active_windowed_screen = OPTION_QUIT,
.active_joint_screen = OPTION_QUIT, .active_top_screen = OPTION_QUIT, .active_bottom_screen = OPTION_QUIT,
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = false,
.out_action = MAIN_MENU_QUIT_APPLICATION};
static const MainMenuOptionInfo shutdown_option = {
.base_name = "Shutdown", .false_name = "",
.active_fullscreen = OPTION_SHUTDOWN, .active_windowed_screen = OPTION_SHUTDOWN,
.active_joint_screen = OPTION_SHUTDOWN, .active_top_screen = OPTION_SHUTDOWN, .active_bottom_screen = OPTION_SHUTDOWN,
.out_action = MAIN_MENU_SHUTDOWN};
static const MainMenuOptionInfo audio_settings_option = {
.base_name = "Audio Settings", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true,
.out_action = MAIN_MENU_AUDIO_SETTINGS};
static const MainMenuOptionInfo save_profiles_option = {
.base_name = "Save Profile", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true,
.out_action = MAIN_MENU_SAVE_PROFILES};
static const MainMenuOptionInfo load_profiles_option = {
.base_name = "Load Profile", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true,
.out_action = MAIN_MENU_LOAD_PROFILES};
static const MainMenuOptionInfo status_option = {
.base_name = "Status", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true,
.out_action = MAIN_MENU_STATUS};
static const MainMenuOptionInfo licenses_option = {
.base_name = "Licenses", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true,
.out_action = MAIN_MENU_LICENSES};
static const MainMenuOptionInfo extra_settings_option = {
.base_name = "Extra Settings", .false_name = "",
.active_fullscreen = OPTION_EXTRA, .active_windowed_screen = OPTION_EXTRA,
.active_joint_screen = OPTION_EXTRA, .active_top_screen = OPTION_EXTRA, .active_bottom_screen = OPTION_EXTRA,
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = false, .enabled_mono_mode = true,
.out_action = MAIN_MENU_EXTRA_SETTINGS};
static const MainMenuOptionInfo* pollable_options[] = {
@ -115,11 +116,10 @@ static const MainMenuOptionInfo* pollable_options[] = {
&audio_settings_option,
&save_profiles_option,
&load_profiles_option,
&extra_settings_option,
&status_option,
&licenses_option,
&extra_settings_option,
&quit_option,
&shutdown_option
};
MainMenu::MainMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){
@ -148,7 +148,7 @@ void MainMenu::class_setup() {
this->show_title = true;
}
void MainMenu::insert_data(ScreenType s_type, bool is_fullscreen) {
void MainMenu::insert_data(ScreenType s_type, bool is_fullscreen, bool mono_app_mode) {
this->num_enabled_options = 0;
for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) {
bool valid = true;
@ -162,6 +162,10 @@ void MainMenu::insert_data(ScreenType s_type, bool is_fullscreen) {
valid = valid && pollable_options[i]->active_bottom_screen;
else
valid = valid && pollable_options[i]->active_joint_screen;
if(mono_app_mode)
valid = valid && pollable_options[i]->enabled_mono_mode;
else
valid = valid && pollable_options[i]->enabled_normal_mode;
if(valid) {
this->options_indexes[this->num_enabled_options] = i;
this->num_enabled_options++;

View File

@ -27,6 +27,7 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp
FPSArrayInit(&this->in_fps);
FPSArrayInit(&this->draw_fps);
FPSArrayInit(&this->poll_fps);
this->triggered_poweroff = false;
this->in_tex.create(IN_VIDEO_WIDTH, IN_VIDEO_HEIGHT);
this->m_in_rect_top.setTexture(&this->in_tex);
this->m_in_rect_bot.setTexture(&this->in_tex);
@ -48,6 +49,8 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp
this->win_title += "_bot";
this->last_connected_status = false;
this->capture_status = capture_status;
if(this->display_data->mono_app_mode && this->m_stype == ScreenType::JOINT)
this->m_info.is_fullscreen = true;
}
WindowScreen::~WindowScreen() {
@ -208,6 +211,8 @@ void WindowScreen::update_connection() {
}
void WindowScreen::print_notification(std::string text, TextKind kind) {
if(this->triggered_poweroff)
return;
this->notification->setText(text);
this->notification->setRectangleKind(kind);
this->notification->startTimer(true);
@ -569,7 +574,7 @@ void WindowScreen::calc_scaling_resize_screens(sf::Vector2f &own_screen_size, sf
int old_scaling = own_scaling;
if(increase && (chosen_ratio > own_scaling) && (chosen_ratio > 0))
own_scaling += 1;
else if(mantain && (chosen_ratio >= own_scaling) && (chosen_ratio > 0))
else if(mantain && (chosen_ratio >= own_scaling) && (chosen_ratio > 0) && (own_scaling >= 0))
own_scaling = own_scaling;
else
own_scaling = chosen_ratio;

View File

@ -391,7 +391,7 @@ void WindowScreen::setup_main_menu(bool reset_data) {
this->curr_menu = MAIN_MENU_TYPE;
if(reset_data)
this->main_menu->reset_data();
this->main_menu->insert_data(this->m_stype, this->m_info.is_fullscreen);
this->main_menu->insert_data(this->m_stype, this->m_info.is_fullscreen, this->display_data->mono_app_mode);
}
}
@ -799,13 +799,28 @@ void WindowScreen::poll() {
while(!events_queue.empty()) {
if(done)
break;
SFEvent event_data = events_queue.front();
if(this->triggered_poweroff) {
// Stop accepting inputs... Not needed, since we're technically powering down...
auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - this->last_poweroff_time;
if(diff.count() < this->poweroff_timeout)
break;
this->triggered_poweroff = false;
}
if((event_data.type == sf::Event::KeyPressed) && event_data.poweroff_cmd) {
this->m_prepare_save = STARTUP_FILE_INDEX;
this->print_notification("Saving and shutting\ndown...Please wait");
this->triggered_poweroff = true;
this->last_poweroff_time = std::chrono::high_resolution_clock::now();
break;
}
if(this->query_reset_request()) {
this->reset_held_times();
this->m_prepare_load = SIMPLE_RESET_DATA_INDEX;
done = true;
continue;
}
SFEvent event_data = events_queue.front();
events_queue.pop();
if(this->common_poll(event_data)) {
if(this->close_capture())
@ -1054,6 +1069,7 @@ void WindowScreen::poll() {
this->video_menu->reset_output_option();
continue;
}
break;
case CROP_MENU_TYPE:
if(this->crop_menu->poll(event_data)) {
switch(this->crop_menu->selected_index) {
@ -1410,7 +1426,7 @@ void WindowScreen::poll_window() {
mouse_x = event.mouseMove.x;
mouse_y = event.mouseMove.y;
}
events_queue.emplace(event.type, event.key.code, event.text.unicode, joystickId, event.joystickButton.button, event.joystickMove.axis, 0.0, event.mouseButton.button, mouse_x, mouse_y);
events_queue.emplace(event.type, event.key.code, event.text.unicode, joystickId, event.joystickButton.button, event.joystickMove.axis, 0.0, event.mouseButton.button, mouse_x, mouse_y, false);
}
if(this->m_win.hasFocus()) {
check_held_reset(sf::Mouse::isButtonPressed(sf::Mouse::Right), this->right_click_action);
@ -1434,12 +1450,13 @@ void WindowScreen::poll_window() {
auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - this->touch_right_click_action.start_time;
if(diff.count() > this->touch_long_press_timer) {
events_queue.emplace(sf::Event::MouseButtonPressed, sf::Keyboard::Backspace, 0, 0, 0, sf::Joystick::Axis::X, 0.0, sf::Mouse::Right, touch_pos.x, touch_pos.y);
events_queue.emplace(sf::Event::MouseButtonPressed, sf::Keyboard::Backspace, 0, 0, 0, sf::Joystick::Axis::X, 0.0, sf::Mouse::Right, touch_pos.x, touch_pos.y, false);
this->touch_right_click_action.start_time = std::chrono::high_resolution_clock::now();
}
events_queue.emplace(sf::Event::MouseButtonPressed, sf::Keyboard::Backspace, 0, 0, 0, sf::Joystick::Axis::X, 0.0, sf::Mouse::Left, touch_pos.x, touch_pos.y);
events_queue.emplace(sf::Event::MouseButtonPressed, sf::Keyboard::Backspace, 0, 0, 0, sf::Joystick::Axis::X, 0.0, sf::Mouse::Left, touch_pos.x, touch_pos.y, false);
}
joystick_axis_poll(this->events_queue);
extra_buttons_poll(this->events_queue);
}
else {
this->reset_held_times();

View File

@ -67,47 +67,61 @@ static bool load(const std::string path, const std::string name, ScreenInfo &top
return false;
}
while(std::getline(file, line)) {
std::istringstream kvp(line);
std::string key;
bool result = true;
if(std::getline(kvp, key, '=')) {
std::string value;
try {
while(std::getline(file, line)) {
std::istringstream kvp(line);
std::string key;
if(std::getline(kvp, value)) {
if(std::getline(kvp, key, '=')) {
std::string value;
if(load_screen_info(key, value, "bot_", bottom_info))
continue;
if(load_screen_info(key, value, "joint_", joint_info))
continue;
if(load_screen_info(key, value, "top_", top_info))
continue;
if(std::getline(kvp, value)) {
if(key == "split") {
display_data.split = std::stoi(value);
continue;
if(load_screen_info(key, value, "bot_", bottom_info))
continue;
if(load_screen_info(key, value, "joint_", joint_info))
continue;
if(load_screen_info(key, value, "top_", top_info))
continue;
if(key == "split") {
display_data.split = std::stoi(value);
continue;
}
if(audio_data->load_audio_data(key, value))
continue;
}
if(audio_data->load_audio_data(key, value))
continue;
}
}
}
catch(...) {
UpdateOutText(out_text_data, "File " + path + name + " load failed.\nDefaults re-loaded.", "Load failed\nDefaults re-loaded", TEXT_KIND_ERROR);
result = false;
}
file.close();
return true;
return result;
}
static void defaults_reload(FrontendData *frontend_data, AudioData* audio_data) {
reset_screen_info(frontend_data->top_screen->m_info);
reset_screen_info(frontend_data->bot_screen->m_info);
reset_screen_info(frontend_data->joint_screen->m_info);
audio_data->reset();
reset_display_data(&frontend_data->display_data);
if(frontend_data->display_data.mono_app_mode)
frontend_data->joint_screen->m_info.is_fullscreen = true;
frontend_data->reload = true;
}
static void load_layout_file(int load_index, FrontendData *frontend_data, AudioData* audio_data, OutTextData &out_text_data, bool skip_io, bool do_print) {
if(skip_io)
return;
reset_screen_info(frontend_data->top_screen->m_info);
reset_screen_info(frontend_data->bot_screen->m_info);
reset_screen_info(frontend_data->joint_screen->m_info);
audio_data->reset();
reset_display_data(&frontend_data->display_data);
frontend_data->reload = true;
defaults_reload(frontend_data, audio_data);
if(load_index == SIMPLE_RESET_DATA_INDEX) {
UpdateOutText(out_text_data, "Reset detected. Defaults re-loaded", "Reset detected\nDefaults re-loaded", TEXT_KIND_WARNING);
@ -122,6 +136,8 @@ static void load_layout_file(int load_index, FrontendData *frontend_data, AudioD
std::string load_name = load_layout_name(load_index, name_load_success);
UpdateOutText(out_text_data, "Layout loaded from: " + layout_path + layout_name, "Layout " + load_name + " loaded", TEXT_KIND_SUCCESS);
}
else if(!op_success)
defaults_reload(frontend_data, audio_data);
}
static bool save(const std::string path, const std::string name, const std::string save_name, const ScreenInfo &top_info, const ScreenInfo &bottom_info, const ScreenInfo &joint_info, DisplayData &display_data, AudioData *audio_data, OutTextData &out_text_data) {
@ -222,13 +238,14 @@ static void soundCall(AudioData *audio_data, CaptureData* capture_data) {
audio.stop();
}
static void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data) {
static void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, bool mono_app) {
VideoOutputData *out_buf;
double last_frame_time = 0.0;
int num_elements_fps_array = 0;
int curr_out, prev_out = NUM_CONCURRENT_DATA_BUFFERS - 1;
FrontendData frontend_data;
reset_display_data(&frontend_data.display_data);
frontend_data.display_data.mono_app_mode = mono_app;
frontend_data.reload = true;
bool skip_io = false;
int num_allowed_blanks = MAX_ALLOWED_BLANKS;
@ -367,10 +384,61 @@ static void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data
delete out_buf;
}
static bool parse_existence_arg(int &index, char **argv, bool &target, bool existence_value, std::string to_check) {
if(argv[index] != to_check)
return false;
target = existence_value;
return true;
}
static bool parse_int_arg(int &index, int argc, char **argv, int &target, std::string to_check) {
if(argv[index] != to_check)
return false;
if((++index) >= argc)
return true;
try {
target = std::stoi(argv[index]);
}
catch(...) {
std::cerr << "Error with input for: " << to_check << std::endl;
}
return true;
}
int main(int argc, char **argv) {
#if defined(__linux__) && defined(XLIB_BASED)
XInitThreads();
#endif
bool mono_app = false;
int page_up_id = -1;
int page_down_id = -1;
int enter_id = -1;
int power_id = -1;
for (int i = 1; i < argc; i++) {
if(parse_existence_arg(i, argv, mono_app, true, "--mono_app"))
continue;
#ifdef RASPI
if(parse_int_arg(i, argc, argv, page_up_id, "--pi_select"))
continue;
if(parse_int_arg(i, argc, argv, page_down_id, "--pi_menu"))
continue;
if(parse_int_arg(i, argc, argv, enter_id, "--pi_enter"))
continue;
if(parse_int_arg(i, argc, argv, power_id, "--pi_power"))
continue;
#endif
std::cout << "Help:" << std::endl;
std::cout << " --mono_app Enables special mode for when only this application" << std::endl;
std::cout << " should run on the system. Disabled by default." << std::endl;
#ifdef RASPI
std::cout << " --pi_select ID Specifies ID for the select GPIO button." << std::endl;
std::cout << " --pi_menu ID Specifies ID for the menu GPIO button." << std::endl;
std::cout << " --pi_enter ID Specifies ID for the enter GPIO button." << std::endl;
std::cout << " --pi_power ID Specifies ID for the poweroff GPIO button." << std::endl;
#endif
return 0;
}
init_extra_buttons_poll(page_up_id, page_down_id, enter_id, power_id);
AudioData audio_data;
audio_data.reset();
CaptureData* capture_data = new CaptureData;
@ -378,10 +446,11 @@ int main(int argc, char **argv) {
std::thread capture_thread(captureCall, capture_data);
std::thread audio_thread(soundCall, &audio_data, capture_data);
mainVideoOutputCall(&audio_data, capture_data);
mainVideoOutputCall(&audio_data, capture_data, mono_app);
audio_thread.join();
capture_thread.join();
delete capture_data;
end_extra_buttons_poll();
return 0;
}

View File

@ -183,11 +183,7 @@ void reset_screen_info(ScreenInfo &info) {
info.bot_rotation = 0;
info.show_mouse = true;
info.v_sync_enabled = false;
#if defined(_WIN32) || defined(_WIN64)
info.async = false;
#else
info.async = true;
#endif
info.top_scaling = -1;
info.bot_scaling = -1;
info.bfi = false;
@ -371,7 +367,7 @@ void joystick_axis_poll(std::queue<SFEvent> &events_queue) {
for(int j = 0; j < sf::Joystick::AxisCount; j++) {
sf::Joystick::Axis axis = sf::Joystick::Axis(sf::Joystick::Axis::X + j);
if(sf::Joystick::hasAxis(i, axis))
events_queue.emplace(sf::Event::JoystickMoved, sf::Keyboard::Backspace, 0, i, 0, axis, sf::Joystick::getAxisPosition(i, axis), sf::Mouse::Left, 0, 0);
events_queue.emplace(sf::Event::JoystickMoved, sf::Keyboard::Backspace, 0, i, 0, axis, sf::Joystick::getAxisPosition(i, axis), sf::Mouse::Left, 0, 0, false);
}
}
}

View File

@ -12,10 +12,14 @@
#define xstr(a) str(a)
#define str(a) #a
#define APP_VERSION_MAJOR 0
#define APP_VERSION_MAJOR 1
#define APP_VERSION_MINOR 0
#define APP_VERSION_REVISION 0
#ifdef RASPI
#define APP_VERSION_LETTER R
#else
#define APP_VERSION_LETTER M
#endif
bool is_big_endian(void) {
union {
@ -59,11 +63,16 @@ std::string LayoutNameGenerator(int index) {
}
std::string LayoutPathGenerator(int index) {
bool success = false;
std::string cfg_dir;
#if !(defined(_WIN32) || defined(_WIN64))
std::string cfg_dir = std::string(std::getenv("HOME")) + "/.config/" + std::string(NAME);
#else
std::string cfg_dir = ".config/" + std::string(NAME);
if(const char* env_p = std::getenv("HOME")) {
cfg_dir = std::string(env_p) + "/.config/" + std::string(NAME);
success = true;
}
#endif
if(!success)
cfg_dir = ".config/" + std::string(NAME);
if(index == STARTUP_FILE_INDEX)
return cfg_dir + "/";
return cfg_dir + "/presets/";
@ -86,21 +95,26 @@ std::string load_layout_name(int index, bool &success) {
}
success = true;
while(std::getline(file, line)) {
std::istringstream kvp(line);
std::string key;
try {
while(std::getline(file, line)) {
std::istringstream kvp(line);
std::string key;
if(std::getline(kvp, key, '=')) {
std::string value;
if(std::getline(kvp, value)) {
if(std::getline(kvp, key, '=')) {
std::string value;
if(std::getline(kvp, value)) {
if(key == "name") {
file.close();
return value;
if(key == "name") {
file.close();
return value;
}
}
}
}
}
catch(...) {
success = false;
}
file.close();
return std::to_string(index);