mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-12-29 11:01:23 +00:00
gfx/shader/param/basic: Fix bool and suffixes, add enums and optimize
Adds support for enumerations, a different way of selecting how something should behave in a shader. Enumerations rely on a continuous list of values, and will automatically detect how many values there are in the enumeration. Only non-vector types are supported as enumeration entries, and array/vector parameters can have each member set to a different enumeration value. Furthermore suffixes now are properly assigned, and 'bool' no longer causes shaders to stop rendering. Additionally by inlining some functions and using std::string_view we can achieve a slightly better performance than before.
This commit is contained in:
parent
a2fd4dd2f6
commit
c1b3972550
2 changed files with 113 additions and 119 deletions
|
@ -22,14 +22,14 @@
|
|||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#define ANNO_FIELD_TYPE "field_type"
|
||||
#define ANNO_SUFFIX "suffix"
|
||||
#define ANNO_VALUE_MINIMUM "minimum"
|
||||
#define ANNO_VALUE_MAXIMUM "maximum"
|
||||
#define ANNO_VALUE_STEP "step"
|
||||
#define ANNO_VALUE_SCALE "scale"
|
||||
#define ANNO_ENUM_VALUES "values"
|
||||
#define ANNO_ENUM_VALUE "value"
|
||||
static const std::string_view _annotation_field_type = "field_type";
|
||||
static const std::string_view _annotation_suffix = "suffix";
|
||||
static const std::string_view _annotation_minimum = "minimum";
|
||||
static const std::string_view _annotation_maximum = "maximum";
|
||||
static const std::string_view _annotation_step = "step";
|
||||
static const std::string_view _annotation_scale = "scale";
|
||||
static const std::string_view _annotation_enum_entry = "enum_%zu";
|
||||
static const std::string_view _annotation_enum_entry_name = "enum_%zu_name";
|
||||
|
||||
inline bool get_annotation_string(gs::effect_parameter param, std::string anno_name, std::string& out)
|
||||
{
|
||||
|
@ -98,45 +98,55 @@ gfx::shader::basic_parameter::basic_parameter(gs::effect_parameter param, std::s
|
|||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
snprintf(string_buffer, sizeof(string_buffer), "[%d]", static_cast<int32_t>(idx));
|
||||
_names[idx] = std::string(string_buffer, string_buffer + strnlen(string_buffer, sizeof(string_buffer)));
|
||||
snprintf(string_buffer, sizeof(string_buffer), "%s[%d]", get_key().c_str(), static_cast<int32_t>(idx));
|
||||
snprintf(string_buffer, sizeof(string_buffer), "%s[%d]", get_key().data(), static_cast<int32_t>(idx));
|
||||
_keys[idx] = std::string(string_buffer, string_buffer + strnlen(string_buffer, sizeof(string_buffer)));
|
||||
}
|
||||
}
|
||||
|
||||
// Detect Field Types
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_FIELD_TYPE); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_field_type); anno) {
|
||||
_field_type = get_field_type_from_string(anno.get_default_string());
|
||||
}
|
||||
|
||||
// Read Suffix Data
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_SUFFIX); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_suffix); anno) {
|
||||
if (anno.get_type() == gs::effect_parameter::type::String)
|
||||
_suffix = anno.get_default_string();
|
||||
}
|
||||
|
||||
// Read Enumeration Data if Enumeration
|
||||
if (get_field_type() == basic_field_type::Enum) {
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_ENUM_VALUES);
|
||||
anno && (anno.get_type() == gs::effect_parameter::type::Integer)) {
|
||||
_values.resize(static_cast<size_t>(std::max(anno.get_default_int(), 0)));
|
||||
for (std::size_t idx = 0; idx < _values.size(); idx++) {
|
||||
auto& entry = _values[idx];
|
||||
snprintf(string_buffer, sizeof(string_buffer), "_%zu", idx);
|
||||
std::string key =
|
||||
std::string(string_buffer, string_buffer + strnlen(string_buffer, sizeof(string_buffer)));
|
||||
if (auto annoe = anno.get_annotation(key);
|
||||
annoe && (annoe.get_type() == gs::effect_parameter::type::String)) {
|
||||
entry.name = annoe.get_default_string();
|
||||
if (auto annoev = annoe.get_annotation(ANNO_ENUM_VALUE); annoev) {
|
||||
load_parameter_data(annoev, entry.data);
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING("[%s] Parameter enumeration entry '%s' is of invalid type, must be string.",
|
||||
get_name().c_str(), string_buffer);
|
||||
}
|
||||
if (field_type() == basic_field_type::Enum) {
|
||||
for (std::size_t idx = 0; idx < std::numeric_limits<std::size_t>::max(); idx++) {
|
||||
// Build key.
|
||||
std::string key_name;
|
||||
std::string key_value;
|
||||
{
|
||||
snprintf(string_buffer, sizeof(string_buffer), _annotation_enum_entry.data(), idx);
|
||||
key_value = std::string(string_buffer);
|
||||
snprintf(string_buffer, sizeof(string_buffer), _annotation_enum_entry_name.data(), idx);
|
||||
key_name = std::string(string_buffer);
|
||||
}
|
||||
} else {
|
||||
LOG_WARNING("[%s] Enumeration is missing entries.", get_name().c_str());
|
||||
|
||||
// Value must be given, name is optional.
|
||||
if (auto eanno = get_parameter().get_annotation(key_value);
|
||||
eanno && (get_type_from_effect_type(eanno.get_type()) == get_type())) {
|
||||
basic_enum_data entry;
|
||||
|
||||
load_parameter_data(eanno, entry.data);
|
||||
if (auto nanno = get_parameter().get_annotation(key_name);
|
||||
nanno && (nanno.get_type() == gs::effect_parameter::type::String)) {
|
||||
entry.name = nanno.get_default_string();
|
||||
} else {
|
||||
entry.name = "Unnamed Entry";
|
||||
}
|
||||
|
||||
_values.push_back(entry);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_values.size() == 0) {
|
||||
_field_type = basic_field_type::Input;
|
||||
}
|
||||
}
|
||||
|
@ -149,30 +159,6 @@ void gfx::shader::basic_parameter::load_parameter_data(gs::effect_parameter para
|
|||
parameter.get_default_value(&data.i32, 1);
|
||||
}
|
||||
|
||||
gfx::shader::basic_field_type gfx::shader::basic_parameter::get_field_type()
|
||||
{
|
||||
return _field_type;
|
||||
}
|
||||
|
||||
const std::string& gfx::shader::basic_parameter::get_suffix()
|
||||
{
|
||||
return _suffix;
|
||||
}
|
||||
|
||||
const std::string& gfx::shader::basic_parameter::get_keys(std::size_t idx)
|
||||
{
|
||||
if (idx >= get_size())
|
||||
throw std::out_of_range("Index out of range.");
|
||||
return _keys[idx];
|
||||
}
|
||||
|
||||
const std::string& gfx::shader::basic_parameter::get_names(std::size_t idx)
|
||||
{
|
||||
if (idx >= get_size())
|
||||
throw std::out_of_range("Index out of range.");
|
||||
return _names[idx];
|
||||
}
|
||||
|
||||
gfx::shader::bool_parameter::bool_parameter(gs::effect_parameter param, std::string prefix)
|
||||
: basic_parameter(param, prefix)
|
||||
{
|
||||
|
@ -181,7 +167,7 @@ gfx::shader::bool_parameter::bool_parameter(gs::effect_parameter param, std::str
|
|||
_step.resize(0);
|
||||
_scale.resize(0);
|
||||
|
||||
_data.resize(get_size(), true);
|
||||
_data.resize(get_size(), 1);
|
||||
}
|
||||
|
||||
gfx::shader::bool_parameter::~bool_parameter() {}
|
||||
|
@ -190,7 +176,7 @@ void gfx::shader::bool_parameter::defaults(obs_data_t* settings)
|
|||
{
|
||||
// TODO: Support for bool[]
|
||||
if (get_size() == 1) {
|
||||
obs_data_set_default_bool(settings, get_key().c_str(), get_parameter().get_default_bool());
|
||||
obs_data_set_default_int(settings, get_key().data(), get_parameter().get_default_bool() ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,10 +187,10 @@ void gfx::shader::bool_parameter::properties(obs_properties_t* props, obs_data_t
|
|||
|
||||
// TODO: Support for bool[]
|
||||
if (get_size() == 1) {
|
||||
auto p = obs_properties_add_list(props, get_key().c_str(), get_name().c_str(), OBS_COMBO_TYPE_LIST,
|
||||
auto p = obs_properties_add_list(props, get_key().data(), get_name().data(), OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_INT);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().c_str());
|
||||
obs_property_set_long_description(p, get_description().data());
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_DISABLED), 0);
|
||||
obs_property_list_add_int(p, D_TRANSLATE(S_STATE_ENABLED), 1);
|
||||
}
|
||||
|
@ -217,13 +203,13 @@ void gfx::shader::bool_parameter::update(obs_data_t* settings)
|
|||
|
||||
// TODO: Support for bool[]
|
||||
if (get_size() == 1) {
|
||||
_data[0] = static_cast<bool>(obs_data_get_int(settings, get_key().c_str()));
|
||||
_data[0] = obs_data_get_int(settings, get_key().data());
|
||||
}
|
||||
}
|
||||
|
||||
void gfx::shader::bool_parameter::assign()
|
||||
{
|
||||
get_parameter().set_value(_data.data(), sizeof(std::uint8_t));
|
||||
get_parameter().set_value(_data.data(), _data.size());
|
||||
}
|
||||
|
||||
gfx::shader::float_parameter::float_parameter(gs::effect_parameter param, std::string prefix)
|
||||
|
@ -240,22 +226,22 @@ gfx::shader::float_parameter::float_parameter(gs::effect_parameter param, std::s
|
|||
}
|
||||
|
||||
// Load Limits
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_MINIMUM); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_minimum); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_min.data(), get_size());
|
||||
}
|
||||
}
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_MAXIMUM); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_maximum); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_max.data(), get_size());
|
||||
}
|
||||
}
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_STEP); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_step); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_step.data(), get_size());
|
||||
}
|
||||
}
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_SCALE); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_scale); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_scale.data(), get_size());
|
||||
}
|
||||
|
@ -271,19 +257,18 @@ void gfx::shader::float_parameter::defaults(obs_data_t* settings)
|
|||
get_parameter().get_default_value(defaults.data(), get_size());
|
||||
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
obs_data_set_default_double(settings, get_keys(idx).c_str(), static_cast<double_t>(defaults[idx]));
|
||||
obs_data_set_default_double(settings, key_at(idx).data(), static_cast<double_t>(defaults[idx]));
|
||||
}
|
||||
}
|
||||
|
||||
static inline obs_property_t* build_float_property(gfx::shader::basic_field_type ft, obs_properties_t* props,
|
||||
const char* key, const char* name, float_t min, float_t max,
|
||||
float_t step, std::vector<gfx::shader::basic_enum_data> edata)
|
||||
float_t step, std::list<gfx::shader::basic_enum_data> edata)
|
||||
{
|
||||
switch (ft) {
|
||||
case gfx::shader::basic_field_type::Enum: {
|
||||
auto p = obs_properties_add_list(props, key, name, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_FLOAT);
|
||||
for (std::size_t idx = 0; idx < edata.size(); idx++) {
|
||||
auto& el = edata.at(idx);
|
||||
for (auto& el : edata) {
|
||||
obs_property_list_add_float(p, el.name.c_str(), el.data.f32);
|
||||
}
|
||||
return p;
|
||||
|
@ -301,31 +286,28 @@ void gfx::shader::float_parameter::properties(obs_properties_t* props, obs_data_
|
|||
if (!is_visible())
|
||||
return;
|
||||
|
||||
if (get_size() == 1) {
|
||||
auto p = build_float_property(_field_type, props, _keys[0].c_str(), _names[0].c_str(), _min[0].f32, _max[0].f32,
|
||||
_step[0].f32, _values);
|
||||
obs_properties_t* pr = props;
|
||||
if (get_size() > 1) {
|
||||
pr = obs_properties_create();
|
||||
auto p = obs_properties_add_group(props, get_key().data(), has_name() ? get_name().data() : get_key().data(),
|
||||
OBS_GROUP_NORMAL, pr);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().c_str());
|
||||
} else {
|
||||
auto grp = obs_properties_create();
|
||||
auto p = obs_properties_add_group(props, get_key().c_str(), has_name() ? get_name().c_str() : get_key().c_str(),
|
||||
OBS_GROUP_NORMAL, grp);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().c_str());
|
||||
obs_property_set_long_description(p, get_description().data());
|
||||
}
|
||||
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
p = build_float_property(_field_type, grp, _keys[idx].c_str(), _names[idx].c_str(), _min[idx].f32,
|
||||
_max[idx].f32, _step[idx].f32, _values);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().c_str());
|
||||
}
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
auto p = build_float_property(field_type(), pr, key_at(idx).data(), name_at(idx).data(), _min[idx].f32,
|
||||
_max[idx].f32, _step[idx].f32, _values);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().data());
|
||||
obs_property_float_set_suffix(p, suffix().data());
|
||||
}
|
||||
}
|
||||
|
||||
void gfx::shader::float_parameter::update(obs_data_t* settings)
|
||||
{
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
_data[idx].f32 = static_cast<float_t>(obs_data_get_double(settings, _keys[idx].c_str())) * _scale[idx].f32;
|
||||
_data[idx].f32 = static_cast<float_t>(obs_data_get_double(settings, key_at(idx).data())) * _scale[idx].f32;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,13 +320,12 @@ void gfx::shader::float_parameter::assign()
|
|||
}
|
||||
static inline obs_property_t* build_int_property(gfx::shader::basic_field_type ft, obs_properties_t* props,
|
||||
const char* key, const char* name, int32_t min, int32_t max,
|
||||
int32_t step, std::vector<gfx::shader::basic_enum_data> edata)
|
||||
int32_t step, std::list<gfx::shader::basic_enum_data> edata)
|
||||
{
|
||||
switch (ft) {
|
||||
case gfx::shader::basic_field_type::Enum: {
|
||||
auto p = obs_properties_add_list(props, key, name, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
||||
for (std::size_t idx = 0; idx < edata.size(); idx++) {
|
||||
auto& el = edata.at(idx);
|
||||
for (auto& el : edata) {
|
||||
obs_property_list_add_int(p, el.name.c_str(), el.data.i32);
|
||||
}
|
||||
return p;
|
||||
|
@ -371,22 +352,22 @@ gfx::shader::int_parameter::int_parameter(gs::effect_parameter param, std::strin
|
|||
}
|
||||
|
||||
// Load Limits
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_MINIMUM); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_minimum); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_min.data(), get_size());
|
||||
}
|
||||
}
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_MAXIMUM); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_maximum); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_max.data(), get_size());
|
||||
}
|
||||
}
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_STEP); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_step); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_step.data(), get_size());
|
||||
}
|
||||
}
|
||||
if (auto anno = get_parameter().get_annotation(ANNO_VALUE_SCALE); anno) {
|
||||
if (auto anno = get_parameter().get_annotation(_annotation_scale); anno) {
|
||||
if (anno.get_type() == get_parameter().get_type()) {
|
||||
anno.get_default_value(_scale.data(), get_size());
|
||||
}
|
||||
|
@ -401,7 +382,7 @@ void gfx::shader::int_parameter::defaults(obs_data_t* settings)
|
|||
defaults.resize(get_size());
|
||||
get_parameter().get_default_value(defaults.data(), get_size());
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
obs_data_set_default_int(settings, get_keys(idx).c_str(), defaults[idx]);
|
||||
obs_data_set_default_int(settings, key_at(idx).data(), defaults[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,31 +391,28 @@ void gfx::shader::int_parameter::properties(obs_properties_t* props, obs_data_t*
|
|||
if (!is_visible())
|
||||
return;
|
||||
|
||||
if (get_size() == 1) {
|
||||
auto p = build_int_property(_field_type, props, _keys[0].c_str(), _names[0].c_str(), _min[0].i32, _max[0].i32,
|
||||
_step[0].i32, _values);
|
||||
obs_properties_t* pr = props;
|
||||
if (get_size() > 1) {
|
||||
pr = obs_properties_create();
|
||||
auto p = obs_properties_add_group(props, get_key().data(), has_name() ? get_name().data() : get_key().data(),
|
||||
OBS_GROUP_NORMAL, pr);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().c_str());
|
||||
} else {
|
||||
auto grp = obs_properties_create();
|
||||
auto p = obs_properties_add_group(props, get_key().c_str(), has_name() ? get_name().c_str() : get_key().c_str(),
|
||||
OBS_GROUP_NORMAL, grp);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().c_str());
|
||||
obs_property_set_long_description(p, get_description().data());
|
||||
}
|
||||
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
p = build_int_property(_field_type, grp, _keys[idx].c_str(), _names[idx].c_str(), _min[idx].i32,
|
||||
_max[idx].i32, _step[idx].i32, _values);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().c_str());
|
||||
}
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
auto p = build_int_property(field_type(), pr, key_at(idx).data(), name_at(idx).data(), _min[idx].i32,
|
||||
_max[idx].i32, _step[idx].i32, _values);
|
||||
if (has_description())
|
||||
obs_property_set_long_description(p, get_description().data());
|
||||
obs_property_int_set_suffix(p, suffix().data());
|
||||
}
|
||||
}
|
||||
|
||||
void gfx::shader::int_parameter::update(obs_data_t* settings)
|
||||
{
|
||||
for (std::size_t idx = 0; idx < get_size(); idx++) {
|
||||
_data[idx].i32 = static_cast<int32_t>(obs_data_get_int(settings, _keys[idx].c_str()) * _scale[idx].i32);
|
||||
_data[idx].i32 = static_cast<int32_t>(obs_data_get_int(settings, key_at(idx).data()) * _scale[idx].i32);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace gfx {
|
|||
basic_data data;
|
||||
};
|
||||
|
||||
struct basic_parameter : public parameter {
|
||||
class basic_parameter : public parameter {
|
||||
// Descriptor
|
||||
basic_field_type _field_type;
|
||||
std::string _suffix;
|
||||
|
@ -59,7 +59,7 @@ namespace gfx {
|
|||
std::vector<basic_data> _scale;
|
||||
|
||||
// Enumeration Information
|
||||
std::vector<basic_enum_data> _values;
|
||||
std::list<basic_enum_data> _values;
|
||||
|
||||
public:
|
||||
basic_parameter(gs::effect_parameter param, std::string prefix);
|
||||
|
@ -68,18 +68,34 @@ namespace gfx {
|
|||
virtual void load_parameter_data(gs::effect_parameter parameter, basic_data& data);
|
||||
|
||||
public:
|
||||
basic_field_type get_field_type();
|
||||
inline basic_field_type field_type()
|
||||
{
|
||||
return _field_type;
|
||||
}
|
||||
|
||||
const std::string& get_suffix();
|
||||
inline std::string_view suffix()
|
||||
{
|
||||
return _suffix;
|
||||
}
|
||||
|
||||
const std::string& get_keys(std::size_t idx);
|
||||
inline std::string_view key_at(std::size_t idx)
|
||||
{
|
||||
if (idx >= get_size())
|
||||
throw std::out_of_range("Index out of range.");
|
||||
return _keys[idx];
|
||||
}
|
||||
|
||||
const std::string& get_names(std::size_t idx);
|
||||
inline std::string_view name_at(std::size_t idx)
|
||||
{
|
||||
if (idx >= get_size())
|
||||
throw std::out_of_range("Index out of range.");
|
||||
return _names[idx];
|
||||
}
|
||||
};
|
||||
|
||||
struct bool_parameter : public basic_parameter {
|
||||
// std::vector<bool> doesn't allow .data()
|
||||
std::vector<std::uint8_t> _data;
|
||||
std::vector<std::int32_t> _data;
|
||||
|
||||
public:
|
||||
bool_parameter(gs::effect_parameter param, std::string prefix);
|
||||
|
|
Loading…
Reference in a new issue