Implement input based shaders
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 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 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 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 2024-11-17 14:34:23 +01:00
parent 4fb88bb057
commit a9df82b89b
22 changed files with 798 additions and 46 deletions

View File

@ -399,7 +399,7 @@ if(MSVC)
else()
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "-O3")
endif()
add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/CaptureDataBuffers.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${SOURCE_CPP_EXTRA_FILES})
add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
if(NOT ("${EXTRA_DEPENDENCIES}" STREQUAL ""))
@ -426,6 +426,16 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/data/font.ttf ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
set(SHADERS_LIST "")
list(APPEND SHADERS_LIST ${CMAKE_SOURCE_DIR}/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_fragment_shader.frag ${CMAKE_SOURCE_DIR}/shaders/no_effect_fragment_shader.frag)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/shaders_list.cpp
COMMENT "Prepare shaders list"
COMMAND ${TOOLS_DATA_DIR}/CMakeShader2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/shaders ${CMAKE_SOURCE_DIR}/source/shaders_list_template.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp
DEPENDS ${CMAKE_SOURCE_DIR}/source/shaders_list_template.cpp ${SHADERS_LIST} ${TOOLS_DATA_DIR}/CMakeShader2C${HOST_FINAL_EXTENSION}
)
if(WIN32)
if(N3DSXL_LOOPY_SUPPORT AND WINDOWS_FTD3XX_USE_SHARED_LIB)
add_custom_command(

View File

@ -0,0 +1,39 @@
#ifndef __VIDEOEFFECTSMENU_HPP
#define __VIDEOEFFECTSMENU_HPP
#include "OptionSelectionMenu.hpp"
#include <chrono>
#include "TextRectangle.hpp"
#include "sfml_gfx_structs.hpp"
#include "display_structs.hpp"
enum VideoEffectsMenuOutAction{
VIDEO_EFFECTS_MENU_NO_ACTION,
VIDEO_EFFECTS_MENU_BACK,
VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_INC,
VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_DEC,
VIDEO_EFFECTS_MENU_FRAME_BLENDING_INC,
VIDEO_EFFECTS_MENU_FRAME_BLENDING_DEC,
};
class VideoEffectsMenu : public OptionSelectionMenu {
public:
VideoEffectsMenu(bool font_load_success, sf::Font &text_font);
~VideoEffectsMenu();
void prepare(float scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info);
void insert_data();
VideoEffectsMenuOutAction selected_index = VideoEffectsMenuOutAction::VIDEO_EFFECTS_MENU_NO_ACTION;
void reset_output_option();
protected:
bool is_option_selectable(int index, int action);
bool is_option_inc_dec(int index);
void set_output_option(int index, int action);
int get_num_options();
std::string get_string_option(int index, int action);
void class_setup();
private:
int *options_indexes;
int num_enabled_options;
};
#endif

View File

@ -39,6 +39,7 @@ enum VideoMenuOutAction{
VIDEO_MENU_NON_INT_SCALING,
VIDEO_MENU_SCALING_RATIO_SETTINGS,
VIDEO_MENU_CHANGE_TITLEBAR,
VIDEO_MENU_VIDEO_EFFECTS_SETTINGS,
};
class VideoMenu : public OptionSelectionMenu {

View File

@ -3,11 +3,14 @@
#include "utils.hpp"
#include "hw_defs.hpp"
#include "shaders_list.hpp"
enum ScreenType { TOP, BOTTOM, JOINT };
enum BottomRelativePosition { UNDER_TOP, LEFT_TOP, ABOVE_TOP, RIGHT_TOP, BOT_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 };
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 };
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 };
struct ScreenInfo {
bool is_blurred;
@ -39,6 +42,10 @@ struct ScreenInfo {
bool use_non_integer_scaling_bottom;
bool failed_fullscreen;
bool have_titlebar;
InputColorspaceMode in_colorspace_top;
InputColorspaceMode in_colorspace_bot;
FrameBlendingMode frame_blending_top;
FrameBlendingMode frame_blending_bot;
};
struct DisplayData {

View File

@ -31,9 +31,11 @@
#include "ActionSelectionMenu.hpp"
#include "ScalingRatioMenu.hpp"
#include "ISNitroMenu.hpp"
#include "VideoEffectsMenu.hpp"
#include "display_structs.hpp"
#include "WindowCommands.hpp"
#include "event_structs.hpp"
#include "shaders_list.hpp"
struct HeldTime {
std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
@ -152,6 +154,7 @@ private:
ActionSelectionMenu *action_selection_menu;
ISNitroMenu *is_nitro_menu;
ScalingRatioMenu *scaling_ratio_menu;
VideoEffectsMenu *video_effects_menu;
std::vector<const CropData*> possible_crops;
std::vector<const CropData*> possible_crops_ds;
std::vector<const CropData*> possible_crops_with_games;
@ -170,6 +173,7 @@ private:
FPSArray poll_fps;
std::chrono::time_point<std::chrono::high_resolution_clock> last_poll_time;
std::chrono::time_point<std::chrono::high_resolution_clock> last_menu_change_time;
int curr_frame_texture_pos = 0;
sf::Texture in_tex;
@ -180,7 +184,7 @@ private:
volatile bool scheduled_work_on_window;
volatile bool is_thread_done;
sf::Shader *in_top_shader, *in_bot_shader, *top_shader, *bot_shader;
bool was_last_frame_null;
sf::RectangleShape m_in_rect_top, m_in_rect_bot;
out_rect_data m_out_rect_top, m_out_rect_bot;
ScreenType m_stype;
@ -239,6 +243,8 @@ private:
void non_int_scaling_change(bool target_top);
void non_int_mode_change(bool positive);
void titlebar_change();
void input_colorspace_mode_change(bool positive);
void frame_blending_mode_change(bool positive);
bool query_reset_request();
void reset_held_times();
void poll_window(bool do_everything);
@ -249,8 +255,11 @@ private:
bool window_needs_work();
void window_factory(bool is_main_thread);
void update_texture();
int _choose_shader(bool is_input, bool is_top);
int choose_shader(bool is_input, bool is_top);
void pre_texture_conversion_processing();
void post_texture_conversion_processing(out_rect_data &rect_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top, bool is_debug);
void draw_rect_to_window(const sf::RectangleShape &out_rect, bool is_top);
void window_bg_processing();
void display_data_to_window(bool actually_draw, bool is_debug = false);
void window_render_call();
@ -299,6 +308,7 @@ private:
void setup_relative_pos_menu(bool reset_data = true);
void setup_scaling_ratio_menu(bool reset_data = true);
void setup_is_nitro_menu(bool reset_data = true);
void setup_video_effects_menu(bool reset_data = true);
void update_connection();
};
@ -327,5 +337,7 @@ void update_connected_3ds_ds(FrontendData* frontend_data, const CaptureDevice &o
void update_connected_specific_settings(FrontendData* frontend_data, const CaptureDevice &cc_device);
void screen_display_thread(WindowScreen *screen);
std::string get_name_non_int_mode(NonIntegerScalingModes input);
std::string get_name_frame_blending_mode(FrameBlendingMode input);
std::string get_name_input_colorspace_mode(InputColorspaceMode input);
void default_sleep(float wanted_ms = -1);
#endif

45
include/shaders_list.hpp Normal file
View File

@ -0,0 +1,45 @@
#ifndef __SHADERS_LIST_HPP
#define __SHADERS_LIST_HPP
#include<string>
enum shader_list_enum {
NO_EFFECT_FRAGMENT_SHADER,
FRAME_BLENDING_FRAGMENT_SHADER,
BIT_CRUSHER_FRAGMENT_SHADER_1,
BIT_CRUSHER_FRAGMENT_SHADER_2,
BIT_CRUSHER_FRAGMENT_SHADER_3,
BIT_CRUSHER_FRAGMENT_SHADER_4,
BIT_CRUSHER_FRAGMENT_SHADER_5,
BIT_CRUSHER_FRAGMENT_SHADER_6,
BIT_CRUSHER_FRAGMENT_SHADER_7,
BIT_MERGER_FRAGMENT_SHADER_0,
BIT_MERGER_FRAGMENT_SHADER_1,
BIT_MERGER_FRAGMENT_SHADER_2,
BIT_MERGER_FRAGMENT_SHADER_3,
BIT_MERGER_FRAGMENT_SHADER_4,
BIT_MERGER_FRAGMENT_SHADER_5,
BIT_MERGER_FRAGMENT_SHADER_6,
BIT_MERGER_FRAGMENT_SHADER_7,
BIT_MERGER_CRUSHER_FRAGMENT_SHADER_1,
BIT_MERGER_CRUSHER_FRAGMENT_SHADER_2,
BIT_MERGER_CRUSHER_FRAGMENT_SHADER_3,
BIT_MERGER_CRUSHER_FRAGMENT_SHADER_4,
BIT_MERGER_CRUSHER_FRAGMENT_SHADER_5,
BIT_MERGER_CRUSHER_FRAGMENT_SHADER_6,
BIT_MERGER_CRUSHER_FRAGMENT_SHADER_7,
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_1,
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_2,
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_3,
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_4,
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_5,
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_6,
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_7,
TOTAL_NUM_SHADERS
};
std::string get_shader_string(shader_list_enum requested_shader);
void shader_strings_init();
#endif

View File

@ -0,0 +1,9 @@
uniform sampler2D Texture0;
const float inner_divisor = x;
const float bit_crusher = 255.0 / inner_divisor;
const float normalizer = inner_divisor * (255.0 / (256.0 - inner_divisor)) / 255.0;
void main() {
gl_FragColor = clamp(floor(texture2D(Texture0, gl_TexCoord[0].xy) * bit_crusher) * normalizer, 0.0, 1.0);
};

View File

@ -0,0 +1,19 @@
uniform sampler2D Texture0;
uniform vec2 old_frame_offset;
const float inner_divisor = x;
const float inner_divisor_greater = inner_divisor * 2.0;
const float bit_crusher = 255.0 / inner_divisor;
const float bit_crusher_greater = 255.0 / inner_divisor_greater;
const float normalizer = inner_divisor * (255.0 / (256.0 - inner_divisor)) / 255.0;
vec4 get_nth_bit_component(vec4 colors) {
return (floor(colors * bit_crusher) * inner_divisor) - (floor(colors * bit_crusher_greater) * inner_divisor_greater);
}
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset);
vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor);
vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor);
gl_FragColor = clamp((((floor(gl_FragColor * bit_crusher_greater) * inner_divisor_greater) + ((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / inner_divisor) * normalizer, 0.0, 1.0);
};

View File

@ -0,0 +1,17 @@
uniform sampler2D Texture0;
uniform vec2 old_frame_offset;
const float inner_divisor = 128.0;
const float bit_crusher = 255.0 / inner_divisor;
const float normalizer = inner_divisor * (255.0 / (256.0 - inner_divisor)) / 255.0;
vec4 get_nth_bit_component(vec4 colors) {
return floor(colors * bit_crusher) * inner_divisor;
}
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset);
vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor);
vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor);
gl_FragColor = clamp(((((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / inner_divisor) * normalizer, 0.0, 1.0);
};

View File

@ -0,0 +1,19 @@
uniform sampler2D Texture0;
uniform vec2 old_frame_offset;
const float inner_divisor = x;
const float inner_divisor_greater = inner_divisor * 2.0;
const float bit_crusher = 255.0 / inner_divisor;
const float bit_crusher_greater = 255.0 / inner_divisor_greater;
vec4 get_nth_bit_component(vec4 colors) {
return (floor(colors * bit_crusher) * inner_divisor) - (floor(colors * bit_crusher_greater) * inner_divisor_greater);
}
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset);
vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor);
vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor);
gl_FragColor = clamp((floor(gl_FragColor * 255.0) - actual_nth_bit_component + ((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / 255.0, 0.0, 1.0);
};

View File

@ -0,0 +1,16 @@
uniform sampler2D Texture0;
uniform vec2 old_frame_offset;
const float inner_divisor = 128.0;
const float bit_crusher = 255.0 / inner_divisor;
vec4 get_nth_bit_component(vec4 colors) {
return floor(colors * bit_crusher) * inner_divisor;
}
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset);
vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor);
vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor);
gl_FragColor = clamp((floor(gl_FragColor * 255.0) - actual_nth_bit_component + ((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / 255.0, 0.0, 1.0);
};

View File

@ -0,0 +1,14 @@
uniform sampler2D Texture0;
uniform vec2 old_frame_offset;
const float inner_divisor = x;
const float bit_crusher = 255.0 / inner_divisor;
const float normalizer = inner_divisor * (255.0 / (256.0 - inner_divisor)) / 255.0;
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
gl_FragColor = clamp(floor(gl_FragColor * bit_crusher) * normalizer, 0.0, 1.0);
vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset);
OldFragColor = clamp(floor(OldFragColor * bit_crusher) * normalizer, 0.0, 1.0);
gl_FragColor = (gl_FragColor + OldFragColor) / 2.0;
};

