summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/PostProcessing.cpp
diff options
context:
space:
mode:
authorJules Blok <jules.blok@gmail.com>2015-06-10 00:00:12 +0200
committerJules Blok <jules.blok@gmail.com>2015-06-10 00:00:12 +0200
commit7dfced21a2e5aac7195e0e1ad76468e30306766b (patch)
treebd671b639d3d911460b767caabad8fc8a759a6bf /Source/Core/VideoCommon/PostProcessing.cpp
parentc25be031fc1031d795157d8344b87b7841145197 (diff)
parent7b0a65e295c784f9d573f2ef52d4e2a7b9bb2889 (diff)
Merge branch 'master' into stable
Diffstat (limited to 'Source/Core/VideoCommon/PostProcessing.cpp')
-rw-r--r--Source/Core/VideoCommon/PostProcessing.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/Source/Core/VideoCommon/PostProcessing.cpp b/Source/Core/VideoCommon/PostProcessing.cpp
new file mode 100644
index 0000000000..1ee7e142dd
--- /dev/null
+++ b/Source/Core/VideoCommon/PostProcessing.cpp
@@ -0,0 +1,321 @@
+// Copyright 2014 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"
+
+
+static const char s_default_shader[] = "void main() { SetOutput(Sample()); }\n";
+
+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;
+
+ const std::string sub_dir = (g_Config.iStereoMode == STEREO_ANAGLYPH) ? ANAGLYPH_DIR DIR_SEP : "";
+
+ // loading shader code
+ std::string code;
+ std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl";
+
+ if (shader == "")
+ {
+ code = s_default_shader;
+ }
+ else
+ {
+ if (!File::Exists(path))
+ {
+ // Fallback to shared user dir
+ path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl";
+ }
+
+ if (!File::ReadFileToString(path, code))
+ {
+ ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
+ code = s_default_shader;
+ }
+ }
+
+ 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.emplace_back(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::ostringstream value;
+ value.imbue(std::locale("C"));
+
+ for (size_t i = 0; i < it.second.m_float_values.size(); ++i)
+ {
+ value << it.second.m_float_values[i];
+ if (i != (it.second.m_float_values.size() - 1))
+ value << ", ";
+ }
+ ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value.str());
+ }
+ break;
+ }
+ }
+ ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
+}
+
+void PostProcessingShaderConfiguration::ReloadShader()
+{
+ m_current_shader = "";
+}
+
+void PostProcessingShaderConfiguration::SetOptionf(const 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(const 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(const 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;
+}