From c1b3972550f5fa4a74909533192ce9f64d694dda Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Wed, 13 May 2020 08:43:37 +0200 Subject: [PATCH] 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. --- source/gfx/shader/gfx-shader-param-basic.cpp | 202 +++++++++---------- source/gfx/shader/gfx-shader-param-basic.hpp | 30 ++- 2 files changed, 113 insertions(+), 119 deletions(-) diff --git a/source/gfx/shader/gfx-shader-param-basic.cpp b/source/gfx/shader/gfx-shader-param-basic.cpp index cfc558c..3d411e0 100644 --- a/source/gfx/shader/gfx-shader-param-basic.cpp +++ b/source/gfx/shader/gfx-shader-param-basic.cpp @@ -22,14 +22,14 @@ #include #include -#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(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(idx)); + snprintf(string_buffer, sizeof(string_buffer), "%s[%d]", get_key().data(), static_cast(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(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::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(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(defaults[idx])); + obs_data_set_default_double(settings, key_at(idx).data(), static_cast(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 edata) + float_t step, std::list 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(obs_data_get_double(settings, _keys[idx].c_str())) * _scale[idx].f32; + _data[idx].f32 = static_cast(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 edata) + int32_t step, std::list 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(obs_data_get_int(settings, _keys[idx].c_str()) * _scale[idx].i32); + _data[idx].i32 = static_cast(obs_data_get_int(settings, key_at(idx).data()) * _scale[idx].i32); } } diff --git a/source/gfx/shader/gfx-shader-param-basic.hpp b/source/gfx/shader/gfx-shader-param-basic.hpp index 5e567c1..007dfc9 100644 --- a/source/gfx/shader/gfx-shader-param-basic.hpp +++ b/source/gfx/shader/gfx-shader-param-basic.hpp @@ -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 _scale; // Enumeration Information - std::vector _values; + std::list _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 doesn't allow .data() - std::vector _data; + std::vector _data; public: bool_parameter(gs::effect_parameter param, std::string prefix);