PostProcessing: Add categories/combos/tooltips
This commit is contained in:
parent
5e45d365c2
commit
10473f1cfb
|
@ -308,14 +308,45 @@ void PostProcessingShaderConfigWidget::createUi()
|
||||||
{
|
{
|
||||||
u32 row = 0;
|
u32 row = 0;
|
||||||
|
|
||||||
|
const std::string* last_category = nullptr;
|
||||||
|
|
||||||
for (PostProcessing::ShaderOption& option : m_options)
|
for (PostProcessing::ShaderOption& option : m_options)
|
||||||
{
|
{
|
||||||
if (option.ui_name.empty())
|
if (option.ui_name.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!last_category || option.category != *last_category)
|
||||||
|
{
|
||||||
|
if (last_category)
|
||||||
|
m_layout->addItem(new QSpacerItem(1, 4), row++, 0);
|
||||||
|
|
||||||
|
if (!option.category.empty())
|
||||||
|
{
|
||||||
|
QLabel* label = new QLabel(QString::fromStdString(option.category), this);
|
||||||
|
QFont label_font(label->font());
|
||||||
|
label_font.setPointSizeF(12.0f);
|
||||||
|
label->setFont(label_font);
|
||||||
|
m_layout->addWidget(label, row++, 0, 1, 3, Qt::AlignLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_category)
|
||||||
|
{
|
||||||
|
QLabel* line = new QLabel(this);
|
||||||
|
line->setFrameShape(QFrame::HLine);
|
||||||
|
line->setFixedHeight(4);
|
||||||
|
line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
m_layout->addWidget(line, row++, 0, 1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_category = &option.category;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString tooltip = QString::fromStdString(option.tooltip);
|
||||||
|
|
||||||
if (option.type == PostProcessing::ShaderOption::Type::Bool)
|
if (option.type == PostProcessing::ShaderOption::Type::Bool)
|
||||||
{
|
{
|
||||||
QCheckBox* checkbox = new QCheckBox(QString::fromStdString(option.ui_name), this);
|
QCheckBox* checkbox = new QCheckBox(QString::fromStdString(option.ui_name), this);
|
||||||
|
checkbox->setToolTip(tooltip);
|
||||||
checkbox->setChecked(option.value[0].int_value != 0);
|
checkbox->setChecked(option.value[0].int_value != 0);
|
||||||
connect(checkbox, &QCheckBox::stateChanged, [this, &option](int state) {
|
connect(checkbox, &QCheckBox::stateChanged, [this, &option](int state) {
|
||||||
option.value[0].int_value = (state == Qt::Checked) ? 1 : 0;
|
option.value[0].int_value = (state == Qt::Checked) ? 1 : 0;
|
||||||
|
@ -325,6 +356,24 @@ void PostProcessingShaderConfigWidget::createUi()
|
||||||
m_widgets.push_back(checkbox);
|
m_widgets.push_back(checkbox);
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
|
else if (option.type == PostProcessing::ShaderOption::Type::Int && !option.choice_options.empty())
|
||||||
|
{
|
||||||
|
QLabel* label = new QLabel(QString::fromStdString(option.ui_name), this);
|
||||||
|
label->setToolTip(tooltip);
|
||||||
|
m_layout->addWidget(label, row, 0, 1, 1, Qt::AlignLeft);
|
||||||
|
|
||||||
|
QComboBox* combo = new QComboBox(this);
|
||||||
|
combo->setToolTip(tooltip);
|
||||||
|
for (const std::string& combo_option : option.choice_options)
|
||||||
|
combo->addItem(QString::fromStdString(combo_option));
|
||||||
|
connect(combo, &QComboBox::currentIndexChanged, [this, &option](int index) {
|
||||||
|
option.value[0].int_value = index;
|
||||||
|
updateConfigForOption(option);
|
||||||
|
});
|
||||||
|
m_layout->addWidget(combo, row, 1, 1, 2, Qt::AlignLeft);
|
||||||
|
m_widgets.push_back(combo);
|
||||||
|
row++;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < option.vector_size; i++)
|
for (u32 i = 0; i < option.vector_size; i++)
|
||||||
|
@ -342,14 +391,17 @@ void PostProcessingShaderConfigWidget::createUi()
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* label_w = new QLabel(label, this);
|
QWidget* label_w = new QLabel(label, this);
|
||||||
|
label_w->setToolTip(tooltip);
|
||||||
m_layout->addWidget(label_w, row, 0, 1, 1, Qt::AlignLeft);
|
m_layout->addWidget(label_w, row, 0, 1, 1, Qt::AlignLeft);
|
||||||
m_widgets.push_back(label_w);
|
m_widgets.push_back(label_w);
|
||||||
|
|
||||||
QSlider* slider = new QSlider(Qt::Horizontal, this);
|
QSlider* slider = new QSlider(Qt::Horizontal, this);
|
||||||
|
slider->setToolTip(tooltip);
|
||||||
m_layout->addWidget(slider, row, 1, 1, 1, Qt::AlignLeft);
|
m_layout->addWidget(slider, row, 1, 1, 1, Qt::AlignLeft);
|
||||||
m_widgets.push_back(slider);
|
m_widgets.push_back(slider);
|
||||||
|
|
||||||
QLabel* slider_label = new QLabel(this);
|
QLabel* slider_label = new QLabel(this);
|
||||||
|
slider_label->setToolTip(tooltip);
|
||||||
m_layout->addWidget(slider_label, row, 2, 1, 1, Qt::AlignLeft);
|
m_layout->addWidget(slider_label, row, 2, 1, 1, Qt::AlignLeft);
|
||||||
m_widgets.push_back(slider_label);
|
m_widgets.push_back(slider_label);
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,8 @@ struct ShaderOption
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string ui_name;
|
std::string ui_name;
|
||||||
std::string dependent_option;
|
std::string dependent_option;
|
||||||
|
std::string category;
|
||||||
|
std::string tooltip;
|
||||||
Type type;
|
Type type;
|
||||||
u32 vector_size;
|
u32 vector_size;
|
||||||
u32 buffer_size;
|
u32 buffer_size;
|
||||||
|
@ -60,6 +62,7 @@ struct ShaderOption
|
||||||
ValueVector max_value;
|
ValueVector max_value;
|
||||||
ValueVector step_value;
|
ValueVector step_value;
|
||||||
ValueVector value;
|
ValueVector value;
|
||||||
|
std::vector<std::string> choice_options;
|
||||||
|
|
||||||
static u32 ParseIntVector(const std::string_view& line, ValueVector* values);
|
static u32 ParseIntVector(const std::string_view& line, ValueVector* values);
|
||||||
static u32 ParseFloatVector(const std::string_view& line, ValueVector* values);
|
static u32 ParseFloatVector(const std::string_view& line, ValueVector* values);
|
||||||
|
|
|
@ -430,9 +430,20 @@ bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool HasAnnotationWithName(const reshadefx::uniform_info& uniform, const std::string_view& annotation_name)
|
||||||
|
{
|
||||||
|
for (const reshadefx::annotation& an : uniform.annotations)
|
||||||
|
{
|
||||||
|
if (an.name == annotation_name)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static std::string_view GetStringAnnotationValue(const std::vector<reshadefx::annotation>& annotations,
|
static std::string_view GetStringAnnotationValue(const std::vector<reshadefx::annotation>& annotations,
|
||||||
const std::string_view& annotation_name,
|
const std::string_view annotation_name,
|
||||||
const std::string_view& default_value)
|
const std::string_view default_value)
|
||||||
{
|
{
|
||||||
for (const reshadefx::annotation& an : annotations)
|
for (const reshadefx::annotation& an : annotations)
|
||||||
{
|
{
|
||||||
|
@ -449,7 +460,7 @@ static std::string_view GetStringAnnotationValue(const std::vector<reshadefx::an
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetBooleanAnnotationValue(const std::vector<reshadefx::annotation>& annotations,
|
static bool GetBooleanAnnotationValue(const std::vector<reshadefx::annotation>& annotations,
|
||||||
const std::string_view& annotation_name, bool default_value)
|
const std::string_view annotation_name, bool default_value)
|
||||||
{
|
{
|
||||||
for (const reshadefx::annotation& an : annotations)
|
for (const reshadefx::annotation& an : annotations)
|
||||||
{
|
{
|
||||||
|
@ -466,7 +477,7 @@ static bool GetBooleanAnnotationValue(const std::vector<reshadefx::annotation>&
|
||||||
}
|
}
|
||||||
|
|
||||||
static PostProcessing::ShaderOption::ValueVector
|
static PostProcessing::ShaderOption::ValueVector
|
||||||
GetVectorAnnotationValue(const reshadefx::uniform_info& uniform, const std::string_view& annotation_name,
|
GetVectorAnnotationValue(const reshadefx::uniform_info& uniform, const std::string_view annotation_name,
|
||||||
const PostProcessing::ShaderOption::ValueVector& default_value)
|
const PostProcessing::ShaderOption::ValueVector& default_value)
|
||||||
{
|
{
|
||||||
PostProcessing::ShaderOption::ValueVector vv = default_value;
|
PostProcessing::ShaderOption::ValueVector vv = default_value;
|
||||||
|
@ -477,7 +488,7 @@ GetVectorAnnotationValue(const reshadefx::uniform_info& uniform, const std::stri
|
||||||
|
|
||||||
const u32 components = std::min<u32>(an.type.components(), PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS);
|
const u32 components = std::min<u32>(an.type.components(), PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS);
|
||||||
|
|
||||||
if (an.type.base == uniform.type.base)
|
if (an.type.base == uniform.type.base || (an.type.is_integral() && uniform.type.is_integral())) // int<->uint
|
||||||
{
|
{
|
||||||
if (components > 0)
|
if (components > 0)
|
||||||
std::memcpy(&vv[0].float_value, &an.value.as_float[0], sizeof(float) * components);
|
std::memcpy(&vv[0].float_value, &an.value.as_float[0], sizeof(float) * components);
|
||||||
|
@ -584,6 +595,8 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
|
||||||
|
|
||||||
ShaderOption opt;
|
ShaderOption opt;
|
||||||
opt.name = ui.name;
|
opt.name = ui.name;
|
||||||
|
opt.category = GetStringAnnotationValue(ui.annotations, "ui_category", std::string_view());
|
||||||
|
opt.tooltip = GetStringAnnotationValue(ui.annotations, "ui_tooltip", std::string_view());
|
||||||
|
|
||||||
if (!GetBooleanAnnotationValue(ui.annotations, "hidden", false))
|
if (!GetBooleanAnnotationValue(ui.annotations, "hidden", false))
|
||||||
{
|
{
|
||||||
|
@ -592,7 +605,7 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
|
||||||
opt.ui_name = ui.name;
|
opt.ui_name = ui.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const std::string_view ui_type = GetStringAnnotationValue(ui.annotations, "ui_type", std::string_view();
|
const std::string_view ui_type = GetStringAnnotationValue(ui.annotations, "ui_type", std::string_view());
|
||||||
|
|
||||||
switch (ui.type.base)
|
switch (ui.type.base)
|
||||||
{
|
{
|
||||||
|
@ -624,8 +637,8 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
opt.min_value = GetVectorAnnotationValue(ui, "ui_min", {});
|
opt.min_value = GetVectorAnnotationValue(ui, "ui_min", opt.default_value);
|
||||||
opt.max_value = GetVectorAnnotationValue(ui, "ui_max", {});
|
opt.max_value = GetVectorAnnotationValue(ui, "ui_max", opt.default_value);
|
||||||
ShaderOption::ValueVector default_step = {};
|
ShaderOption::ValueVector default_step = {};
|
||||||
switch (opt.type)
|
switch (opt.type)
|
||||||
{
|
{
|
||||||
|
@ -654,6 +667,25 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
|
||||||
}
|
}
|
||||||
opt.step_value = GetVectorAnnotationValue(ui, "ui_step", default_step);
|
opt.step_value = GetVectorAnnotationValue(ui, "ui_step", default_step);
|
||||||
|
|
||||||
|
// set a default maximum based on step if there isn't one
|
||||||
|
if (!HasAnnotationWithName(ui, "ui_max") && HasAnnotationWithName(ui, "ui_step"))
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < opt.vector_size; i++)
|
||||||
|
{
|
||||||
|
switch (opt.type)
|
||||||
|
{
|
||||||
|
case ShaderOption::Type::Float:
|
||||||
|
opt.max_value[i].float_value = opt.min_value[i].float_value + (opt.step_value[i].float_value * 100.0f);
|
||||||
|
break;
|
||||||
|
case ShaderOption::Type::Int:
|
||||||
|
opt.max_value[i].int_value = opt.min_value[i].int_value + (opt.step_value[i].int_value * 100);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ui.has_initializer_value)
|
if (ui.has_initializer_value)
|
||||||
{
|
{
|
||||||
std::memcpy(&opt.default_value[0].float_value, &ui.initializer_value.as_float[0],
|
std::memcpy(&opt.default_value[0].float_value, &ui.initializer_value.as_float[0],
|
||||||
|
@ -667,9 +699,44 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
|
||||||
// Assume default if user doesn't set it.
|
// Assume default if user doesn't set it.
|
||||||
opt.value = opt.default_value;
|
opt.value = opt.default_value;
|
||||||
|
|
||||||
|
if (!ui_type.empty() && opt.vector_size > 1)
|
||||||
|
{
|
||||||
|
Log_WarningFmt("Uniform '{}' has UI type of '{}' but is vector not scalar ({}), ignoring", opt.name, ui_type,
|
||||||
|
opt.vector_size);
|
||||||
|
}
|
||||||
|
else if (!ui_type.empty())
|
||||||
|
{
|
||||||
|
if ((ui_type == "combo" || ui_type == "radio") && opt.type == ShaderOption::Type::Int)
|
||||||
|
{
|
||||||
|
const std::string_view ui_values = GetStringAnnotationValue(ui.annotations, "ui_items", std::string_view());
|
||||||
|
|
||||||
|
size_t start_pos = 0;
|
||||||
|
while (start_pos < ui_values.size())
|
||||||
|
{
|
||||||
|
size_t end_pos = start_pos;
|
||||||
|
while (end_pos < ui_values.size() && ui_values[end_pos] != '\0')
|
||||||
|
end_pos++;
|
||||||
|
|
||||||
|
const size_t len = end_pos - start_pos;
|
||||||
|
if (len > 0)
|
||||||
|
opt.choice_options.emplace_back(ui_values.substr(start_pos, len));
|
||||||
|
start_pos = end_pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update max if it hasn't been specified
|
||||||
|
const size_t num_choices = opt.choice_options.size();
|
||||||
|
if (num_choices > 0)
|
||||||
|
opt.max_value[0].int_value = std::max(static_cast<s32>(num_choices - 1), opt.max_value[0].int_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_options.push_back(std::move(opt));
|
m_options.push_back(std::move(opt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sort based on category
|
||||||
|
std::sort(m_options.begin(), m_options.end(),
|
||||||
|
[](const ShaderOption& lhs, const ShaderOption& rhs) { return lhs.category < rhs.category; });
|
||||||
|
|
||||||
m_uniforms_size = mod.total_uniform_size;
|
m_uniforms_size = mod.total_uniform_size;
|
||||||
Log_DevFmt("{}: {} options", m_filename, m_options.size());
|
Log_DevFmt("{}: {} options", m_filename, m_options.size());
|
||||||
return true;
|
return true;
|
||||||
|
@ -741,6 +808,12 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
|
||||||
*si = SourceOptionType::MousePoint;
|
*si = SourceOptionType::MousePoint;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (source == "mousebutton")
|
||||||
|
{
|
||||||
|
Log_WarningFmt("Ignoring mousebutton source in uniform '{}', not supported.", ui.name);
|
||||||
|
*si = SourceOptionType::Zero;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else if (source == "random")
|
else if (source == "random")
|
||||||
{
|
{
|
||||||
if ((!ui.type.is_floating_point() && !ui.type.is_integral()) || ui.type.components() != 1)
|
if ((!ui.type.is_floating_point() && !ui.type.is_integral()) || ui.type.components() != 1)
|
||||||
|
|
Loading…
Reference in New Issue