View File

@ -0,0 +1,8 @@
uniform sampler2D Texture0;
uniform vec2 old_frame_offset;
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset);
gl_FragColor = (gl_FragColor + OldFragColor) / 2.0;
};

View File

@ -0,0 +1,5 @@
uniform sampler2D Texture0;
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
};

View File

@ -0,0 +1,126 @@
#include "VideoEffectsMenu.hpp"
#include "frontend.hpp"
#define NUM_TOTAL_MENU_OPTIONS (sizeof(pollable_options)/sizeof(pollable_options[0]))
struct VideoEffectsMenuOptionInfo {
const std::string base_name;
const std::string false_name;
const bool is_selectable;
const bool is_inc;
const std::string dec_str;
const std::string inc_str;
const VideoEffectsMenuOutAction inc_out_action;
const VideoEffectsMenuOutAction out_action;
};
static const VideoEffectsMenuOptionInfo input_colorspace_option = {
.base_name = "Input Colors", .false_name = "", .is_selectable = true,
.is_inc = true, .dec_str = "<", .inc_str = ">", .inc_out_action = VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_INC,
.out_action = VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_DEC};
static const VideoEffectsMenuOptionInfo frame_blending_option = {
.base_name = "Frame Blending", .false_name = "", .is_selectable = true,
.is_inc = true, .dec_str = "<", .inc_str = ">", .inc_out_action = VIDEO_EFFECTS_MENU_FRAME_BLENDING_INC,
.out_action = VIDEO_EFFECTS_MENU_FRAME_BLENDING_DEC};
static const VideoEffectsMenuOptionInfo* pollable_options[] = {
&input_colorspace_option,
&frame_blending_option,
};
VideoEffectsMenu::VideoEffectsMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){
this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS];
this->initialize(font_load_success, text_font);
this->num_enabled_options = 0;
}
VideoEffectsMenu::~VideoEffectsMenu() {
delete []this->options_indexes;
}
void VideoEffectsMenu::class_setup() {
this->num_options_per_screen = 5;
this->min_elements_text_scaling_factor = num_options_per_screen + 2;
this->width_factor_menu = 16;
this->width_divisor_menu = 9;
this->base_height_factor_menu = 12;
this->base_height_divisor_menu = 6;
this->min_text_size = 0.3;
this->max_width_slack = 1.1;
this->menu_color = sf::Color(30, 30, 60, 192);
this->title = "Video Effects Settings";
this->show_back_x = true;
this->show_x = false;
this->show_title = true;
}
void VideoEffectsMenu::insert_data() {
this->num_enabled_options = 0;
for(int i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) {
this->options_indexes[this->num_enabled_options] = i;
this->num_enabled_options++;
}
this->prepare_options();
}
void VideoEffectsMenu::reset_output_option() {
this->selected_index = VideoEffectsMenuOutAction::VIDEO_EFFECTS_MENU_NO_ACTION;
}
void VideoEffectsMenu::set_output_option(int index, int action) {
if(index == BACK_X_OUTPUT_OPTION)
this->selected_index = VIDEO_EFFECTS_MENU_BACK;
else if((action == INC_ACTION) && this->is_option_inc_dec(index))
this->selected_index = pollable_options[this->options_indexes[index]]->inc_out_action;
else
this->selected_index = pollable_options[this->options_indexes[index]]->out_action;
}
int VideoEffectsMenu::get_num_options() {
return this->num_enabled_options;
}
std::string VideoEffectsMenu::get_string_option(int index, int action) {
if((action == INC_ACTION) && this->is_option_inc_dec(index))
return pollable_options[this->options_indexes[index]]->inc_str;
if((action == DEC_ACTION) && this->is_option_inc_dec(index))
return pollable_options[this->options_indexes[index]]->dec_str;
if(action == FALSE_ACTION)
return pollable_options[this->options_indexes[index]]->false_name;
return pollable_options[this->options_indexes[index]]->base_name;
}
bool VideoEffectsMenu::is_option_selectable(int index, int action) {
return pollable_options[this->options_indexes[index]]->is_selectable;
}
bool VideoEffectsMenu::is_option_inc_dec(int index) {
return pollable_options[this->options_indexes[index]]->is_inc;
}
void VideoEffectsMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, ScreenInfo *info) {
int num_pages = this->get_num_pages();
if(this->future_data.page >= num_pages)
this->future_data.page = num_pages - 1;
int start = this->future_data.page * this->num_options_per_screen;
for(int i = 0; i < this->num_options_per_screen + 1; i++) {
int index = (i * this->single_option_multiplier) + this->elements_start_id;
if(!this->future_enabled_labels[index])
continue;
int real_index = start + i;
int option_index = this->options_indexes[real_index];
switch(pollable_options[option_index]->out_action) {
case VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_DEC:
this->labels[index]->setText(this->setTextOptionString(real_index, get_name_input_colorspace_mode(info->in_colorspace_top)));
break;
case VIDEO_EFFECTS_MENU_FRAME_BLENDING_DEC:
this->labels[index]->setText(this->setTextOptionString(real_index, get_name_frame_blending_mode(info->frame_blending_top)));
break;
default:
break;
}
}
this->base_prepare(menu_scaling_factor, view_size_x, view_size_y);
}

