mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2025-06-18 08:35:33 -04:00
Add Color Correction Menu
This commit is contained in:
parent
82698d3376
commit
591b2f87d2
@ -525,7 +525,7 @@ if(MSVC)
|
||||
else()
|
||||
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$<CONFIG:Release>:-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/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp source/Menus/InputMenu.cpp source/Menus/AudioDeviceMenu.cpp source/Menus/SeparatorMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
|
||||
add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/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 ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
|
||||
|
||||
|
||||
if(NOT ("${EXTRA_DEPENDENCIES}" STREQUAL ""))
|
||||
@ -591,7 +591,7 @@ add_custom_command(
|
||||
)
|
||||
|
||||
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)
|
||||
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 ${CMAKE_SOURCE_DIR}/shaders/color_emulation_fragment_shader.frag)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${TOOLS_DATA_DIR}/shaders_list.cpp
|
||||
|
32
include/Menus/ColorCorrectionMenu.hpp
Normal file
32
include/Menus/ColorCorrectionMenu.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __COLORCORRECTIONMENU_HPP
|
||||
#define __COLORCORRECTIONMENU_HPP
|
||||
|
||||
#include "OptionSelectionMenu.hpp"
|
||||
#include <chrono>
|
||||
|
||||
#include "TextRectangle.hpp"
|
||||
#include "sfml_gfx_structs.hpp"
|
||||
#include "display_structs.hpp"
|
||||
|
||||
#define COLORCORRECTION_MENU_NO_ACTION -1
|
||||
#define COLORCORRECTION_MENU_BACK -2
|
||||
|
||||
class ColorCorrectionMenu : public OptionSelectionMenu {
|
||||
public:
|
||||
ColorCorrectionMenu(bool font_load_success, sf::Font &text_font);
|
||||
~ColorCorrectionMenu();
|
||||
void setup_title(std::string added_name);
|
||||
void prepare(float scaling_factor, int view_size_x, int view_size_y, int current_crop);
|
||||
void insert_data(std::vector<const ShaderColorEmulationData*>* possible_correction_data);
|
||||
int selected_index = COLORCORRECTION_MENU_NO_ACTION;
|
||||
void reset_output_option();
|
||||
protected:
|
||||
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:
|
||||
const std::string base_name = "Color Correction";
|
||||
std::vector<const ShaderColorEmulationData*>* possible_correction_data;
|
||||
};
|
||||
#endif
|
@ -15,6 +15,7 @@ enum VideoEffectsMenuOutAction{
|
||||
VIDEO_EFFECTS_MENU_INPUT_COLORSPACE_DEC,
|
||||
VIDEO_EFFECTS_MENU_FRAME_BLENDING_INC,
|
||||
VIDEO_EFFECTS_MENU_FRAME_BLENDING_DEC,
|
||||
VIDEO_EFFECTS_MENU_COLOR_CORRECTION_MENU,
|
||||
};
|
||||
|
||||
class VideoEffectsMenu : public OptionSelectionMenu {
|
||||
|
@ -25,7 +25,7 @@
|
||||
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, VIDEO_EFFECTS_MENU_TYPE, INPUT_MENU_TYPE, AUDIO_DEVICE_MENU_TYPE, SEPARATOR_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 };
|
||||
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 };
|
||||
|
||||
@ -70,6 +70,8 @@ struct ScreenInfo {
|
||||
bool use_non_integer_scaling_bottom;
|
||||
bool failed_fullscreen;
|
||||
bool have_titlebar;
|
||||
int top_color_correction;
|
||||
int bot_color_correction;
|
||||
InputColorspaceMode in_colorspace_top;
|
||||
InputColorspaceMode in_colorspace_bot;
|
||||
FrameBlendingMode frame_blending_top;
|
||||
@ -133,4 +135,13 @@ struct PARData {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct ShaderColorEmulationData {
|
||||
float targetGamma;
|
||||
float lum;
|
||||
float rgb_mod[3][3];
|
||||
float displayGamma;
|
||||
bool is_valid;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "InputMenu.hpp"
|
||||
#include "AudioDeviceMenu.hpp"
|
||||
#include "SeparatorMenu.hpp"
|
||||
#include "ColorCorrectionMenu.hpp"
|
||||
#include "display_structs.hpp"
|
||||
#include "event_structs.hpp"
|
||||
#include "shaders_list.hpp"
|
||||
@ -81,6 +82,7 @@ public:
|
||||
int get_ret_val();
|
||||
|
||||
private:
|
||||
enum PossibleShaderTypes { BASE_INPUT_SHADER_TYPE, BASE_FINAL_OUTPUT_SHADER_TYPE, COLOR_PROCESSING_SHADER_TYPE };
|
||||
struct ScreenOperations {
|
||||
bool call_create;
|
||||
bool call_close;
|
||||
@ -157,11 +159,13 @@ private:
|
||||
InputMenu *input_menu;
|
||||
AudioDeviceMenu *audio_device_menu;
|
||||
SeparatorMenu *separator_menu;
|
||||
ColorCorrectionMenu *color_correction_menu;
|
||||
std::vector<const CropData*> possible_crops;
|
||||
std::vector<const CropData*> possible_crops_ds;
|
||||
std::vector<const CropData*> possible_crops_with_games;
|
||||
std::vector<const CropData*> possible_crops_ds_with_games;
|
||||
std::vector<const PARData*> possible_pars;
|
||||
std::vector<const ShaderColorEmulationData*> possible_color_profiles;
|
||||
std::vector<sf::VideoMode> possible_resolutions;
|
||||
std::vector<std::string> possible_audio_devices;
|
||||
std::vector<FileData> possible_files;
|
||||
@ -192,6 +196,8 @@ private:
|
||||
out_rect_data m_out_rect_top, m_out_rect_bot;
|
||||
ScreenType m_stype;
|
||||
|
||||
const ShaderColorEmulationData* sent_shader_color_data;
|
||||
|
||||
std::queue<SFEvent> events_queue;
|
||||
|
||||
sf::View m_view;
|
||||
@ -257,6 +263,7 @@ private:
|
||||
void separator_multiplier_change(bool positive, float& multiplier_to_check, float lower_limit, float upper_limit);
|
||||
void separator_windowed_multiplier_change(bool positive);
|
||||
void separator_fullscreen_multiplier_change(bool positive);
|
||||
void color_correction_value_change(int new_color_correction_value);
|
||||
bool query_reset_request();
|
||||
void reset_held_times(bool force = true);
|
||||
void poll_window(bool do_everything);
|
||||
@ -267,8 +274,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);
|
||||
int _choose_base_input_shader(bool is_top);
|
||||
int _choose_color_emulation_shader(bool is_top);
|
||||
int _choose_shader(PossibleShaderTypes shader_type, bool is_top);
|
||||
int choose_shader(PossibleShaderTypes shader_type, bool is_top);
|
||||
bool apply_shaders_to_input(out_rect_data &rect_data, const sf::RectangleShape &final_in_rect, 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);
|
||||
@ -327,6 +337,7 @@ private:
|
||||
void setup_video_effects_menu(bool reset_data = true);
|
||||
void setup_input_menu(bool reset_data = true);
|
||||
void setup_separator_menu(bool reset_data = true);
|
||||
void setup_color_correction_menu(bool reset_data = true);
|
||||
void update_connection();
|
||||
};
|
||||
|
||||
@ -344,6 +355,7 @@ void FPSArrayDestroy(FPSArray *array);
|
||||
void FPSArrayInsertElement(FPSArray *array, double frame_time);
|
||||
void insert_basic_crops(std::vector<const CropData*> &crop_vector, ScreenType s_type, bool is_ds, bool allow_game_specific);
|
||||
void insert_basic_pars(std::vector<const PARData*> &par_vector);
|
||||
void insert_basic_color_profiles(std::vector<const ShaderColorEmulationData*> &color_profiles_vector);
|
||||
void reset_display_data(DisplayData *display_data);
|
||||
void reset_input_data(InputData* input_data);
|
||||
void reset_shared_data(SharedData* shared_data);
|
||||
|
@ -35,6 +35,7 @@ enum shader_list_enum {
|
||||
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_5,
|
||||
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_6,
|
||||
FRAME_BLENDING_BIT_CRUSHER_FRAGMENT_SHADER_7,
|
||||
COLOR_EMULATION_FRAGMENT_SHADER,
|
||||
|
||||
TOTAL_NUM_SHADERS
|
||||
};
|
||||
|
33
shaders/color_emulation_fragment_shader.frag
Normal file
33
shaders/color_emulation_fragment_shader.frag
Normal file
@ -0,0 +1,33 @@
|
||||
uniform sampler2D Texture0;
|
||||
uniform float targetContrast;
|
||||
uniform float targetBrightness;
|
||||
uniform float targetLuminance;
|
||||
uniform float targetGamma;
|
||||
uniform float displayGamma;
|
||||
uniform mat3 color_corr_mat;
|
||||
uniform mat3 saturation_mat;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
|
||||
vec3 colors_to_edit = gl_FragColor.rgb;
|
||||
vec3 tatget_brightness_vec = vec3(targetBrightness);
|
||||
vec3 tatget_gamma_vec = vec3(targetGamma);
|
||||
vec3 display_gamma_vec = vec3(displayGamma);
|
||||
|
||||
colors_to_edit += tatget_brightness_vec;
|
||||
colors_to_edit = pow(colors_to_edit, tatget_gamma_vec);
|
||||
|
||||
colors_to_edit *= targetLuminance;
|
||||
colors_to_edit = clamp(colors_to_edit, 0.0, 1.0);
|
||||
|
||||
colors_to_edit = color_corr_mat * colors_to_edit;
|
||||
colors_to_edit = saturation_mat * colors_to_edit;
|
||||
|
||||
colors_to_edit = clamp(colors_to_edit, 0.0, 1.0);
|
||||
|
||||
colors_to_edit *= targetContrast;
|
||||
colors_to_edit = pow(colors_to_edit, display_gamma_vec);
|
||||
|
||||
colors_to_edit = clamp(colors_to_edit, 0.0, 1.0);
|
||||
gl_FragColor.rgb = colors_to_edit;
|
||||
}
|
70
source/Menus/ColorCorrectionMenu.cpp
Normal file
70
source/Menus/ColorCorrectionMenu.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "ColorCorrectionMenu.hpp"
|
||||
|
||||
ColorCorrectionMenu::ColorCorrectionMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){
|
||||
this->initialize(font_load_success, text_font);
|
||||
}
|
||||
|
||||
ColorCorrectionMenu::~ColorCorrectionMenu() {
|
||||
}
|
||||
|
||||
void ColorCorrectionMenu::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 = this->base_name;
|
||||
this->show_back_x = true;
|
||||
this->show_x = false;
|
||||
this->show_title = true;
|
||||
}
|
||||
|
||||
void ColorCorrectionMenu::setup_title(std::string added_name) {
|
||||
this->title = added_name + (added_name != "" ? " " : "") + this->base_name;
|
||||
}
|
||||
|
||||
void ColorCorrectionMenu::insert_data(std::vector<const ShaderColorEmulationData*>* possible_correction_data) {
|
||||
this->possible_correction_data = possible_correction_data;
|
||||
this->prepare_options();
|
||||
}
|
||||
|
||||
void ColorCorrectionMenu::reset_output_option() {
|
||||
this->selected_index = COLORCORRECTION_MENU_NO_ACTION;
|
||||
}
|
||||
|
||||
void ColorCorrectionMenu::set_output_option(int index, int action) {
|
||||
if(index == BACK_X_OUTPUT_OPTION)
|
||||
this->selected_index = COLORCORRECTION_MENU_BACK;
|
||||
else
|
||||
this->selected_index = index;
|
||||
}
|
||||
|
||||
int ColorCorrectionMenu::get_num_options() {
|
||||
return (*this->possible_correction_data).size();
|
||||
}
|
||||
|
||||
std::string ColorCorrectionMenu::get_string_option(int index, int action) {
|
||||
return (*this->possible_correction_data)[index]->name;
|
||||
}
|
||||
|
||||
void ColorCorrectionMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, int current_corr) {
|
||||
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 corr_index = start + i;
|
||||
if(corr_index == current_corr)
|
||||
this->labels[index]->setText("<" + this->get_string_option(corr_index, DEFAULT_ACTION) + ">");
|
||||
else
|
||||
this->labels[index]->setText(this->get_string_option(corr_index, DEFAULT_ACTION));
|
||||
}
|
||||
this->base_prepare(menu_scaling_factor, view_size_x, view_size_y);
|
||||
}
|
@ -24,9 +24,15 @@ static const VideoEffectsMenuOptionInfo frame_blending_option = {
|
||||
.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 color_correction_menu_option = {
|
||||
.base_name = "Color Correction", .false_name = "", .is_selectable = true,
|
||||
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = VIDEO_EFFECTS_MENU_NO_ACTION,
|
||||
.out_action = VIDEO_EFFECTS_MENU_COLOR_CORRECTION_MENU};
|
||||
|
||||
static const VideoEffectsMenuOptionInfo* pollable_options[] = {
|
||||
&input_colorspace_option,
|
||||
&frame_blending_option,
|
||||
&color_correction_menu_option,
|
||||
};
|
||||
|
||||
VideoEffectsMenu::VideoEffectsMenu(bool font_load_success, sf::Font &text_font) : OptionSelectionMenu(){
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define GL_SILENCE_DEPRECATION
|
||||
#include <SFML/OpenGL.hpp>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include "font_ttf.h"
|
||||
#include "shaders_list.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
@ -43,6 +44,8 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp
|
||||
insert_basic_crops(this->possible_crops_with_games, this->m_stype, false, true);
|
||||
insert_basic_crops(this->possible_crops_ds_with_games, this->m_stype, true, true);
|
||||
insert_basic_pars(this->possible_pars);
|
||||
insert_basic_color_profiles(this->possible_color_profiles);
|
||||
this->sent_shader_color_data = NULL;
|
||||
this->m_prepare_save = 0;
|
||||
this->m_prepare_load = 0;
|
||||
this->m_prepare_open = false;
|
||||
@ -510,13 +513,62 @@ 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;
|
||||
}
|
||||
static void transpose_matrix_to_new_one(float target[3][3], const float source[3][3]) {
|
||||
for(int i = 0; i < 3; i++)
|
||||
for(int j = 0; j < 3; j++)
|
||||
target[i][j] = source[j][i];
|
||||
}
|
||||
|
||||
int WindowScreen::_choose_color_emulation_shader(bool is_top) {
|
||||
int color_profile_index = this->loaded_info.top_color_correction;
|
||||
if(!is_top)
|
||||
color_profile_index = this->loaded_info.bot_color_correction;
|
||||
if((color_profile_index >= possible_color_profiles.size()) || (color_profile_index < 0))
|
||||
color_profile_index = 0;
|
||||
|
||||
const ShaderColorEmulationData* shader_color_data = possible_color_profiles[color_profile_index];
|
||||
|
||||
if(!shader_color_data->is_valid)
|
||||
return -1;
|
||||
|
||||
int shader_index = COLOR_EMULATION_FRAGMENT_SHADER;
|
||||
if(sent_shader_color_data == shader_color_data)
|
||||
return shader_index;
|
||||
|
||||
const float contrast = 1.0;
|
||||
const float brightness = 0.0;
|
||||
const float saturation = 1.0;
|
||||
// Calculate saturation weights.
|
||||
// Note: We are using the Rec. 709 luminance vector here.
|
||||
// From Open AGB Firm, thanks to profi200
|
||||
const float rwgt = (1.f - saturation) * 0.2126f;
|
||||
const float gwgt = (1.f - saturation) * 0.7152f;
|
||||
const float bwgt = (1.f - saturation) * 0.0722f;
|
||||
float saturation_matrix[3][3] = {
|
||||
{rwgt + saturation, gwgt, bwgt},
|
||||
{rwgt, gwgt + saturation, bwgt},
|
||||
{rwgt, gwgt, bwgt + saturation}
|
||||
};
|
||||
// OpenGL is column major... Do the transpose of the matrixes
|
||||
float saturation_matrix_transposed[3][3];
|
||||
float color_corr_matrix_transposed[3][3];
|
||||
transpose_matrix_to_new_one(color_corr_matrix_transposed, shader_color_data->rgb_mod);
|
||||
transpose_matrix_to_new_one(saturation_matrix_transposed, saturation_matrix);
|
||||
|
||||
usable_shaders[shader_index].shader.setUniform("targetContrast", (float)(pow(contrast, shader_color_data->targetGamma)));
|
||||
usable_shaders[shader_index].shader.setUniform("targetBrightness", brightness / contrast);
|
||||
usable_shaders[shader_index].shader.setUniform("targetLuminance", shader_color_data->lum);
|
||||
usable_shaders[shader_index].shader.setUniform("targetGamma", shader_color_data->targetGamma);
|
||||
usable_shaders[shader_index].shader.setUniform("displayGamma", shader_color_data->displayGamma);
|
||||
usable_shaders[shader_index].shader.setUniform("color_corr_mat",
|
||||
sf::Glsl::Mat3((float*)color_corr_matrix_transposed));
|
||||
usable_shaders[shader_index].shader.setUniform("saturation_mat", sf::Glsl::Mat3((float*)saturation_matrix_transposed));
|
||||
|
||||
sent_shader_color_data = shader_color_data;
|
||||
return shader_index;
|
||||
}
|
||||
|
||||
int WindowScreen::_choose_base_input_shader(bool is_top) {
|
||||
InputColorspaceMode *in_colorspace = &this->loaded_info.in_colorspace_top;
|
||||
FrameBlendingMode *frame_blending = &this->loaded_info.frame_blending_top;
|
||||
if(!is_top) {
|
||||
@ -558,13 +610,60 @@ int WindowScreen::_choose_shader(bool is_input, bool is_top) {
|
||||
}
|
||||
}
|
||||
|
||||
int WindowScreen::choose_shader(bool is_input, bool is_top) {
|
||||
int chosen_shader = _choose_shader(is_input, is_top);
|
||||
int WindowScreen::_choose_shader(PossibleShaderTypes shader_type, bool is_top) {
|
||||
if(this->was_last_frame_null) {
|
||||
this->was_last_frame_null = false;
|
||||
return NO_EFFECT_FRAGMENT_SHADER;
|
||||
}
|
||||
switch(shader_type) {
|
||||
case BASE_FINAL_OUTPUT_SHADER_TYPE:
|
||||
return NO_EFFECT_FRAGMENT_SHADER;
|
||||
case BASE_INPUT_SHADER_TYPE:
|
||||
return _choose_base_input_shader(is_top);
|
||||
case COLOR_PROCESSING_SHADER_TYPE:
|
||||
return _choose_color_emulation_shader(is_top);
|
||||
default:
|
||||
return NO_EFFECT_FRAGMENT_SHADER;
|
||||
}
|
||||
}
|
||||
|
||||
int WindowScreen::choose_shader(PossibleShaderTypes shader_type, bool is_top) {
|
||||
int chosen_shader = _choose_shader(shader_type, is_top);
|
||||
if((chosen_shader >= 0) && (chosen_shader < usable_shaders.size()) && usable_shaders[chosen_shader].is_valid)
|
||||
return chosen_shader;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool WindowScreen::apply_shaders_to_input(out_rect_data &rect_data, const sf::RectangleShape &final_in_rect, bool is_top) {
|
||||
if(!sf::Shader::isAvailable())
|
||||
return false;
|
||||
|
||||
int chosen_shader = choose_shader(BASE_INPUT_SHADER_TYPE, is_top);
|
||||
if(chosen_shader < 0)
|
||||
return false;
|
||||
|
||||
float old_frame_pos_x = ((float)(NUM_FRAMES_BLENDED - 1)) / NUM_FRAMES_BLENDED;
|
||||
if(this->curr_frame_texture_pos > 0)
|
||||
old_frame_pos_x = -1.0 / NUM_FRAMES_BLENDED;
|
||||
sf::Glsl::Vec2 old_pos = {old_frame_pos_x, 0.0};
|
||||
usable_shaders[chosen_shader].shader.setUniform("old_frame_offset", old_pos);
|
||||
rect_data.out_tex.draw(final_in_rect, &usable_shaders[chosen_shader].shader);
|
||||
|
||||
chosen_shader = choose_shader(COLOR_PROCESSING_SHADER_TYPE, is_top);
|
||||
if(chosen_shader < 0)
|
||||
return true;
|
||||
sf::RectangleShape new_final_in_rect = final_in_rect;
|
||||
new_final_in_rect.setTexture(&rect_data.out_tex.getTexture());
|
||||
const sf::IntRect texture_rect = rect_data.out_rect.getTextureRect();
|
||||
new_final_in_rect.setTextureRect(texture_rect);
|
||||
new_final_in_rect.setSize({(float)texture_rect.size.x, (float)texture_rect.size.y});
|
||||
new_final_in_rect.setPosition({(float)texture_rect.position.x, (float)texture_rect.position.y});
|
||||
new_final_in_rect.setOrigin({0, 0});
|
||||
rect_data.out_tex.draw(new_final_in_rect, &usable_shaders[chosen_shader].shader);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
@ -584,19 +683,7 @@ void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data,
|
||||
text_coords_rect.position.x += this->curr_frame_texture_pos * MAX_IN_VIDEO_WIDTH;
|
||||
final_in_rect.setTextureRect(text_coords_rect);
|
||||
if(this->capture_status->connected && actually_draw) {
|
||||
bool use_default_shader = true;
|
||||
if(sf::Shader::isAvailable()) {
|
||||
int chosen_shader = choose_shader(true, is_top);
|
||||
if(chosen_shader >= 0) {
|
||||
float old_frame_pos_x = ((float)(NUM_FRAMES_BLENDED - 1)) / NUM_FRAMES_BLENDED;
|
||||
if(this->curr_frame_texture_pos > 0)
|
||||
old_frame_pos_x = -1.0 / NUM_FRAMES_BLENDED;
|
||||
sf::Glsl::Vec2 old_pos = {old_frame_pos_x, 0.0};
|
||||
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;
|
||||
}
|
||||
}
|
||||
bool use_default_shader = !(this->apply_shaders_to_input(rect_data, final_in_rect, is_top));
|
||||
if(use_default_shader)
|
||||
rect_data.out_tex.draw(final_in_rect);
|
||||
//Place postprocessing effects here
|
||||
@ -613,7 +700,7 @@ void WindowScreen::draw_rect_to_window(const sf::RectangleShape &out_rect, bool
|
||||
|
||||
bool use_default_shader = true;
|
||||
if(sf::Shader::isAvailable()) {
|
||||
int chosen_shader = choose_shader(false, is_top);
|
||||
int chosen_shader = choose_shader(BASE_FINAL_OUTPUT_SHADER_TYPE, is_top);
|
||||
if(chosen_shader >= 0) {
|
||||
this->m_win.draw(out_rect, &usable_shaders[chosen_shader].shader);
|
||||
use_default_shader = false;
|
||||
|
@ -119,6 +119,7 @@ void WindowScreen::init_menus() {
|
||||
this->input_menu = new InputMenu(this->font_load_success, this->text_font);
|
||||
this->audio_device_menu = new AudioDeviceMenu(this->font_load_success, this->text_font);
|
||||
this->separator_menu = new SeparatorMenu(this->font_load_success, this->text_font);
|
||||
this->color_correction_menu = new ColorCorrectionMenu(this->font_load_success, this->text_font);
|
||||
}
|
||||
|
||||
void WindowScreen::destroy_menus() {
|
||||
@ -145,6 +146,7 @@ void WindowScreen::destroy_menus() {
|
||||
delete this->input_menu;
|
||||
delete this->audio_device_menu;
|
||||
delete this->separator_menu;
|
||||
delete this->color_correction_menu;
|
||||
}
|
||||
|
||||
void WindowScreen::set_close(int ret_val) {
|
||||
@ -299,6 +301,22 @@ void WindowScreen::par_value_change(int new_par_value, bool is_top) {
|
||||
}
|
||||
}
|
||||
|
||||
void WindowScreen::color_correction_value_change(int new_color_correction_value) {
|
||||
int color_correction_index = new_color_correction_value % this->possible_color_profiles.size();
|
||||
if(color_correction_index < 0)
|
||||
color_correction_index = 0;
|
||||
std::string setting_name = "Color Correction: ";
|
||||
bool updated = false;
|
||||
if(this->m_info.top_color_correction != color_correction_index)
|
||||
updated = true;
|
||||
this->m_info.top_color_correction = color_correction_index;
|
||||
if(this->m_info.bot_color_correction != color_correction_index)
|
||||
updated = true;
|
||||
this->m_info.bot_color_correction = color_correction_index;
|
||||
if(updated)
|
||||
this->print_notification(setting_name + this->possible_color_profiles[color_correction_index]->name);
|
||||
}
|
||||
|
||||
void WindowScreen::offset_change(float &value, float change) {
|
||||
if(change >= 1.0)
|
||||
return;
|
||||
@ -1115,6 +1133,18 @@ void WindowScreen::setup_separator_menu(bool reset_data) {
|
||||
}
|
||||
}
|
||||
|
||||
void WindowScreen::setup_color_correction_menu(bool reset_data) {
|
||||
if(!this->can_setup_menu())
|
||||
return;
|
||||
if(this->curr_menu != COLOR_CORRECTION_MENU_TYPE) {
|
||||
this->curr_menu = COLOR_CORRECTION_MENU_TYPE;
|
||||
if(reset_data)
|
||||
this->color_correction_menu->reset_data();
|
||||
this->color_correction_menu->insert_data(&this->possible_color_profiles);
|
||||
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;
|
||||
@ -2073,6 +2103,10 @@ void WindowScreen::poll(bool do_everything) {
|
||||
case VIDEO_EFFECTS_MENU_FRAME_BLENDING_DEC:
|
||||
this->frame_blending_mode_change(false);
|
||||
break;
|
||||
case VIDEO_EFFECTS_MENU_COLOR_CORRECTION_MENU:
|
||||
this->setup_color_correction_menu();
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2178,6 +2212,23 @@ void WindowScreen::poll(bool do_everything) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case COLOR_CORRECTION_MENU_TYPE:
|
||||
if(this->color_correction_menu->poll(event_data)) {
|
||||
switch(this->color_correction_menu->selected_index) {
|
||||
case COLORCORRECTION_MENU_BACK:
|
||||
this->setup_video_effects_menu(false);
|
||||
done = true;
|
||||
break;
|
||||
case COLORCORRECTION_MENU_NO_ACTION:
|
||||
break;
|
||||
default:
|
||||
this->color_correction_value_change(this->color_correction_menu->selected_index);
|
||||
break;
|
||||
}
|
||||
this->color_correction_menu->reset_output_option();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2457,6 +2508,9 @@ void WindowScreen::prepare_menu_draws(int view_size_x, int view_size_y) {
|
||||
case SEPARATOR_MENU_TYPE:
|
||||
this->separator_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, &this->loaded_info);
|
||||
break;
|
||||
case COLOR_CORRECTION_MENU_TYPE:
|
||||
this->color_correction_menu->prepare(this->loaded_info.menu_scaling_factor, view_size_x, view_size_y, this->loaded_info.top_color_correction);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2539,6 +2593,9 @@ void WindowScreen::execute_menu_draws() {
|
||||
case SEPARATOR_MENU_TYPE:
|
||||
this->separator_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win);
|
||||
break;
|
||||
case COLOR_CORRECTION_MENU_TYPE:
|
||||
this->color_correction_menu->draw(this->loaded_info.menu_scaling_factor, this->m_win);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -363,6 +363,142 @@ static const PARData* basic_possible_pars[] = {
|
||||
&fit_wide_vertical_par,
|
||||
};
|
||||
|
||||
// libretro shader values. Credits: hunterk and Pokefan531.
|
||||
// Based on profi200's open_agb_firm implementation.
|
||||
// https://github.com/libretro/slang-shaders/tree/master/handheld/shaders/color
|
||||
const ShaderColorEmulationData color_profile_identity = {
|
||||
.targetGamma = 1.f, .lum = 1.f,
|
||||
.rgb_mod = {
|
||||
{1.f, 0.f, 0.f},
|
||||
{0.f, 1.f, 0.f},
|
||||
{0.f, 0.f, 1.f}
|
||||
},
|
||||
.displayGamma = 1.f / 1.f,
|
||||
.is_valid = false,
|
||||
.name = "No Correction"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_gba = {
|
||||
.targetGamma = 2.2f, .lum = 0.91f,
|
||||
.rgb_mod = {
|
||||
{0.905f, 0.195f, -0.1f},
|
||||
{0.1f, 0.65f, 0.25f},
|
||||
{0.1575f, 0.1425f, 0.7f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "GBA"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_gb_micro = {
|
||||
.targetGamma = 2.2f, .lum = 0.9f,
|
||||
.rgb_mod = {
|
||||
{0.8025f, 0.31f, -0.1125f},
|
||||
{0.1f, 0.6875f, 0.2125f},
|
||||
{0.1225f, 0.1125f, 0.765f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "GB Micro"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_gba_sp_101 = {
|
||||
.targetGamma = 2.2f, .lum = 0.935f,
|
||||
.rgb_mod = {
|
||||
{0.96f, 0.11f, -0.07f},
|
||||
{0.0325f, 0.89f, 0.0775f},
|
||||
{0.001f, -0.03f, 1.029f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "GBA SP 101"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_nds = {
|
||||
.targetGamma = 2.2f, .lum = 0.905f,
|
||||
.rgb_mod = {
|
||||
{0.835f, 0.27f, -0.105f},
|
||||
{0.1f, 0.6375f, 0.2625f},
|
||||
{0.105f, 0.175f, 0.72f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "Nintendo DS"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_nds_lite = {
|
||||
.targetGamma = 2.2f, .lum = 0.935f,
|
||||
.rgb_mod = {
|
||||
{0.93f, 0.14f, -0.07f},
|
||||
{0.025f, 0.9f, 0.075f},
|
||||
{0.008f, -0.03f, 1.022f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "Nintendo DS Lite"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_nso_gba = {
|
||||
.targetGamma = 2.2f, .lum = 1.f,
|
||||
.rgb_mod = {
|
||||
{0.865f, 0.1225f, 0.0125f},
|
||||
{0.0575f, 0.925f, 0.0125f},
|
||||
{0.0575f, 0.1225f, 0.82f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "NSO GBA"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_emulators_gba = {
|
||||
.targetGamma = 1.45f, .lum = 1.f,
|
||||
.rgb_mod = {
|
||||
{0.73f, 0.27f, 0.f},
|
||||
{0.0825f, 0.6775f, 0.24f},
|
||||
{0.0825f, 0.24f, 0.6775f}
|
||||
},
|
||||
.displayGamma = 1.f / 1.45f,
|
||||
.is_valid = true,
|
||||
.name = "Emulators GBA"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_libretro_gbc = {
|
||||
.targetGamma = 2.2f, .lum = 0.91f,
|
||||
.rgb_mod = {
|
||||
{0.905f, 0.195f, -0.1f},
|
||||
{0.1f, 0.65f, 0.25f},
|
||||
{0.1575f, 0.1425f, 0.7f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "GBC"
|
||||
};
|
||||
|
||||
const ShaderColorEmulationData color_profile_nso_gbc = {
|
||||
.targetGamma = 2.2f, .lum = 0.85f,
|
||||
.rgb_mod = {
|
||||
{0.84f, 0.265f, 0.f},
|
||||
{0.105f, 0.67f, 0.24f},
|
||||
{0.15f, 0.30f, 0.525f}
|
||||
},
|
||||
.displayGamma = 1.f / 2.2f,
|
||||
.is_valid = true,
|
||||
.name = "NSO GBC"
|
||||
};
|
||||
|
||||
static const ShaderColorEmulationData* basic_possible_color_profiles[] = {
|
||||
&color_profile_identity,
|
||||
&color_profile_libretro_nds,
|
||||
&color_profile_libretro_nds_lite,
|
||||
&color_profile_libretro_gba,
|
||||
&color_profile_libretro_gb_micro,
|
||||
&color_profile_libretro_gba_sp_101,
|
||||
&color_profile_libretro_nso_gba,
|
||||
&color_profile_libretro_emulators_gba,
|
||||
&color_profile_libretro_gbc,
|
||||
&color_profile_nso_gbc,
|
||||
};
|
||||
|
||||
static bool is_allowed_crop(const CropData* crop_data, ScreenType s_type, bool is_ds, bool allow_game_specific) {
|
||||
if(is_ds && (!crop_data->allowed_ds))
|
||||
return false;
|
||||
@ -392,6 +528,12 @@ void insert_basic_pars(std::vector<const PARData*> &par_vector) {
|
||||
}
|
||||
}
|
||||
|
||||
void insert_basic_color_profiles(std::vector<const ShaderColorEmulationData*> &color_profiles_vector) {
|
||||
for(int i = 0; i < (sizeof(basic_possible_color_profiles) / sizeof(basic_possible_color_profiles[0])); i++) {
|
||||
color_profiles_vector.push_back(basic_possible_color_profiles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void reset_display_data(DisplayData* display_data) {
|
||||
display_data->last_connected_ds = false;
|
||||
}
|
||||
@ -461,6 +603,8 @@ void reset_screen_info(ScreenInfo &info) {
|
||||
info.use_non_integer_scaling_bottom = false;
|
||||
info.failed_fullscreen = false;
|
||||
info.have_titlebar = true;
|
||||
info.top_color_correction = 0;
|
||||
info.bot_color_correction = 0;
|
||||
info.in_colorspace_top = FULL_COLORSPACE;
|
||||
info.in_colorspace_bot = FULL_COLORSPACE;
|
||||
info.frame_blending_top = NO_FRAME_BLENDING;
|
||||
@ -684,6 +828,14 @@ 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 + "top_color_correction")) {
|
||||
info.top_color_correction = std::stoi(value);
|
||||
return true;
|
||||
}
|
||||
if(key == (base + "bot_color_correction")) {
|
||||
info.bot_color_correction = std::stoi(value);
|
||||
return true;
|
||||
}
|
||||
if(key == (base + "in_colorspace_top")) {
|
||||
info.in_colorspace_top = input_colorspace_sanitization(std::stoi(value));
|
||||
return true;
|
||||
@ -740,6 +892,8 @@ 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 + "top_color_correction=" + std::to_string(info.top_color_correction) + "\n";
|
||||
out += base + "bot_color_correction=" + std::to_string(info.bot_color_correction) + "\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";
|
||||
|
Loading…
Reference in New Issue
Block a user