mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-11 06:15:05 +00:00
source-shader: Update to new gfx::shader::shader
This commit is contained in:
parent
e6220b18f6
commit
47dba25052
2 changed files with 88 additions and 266 deletions
|
@ -23,279 +23,97 @@
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
|
|
||||||
#define ST "Source.Shader"
|
#define ST "Source.Shader"
|
||||||
#define ST_WIDTH ST ".Width"
|
|
||||||
#define ST_HEIGHT ST ".Height"
|
|
||||||
|
|
||||||
static std::shared_ptr<source::shader::shader_factory> factory_instance = nullptr;
|
|
||||||
|
|
||||||
void source::shader::shader_factory::initialize()
|
|
||||||
{
|
|
||||||
factory_instance = std::make_shared<source::shader::shader_factory>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void source::shader::shader_factory::finalize()
|
|
||||||
{
|
|
||||||
factory_instance.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<source::shader::shader_factory> source::shader::shader_factory::get()
|
|
||||||
{
|
|
||||||
return factory_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_defaults(obs_data_t* data)
|
|
||||||
{
|
|
||||||
obs_data_set_default_int(data, ST_WIDTH, 1920);
|
|
||||||
obs_data_set_default_int(data, ST_HEIGHT, 1080);
|
|
||||||
obs_data_set_default_string(data, S_SHADER_FILE, obs_module_file("shaders/source/example.effect"));
|
|
||||||
obs_data_set_default_string(data, S_SHADER_TECHNIQUE, "Draw");
|
|
||||||
}
|
|
||||||
|
|
||||||
source::shader::shader_factory::shader_factory()
|
|
||||||
{
|
|
||||||
memset(&_source_info, 0, sizeof(obs_source_info));
|
|
||||||
_source_info.id = "obs-stream-effects-source-shader";
|
|
||||||
_source_info.type = OBS_SOURCE_TYPE_INPUT;
|
|
||||||
_source_info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW;
|
|
||||||
_source_info.get_name = [](void*) { return D_TRANSLATE(ST); };
|
|
||||||
_source_info.get_defaults = get_defaults;
|
|
||||||
|
|
||||||
_source_info.create = [](obs_data_t* data, obs_source_t* self) {
|
|
||||||
try {
|
|
||||||
return static_cast<void*>(new source::shader::shader_instance(data, self));
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to create source, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to create source.");
|
|
||||||
}
|
|
||||||
return static_cast<void*>(nullptr);
|
|
||||||
};
|
|
||||||
_source_info.destroy = [](void* ptr) {
|
|
||||||
try {
|
|
||||||
delete reinterpret_cast<source::shader::shader_instance*>(ptr);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to delete source, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to delete source.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_source_info.get_properties = [](void* ptr) {
|
|
||||||
obs_properties_t* pr = obs_properties_create();
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->properties(pr);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to retrieve options, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to retrieve options.");
|
|
||||||
}
|
|
||||||
return pr;
|
|
||||||
};
|
|
||||||
_source_info.get_width = [](void* ptr) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
return reinterpret_cast<source::shader::shader_instance*>(ptr)->width();
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to retrieve width, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to retrieve width.");
|
|
||||||
}
|
|
||||||
return uint32_t(0);
|
|
||||||
};
|
|
||||||
_source_info.get_height = [](void* ptr) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
return reinterpret_cast<source::shader::shader_instance*>(ptr)->height();
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to retrieve height, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to retrieve height.");
|
|
||||||
}
|
|
||||||
return uint32_t(0);
|
|
||||||
};
|
|
||||||
_source_info.load = [](void* ptr, obs_data_t* data) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->load(data);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to load, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to load.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_source_info.update = [](void* ptr, obs_data_t* data) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->update(data);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to update, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to update.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_source_info.activate = [](void* ptr) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->activate();
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to activate, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to activate.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_source_info.deactivate = [](void* ptr) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->deactivate();
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to deactivate, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to deactivate.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_source_info.video_tick = [](void* ptr, float_t time) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->video_tick(time);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to tick, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to tick.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_source_info.video_render = [](void* ptr, gs_effect_t* effect) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->video_render(effect);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to render, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to render.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_source_info.enum_active_sources = [](void* ptr, obs_source_enum_proc_t enum_callback, void* param) {
|
|
||||||
try {
|
|
||||||
if (ptr)
|
|
||||||
reinterpret_cast<source::shader::shader_instance*>(ptr)->enum_active_sources(enum_callback, param);
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to enumerate sources, error: %s", ex.what());
|
|
||||||
} catch (...) {
|
|
||||||
P_LOG_ERROR("<source-shader> Failed to enumerate sources.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
obs_register_source(&_source_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
source::shader::shader_factory::~shader_factory() {}
|
|
||||||
|
|
||||||
source::shader::shader_instance::shader_instance(obs_data_t* data, obs_source_t* self)
|
source::shader::shader_instance::shader_instance(obs_data_t* data, obs_source_t* self)
|
||||||
: _self(self), _active(true), _width(0), _height(0)
|
: obs::source_instance(data, self), _is_main(false)
|
||||||
{
|
{
|
||||||
_fx = std::make_shared<gfx::effect_source::effect_source>(self);
|
_fx = std::make_shared<gfx::shader::shader>(self, gfx::shader::shader_mode::Source);
|
||||||
_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));
|
|
||||||
|
|
||||||
_rt = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
|
||||||
|
|
||||||
update(data);
|
update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
source::shader::shader_instance::~shader_instance() {}
|
source::shader::shader_instance::~shader_instance() {}
|
||||||
|
|
||||||
uint32_t source::shader::shader_instance::width()
|
uint32_t source::shader::shader_instance::get_width()
|
||||||
{
|
{
|
||||||
return _width;
|
return _fx->width();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t source::shader::shader_instance::height()
|
uint32_t source::shader::shader_instance::get_height()
|
||||||
{
|
{
|
||||||
return _height;
|
return _fx->height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void source::shader::shader_instance::properties(obs_properties_t* props)
|
void source::shader::shader_instance::properties(obs_properties_t* props)
|
||||||
{
|
{
|
||||||
obs_properties_add_int(props, ST_WIDTH, D_TRANSLATE(ST_WIDTH), 1, 32768, 1);
|
|
||||||
obs_properties_add_int(props, ST_HEIGHT, D_TRANSLATE(ST_HEIGHT), 1, 32768, 1);
|
|
||||||
|
|
||||||
_fx->properties(props);
|
_fx->properties(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
void source::shader::shader_instance::load(obs_data_t* data)
|
void source::shader::shader_instance::load(obs_data_t* data)
|
||||||
{
|
{
|
||||||
update(data);
|
_fx->update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void source::shader::shader_instance::update(obs_data_t* data)
|
void source::shader::shader_instance::update(obs_data_t* data)
|
||||||
{
|
{
|
||||||
_width = static_cast<uint32_t>(obs_data_get_int(data, ST_WIDTH));
|
|
||||||
_height = static_cast<uint32_t>(obs_data_get_int(data, ST_HEIGHT));
|
|
||||||
|
|
||||||
_fx->update(data);
|
_fx->update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void source::shader::shader_instance::activate()
|
|
||||||
{
|
|
||||||
_active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void source::shader::shader_instance::deactivate()
|
|
||||||
{
|
|
||||||
_active = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool source::shader::shader_instance::valid_param(std::shared_ptr<gs::effect_parameter> param)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void source::shader::shader_instance::override_param(std::shared_ptr<gs::effect> effect) {}
|
|
||||||
|
|
||||||
void source::shader::shader_instance::enum_active_sources(obs_source_enum_proc_t r, void* p)
|
|
||||||
{
|
|
||||||
_fx->enum_active_sources(r, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void source::shader::shader_instance::video_tick(float_t sec_since_last)
|
void source::shader::shader_instance::video_tick(float_t sec_since_last)
|
||||||
{
|
{
|
||||||
if (_fx->tick(sec_since_last)) {
|
if (_fx->tick(sec_since_last)) {
|
||||||
obs_data_t* data = obs_source_get_settings(_self);
|
obs_data_t* data = obs_source_get_settings(_self);
|
||||||
update(data);
|
_fx->update(data);
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rt_updated = false;
|
_is_main = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void source::shader::shader_instance::video_render(gs_effect_t* effect)
|
void source::shader::shader_instance::video_render(gs_effect_t* effect)
|
||||||
{
|
{
|
||||||
// Grab initial values.
|
if (!_fx) {
|
||||||
gs_effect_t* effect_default = obs_get_base_effect(obs_base_effect::OBS_EFFECT_DEFAULT);
|
|
||||||
|
|
||||||
// Skip filter if anything is wrong.
|
|
||||||
if (!_active || !_width || !_height || !effect_default) {
|
|
||||||
obs_source_skip_video_filter(_self);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_rt_updated) {
|
if (_is_main) { // Dirty hack to only take the value from the first render, which usually is the main view.
|
||||||
try {
|
gs_rect vect;
|
||||||
auto op = _rt->render(_width, _height);
|
gs_get_viewport(&vect);
|
||||||
_fx->render();
|
_fx->set_size(static_cast<uint32_t>(vect.cx), static_cast<uint32_t>(vect.cy));
|
||||||
} catch (...) {
|
_is_main = false;
|
||||||
}
|
|
||||||
_rt_tex = _rt->get_texture();
|
|
||||||
_rt_updated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_rt_tex)
|
_fx->render();
|
||||||
return;
|
}
|
||||||
|
|
||||||
gs_effect_t* ef = effect ? effect : effect_default;
|
std::shared_ptr<source::shader::shader_factory> source::shader::shader_factory::factory_instance = nullptr;
|
||||||
if (gs_eparam_t* prm = gs_effect_get_param_by_name(ef, "image"))
|
|
||||||
gs_effect_set_texture(prm, _rt_tex->get_object());
|
source::shader::shader_factory::shader_factory()
|
||||||
|
{
|
||||||
while (gs_effect_loop(ef, "Draw")) {
|
_info.id = "obs-stream-effects-source-shader";
|
||||||
gs_draw_sprite(nullptr, 0, _width, _height);
|
_info.type = OBS_SOURCE_TYPE_INPUT;
|
||||||
}
|
_info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW;
|
||||||
|
|
||||||
|
finish_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
source::shader::shader_factory::~shader_factory() {}
|
||||||
|
|
||||||
|
const char* source::shader::shader_factory::get_name()
|
||||||
|
{
|
||||||
|
return D_TRANSLATE(ST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void source::shader::shader_factory::get_defaults2(obs_data_t* data) {}
|
||||||
|
|
||||||
|
obs_properties_t* source::shader::shader_factory::get_properties2(source::shader::shader_instance* data)
|
||||||
|
{
|
||||||
|
auto pr = obs_properties_create();
|
||||||
|
obs_properties_set_param(pr, data, nullptr);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
reinterpret_cast<shader_instance*>(data)->properties(pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gfx/gfx-effect-source.hpp"
|
#include "gfx/shader/gfx-shader.hpp"
|
||||||
#include "obs/gs/gs-rendertarget.hpp"
|
#include "obs/gs/gs-rendertarget.hpp"
|
||||||
|
#include "obs/obs-source-factory.hpp"
|
||||||
#include "plugin.hpp"
|
#include "plugin.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -29,53 +30,56 @@ extern "C" {
|
||||||
|
|
||||||
namespace source {
|
namespace source {
|
||||||
namespace shader {
|
namespace shader {
|
||||||
class shader_factory {
|
class shader_instance : public obs::source_instance {
|
||||||
obs_source_info _source_info;
|
std::shared_ptr<gfx::shader::shader> _fx;
|
||||||
|
|
||||||
public: // Singleton
|
bool _is_main;
|
||||||
static void initialize();
|
|
||||||
static void finalize();
|
|
||||||
static std::shared_ptr<shader_factory> get();
|
|
||||||
|
|
||||||
public:
|
|
||||||
shader_factory();
|
|
||||||
~shader_factory();
|
|
||||||
};
|
|
||||||
|
|
||||||
class shader_instance {
|
|
||||||
obs_source_t* _self;
|
|
||||||
bool _active;
|
|
||||||
|
|
||||||
uint32_t _width, _height;
|
|
||||||
|
|
||||||
std::shared_ptr<gs::rendertarget> _rt;
|
|
||||||
bool _rt_updated;
|
|
||||||
std::shared_ptr<gs::texture> _rt_tex;
|
|
||||||
|
|
||||||
std::shared_ptr<gfx::effect_source::effect_source> _fx;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shader_instance(obs_data_t* data, obs_source_t* self);
|
shader_instance(obs_data_t* data, obs_source_t* self);
|
||||||
~shader_instance();
|
virtual ~shader_instance();
|
||||||
|
|
||||||
uint32_t width();
|
virtual uint32_t get_width() override;
|
||||||
uint32_t height();
|
virtual uint32_t get_height() override;
|
||||||
|
|
||||||
void properties(obs_properties_t* props);
|
void properties(obs_properties_t* props);
|
||||||
|
|
||||||
void load(obs_data_t* data);
|
virtual void load(obs_data_t* data) override;
|
||||||
void update(obs_data_t* data);
|
virtual void update(obs_data_t* data) override;
|
||||||
|
|
||||||
void activate();
|
virtual void video_tick(float_t sec_since_last) override;
|
||||||
void deactivate();
|
virtual void video_render(gs_effect_t* effect) override;
|
||||||
|
};
|
||||||
|
|
||||||
bool valid_param(std::shared_ptr<gs::effect_parameter> param);
|
class shader_factory
|
||||||
void override_param(std::shared_ptr<gs::effect> effect);
|
: public obs::source_factory<source::shader::shader_factory, source::shader::shader_instance> {
|
||||||
|
static std::shared_ptr<source::shader::shader_factory> factory_instance;
|
||||||
|
|
||||||
void enum_active_sources(obs_source_enum_proc_t, void*);
|
public: // Singleton
|
||||||
|
static void initialize()
|
||||||
|
{
|
||||||
|
factory_instance = std::make_shared<source::shader::shader_factory>();
|
||||||
|
}
|
||||||
|
|
||||||
void video_tick(float_t sec_since_last);
|
static void finalize()
|
||||||
void video_render(gs_effect_t* effect);
|
{
|
||||||
|
factory_instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<shader_factory> get()
|
||||||
|
{
|
||||||
|
return factory_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
shader_factory();
|
||||||
|
virtual ~shader_factory();
|
||||||
|
|
||||||
|
virtual const char* get_name() override;
|
||||||
|
|
||||||
|
virtual void get_defaults2(obs_data_t* data) override;
|
||||||
|
|
||||||
|
virtual obs_properties_t* get_properties2(source::shader::shader_instance* data) override;
|
||||||
};
|
};
|
||||||
} // namespace shader
|
} // namespace shader
|
||||||
} // namespace source
|
} // namespace source
|
||||||
|
|
Loading…
Reference in a new issue