View File

@ -179,6 +179,13 @@ static const VideoMenuOptionInfo titlebar_change_option = {
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = VIDEO_MENU_NO_ACTION,
.out_action = VIDEO_MENU_CHANGE_TITLEBAR};
static const VideoMenuOptionInfo video_effects_settings_option = {
.base_name = "Video Effects Settings", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true, .requires_titlebar_possible = false,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = VIDEO_MENU_NO_ACTION,
.out_action = VIDEO_MENU_VIDEO_EFFECTS_SETTINGS};
static const VideoMenuOptionInfo* pollable_options[] = {
&crop_option,
&window_scaling_option,
@ -195,6 +202,7 @@ static const VideoMenuOptionInfo* pollable_options[] = {
&rotation_settings_option,
&top_one_rotation_option,
&bottom_one_rotation_option,
&video_effects_settings_option,
&top_par_option,
&bot_par_option,
&one_par_option,

View File

@ -4,6 +4,7 @@
#include <SFML/OpenGL.hpp>
#include <cstring>
#include "font_ttf.h"
#include "shaders_list.hpp"
#include "devicecapture.hpp"
#define LEFT_ROUNDED_PADDING 5
@ -15,16 +16,20 @@
#define FALLBACK_FS_RESOLUTION_HEIGHT 1080
#define FALLBACK_FS_RESOLUTION_BPP 32
const std::string no_effect_fragment_shader = \
"uniform sampler2D Texture0;" \
"" \
"void main() {" \
" gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);" \
"}";
#define NUM_FRAMES_BLENDED 2
static bool loaded_shaders = false;
static int n_shader_refs = 0;
static sf::Shader *base_shader = NULL;
struct shader_and_data {
shader_and_data(shader_list_enum value) : shader(sf::Shader()), is_valid(false), shader_enum(value) {}
sf::Shader shader;
bool is_valid;
shader_list_enum shader_enum;
};
static std::vector<shader_and_data> usable_shaders;
WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, AudioData* audio_data, ExtraButtonShortcuts* extra_button_shortcuts, ConsumerMutex *draw_lock, bool created_proper_folder) {
this->draw_lock = draw_lock;
@ -46,7 +51,7 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp
FPSArrayInit(&this->in_fps);
FPSArrayInit(&this->draw_fps);
FPSArrayInit(&this->poll_fps);
(void)this->in_tex.resize({MAX_IN_VIDEO_WIDTH, MAX_IN_VIDEO_HEIGHT});
(void)this->in_tex.resize({MAX_IN_VIDEO_WIDTH, MAX_IN_VIDEO_HEIGHT * NUM_FRAMES_BLENDED});
this->m_in_rect_top.setTexture(&this->in_tex);
this->m_in_rect_bot.setTexture(&this->in_tex);
this->display_data = display_data;
@ -71,15 +76,23 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp
if(this->display_data->mono_app_mode && this->m_stype == ScreenType::JOINT)
this->m_info.is_fullscreen = true;
if(sf::Shader::isAvailable() && (!loaded_shaders)) {
base_shader = new sf::Shader();
if(base_shader->loadFromMemory(no_effect_fragment_shader, sf::Shader::Type::Fragment))
loaded_shaders = true;
shader_strings_init();
for(int i = 0; i < TOTAL_NUM_SHADERS; i++) {
usable_shaders.emplace_back(static_cast<shader_list_enum>(i));
shader_and_data* current_shader = &usable_shaders[usable_shaders.size()-1];
if(current_shader->shader.loadFromMemory(get_shader_string(current_shader->shader_enum), sf::Shader::Type::Fragment)) {
current_shader->is_valid = true;
auto* const defaultStreamBuffer = sf::err().rdbuf();
sf::err().rdbuf(nullptr);
sf::Glsl::Vec2 old_pos = {0.0, 0.0};
current_shader->shader.setUniform("old_frame_offset", old_pos);
sf::err().rdbuf(defaultStreamBuffer);
}
}
loaded_shaders = true;
}
n_shader_refs += 1;
this->in_top_shader = base_shader;
this->in_bot_shader = base_shader;
this->top_shader = base_shader;
this->bot_shader = base_shader;
this->was_last_frame_null = true;
this->created_proper_folder = created_proper_folder;
}
@ -93,7 +106,8 @@ WindowScreen::~WindowScreen() {
FPSArrayDestroy(&this->draw_fps);
FPSArrayDestroy(&this->poll_fps);
if(sf::Shader::isAvailable() && (n_shader_refs == 1)) {
delete base_shader;
while(!usable_shaders.empty())
usable_shaders.pop_back();
loaded_shaders = false;
}
n_shader_refs -= 1;
@ -212,6 +226,7 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) {
this->last_poll_time = std::chrono::high_resolution_clock::now();
}
if(this->m_win.isOpen() || this->loaded_operations.call_create) {
this->curr_frame_texture_pos = (this->curr_frame_texture_pos + 1) % NUM_FRAMES_BLENDED;
auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - this->last_draw_time;
FPSArrayInsertElement(&draw_fps, diff.count());
@ -219,8 +234,10 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) {
WindowScreen::reset_operations(future_operations);
if(out_buf != NULL)
memcpy(this->saved_buf, out_buf, sizeof(VideoOutputData));
else
else {
memset(this->saved_buf, 0, sizeof(VideoOutputData));
this->was_last_frame_null = true;
}
loaded_info = m_info;
this->notification->setTextFactor(this->loaded_info.menu_scaling_factor);
this->notification->prepareRenderText();
@ -244,6 +261,8 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) {
if(!this->loaded_info.async)
this->display_call(true);
}
else
this->was_last_frame_null = true;
}
void WindowScreen::update_connection() {
@ -460,7 +479,7 @@ void WindowScreen::update_texture() {
type = GL_UNSIGNED_SHORT_5_6_5;
if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR16)
type = GL_UNSIGNED_SHORT_5_6_5_REV;
glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast<GLint>(0), static_cast<GLint>(0), static_cast<GLsizei>(this->capture_status->device.width), static_cast<GLsizei>(this->capture_status->device.height), format, type, this->saved_buf);
glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast<GLint>(0), static_cast<GLint>(this->curr_frame_texture_pos * MAX_IN_VIDEO_HEIGHT), static_cast<GLsizei>(this->capture_status->device.width), static_cast<GLsizei>(this->capture_status->device.height), format, type, this->saved_buf);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Force an OpenGL flush, so that the texture data will appear updated
@ -480,6 +499,61 @@ void WindowScreen::pre_texture_conversion_processing() {
this->draw_lock->unlock();
}
int WindowScreen::_choose_shader(bool is_input, bool is_top) {
if(!is_input)
return NO_EFFECT_FRAGMENT_SHADER;
if(this->was_last_frame_null) {
this->was_last_frame_null = false;
return NO_EFFECT_FRAGMENT_SHADER;
}
InputColorspaceMode *in_colorspace = &this->loaded_info.in_colorspace_top;
FrameBlendingMode *frame_blending = &this->loaded_info.frame_blending_top;
if(!is_top) {
in_colorspace = &this->loaded_info.in_colorspace_bot;
frame_blending = &this->loaded_info.frame_blending_bot;
}
switch(*frame_blending) {
case FULL_FRAME_BLENDING:
switch(*in_colorspace) {
case DS_COLORSPACE:
return FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_2;
case GBA_COLORSPACE:
return FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_3;
default:
return FRAME_BLENDING_FRAGMENT_SHADER;
}
break;
case DS_3D_BOTH_SCREENS_FRAME_BLENDING:
switch(*in_colorspace) {
case DS_COLORSPACE:
return BIT_MERGER_CRUSHER_FRAGMENT_SHADER_2;
case GBA_COLORSPACE:
return BIT_CRUSHER_FRAGMENT_SHADER_3;
default:
return BIT_MERGER_FRAGMENT_SHADER_2;
}
break;
default:
switch(*in_colorspace) {
case DS_COLORSPACE:
return BIT_CRUSHER_FRAGMENT_SHADER_2;
case GBA_COLORSPACE:
return BIT_CRUSHER_FRAGMENT_SHADER_3;
default:
return NO_EFFECT_FRAGMENT_SHADER;
}
break;
}
}
int WindowScreen::choose_shader(bool is_input, bool is_top) {
int chosen_shader = _choose_shader(is_input, is_top);
if((chosen_shader >= 0) && (chosen_shader < usable_shaders.size()) && usable_shaders[chosen_shader].is_valid)
return chosen_shader;
return -1;
}
void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data, const sf::RectangleShape &in_rect, bool actually_draw, bool is_top, bool is_debug) {
if((is_top && this->m_stype == ScreenType::BOTTOM) || ((!is_top) && this->m_stype == ScreenType::TOP))
return;
@ -494,21 +568,50 @@ void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data,
}
else {
rect_data.out_tex.clear();
sf::RectangleShape final_in_rect = in_rect;
sf::IntRect text_coords_rect = final_in_rect.getTextureRect();
text_coords_rect.position.y += this->curr_frame_texture_pos * MAX_IN_VIDEO_HEIGHT;
final_in_rect.setTextureRect(text_coords_rect);
if(this->capture_status->connected && actually_draw) {
bool use_default_shader = true;
if(sf::Shader::isAvailable()) {
sf::Shader* chosen_shader = this->in_top_shader;
if(!is_top)
chosen_shader = this->in_bot_shader;
rect_data.out_tex.draw(in_rect, chosen_shader);
int chosen_shader = choose_shader(true, is_top);
if(chosen_shader >= 0) {
float old_frame_pos_y = 1.0 / NUM_FRAMES_BLENDED;
if(this->curr_frame_texture_pos == 1)
old_frame_pos_y = -1.0 / NUM_FRAMES_BLENDED;
sf::Glsl::Vec2 old_pos = {0.0, old_frame_pos_y};
usable_shaders[chosen_shader].shader.setUniform("old_frame_offset", old_pos);
rect_data.out_tex.draw(final_in_rect, &usable_shaders[chosen_shader].shader);
use_default_shader = false;
}
}
else
rect_data.out_tex.draw(in_rect);
if(use_default_shader)
rect_data.out_tex.draw(final_in_rect);
//Place postprocessing effects here
}
}
rect_data.out_tex.display();
}
void WindowScreen::draw_rect_to_window(const sf::RectangleShape &out_rect, bool is_top) {
if((is_top && this->m_stype == ScreenType::BOTTOM) || ((!is_top) && this->m_stype == ScreenType::TOP))
return;
if(this->loaded_menu == CONNECT_MENU_TYPE)
return;
bool use_default_shader = true;
if(sf::Shader::isAvailable()) {
int chosen_shader = choose_shader(false, is_top);
if(chosen_shader >= 0) {
this->m_win.draw(out_rect, &usable_shaders[chosen_shader].shader);
use_default_shader = false;
}
}
if(use_default_shader)
this->m_win.draw(out_rect);
}
void WindowScreen::window_bg_processing() {
//Place BG processing here
}
@ -523,20 +626,8 @@ void WindowScreen::display_data_to_window(bool actually_draw, bool is_debug) {
else
this->m_win.clear();
this->window_bg_processing();
if(this->loaded_menu != CONNECT_MENU_TYPE) {
if (this->m_stype != ScreenType::BOTTOM) {
if (sf::Shader::isAvailable())
this->m_win.draw(this->m_out_rect_top.out_rect, this->top_shader);
else
this->m_win.draw(this->m_out_rect_top.out_rect);
}
if (this->m_stype != ScreenType::TOP) {
if (sf::Shader::isAvailable())
this->m_win.draw(this->m_out_rect_bot.out_rect, this->bot_shader);
else
this->m_win.draw(this->m_out_rect_bot.out_rect);
}
}
this->draw_rect_to_window(this->m_out_rect_top.out_rect, true);
this->draw_rect_to_window(this->m_out_rect_bot.out_rect, false);
this->execute_menu_draws();
this->notification->draw(this->m_win);
this->m_win.display();

View File

@ -110,6 +110,7 @@ void WindowScreen::init_menus() {
this->action_selection_menu = new ActionSelectionMenu(this->font_load_success, this->text_font);
this->scaling_ratio_menu = new ScalingRatioMenu(this->font_load_success, this->text_font);
this->is_nitro_menu = new ISNitroMenu(this->font_load_success, this->text_font);
this->video_effects_menu = new VideoEffectsMenu(this->font_load_success, this->text_font);
}
void WindowScreen::destroy_menus() {
@ -132,6 +133,7 @@ void WindowScreen::destroy_menus() {
delete this->action_selection_menu;
delete this->scaling_ratio_menu;
delete this->is_nitro_menu;
delete this->video_effects_menu;
}
void WindowScreen::set_close(int ret_val) {
@ -371,6 +373,22 @@ void WindowScreen::titlebar_change() {
this->future_operations.call_titlebar = true;
}
void WindowScreen::input_colorspace_mode_change(bool positive) {
int change = 1;
if(!positive)
change = INPUT_COLORSPACE_END - 1;
this->m_info.in_colorspace_top = static_cast<InputColorspaceMode>((this->m_info.in_colorspace_top + change) % INPUT_COLORSPACE_END);
this->m_info.in_colorspace_bot = this->m_info.in_colorspace_top;
}
void WindowScreen::frame_blending_mode_change(bool positive) {
int change = 1;
if(!positive)
change = FRAME_BLENDING_END - 1;
this->m_info.frame_blending_top = static_cast<FrameBlendingMode>((this->m_info.frame_blending_top + change) % FRAME_BLENDING_END);
this->m_info.frame_blending_bot = this->m_info.frame_blending_top;
}
bool WindowScreen::can_execute_cmd(const WindowCommand* window_cmd, bool is_extra, bool is_always) {
if((!window_cmd->usable_always) && is_always)
return false;
@ -936,6 +954,18 @@ void WindowScreen::setup_is_nitro_menu(bool reset_data) {
}
}
void WindowScreen::setup_video_effects_menu(bool reset_data) {
if(!this->can_setup_menu())
return;
if(this->curr_menu != VIDEO_EFFECTS_MENU_TYPE) {
this->curr_menu = VIDEO_EFFECTS_MENU_TYPE;
if(reset_data)
this->video_effects_menu->reset_data();
this->video_effects_menu->insert_data();
this->last_menu_change_time = std::chrono::high_resolution_clock::now();
}
}
void WindowScreen::update_save_menu() {
if(this->curr_menu == SAVE_MENU_TYPE) {
this->curr_menu = DEFAULT_MENU_TYPE;
@ -1466,6 +1496,9 @@ void WindowScreen::poll(bool do_everything) {
case VIDEO_MENU_CHANGE_TITLEBAR:
this->titlebar_change();
break;
case VIDEO_MENU_VIDEO_EFFECTS_SETTINGS:
this->setup_video_effects_menu();
break;
default:
break;
}
@ -1844,6 +1877,34 @@ void WindowScreen::poll(bool do_everything) {
continue;
}
break;
case VIDEO_EFFECTS_MENU_TYPE:
if(this->video_effects_menu->poll(event_data)) {
switch(this->video_effects_menu->selected_index) {
case VIDEO_EFFECTS_MENU_BACK:
this->setup_video_menu(false);
done = true;
break;
case VIDEO_EFFECTS_MENU_NO_ACTION:
break;
case VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_INC:
this->input_colorspace_mode_change(true);
break;
case VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_DEC:
this->input_colorspace_mode_change(false);
break;
case VIDEO_EFFECTS_MENU_FRAME_BLENDING_INC:
this->frame_blending_mode_change(true);
break;
case VIDEO_EFFECTS_MENU_FRAME_BLENDING_DEC:
this->frame_blending_mode_change(false);
break;
default:
break;
}
this->video_effects_menu->reset_output_option();
continue;
}
break;
default:
break;
}
@ -2077,6 +2138,9 @@ void WindowScreen::prepare_menu_draws(int view_size_x, int view_size_y) {
case ISN_MENU_TYPE:
this->is_nitro_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, this->capture_status);
break;
case VIDEO_EFFECTS_MENU_TYPE:
this->video_effects_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, &this->loaded_info);
break;
default:
break;
}
@ -2147,6 +2211,9 @@ void WindowScreen::execute_menu_draws() {
case ISN_MENU_TYPE:
this->is_nitro_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win);
break;
case VIDEO_EFFECTS_MENU_TYPE:
this->video_effects_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win);
break;
default:
break;
}

