mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 22:09:19 -07:00
6bdc32c54a
This class loads all the common PP shader configuration options and passes those options through to a inherited class that OpenGL or D3D will have. Makes it so all the common code for PP shaders is in VideoCommon instead of duplicating the code across each backend.
305 lines
8.2 KiB
C++
305 lines
8.2 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <string>
|
|
|
|
#include "Common/CommonPaths.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/IniFile.h"
|
|
#include "Common/StringUtil.h"
|
|
|
|
#include "VideoCommon/PostProcessing.h"
|
|
#include "VideoCommon/VideoConfig.h"
|
|
|
|
|
|
PostProcessingShaderImplementation::PostProcessingShaderImplementation()
|
|
{
|
|
m_timer.Start();
|
|
}
|
|
|
|
PostProcessingShaderImplementation::~PostProcessingShaderImplementation()
|
|
{
|
|
m_timer.Stop();
|
|
}
|
|
|
|
std::string PostProcessingShaderConfiguration::LoadShader(std::string shader)
|
|
{
|
|
// Load the shader from the configuration if there isn't one sent to us.
|
|
if (shader == "")
|
|
shader = g_ActiveConfig.sPostProcessingShader;
|
|
m_current_shader = shader;
|
|
|
|
// loading shader code
|
|
std::string code;
|
|
std::string path = File::GetUserPath(D_SHADERS_IDX) + shader + ".glsl";
|
|
|
|
if (!File::Exists(path))
|
|
{
|
|
// Fallback to shared user dir
|
|
path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + shader + ".glsl";
|
|
}
|
|
|
|
if (!File::ReadFileToString(path, code))
|
|
{
|
|
ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
|
|
return "";
|
|
}
|
|
|
|
LoadOptions(code);
|
|
LoadOptionsConfiguration();
|
|
|
|
return code;
|
|
}
|
|
|
|
void PostProcessingShaderConfiguration::LoadOptions(const std::string& code)
|
|
{
|
|
const std::string config_start_delimiter = "[configuration]";
|
|
const std::string config_end_delimiter = "[/configuration]";
|
|
size_t configuration_start = code.find(config_start_delimiter);
|
|
size_t configuration_end = code.find(config_end_delimiter);
|
|
|
|
m_options.clear();
|
|
m_any_options_dirty = true;
|
|
|
|
if (configuration_start == std::string::npos ||
|
|
configuration_end == std::string::npos)
|
|
{
|
|
// Issue loading configuration or there isn't one.
|
|
return;
|
|
}
|
|
|
|
std::string configuration_string = code.substr(configuration_start + config_start_delimiter.size(),
|
|
configuration_end - configuration_start - config_start_delimiter.size());
|
|
|
|
std::istringstream in(configuration_string);
|
|
|
|
struct GLSLStringOption
|
|
{
|
|
std::string m_type;
|
|
std::vector<std::pair<std::string, std::string>> m_options;
|
|
};
|
|
|
|
std::vector<GLSLStringOption> option_strings;
|
|
GLSLStringOption* current_strings = nullptr;
|
|
while (!in.eof())
|
|
{
|
|
std::string line;
|
|
|
|
if (std::getline(in, line))
|
|
{
|
|
#ifndef _WIN32
|
|
// Check for CRLF eol and convert it to LF
|
|
if (!line.empty() && line.at(line.size()-1) == '\r')
|
|
{
|
|
line.erase(line.size()-1);
|
|
}
|
|
#endif
|
|
|
|
if (line.size() > 0)
|
|
{
|
|
if (line[0] == '[')
|
|
{
|
|
size_t endpos = line.find("]");
|
|
|
|
if (endpos != std::string::npos)
|
|
{
|
|
// New section!
|
|
std::string sub = line.substr(1, endpos - 1);
|
|
option_strings.push_back({ sub });
|
|
current_strings = &option_strings.back();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (current_strings)
|
|
{
|
|
std::string key, value;
|
|
IniFile::ParseLine(line, &key, &value);
|
|
|
|
if (!(key == "" && value == ""))
|
|
current_strings->m_options.push_back(std::make_pair(key, value));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const auto& it : option_strings)
|
|
{
|
|
ConfigurationOption option;
|
|
option.m_dirty = true;
|
|
|
|
if (it.m_type == "OptionBool")
|
|
option.m_type = ConfigurationOption::OptionType::OPTION_BOOL;
|
|
else if (it.m_type == "OptionRangeFloat")
|
|
option.m_type = ConfigurationOption::OptionType::OPTION_FLOAT;
|
|
else if (it.m_type == "OptionRangeInteger")
|
|
option.m_type = ConfigurationOption::OptionType::OPTION_INTEGER;
|
|
|
|
for (const auto& string_option : it.m_options)
|
|
{
|
|
if (string_option.first == "GUIName")
|
|
{
|
|
option.m_gui_name = string_option.second;
|
|
}
|
|
else if (string_option.first == "OptionName")
|
|
{
|
|
option.m_option_name = string_option.second;
|
|
}
|
|
else if (string_option.first == "DependentOption")
|
|
{
|
|
option.m_dependent_option = string_option.second;
|
|
}
|
|
else if (string_option.first == "MinValue" ||
|
|
string_option.first == "MaxValue" ||
|
|
string_option.first == "DefaultValue" ||
|
|
string_option.first == "StepAmount")
|
|
{
|
|
std::vector<s32>* output_integer = nullptr;
|
|
std::vector<float>* output_float = nullptr;
|
|
|
|
if (string_option.first == "MinValue")
|
|
{
|
|
output_integer = &option.m_integer_min_values;
|
|
output_float = &option.m_float_min_values;
|
|
}
|
|
else if (string_option.first == "MaxValue")
|
|
{
|
|
output_integer = &option.m_integer_max_values;
|
|
output_float = &option.m_float_max_values;
|
|
}
|
|
else if (string_option.first == "DefaultValue")
|
|
{
|
|
output_integer = &option.m_integer_values;
|
|
output_float = &option.m_float_values;
|
|
}
|
|
else if (string_option.first == "StepAmount")
|
|
{
|
|
output_integer = &option.m_integer_step_values;
|
|
output_float = &option.m_float_step_values;
|
|
}
|
|
|
|
if (option.m_type == ConfigurationOption::OptionType::OPTION_BOOL)
|
|
{
|
|
TryParse(string_option.second, &option.m_bool_value);
|
|
}
|
|
else if (option.m_type == ConfigurationOption::OptionType::OPTION_INTEGER)
|
|
{
|
|
TryParseVector(string_option.second, output_integer);
|
|
if (output_integer->size() > 4)
|
|
output_integer->erase(output_integer->begin() + 4, output_integer->end());
|
|
}
|
|
else if (option.m_type == ConfigurationOption::OptionType::OPTION_FLOAT)
|
|
{
|
|
TryParseVector(string_option.second, output_float);
|
|
if (output_float->size() > 4)
|
|
output_float->erase(output_float->begin() + 4, output_float->end());
|
|
}
|
|
}
|
|
}
|
|
m_options[option.m_option_name] = option;
|
|
}
|
|
}
|
|
|
|
void PostProcessingShaderConfiguration::LoadOptionsConfiguration()
|
|
{
|
|
IniFile ini;
|
|
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
|
std::string section = m_current_shader + "-options";
|
|
|
|
for (auto& it : m_options)
|
|
{
|
|
switch (it.second.m_type)
|
|
{
|
|
case ConfigurationOption::OptionType::OPTION_BOOL:
|
|
ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &it.second.m_bool_value, it.second.m_bool_value);
|
|
break;
|
|
case ConfigurationOption::OptionType::OPTION_INTEGER:
|
|
{
|
|
std::string value;
|
|
ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value);
|
|
if (value != "")
|
|
TryParseVector(value, &it.second.m_integer_values);
|
|
}
|
|
break;
|
|
case ConfigurationOption::OptionType::OPTION_FLOAT:
|
|
{
|
|
std::string value;
|
|
ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value);
|
|
if (value != "")
|
|
TryParseVector(value, &it.second.m_float_values);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PostProcessingShaderConfiguration::SaveOptionsConfiguration()
|
|
{
|
|
IniFile ini;
|
|
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
|
std::string section = m_current_shader + "-options";
|
|
|
|
for (auto& it : m_options)
|
|
{
|
|
switch (it.second.m_type)
|
|
{
|
|
case ConfigurationOption::OptionType::OPTION_BOOL:
|
|
{
|
|
ini.GetOrCreateSection(section)->Set(it.second.m_option_name, it.second.m_bool_value);
|
|
}
|
|
break;
|
|
case ConfigurationOption::OptionType::OPTION_INTEGER:
|
|
{
|
|
std::string value = "";
|
|
for (size_t i = 0; i < it.second.m_integer_values.size(); ++i)
|
|
value += StringFromFormat("%d%s", it.second.m_integer_values[i], i == (it.second.m_integer_values.size() - 1) ? "": ", ");
|
|
ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value);
|
|
}
|
|
break;
|
|
case ConfigurationOption::OptionType::OPTION_FLOAT:
|
|
{
|
|
std::string value = "";
|
|
for (size_t i = 0; i < it.second.m_float_values.size(); ++i)
|
|
value += StringFromFormat("%f%s", it.second.m_float_values[i], i == (it.second.m_float_values.size() - 1) ? "": ", ");
|
|
ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
|
}
|
|
|
|
void PostProcessingShaderConfiguration::ReloadShader()
|
|
{
|
|
m_current_shader = "";
|
|
}
|
|
|
|
void PostProcessingShaderConfiguration::SetOptionf(std::string option, int index, float value)
|
|
{
|
|
auto it = m_options.find(option);
|
|
|
|
it->second.m_float_values[index] = value;
|
|
it->second.m_dirty = true;
|
|
m_any_options_dirty = true;
|
|
}
|
|
|
|
void PostProcessingShaderConfiguration::SetOptioni(std::string option, int index, s32 value)
|
|
{
|
|
auto it = m_options.find(option);
|
|
|
|
it->second.m_integer_values[index] = value;
|
|
it->second.m_dirty = true;
|
|
m_any_options_dirty = true;
|
|
}
|
|
|
|
void PostProcessingShaderConfiguration::SetOptionb(std::string option, bool value)
|
|
{
|
|
auto it = m_options.find(option);
|
|
|
|
it->second.m_bool_value = value;
|
|
it->second.m_dirty = true;
|
|
m_any_options_dirty = true;
|
|
}
|