diff --git a/source/filters/filter-shader.cpp b/source/filters/filter-shader.cpp index 458acfd..2e0ea5f 100644 --- a/source/filters/filter-shader.cpp +++ b/source/filters/filter-shader.cpp @@ -173,7 +173,7 @@ filter::shader::shader_factory::~shader_factory() {} filter::shader::shader_instance::shader_instance(obs_data_t* data, obs_source_t* self) : _self(self), _active(true), _width(0), _height(0) { - _fx = std::make_shared(); + _fx = std::make_shared(self); _fx->set_valid_property_cb(std::bind(&filter::shader::shader_instance::valid_param, this, std::placeholders::_1)); _fx->set_override_cb(std::bind(&filter::shader::shader_instance::override_param, this, std::placeholders::_1)); diff --git a/source/gfx/gfx-effect-source.cpp b/source/gfx/gfx-effect-source.cpp index 4a1bfc0..86c3e69 100644 --- a/source/gfx/gfx-effect-source.cpp +++ b/source/gfx/gfx-effect-source.cpp @@ -23,11 +23,16 @@ #include #include #include "obs/gs/gs-helper.hpp" +#include "obs/obs-source-tracker.hpp" #include "strings.hpp" #define ST_FILE S_SHADER_FILE #define ST_TECHNIQUE S_SHADER_TECHNIQUE +#define ST_TEXTURE_TYPE "Shader.Texture.Type" +#define ST_TEXTURE_FILE S_FILETYPE_IMAGE +#define ST_TEXTURE_SOURCE S_SOURCETYPE_SOURCE + #define UNIQUE_PREFIX "HelloThisIsPatrick." static std::vector static_parameters{ @@ -36,9 +41,10 @@ static std::vector static_parameters{ "Random", }; -gfx::effect_source::parameter::parameter(std::shared_ptr effect, - std::shared_ptr param) - : _effect(effect), _param(param), _description(""), _formulae(""), _visible(true) +gfx::effect_source::parameter::parameter(std::shared_ptr parent, + std::shared_ptr effect, + std::shared_ptr param) + : _parent(parent), _effect(effect), _param(param), _description(""), _formulae(""), _visible(true) { if (!effect) throw std::invalid_argument("effect"); @@ -87,8 +93,9 @@ std::shared_ptr gfx::effect_source::parameter::get_param() } std::shared_ptr - gfx::effect_source::parameter::create(std::shared_ptr effect, - std::shared_ptr param) + gfx::effect_source::parameter::create(std::shared_ptr parent, + std::shared_ptr effect, + std::shared_ptr param) { if (!effect) throw std::invalid_argument("effect"); @@ -99,7 +106,7 @@ std::shared_ptr switch (param->get_type()) { case gs::effect_parameter::type::Boolean: - return std::make_shared(effect, param); + return std::make_shared(parent, effect, param); case gs::effect_parameter::type::Float: case gs::effect_parameter::type::Float2: case gs::effect_parameter::type::Float3: @@ -108,19 +115,20 @@ std::shared_ptr case gs::effect_parameter::type::Integer2: case gs::effect_parameter::type::Integer3: case gs::effect_parameter::type::Integer4: - return std::make_shared(effect, param); + return std::make_shared(parent, effect, param); case gs::effect_parameter::type::Matrix: - return std::make_shared(effect, param); + return std::make_shared(parent, effect, param); case gs::effect_parameter::type::Texture: - return std::make_shared(effect, param); + return std::make_shared(parent, effect, param); } return nullptr; } -gfx::effect_source::bool_parameter::bool_parameter(std::shared_ptr effect, - std::shared_ptr param) - : parameter(effect, param) +gfx::effect_source::bool_parameter::bool_parameter(std::shared_ptr parent, + std::shared_ptr effect, + std::shared_ptr param) + : parameter(parent, effect, param) { if (param->get_type() != gs::effect_parameter::type::Boolean) throw std::bad_cast(); @@ -128,7 +136,8 @@ gfx::effect_source::bool_parameter::bool_parameter(std::shared_ptr param->get_default_bool(_value); } -void gfx::effect_source::bool_parameter::defaults(obs_properties_t* props, obs_data_t* data) { +void gfx::effect_source::bool_parameter::defaults(obs_properties_t* props, obs_data_t* data) +{ obs_data_set_default_bool(data, _name.c_str(), _value); obs_data_set_bool(data, _name.c_str(), _value); } @@ -159,9 +168,10 @@ void gfx::effect_source::bool_parameter::assign() _param->set_bool(_value); } -gfx::effect_source::value_parameter::value_parameter(std::shared_ptr effect, - std::shared_ptr param) - : parameter(effect, param) +gfx::effect_source::value_parameter::value_parameter(std::shared_ptr parent, + std::shared_ptr effect, + std::shared_ptr param) + : parameter(parent, effect, param) { std::shared_ptr min = param->get_annotation("minimum"); std::shared_ptr max = param->get_annotation("maximum"); @@ -547,9 +557,10 @@ void gfx::effect_source::value_parameter::assign() } } -gfx::effect_source::matrix_parameter::matrix_parameter(std::shared_ptr effect, - std::shared_ptr param) - : parameter(effect, param) +gfx::effect_source::matrix_parameter::matrix_parameter(std::shared_ptr parent, + std::shared_ptr effect, + std::shared_ptr param) + : parameter(parent, effect, param) { std::shared_ptr min = param->get_annotation("minimum"); std::shared_ptr max = param->get_annotation("maximum"); @@ -617,7 +628,7 @@ void gfx::effect_source::matrix_parameter::defaults(obs_properties_t* props, obs } for (size_t y = 0; y < 4; y++) { - size_t idx = x * 4 + y; + size_t idx = x * 4 + y; obs_data_set_double(data, _cache.name[idx].c_str(), v_ref.ptr[y]); obs_data_set_default_double(data, _cache.name[idx].c_str(), v_ref.ptr[y]); } @@ -713,9 +724,10 @@ void gfx::effect_source::matrix_parameter::assign() _param->set_matrix(_value); } -gfx::effect_source::string_parameter::string_parameter(std::shared_ptr effect, - std::shared_ptr param) - : parameter(effect, param) +gfx::effect_source::string_parameter::string_parameter(std::shared_ptr parent, + std::shared_ptr effect, + std::shared_ptr param) + : parameter(parent, effect, param) { param->get_default_string(_value); } @@ -734,24 +746,167 @@ void gfx::effect_source::string_parameter::prepare() {} void gfx::effect_source::string_parameter::assign() {} -gfx::effect_source::texture_parameter::texture_parameter(std::shared_ptr effect, - std::shared_ptr param) - : parameter(effect, param) -{} +void gfx::effect_source::texture_parameter::load_texture(std::string file) +{ + _file_name = file; -void gfx::effect_source::texture_parameter::defaults(obs_properties_t* props, obs_data_t* data) {} + struct stat st; + if (os_stat(_file_name.c_str(), &st) == -1) { + _last_size = 0; + _last_modify_time = 0; + _last_create_time = 0; + throw std::system_error(std::error_code(ENOENT, std::system_category()), file.c_str()); + } else { + _last_size = st.st_size; + _last_modify_time = st.st_mtime; + _last_create_time = st.st_ctime; + } -void gfx::effect_source::texture_parameter::properties(obs_properties_t* props) {} + _file = std::make_shared(_file_name); +} + +gfx::effect_source::texture_parameter::texture_parameter(std::shared_ptr parent, + std::shared_ptr effect, + std::shared_ptr param) + : parameter(parent, effect, param) +{ + _cache.name[0] = _name + ".Type"; + _cache.visible_name[0] = _visible_name + " " + D_TRANSLATE(ST_TEXTURE_TYPE); + _cache.name[1] = _name + ".File"; + _cache.visible_name[1] = _visible_name; + _cache.name[2] = _name + ".Source"; + _cache.visible_name[2] = _visible_name; +} + +bool gfx::effect_source::texture_parameter::modified2(obs_properties_t* props, obs_property_t* property, + obs_data_t* settings) +{ + _mode = static_cast(obs_data_get_int(settings, _cache.name[0].c_str())); + if (_mode == texture_mode::FILE) { + obs_property_set_visible(obs_properties_get(props, _cache.name[1].c_str()), true); + obs_property_set_visible(obs_properties_get(props, _cache.name[2].c_str()), false); + } else if (_mode == texture_mode::SOURCE) { + obs_property_set_visible(obs_properties_get(props, _cache.name[1].c_str()), false); + obs_property_set_visible(obs_properties_get(props, _cache.name[2].c_str()), true); + } + return true; +} + +void gfx::effect_source::texture_parameter::defaults(obs_properties_t* props, obs_data_t* data) +{ + obs_data_set_int(data, _cache.name[0].c_str(), static_cast(_mode)); + obs_data_set_string(data, _cache.name[1].c_str(), _file_name.c_str()); + obs_data_set_string(data, _cache.name[2].c_str(), _source_name.c_str()); +} + +void gfx::effect_source::texture_parameter::properties(obs_properties_t* props) +{ + auto grp = props; + if (!util::are_property_groups_broken()) { + grp = obs_properties_create(); + auto p = obs_properties_add_group(props, _name.c_str(), _visible_name.c_str(), OBS_GROUP_NORMAL, grp); + obs_property_set_long_description(p, _description.c_str()); + obs_property_set_visible(p, _visible); + } + + { + auto p = obs_properties_add_list(grp, _cache.name[0].c_str(), _cache.visible_name[0].c_str(), + OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_modified_callback2( + p, + [](void* priv, obs_properties_t* props, obs_property_t* property, obs_data_t* settings) { + return reinterpret_cast(priv)->modified2(props, property, settings); + }, + this); + obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_TEXTURE_TYPE))); + obs_property_list_add_int(p, D_TRANSLATE(ST_TEXTURE_FILE), static_cast(texture_mode::FILE)); + obs_property_list_add_int(p, D_TRANSLATE(ST_TEXTURE_SOURCE), static_cast(texture_mode::SOURCE)); + } + { + auto p = obs_properties_add_path(grp, _cache.name[1].c_str(), _cache.visible_name[1].c_str(), OBS_PATH_FILE, + "Textures (" S_FILEFILTERS_TEXTURE ")", nullptr); + obs_property_set_long_description(p, _description.c_str()); + } + { + auto p = obs_properties_add_list(grp, _cache.name[2].c_str(), _cache.visible_name[2].c_str(), + OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); + obs::source_tracker::get()->enumerate( + [&p](std::string name, obs_source_t*) { + obs_property_list_add_string(p, std::string(name + " (Source)").c_str(), name.c_str()); + return false; + }, + obs::source_tracker::filter_video_sources); + obs::source_tracker::get()->enumerate( + [&p](std::string name, obs_source_t*) { + obs_property_list_add_string(p, std::string(name + " (Scene)").c_str(), name.c_str()); + return false; + }, + obs::source_tracker::filter_scenes); + obs_property_set_long_description(p, _description.c_str()); + } +} void gfx::effect_source::texture_parameter::remove_properties(obs_properties_t* props) {} -void gfx::effect_source::texture_parameter::update(obs_data_t* data) {} +void gfx::effect_source::texture_parameter::update(obs_data_t* data) +{ + try { + if (_mode == texture_mode::FILE) { + load_texture(obs_data_get_string(data, _cache.name[1].c_str())); + } else if (_mode == texture_mode::SOURCE) { + _source_name = obs_data_get_string(data, _cache.name[2].c_str()); + if (!_source || (obs_source_get_name(_source->get()) != _source_name)) { + _source = std::make_shared(_source_name); + if (!_parent.expired()) + _source_renderer = std::make_shared(_source, _parent.lock()->get_self()); + } + } + } catch (std::exception& ex) { + P_LOG_ERROR("Update failed, error: %s", ex.what()); + } +} -void gfx::effect_source::texture_parameter::tick(float_t time) {} +void gfx::effect_source::texture_parameter::tick(float_t time) +{ + _last_check += time; + if (_last_check >= 0.5f) { + _last_check -= 0.5f; + bool changed = false; -void gfx::effect_source::texture_parameter::prepare() {} + struct stat st; + if (os_stat(_file_name.c_str(), &st) != -1) { + changed = + (_last_size != st.st_size) || (_last_modify_time != st.st_mtime) || (_last_create_time != st.st_ctime); + } + if (changed) { + try { + load_texture(_file_name); + } catch (std::exception& ex) { + P_LOG_ERROR("Loading texture \"%s\" failed, error: %s", _file_name.c_str(), ex.what()); + } + } + } +} -void gfx::effect_source::texture_parameter::assign() {} +void gfx::effect_source::texture_parameter::prepare() +{ + if (_mode == texture_mode::SOURCE) { + if (_source_renderer) { + _source_tex = _source_renderer->render(_source->width(), _source->height()); + } + } +} + +void gfx::effect_source::texture_parameter::assign() +{ + if (_mode == texture_mode::FILE) { + if (_file) + _param->set_texture(_file); + } else { + if (_source_tex) + _param->set_texture(_source_tex); + } +} bool gfx::effect_source::effect_source::modified2(obs_properties_t* props, obs_property_t* property, obs_data_t* settings) @@ -825,12 +980,12 @@ void gfx::effect_source::effect_source::load_file(std::string file) if (skip) continue; - _params.emplace(identity, parameter::create(_effect, prm)); + _params.emplace(identity, parameter::create(this->shared_from_this(), _effect, prm)); } } -gfx::effect_source::effect_source::effect_source() - : _last_check(0), _last_size(0), _last_modify_time(0), _last_create_time(0), _time(0), _time_active(0), +gfx::effect_source::effect_source::effect_source(obs_source_t* self) + : _self(self), _last_check(0), _last_size(0), _last_modify_time(0), _last_create_time(0), _time(0), _time_active(0), _time_since_last_tick(0) { auto gctx = gs::context(); @@ -988,6 +1143,11 @@ void gfx::effect_source::effect_source::render() gs_blend_state_pop(); } +obs_source_t* gfx::effect_source::effect_source::get_self() +{ + return _self; +} + void gfx::effect_source::effect_source::set_valid_property_cb(valid_property_cb_t cb) { _cb_valid = cb; diff --git a/source/gfx/gfx-effect-source.hpp b/source/gfx/gfx-effect-source.hpp index ee5f458..92e9055 100644 --- a/source/gfx/gfx-effect-source.hpp +++ b/source/gfx/gfx-effect-source.hpp @@ -62,8 +62,12 @@ namespace gfx { SOURCE, }; + class effect_source; + class parameter { protected: + std::weak_ptr _parent; + std::shared_ptr _effect; std::shared_ptr _param; @@ -74,7 +78,8 @@ namespace gfx { bool _visible; public: - parameter(std::shared_ptr effect, std::shared_ptr param); + parameter(std::shared_ptr parent, std::shared_ptr effect, + std::shared_ptr param); virtual ~parameter(); virtual void defaults(obs_properties_t* props, obs_data_t* data) = 0; @@ -94,15 +99,17 @@ namespace gfx { std::shared_ptr get_param(); public: - static std::shared_ptr create(std::shared_ptr effect, - std::shared_ptr param); + static std::shared_ptr + create(std::shared_ptr parent, std::shared_ptr effect, + std::shared_ptr param); }; class bool_parameter : public parameter { bool _value; public: - bool_parameter(std::shared_ptr effect, std::shared_ptr param); + bool_parameter(std::shared_ptr parent, + std::shared_ptr effect, std::shared_ptr param); virtual void defaults(obs_properties_t* props, obs_data_t* data) override; @@ -144,7 +151,8 @@ namespace gfx { } _cache; public: - value_parameter(std::shared_ptr effect, std::shared_ptr param); + value_parameter(std::shared_ptr parent, + std::shared_ptr effect, std::shared_ptr param); virtual void defaults(obs_properties_t* props, obs_data_t* data) override; @@ -174,7 +182,8 @@ namespace gfx { } _cache; public: - matrix_parameter(std::shared_ptr effect, std::shared_ptr param); + matrix_parameter(std::shared_ptr parent, + std::shared_ptr effect, std::shared_ptr param); virtual void defaults(obs_properties_t* props, obs_data_t* data) override; @@ -196,7 +205,8 @@ namespace gfx { string_mode _mode = string_mode::TEXT; public: - string_parameter(std::shared_ptr effect, std::shared_ptr param); + string_parameter(std::shared_ptr parent, + std::shared_ptr effect, std::shared_ptr param); virtual void defaults(obs_properties_t* props, obs_data_t* data) override; @@ -217,14 +227,30 @@ namespace gfx { std::string _file_name; std::shared_ptr _file; + float_t _last_check; + size_t _last_size; + time_t _last_modify_time; + time_t _last_create_time; + std::string _source_name; std::shared_ptr _source; std::shared_ptr _source_renderer; + std::shared_ptr _source_tex; texture_mode _mode = texture_mode::FILE; + struct { + std::string name[4]; + std::string visible_name[4]; + } _cache; + + void load_texture(std::string file); + public: - texture_parameter(std::shared_ptr effect, std::shared_ptr param); + texture_parameter(std::shared_ptr parent, + std::shared_ptr effect, std::shared_ptr param); + + bool modified2(obs_properties_t* props, obs_property_t* property, obs_data_t* settings); virtual void defaults(obs_properties_t* props, obs_data_t* data) override; @@ -245,7 +271,9 @@ namespace gfx { typedef std::function param)> valid_property_cb_t; typedef std::function effect)> param_override_cb_t; - class effect_source { + class effect_source : public std::enable_shared_from_this { + obs_source_t* _self; + std::string _file; std::shared_ptr _effect; std::string _tech; @@ -273,7 +301,7 @@ namespace gfx { void load_file(std::string file); public: - effect_source(); + effect_source(obs_source_t* self); ~effect_source(); void properties(obs_properties_t* props); @@ -284,6 +312,8 @@ namespace gfx { void render(); + obs_source_t* get_self(); + public: void set_valid_property_cb(valid_property_cb_t cb); diff --git a/source/sources/source-shader.cpp b/source/sources/source-shader.cpp index a239336..5c6f24f 100644 --- a/source/sources/source-shader.cpp +++ b/source/sources/source-shader.cpp @@ -177,7 +177,7 @@ source::shader::shader_factory::~shader_factory() {} source::shader::shader_instance::shader_instance(obs_data_t* data, obs_source_t* self) : _self(self), _active(true), _width(0), _height(0) { - _fx = std::make_shared(); + _fx = std::make_shared(self); _fx->set_valid_property_cb(std::bind(&source::shader::shader_instance::valid_param, this, std::placeholders::_1)); _fx->set_override_cb(std::bind(&source::shader::shader_instance::override_param, this, std::placeholders::_1));