View File

@ -437,6 +437,22 @@ void reset_screen_info(ScreenInfo &info) {
info.use_non_integer_scaling_bottom = false;
info.failed_fullscreen = false;
info.have_titlebar = true;
info.in_colorspace_top = FULL_COLORSPACE;
info.in_colorspace_bot = FULL_COLORSPACE;
info.frame_blending_top = NO_FRAME_BLENDING;
info.frame_blending_bot = NO_FRAME_BLENDING;
}
static InputColorspaceMode input_colorspace_sanitization(int value) {
if((value < 0) || (value >= INPUT_COLORSPACE_END))
return FULL_COLORSPACE;
return static_cast<InputColorspaceMode>(value);
}
static FrameBlendingMode frame_blending_sanitization(int value) {
if((value < 0) || (value >= FRAME_BLENDING_END))
return NO_FRAME_BLENDING;
return static_cast<FrameBlendingMode>(value);
}
static float offset_sanitization(float value) {
@ -599,6 +615,22 @@ bool load_screen_info(std::string key, std::string value, std::string base, Scre
info.have_titlebar = std::stoi(value);
return true;
}
if(key == (base + "in_colorspace_top")) {
info.in_colorspace_top = input_colorspace_sanitization(std::stoi(value));
return true;
}
if(key == (base + "in_colorspace_bot")) {
info.in_colorspace_bot = input_colorspace_sanitization(std::stoi(value));
return true;
}
if(key == (base + "frame_blending_top")) {
info.frame_blending_top = frame_blending_sanitization(std::stoi(value));
return true;
}
if(key == (base + "frame_blending_bot")) {
info.frame_blending_bot = frame_blending_sanitization(std::stoi(value));
return true;
}
return false;
}
@ -635,6 +667,10 @@ std::string save_screen_info(std::string base, const ScreenInfo &info) {
out += base + "use_non_integer_scaling_top=" + std::to_string(info.use_non_integer_scaling_top) + "\n";
out += base + "use_non_integer_scaling_bottom=" + std::to_string(info.use_non_integer_scaling_bottom) + "\n";
out += base + "have_titlebar=" + std::to_string(info.have_titlebar) + "\n";
out += base + "in_colorspace_top=" + std::to_string(info.in_colorspace_top) + "\n";
out += base + "in_colorspace_bot=" + std::to_string(info.in_colorspace_bot) + "\n";
out += base + "frame_blending_top=" + std::to_string(info.frame_blending_top) + "\n";
out += base + "frame_blending_bot=" + std::to_string(info.frame_blending_bot) + "\n";
return out;
}
@ -828,3 +864,39 @@ std::string get_name_non_int_mode(NonIntegerScalingModes input) {
}
return output;
}
std::string get_name_frame_blending_mode(FrameBlendingMode input) {
std::string output = "";
switch(input) {
case NO_FRAME_BLENDING:
output = "Off";
break;
case FULL_FRAME_BLENDING:
output = "On";
break;
case DS_3D_BOTH_SCREENS_FRAME_BLENDING:
output = "3D on DS";
break;
default:
break;
}
return output;
}
std::string get_name_input_colorspace_mode(InputColorspaceMode input) {
std::string output = "";
switch(input) {
case FULL_COLORSPACE:
output = "Full";
break;
case DS_COLORSPACE:
output = "DS";
break;
case GBA_COLORSPACE:
output = "GBA";
break;
default:
break;
}
return output;
}

View File

@ -0,0 +1,12 @@
#include "shaders_list.hpp"
static std::string shader_strings[TOTAL_NUM_SHADERS];
std::string get_shader_string(shader_list_enum requested_shader) {
if((requested_shader < 0) || (requested_shader >= TOTAL_NUM_SHADERS))
return "";
return shader_strings[requested_shader];
}
// This is a template
void shader_strings_init() {

View File

@ -1,14 +1,28 @@
cmake_minimum_required(VERSION 3.16)
unset(ENV{CC})
unset(ENV{CXX})
project(CMakeBin2C VERSION 1.0.0 LANGUAGES CXX)
set(OUTPUT_NAME CMakeBin2C)
project(${OUTPUT_NAME} VERSION 1.0.0 LANGUAGES CXX)
add_executable(CMakeBin2C bin2c.cpp)
target_compile_features(CMakeBin2C PRIVATE cxx_std_17)
add_executable(${OUTPUT_NAME} bin2c.cpp)
target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_17)
add_custom_command(
TARGET CMakeBin2C
TARGET ${OUTPUT_NAME}
COMMENT "Copy Output"
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:CMakeBin2C> ${CMAKE_BINARY_DIR}
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${OUTPUT_NAME}> ${CMAKE_BINARY_DIR}
VERBATIM
)
set(OUTPUT_NAME CMakeShader2C)
project(${OUTPUT_NAME} VERSION 1.0.0 LANGUAGES CXX)
add_executable(${OUTPUT_NAME} shader2c.cpp)
target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_17)
add_custom_command(
TARGET ${OUTPUT_NAME}
COMMENT "Copy Output"
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${OUTPUT_NAME}> ${CMAKE_BINARY_DIR}
VERBATIM
)

141
tools/shader2c.cpp Normal file
View File

@ -0,0 +1,141 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#if (!defined(_MSC_VER)) || (_MSC_VER > 1916)
#include <filesystem>
#else
#include <experimental/filesystem>
#endif
#define ENUM_NAME_STR_IDENTIFIER_POS 0
#define OPERATION_POS 1
#define MIN_DOT_SEPARATED_STRINGS 2
using namespace std;
enum shader_operations { NO_OPERATION, POWER_OF_2_OPERATION };
vector<string> split_str_by_char(string str_to_split, char split_char) {
stringstream str_stream(str_to_split);
vector<string> result;
while(str_stream.good())
{
string substr;
getline(str_stream, substr, split_char);
result.push_back(substr);
}
return result;
}
inline bool str_ends_with(string const &value, string const &ending)
{
if(ending.size() > value.size()) return false;
return equal(ending.rbegin(), ending.rend(), value.rbegin());
}
int process_file(filesystem::path input_path, ofstream &output) {
string final_path = input_path.filename().string();
int first = -1;
int last = -1;
shader_operations loaded_operation = NO_OPERATION;
vector<string> dot_separated_names = split_str_by_char(final_path, '.');
if(dot_separated_names.size() < MIN_DOT_SEPARATED_STRINGS) {
cout << "Badly formatted input name!" << endl;
return -3;
}
transform(dot_separated_names[ENUM_NAME_STR_IDENTIFIER_POS].begin(), dot_separated_names[ENUM_NAME_STR_IDENTIFIER_POS].end(), dot_separated_names[ENUM_NAME_STR_IDENTIFIER_POS].begin(), ::toupper);
ifstream input(input_path, ios::in);
if(!input) {
cout << "Couldn't open input file!" << endl;
return -2;
}
vector<string> file_lines;
string single_str = "";
while (getline(input, single_str))
file_lines.push_back(single_str);
input.close();
if(dot_separated_names[OPERATION_POS].rfind("2_to_x", 0) == 0) {
vector<string> underscore_separated_values = split_str_by_char(final_path, '_');
first = stoi(underscore_separated_values[underscore_separated_values.size()-2]);
last = stoi(underscore_separated_values[underscore_separated_values.size()-1]);
loaded_operation = POWER_OF_2_OPERATION;
}
bool first_pass = true;
do {
if(!first_pass)
first += 1;
first_pass = false;
string enum_str = dot_separated_names[ENUM_NAME_STR_IDENTIFIER_POS];
output << "shader_strings[" << dot_separated_names[ENUM_NAME_STR_IDENTIFIER_POS];
if(first != -1)
output << "_" << first;
output << "] = \\" << endl;
for(int i = 0; i < file_lines.size(); i++) {
string line = file_lines[i];
if((loaded_operation == POWER_OF_2_OPERATION) && (str_ends_with(line, "= x;"))) {
vector<string> x_split_line = split_str_by_char(line, 'x');
string new_line = "";
for(int j = 0; j < x_split_line.size() - 1; j++) {
new_line += x_split_line[j];
if(j < x_split_line.size() - 2)
new_line += "x";
}
new_line += to_string((float)(1 << first)) + ";";
line = new_line;
}
output << "\"" << line << "\" \\" <<endl;
}
output << "\"\";" << endl;
} while(first != last);
return 0;
}
int main(int argc, char *argv[]) {
if(argc < 4) {
cout << "Usage: " << argv[0] << " shaders_folder cpp_template_file output_file_name" << endl;
return -1;
}
ifstream input(argv[2], ios::in);
if(!input) {
cout << "Couldn't open template file!" << endl;
return -4;
}
vector<string> file_lines;
string single_str = "";
while (getline(input, single_str))
file_lines.push_back(single_str);
input.close();
ofstream output(argv[3], ios::out);
if(!output) {
cout << "Couldn't open output cpp file!" << endl;
return -5;
}
for(int i = 0; i < file_lines.size(); i++)
output << file_lines[i] << endl;
for(const auto & entry : filesystem::directory_iterator(argv[1])) {
int result = process_file(entry.path(), output);
if(result != 0)
return result;
}
output<<"}"<<endl;
output.close();
return 0;
}