mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-10 22:05:06 +00:00
project: Refactoring Part 1
This commit is contained in:
parent
b91700e74f
commit
d56c0d6f25
10 changed files with 977 additions and 904 deletions
|
@ -74,13 +74,6 @@
|
||||||
#define P_MASK_MULTIPLIER "Filter.Blur.Mask.Multiplier"
|
#define P_MASK_MULTIPLIER "Filter.Blur.Mask.Multiplier"
|
||||||
#define P_COLORFORMAT "Filter.Blur.ColorFormat"
|
#define P_COLORFORMAT "Filter.Blur.ColorFormat"
|
||||||
|
|
||||||
// Initializer & Finalizer
|
|
||||||
INITIALIZER(filterBlurFactoryInitializer)
|
|
||||||
{
|
|
||||||
initializerFunctions.push_back([] { filter::blur::blur_factory::initialize(); });
|
|
||||||
finalizerFunctions.push_back([] { filter::blur::blur_factory::finalize(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ColorFormat : uint64_t { // ToDo: Refactor into full class.
|
enum ColorFormat : uint64_t { // ToDo: Refactor into full class.
|
||||||
RGB,
|
RGB,
|
||||||
YUV, // 701
|
YUV, // 701
|
||||||
|
@ -88,7 +81,344 @@ enum ColorFormat : uint64_t { // ToDo: Refactor into full class.
|
||||||
|
|
||||||
static uint8_t const max_kernel_size = 25;
|
static uint8_t const max_kernel_size = 25;
|
||||||
|
|
||||||
bool filter::blur::blur_instance::apply_shared_param(gs_texture_t* input, float texelX, float texelY)
|
// Initializer & Finalizer
|
||||||
|
INITIALIZER(filterBlurFactoryInitializer)
|
||||||
|
{
|
||||||
|
initializerFunctions.push_back([] { filter::blur::factory::initialize(); });
|
||||||
|
finalizerFunctions.push_back([] { filter::blur::factory::finalize(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<filter::blur::factory> factory_instance = nullptr;
|
||||||
|
|
||||||
|
void filter::blur::factory::initialize()
|
||||||
|
{
|
||||||
|
factory_instance = std::make_shared<filter::blur::factory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::finalize()
|
||||||
|
{
|
||||||
|
factory_instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<filter::blur::factory> filter::blur::factory::get()
|
||||||
|
{
|
||||||
|
return factory_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter::blur::factory::factory()
|
||||||
|
{
|
||||||
|
memset(&source_info, 0, sizeof(obs_source_info));
|
||||||
|
source_info.id = "obs-stream-effects-filter-blur";
|
||||||
|
source_info.type = OBS_SOURCE_TYPE_FILTER;
|
||||||
|
source_info.output_flags = OBS_SOURCE_VIDEO;
|
||||||
|
source_info.get_name = get_name;
|
||||||
|
source_info.get_defaults = get_defaults;
|
||||||
|
source_info.get_properties = get_properties;
|
||||||
|
|
||||||
|
source_info.create = create;
|
||||||
|
source_info.destroy = destroy;
|
||||||
|
source_info.update = update;
|
||||||
|
source_info.activate = activate;
|
||||||
|
source_info.deactivate = deactivate;
|
||||||
|
source_info.video_tick = video_tick;
|
||||||
|
source_info.video_render = video_render;
|
||||||
|
|
||||||
|
obs_register_source(&source_info);
|
||||||
|
|
||||||
|
auto osi = obs_get_signal_handler();
|
||||||
|
signal_handler_connect(osi, "source_create", scene_create_handler, this);
|
||||||
|
signal_handler_connect(osi, "source_destroy", scene_destroy_handler, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter::blur::factory::~factory()
|
||||||
|
{
|
||||||
|
auto osi = obs_get_signal_handler();
|
||||||
|
signal_handler_disconnect(osi, "source_create", scene_create_handler, this);
|
||||||
|
signal_handler_disconnect(osi, "source_destroy", scene_destroy_handler, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::on_list_fill()
|
||||||
|
{
|
||||||
|
obs_enter_graphics();
|
||||||
|
|
||||||
|
{
|
||||||
|
char* file = obs_module_file("effects/blur.effect");
|
||||||
|
try {
|
||||||
|
blur_effect = std::make_shared<gs::effect>(file);
|
||||||
|
} catch (std::runtime_error ex) {
|
||||||
|
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
||||||
|
}
|
||||||
|
bfree(file);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char* file = obs_module_file("effects/color-conversion.effect");
|
||||||
|
try {
|
||||||
|
color_converter_effect = std::make_shared<gs::effect>(file);
|
||||||
|
} catch (std::runtime_error ex) {
|
||||||
|
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
||||||
|
}
|
||||||
|
bfree(file);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
char* file = obs_module_file("effects/mask.effect");
|
||||||
|
try {
|
||||||
|
mask_effect = std::make_shared<gs::effect>(file);
|
||||||
|
} catch (std::runtime_error ex) {
|
||||||
|
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
||||||
|
}
|
||||||
|
bfree(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_kernel_textures();
|
||||||
|
obs_leave_graphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::on_list_empty()
|
||||||
|
{
|
||||||
|
obs_enter_graphics();
|
||||||
|
blur_effect.reset();
|
||||||
|
kernels.clear();
|
||||||
|
color_converter_effect.reset();
|
||||||
|
mask_effect.reset();
|
||||||
|
obs_leave_graphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::generate_gaussian_kernels()
|
||||||
|
{
|
||||||
|
// 2D texture, horizontal is value, vertical is kernel size.
|
||||||
|
size_t size_power_of_two = size_t(pow(2, util::math::get_power_of_two_exponent_ceil(max_kernel_size)));
|
||||||
|
|
||||||
|
std::vector<float_t> texture_data(size_power_of_two * size_power_of_two);
|
||||||
|
std::vector<float_t> math_data(size_power_of_two);
|
||||||
|
std::shared_ptr<std::vector<float_t>> kernel_data;
|
||||||
|
|
||||||
|
for (size_t width = 1; width <= max_kernel_size; width++) {
|
||||||
|
size_t v = (width - 1) * size_power_of_two;
|
||||||
|
kernel_data = std::make_shared<std::vector<float_t>>(size_power_of_two);
|
||||||
|
|
||||||
|
// Calculate and normalize
|
||||||
|
float_t sum = 0;
|
||||||
|
for (size_t p = 0; p <= width; p++) {
|
||||||
|
math_data[p] = float_t(Gaussian1D(double_t(p), double_t(width)));
|
||||||
|
sum += math_data[p] * (p > 0 ? 2 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize to Texture Buffer
|
||||||
|
double_t inverse_sum = 1.0 / sum;
|
||||||
|
for (size_t p = 0; p <= width; p++) {
|
||||||
|
texture_data[v + p] = float_t(math_data[p] * inverse_sum);
|
||||||
|
kernel_data->at(p) = texture_data[v + p];
|
||||||
|
}
|
||||||
|
|
||||||
|
gaussian_kernels.insert({uint8_t(width), kernel_data});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Texture
|
||||||
|
try {
|
||||||
|
auto texture_buffer = reinterpret_cast<uint8_t*>(texture_data.data());
|
||||||
|
auto unsafe_buffer = const_cast<const uint8_t**>(&texture_buffer);
|
||||||
|
|
||||||
|
kernels.insert_or_assign(filter::blur::type::Gaussian,
|
||||||
|
std::make_shared<gs::texture>(uint32_t(size_power_of_two), uint32_t(size_power_of_two),
|
||||||
|
GS_R32F, 1, unsafe_buffer, gs::texture::flags::None));
|
||||||
|
} catch (std::runtime_error ex) {
|
||||||
|
P_LOG_ERROR("<filter-blur> Failed to create gaussian kernel texture.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::generate_kernel_textures()
|
||||||
|
{
|
||||||
|
generate_gaussian_kernels();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* filter::blur::factory::create(obs_data_t* data, obs_source_t* parent)
|
||||||
|
{
|
||||||
|
if (get()->sources.empty()) {
|
||||||
|
get()->on_list_fill();
|
||||||
|
}
|
||||||
|
filter::blur::instance* ptr = new filter::blur::instance(data, parent);
|
||||||
|
get()->sources.push_back(ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::destroy(void* inptr)
|
||||||
|
{
|
||||||
|
filter::blur::instance* ptr = reinterpret_cast<filter::blur::instance*>(inptr);
|
||||||
|
get()->sources.remove(ptr);
|
||||||
|
if (get()->sources.empty()) {
|
||||||
|
get()->on_list_empty();
|
||||||
|
}
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::get_defaults(obs_data_t* data)
|
||||||
|
{
|
||||||
|
obs_data_set_default_int(data, P_TYPE, filter::blur::type::Box);
|
||||||
|
obs_data_set_default_int(data, P_SIZE, 5);
|
||||||
|
|
||||||
|
// Bilateral Only
|
||||||
|
obs_data_set_default_double(data, P_BILATERAL_SMOOTHING, 50.0);
|
||||||
|
obs_data_set_default_double(data, P_BILATERAL_SHARPNESS, 90.0);
|
||||||
|
|
||||||
|
// Masking
|
||||||
|
obs_data_set_default_bool(data, P_MASK, false);
|
||||||
|
obs_data_set_default_int(data, P_MASK_TYPE, mask_type::Region);
|
||||||
|
obs_data_set_default_double(data, P_MASK_REGION_LEFT, 0.0);
|
||||||
|
obs_data_set_default_double(data, P_MASK_REGION_RIGHT, 0.0);
|
||||||
|
obs_data_set_default_double(data, P_MASK_REGION_TOP, 0.0);
|
||||||
|
obs_data_set_default_double(data, P_MASK_REGION_BOTTOM, 0.0);
|
||||||
|
obs_data_set_default_double(data, P_MASK_REGION_FEATHER, 0.0);
|
||||||
|
obs_data_set_default_double(data, P_MASK_REGION_FEATHER_SHIFT, 0.0);
|
||||||
|
obs_data_set_default_bool(data, P_MASK_REGION_INVERT, false);
|
||||||
|
char* default_file = obs_module_file("white.png");
|
||||||
|
obs_data_set_default_string(data, P_MASK_IMAGE, default_file);
|
||||||
|
bfree(default_file);
|
||||||
|
obs_data_set_default_string(data, P_MASK_SOURCE, "");
|
||||||
|
obs_data_set_default_int(data, P_MASK_COLOR, 0xFFFFFFFFull);
|
||||||
|
obs_data_set_default_double(data, P_MASK_MULTIPLIER, 1.0);
|
||||||
|
|
||||||
|
// Directional Blur
|
||||||
|
obs_data_set_default_bool(data, P_DIRECTIONAL, false);
|
||||||
|
obs_data_set_default_double(data, P_DIRECTIONAL_ANGLE, 0.0);
|
||||||
|
|
||||||
|
// Scaling
|
||||||
|
obs_data_set_default_bool(data, P_STEPSCALE, false);
|
||||||
|
obs_data_set_default_double(data, P_STEPSCALE_X, 100.0);
|
||||||
|
obs_data_set_default_double(data, P_STEPSCALE_Y, 100.0);
|
||||||
|
|
||||||
|
// Advanced
|
||||||
|
obs_data_set_default_bool(data, S_ADVANCED, false);
|
||||||
|
obs_data_set_default_int(data, P_COLORFORMAT, ColorFormat::RGB);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_properties_t* filter::blur::factory::get_properties(void* inptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<filter::blur::instance*>(inptr)->get_properties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::update(void* inptr, obs_data_t* settings)
|
||||||
|
{
|
||||||
|
reinterpret_cast<filter::blur::instance*>(inptr)->update(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* filter::blur::factory::get_name(void*)
|
||||||
|
{
|
||||||
|
return P_TRANSLATE(SOURCE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t filter::blur::factory::get_width(void* inptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<filter::blur::instance*>(inptr)->get_width();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t filter::blur::factory::get_height(void* inptr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<filter::blur::instance*>(inptr)->get_height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::activate(void* inptr)
|
||||||
|
{
|
||||||
|
reinterpret_cast<filter::blur::instance*>(inptr)->activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::deactivate(void* inptr)
|
||||||
|
{
|
||||||
|
reinterpret_cast<filter::blur::instance*>(inptr)->deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::video_tick(void* inptr, float delta)
|
||||||
|
{
|
||||||
|
reinterpret_cast<filter::blur::instance*>(inptr)->video_tick(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::video_render(void* inptr, gs_effect_t* effect)
|
||||||
|
{
|
||||||
|
reinterpret_cast<filter::blur::instance*>(inptr)->video_render(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::scene_create_handler(void* ptr, calldata_t* data)
|
||||||
|
{
|
||||||
|
filter::blur::factory* self = reinterpret_cast<filter::blur::factory*>(ptr);
|
||||||
|
obs_source_t* source = nullptr;
|
||||||
|
calldata_get_ptr(data, "source", &source);
|
||||||
|
obs_scene_t* scene = obs_scene_from_source(source);
|
||||||
|
if (scene) {
|
||||||
|
self->scenes.insert_or_assign(std::string(obs_source_get_name(source)), scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::scene_destroy_handler(void* ptr, calldata_t* data)
|
||||||
|
{
|
||||||
|
filter::blur::factory* self = reinterpret_cast<filter::blur::factory*>(ptr);
|
||||||
|
obs_source_t* source = nullptr;
|
||||||
|
calldata_get_ptr(data, "source", &source);
|
||||||
|
obs_scene_t* scene = obs_scene_from_source(source);
|
||||||
|
if (scene) {
|
||||||
|
self->scenes.erase(std::string(obs_source_get_name(source)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<gs::effect> filter::blur::factory::get_effect(filter::blur::type)
|
||||||
|
{
|
||||||
|
return blur_effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filter::blur::factory::get_technique(filter::blur::type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case type::Box:
|
||||||
|
return "Box";
|
||||||
|
case type::Gaussian:
|
||||||
|
return "Gaussian";
|
||||||
|
case type::Bilateral:
|
||||||
|
return "Bilateral";
|
||||||
|
case type::BoxLinear:
|
||||||
|
return "BoxLinear";
|
||||||
|
case type::GaussianLinear:
|
||||||
|
return "GaussianLinear";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<gs::effect> filter::blur::factory::get_color_converter_effect()
|
||||||
|
{
|
||||||
|
return color_converter_effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<gs::effect> filter::blur::factory::get_mask_effect()
|
||||||
|
{
|
||||||
|
return mask_effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<gs::texture> filter::blur::factory::get_kernel(filter::blur::type type)
|
||||||
|
{
|
||||||
|
return kernels.at(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<std::vector<float_t>> filter::blur::factory::get_gaussian_kernel(uint8_t size)
|
||||||
|
{
|
||||||
|
return gaussian_kernels.at(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_scene_t* filter::blur::factory::get_scene(std::string name)
|
||||||
|
{
|
||||||
|
auto kv = scenes.find(name);
|
||||||
|
if (kv != scenes.end()) {
|
||||||
|
return kv->second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::blur::factory::enum_scenes(std::function<bool(obs_scene_t*)> fnc)
|
||||||
|
{
|
||||||
|
for (auto kv : scenes) {
|
||||||
|
if (!fnc(kv.second)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool filter::blur::instance::apply_shared_param(gs_texture_t* input, float texelX, float texelY)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
|
@ -113,7 +443,7 @@ bool filter::blur::blur_instance::apply_shared_param(gs_texture_t* input, float
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::blur::blur_instance::apply_bilateral_param()
|
bool filter::blur::instance::apply_bilateral_param()
|
||||||
{
|
{
|
||||||
if (type != type::Bilateral)
|
if (type != type::Bilateral)
|
||||||
return false;
|
return false;
|
||||||
|
@ -129,9 +459,9 @@ bool filter::blur::blur_instance::apply_bilateral_param()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::blur::blur_instance::apply_gaussian_param(uint8_t width)
|
bool filter::blur::instance::apply_gaussian_param(uint8_t width)
|
||||||
{
|
{
|
||||||
auto kernel = filter::blur::blur_factory::get()->get_gaussian_kernel(width);
|
auto kernel = filter::blur::factory::get()->get_gaussian_kernel(width);
|
||||||
|
|
||||||
if (blur_effect->has_parameter("kernel")) {
|
if (blur_effect->has_parameter("kernel")) {
|
||||||
blur_effect->get_parameter("kernel").set_float_array(&(kernel->front()), kernel->size());
|
blur_effect->get_parameter("kernel").set_float_array(&(kernel->front()), kernel->size());
|
||||||
|
@ -140,7 +470,7 @@ bool filter::blur::blur_instance::apply_gaussian_param(uint8_t width)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptr<gs::effect> effect,
|
bool filter::blur::instance::apply_mask_parameters(std::shared_ptr<gs::effect> effect,
|
||||||
gs_texture_t* original_texture, gs_texture_t* blurred_texture)
|
gs_texture_t* original_texture, gs_texture_t* blurred_texture)
|
||||||
{
|
{
|
||||||
if (effect->has_parameter("image_orig")) {
|
if (effect->has_parameter("image_orig")) {
|
||||||
|
@ -205,7 +535,7 @@ bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptr<gs::effe
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::blur::blur_instance::modified_properties(void*, obs_properties_t* props, obs_property*,
|
bool filter::blur::instance::modified_properties(void*, obs_properties_t* props, obs_property*,
|
||||||
obs_data_t* settings)
|
obs_data_t* settings)
|
||||||
{
|
{
|
||||||
// bilateral blur
|
// bilateral blur
|
||||||
|
@ -249,7 +579,7 @@ bool filter::blur::blur_instance::modified_properties(void*, obs_properties_t* p
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::blur::blur_instance::can_log()
|
bool filter::blur::instance::can_log()
|
||||||
{
|
{
|
||||||
// Only allow logging errors every 200ms.
|
// Only allow logging errors every 200ms.
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
@ -258,7 +588,7 @@ bool filter::blur::blur_instance::can_log()
|
||||||
return std::chrono::duration_cast<std::chrono::milliseconds>(delta) > std::chrono::milliseconds(200);
|
return std::chrono::duration_cast<std::chrono::milliseconds>(delta) > std::chrono::milliseconds(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::blur::blur_instance::blur_instance(obs_data_t* settings, obs_source_t* parent)
|
filter::blur::instance::instance(obs_data_t* settings, obs_source_t* parent)
|
||||||
{
|
{
|
||||||
m_source = parent;
|
m_source = parent;
|
||||||
|
|
||||||
|
@ -273,18 +603,18 @@ filter::blur::blur_instance::blur_instance(obs_data_t* settings, obs_source_t* p
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get initial Blur effect.
|
// Get initial Blur effect.
|
||||||
blur_effect = filter::blur::blur_factory::get()->get_effect(filter::blur::type::Box);
|
blur_effect = filter::blur::factory::get()->get_effect(filter::blur::type::Box);
|
||||||
|
|
||||||
update(settings);
|
update(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::blur::blur_instance::~blur_instance()
|
filter::blur::instance::~instance()
|
||||||
{
|
{
|
||||||
this->rt_primary.reset();
|
this->rt_primary.reset();
|
||||||
this->rt_secondary.reset();
|
this->rt_secondary.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_properties_t* filter::blur::blur_instance::get_properties()
|
obs_properties_t* filter::blur::instance::get_properties()
|
||||||
{
|
{
|
||||||
obs_properties_t* pr = obs_properties_create();
|
obs_properties_t* pr = obs_properties_create();
|
||||||
obs_property_t* p = NULL;
|
obs_property_t* p = NULL;
|
||||||
|
@ -352,9 +682,9 @@ obs_properties_t* filter::blur::blur_instance::get_properties()
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
p);
|
p);
|
||||||
blur_factory::get()->enum_scenes([this, p](obs_scene_t* scene) {
|
factory::get()->enum_scenes([this, p](obs_scene_t* scene) {
|
||||||
struct data {
|
struct data {
|
||||||
blur_instance* self;
|
instance* self;
|
||||||
obs_property_t* prop;
|
obs_property_t* prop;
|
||||||
std::string parent_name;
|
std::string parent_name;
|
||||||
};
|
};
|
||||||
|
@ -404,11 +734,11 @@ obs_properties_t* filter::blur::blur_instance::get_properties()
|
||||||
return pr;
|
return pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::blur::blur_instance::update(obs_data_t* settings)
|
void filter::blur::instance::update(obs_data_t* settings)
|
||||||
{
|
{
|
||||||
type = (blur::type)obs_data_get_int(settings, P_TYPE);
|
type = (blur::type)obs_data_get_int(settings, P_TYPE);
|
||||||
blur_effect = blur_factory::get()->get_effect(type);
|
blur_effect = factory::get()->get_effect(type);
|
||||||
blur_technique = blur_factory::get()->get_technique(type);
|
blur_technique = factory::get()->get_technique(type);
|
||||||
size = (uint64_t)obs_data_get_int(settings, P_SIZE);
|
size = (uint64_t)obs_data_get_int(settings, P_SIZE);
|
||||||
|
|
||||||
// bilateral blur
|
// bilateral blur
|
||||||
|
@ -463,21 +793,21 @@ void filter::blur::blur_instance::update(obs_data_t* settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::blur::blur_instance::get_width()
|
uint32_t filter::blur::instance::get_width()
|
||||||
{
|
{
|
||||||
return uint32_t(0);
|
return uint32_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::blur::blur_instance::get_height()
|
uint32_t filter::blur::instance::get_height()
|
||||||
{
|
{
|
||||||
return uint32_t(0);
|
return uint32_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::blur::blur_instance::activate() {}
|
void filter::blur::instance::activate() {}
|
||||||
|
|
||||||
void filter::blur::blur_instance::deactivate() {}
|
void filter::blur::instance::deactivate() {}
|
||||||
|
|
||||||
void filter::blur::blur_instance::video_tick(float)
|
void filter::blur::instance::video_tick(float)
|
||||||
{
|
{
|
||||||
if (mask.type == mask_type::Image) {
|
if (mask.type == mask_type::Image) {
|
||||||
if (mask.image.path_old != mask.image.path) {
|
if (mask.image.path_old != mask.image.path) {
|
||||||
|
@ -503,7 +833,7 @@ void filter::blur::blur_instance::video_tick(float)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::blur::blur_instance::video_render(gs_effect_t* effect)
|
void filter::blur::instance::video_render(gs_effect_t* effect)
|
||||||
{
|
{
|
||||||
obs_source_t* parent = obs_filter_get_parent(this->m_source);
|
obs_source_t* parent = obs_filter_get_parent(this->m_source);
|
||||||
obs_source_t* target = obs_filter_get_target(this->m_source);
|
obs_source_t* target = obs_filter_get_target(this->m_source);
|
||||||
|
@ -514,7 +844,7 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect)
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> colorConversionEffect = blur_factory::get()->get_color_converter_effect();
|
std::shared_ptr<gs::effect> colorConversionEffect = factory::get()->get_color_converter_effect();
|
||||||
|
|
||||||
// Verify that we can actually run first.
|
// Verify that we can actually run first.
|
||||||
if (!target || !parent || !this->m_source) {
|
if (!target || !parent || !this->m_source) {
|
||||||
|
@ -802,7 +1132,7 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect)
|
||||||
this->mask.source.texture = this->mask.source.source_texture->render(source_width, source_height);
|
this->mask.source.texture = this->mask.source.source_texture->render(source_width, source_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> mask_effect = blur_factory::get()->get_mask_effect();
|
std::shared_ptr<gs::effect> mask_effect = factory::get()->get_mask_effect();
|
||||||
apply_mask_parameters(mask_effect, tex_source->get_object(), tex_intermediate->get_object());
|
apply_mask_parameters(mask_effect, tex_source->get_object(), tex_intermediate->get_object());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -874,333 +1204,3 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::blur::blur_factory::blur_factory()
|
|
||||||
{
|
|
||||||
memset(&source_info, 0, sizeof(obs_source_info));
|
|
||||||
source_info.id = "obs-stream-effects-filter-blur";
|
|
||||||
source_info.type = OBS_SOURCE_TYPE_FILTER;
|
|
||||||
source_info.output_flags = OBS_SOURCE_VIDEO;
|
|
||||||
source_info.get_name = get_name;
|
|
||||||
source_info.get_defaults = get_defaults;
|
|
||||||
source_info.get_properties = get_properties;
|
|
||||||
|
|
||||||
source_info.create = create;
|
|
||||||
source_info.destroy = destroy;
|
|
||||||
source_info.update = update;
|
|
||||||
source_info.activate = activate;
|
|
||||||
source_info.deactivate = deactivate;
|
|
||||||
source_info.video_tick = video_tick;
|
|
||||||
source_info.video_render = video_render;
|
|
||||||
|
|
||||||
obs_register_source(&source_info);
|
|
||||||
|
|
||||||
auto osi = obs_get_signal_handler();
|
|
||||||
signal_handler_connect(osi, "source_create", scene_create_handler, this);
|
|
||||||
signal_handler_connect(osi, "source_destroy", scene_destroy_handler, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
filter::blur::blur_factory::~blur_factory()
|
|
||||||
{
|
|
||||||
auto osi = obs_get_signal_handler();
|
|
||||||
signal_handler_disconnect(osi, "source_create", scene_create_handler, this);
|
|
||||||
signal_handler_disconnect(osi, "source_destroy", scene_destroy_handler, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::on_list_fill()
|
|
||||||
{
|
|
||||||
obs_enter_graphics();
|
|
||||||
|
|
||||||
{
|
|
||||||
char* file = obs_module_file("effects/blur.effect");
|
|
||||||
try {
|
|
||||||
blur_effect = std::make_shared<gs::effect>(file);
|
|
||||||
} catch (std::runtime_error ex) {
|
|
||||||
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
|
||||||
}
|
|
||||||
bfree(file);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char* file = obs_module_file("effects/color-conversion.effect");
|
|
||||||
try {
|
|
||||||
color_converter_effect = std::make_shared<gs::effect>(file);
|
|
||||||
} catch (std::runtime_error ex) {
|
|
||||||
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
|
||||||
}
|
|
||||||
bfree(file);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char* file = obs_module_file("effects/mask.effect");
|
|
||||||
try {
|
|
||||||
mask_effect = std::make_shared<gs::effect>(file);
|
|
||||||
} catch (std::runtime_error ex) {
|
|
||||||
P_LOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file, ex.what());
|
|
||||||
}
|
|
||||||
bfree(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_kernel_textures();
|
|
||||||
obs_leave_graphics();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::on_list_empty()
|
|
||||||
{
|
|
||||||
obs_enter_graphics();
|
|
||||||
blur_effect.reset();
|
|
||||||
kernels.clear();
|
|
||||||
color_converter_effect.reset();
|
|
||||||
mask_effect.reset();
|
|
||||||
obs_leave_graphics();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::generate_gaussian_kernels()
|
|
||||||
{
|
|
||||||
// 2D texture, horizontal is value, vertical is kernel size.
|
|
||||||
size_t size_power_of_two = size_t(pow(2, util::math::get_power_of_two_exponent_ceil(max_kernel_size)));
|
|
||||||
|
|
||||||
std::vector<float_t> texture_data(size_power_of_two * size_power_of_two);
|
|
||||||
std::vector<float_t> math_data(size_power_of_two);
|
|
||||||
std::shared_ptr<std::vector<float_t>> kernel_data;
|
|
||||||
|
|
||||||
for (size_t width = 1; width <= max_kernel_size; width++) {
|
|
||||||
size_t v = (width - 1) * size_power_of_two;
|
|
||||||
kernel_data = std::make_shared<std::vector<float_t>>(size_power_of_two);
|
|
||||||
|
|
||||||
// Calculate and normalize
|
|
||||||
float_t sum = 0;
|
|
||||||
for (size_t p = 0; p <= width; p++) {
|
|
||||||
math_data[p] = float_t(Gaussian1D(double_t(p), double_t(width)));
|
|
||||||
sum += math_data[p] * (p > 0 ? 2 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize to Texture Buffer
|
|
||||||
double_t inverse_sum = 1.0 / sum;
|
|
||||||
for (size_t p = 0; p <= width; p++) {
|
|
||||||
texture_data[v + p] = float_t(math_data[p] * inverse_sum);
|
|
||||||
kernel_data->at(p) = texture_data[v + p];
|
|
||||||
}
|
|
||||||
|
|
||||||
gaussian_kernels.insert({uint8_t(width), kernel_data});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Texture
|
|
||||||
try {
|
|
||||||
auto texture_buffer = reinterpret_cast<uint8_t*>(texture_data.data());
|
|
||||||
auto unsafe_buffer = const_cast<const uint8_t**>(&texture_buffer);
|
|
||||||
|
|
||||||
kernels.insert_or_assign(filter::blur::type::Gaussian,
|
|
||||||
std::make_shared<gs::texture>(uint32_t(size_power_of_two), uint32_t(size_power_of_two),
|
|
||||||
GS_R32F, 1, unsafe_buffer, gs::texture::flags::None));
|
|
||||||
} catch (std::runtime_error ex) {
|
|
||||||
P_LOG_ERROR("<filter-blur> Failed to create gaussian kernel texture.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::generate_kernel_textures()
|
|
||||||
{
|
|
||||||
generate_gaussian_kernels();
|
|
||||||
}
|
|
||||||
|
|
||||||
void* filter::blur::blur_factory::create(obs_data_t* data, obs_source_t* parent)
|
|
||||||
{
|
|
||||||
if (get()->sources.empty()) {
|
|
||||||
get()->on_list_fill();
|
|
||||||
}
|
|
||||||
filter::blur::blur_instance* ptr = new filter::blur::blur_instance(data, parent);
|
|
||||||
get()->sources.push_back(ptr);
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::destroy(void* inptr)
|
|
||||||
{
|
|
||||||
filter::blur::blur_instance* ptr = reinterpret_cast<filter::blur::blur_instance*>(inptr);
|
|
||||||
get()->sources.remove(ptr);
|
|
||||||
if (get()->sources.empty()) {
|
|
||||||
get()->on_list_empty();
|
|
||||||
}
|
|
||||||
delete ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::get_defaults(obs_data_t* data)
|
|
||||||
{
|
|
||||||
obs_data_set_default_int(data, P_TYPE, filter::blur::type::Box);
|
|
||||||
obs_data_set_default_int(data, P_SIZE, 5);
|
|
||||||
|
|
||||||
// Bilateral Only
|
|
||||||
obs_data_set_default_double(data, P_BILATERAL_SMOOTHING, 50.0);
|
|
||||||
obs_data_set_default_double(data, P_BILATERAL_SHARPNESS, 90.0);
|
|
||||||
|
|
||||||
// Masking
|
|
||||||
obs_data_set_default_bool(data, P_MASK, false);
|
|
||||||
obs_data_set_default_int(data, P_MASK_TYPE, mask_type::Region);
|
|
||||||
obs_data_set_default_double(data, P_MASK_REGION_LEFT, 0.0);
|
|
||||||
obs_data_set_default_double(data, P_MASK_REGION_RIGHT, 0.0);
|
|
||||||
obs_data_set_default_double(data, P_MASK_REGION_TOP, 0.0);
|
|
||||||
obs_data_set_default_double(data, P_MASK_REGION_BOTTOM, 0.0);
|
|
||||||
obs_data_set_default_double(data, P_MASK_REGION_FEATHER, 0.0);
|
|
||||||
obs_data_set_default_double(data, P_MASK_REGION_FEATHER_SHIFT, 0.0);
|
|
||||||
obs_data_set_default_bool(data, P_MASK_REGION_INVERT, false);
|
|
||||||
char* default_file = obs_module_file("white.png");
|
|
||||||
obs_data_set_default_string(data, P_MASK_IMAGE, default_file);
|
|
||||||
bfree(default_file);
|
|
||||||
obs_data_set_default_string(data, P_MASK_SOURCE, "");
|
|
||||||
obs_data_set_default_int(data, P_MASK_COLOR, 0xFFFFFFFFull);
|
|
||||||
obs_data_set_default_double(data, P_MASK_MULTIPLIER, 1.0);
|
|
||||||
|
|
||||||
// Directional Blur
|
|
||||||
obs_data_set_default_bool(data, P_DIRECTIONAL, false);
|
|
||||||
obs_data_set_default_double(data, P_DIRECTIONAL_ANGLE, 0.0);
|
|
||||||
|
|
||||||
// Scaling
|
|
||||||
obs_data_set_default_bool(data, P_STEPSCALE, false);
|
|
||||||
obs_data_set_default_double(data, P_STEPSCALE_X, 100.0);
|
|
||||||
obs_data_set_default_double(data, P_STEPSCALE_Y, 100.0);
|
|
||||||
|
|
||||||
// Advanced
|
|
||||||
obs_data_set_default_bool(data, S_ADVANCED, false);
|
|
||||||
obs_data_set_default_int(data, P_COLORFORMAT, ColorFormat::RGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_properties_t* filter::blur::blur_factory::get_properties(void* inptr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<filter::blur::blur_instance*>(inptr)->get_properties();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::update(void* inptr, obs_data_t* settings)
|
|
||||||
{
|
|
||||||
reinterpret_cast<filter::blur::blur_instance*>(inptr)->update(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* filter::blur::blur_factory::get_name(void*)
|
|
||||||
{
|
|
||||||
return P_TRANSLATE(SOURCE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t filter::blur::blur_factory::get_width(void* inptr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<filter::blur::blur_instance*>(inptr)->get_width();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t filter::blur::blur_factory::get_height(void* inptr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<filter::blur::blur_instance*>(inptr)->get_height();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::activate(void* inptr)
|
|
||||||
{
|
|
||||||
reinterpret_cast<filter::blur::blur_instance*>(inptr)->activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::deactivate(void* inptr)
|
|
||||||
{
|
|
||||||
reinterpret_cast<filter::blur::blur_instance*>(inptr)->deactivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::video_tick(void* inptr, float delta)
|
|
||||||
{
|
|
||||||
reinterpret_cast<filter::blur::blur_instance*>(inptr)->video_tick(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::video_render(void* inptr, gs_effect_t* effect)
|
|
||||||
{
|
|
||||||
reinterpret_cast<filter::blur::blur_instance*>(inptr)->video_render(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::scene_create_handler(void* ptr, calldata_t* data)
|
|
||||||
{
|
|
||||||
filter::blur::blur_factory* self = reinterpret_cast<filter::blur::blur_factory*>(ptr);
|
|
||||||
obs_source_t* source = nullptr;
|
|
||||||
calldata_get_ptr(data, "source", &source);
|
|
||||||
obs_scene_t* scene = obs_scene_from_source(source);
|
|
||||||
if (scene) {
|
|
||||||
self->scenes.insert_or_assign(std::string(obs_source_get_name(source)), scene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::scene_destroy_handler(void* ptr, calldata_t* data)
|
|
||||||
{
|
|
||||||
filter::blur::blur_factory* self = reinterpret_cast<filter::blur::blur_factory*>(ptr);
|
|
||||||
obs_source_t* source = nullptr;
|
|
||||||
calldata_get_ptr(data, "source", &source);
|
|
||||||
obs_scene_t* scene = obs_scene_from_source(source);
|
|
||||||
if (scene) {
|
|
||||||
self->scenes.erase(std::string(obs_source_get_name(source)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_effect(filter::blur::type)
|
|
||||||
{
|
|
||||||
return blur_effect;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string filter::blur::blur_factory::get_technique(filter::blur::type type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case type::Box:
|
|
||||||
return "Box";
|
|
||||||
case type::Gaussian:
|
|
||||||
return "Gaussian";
|
|
||||||
case type::Bilateral:
|
|
||||||
return "Bilateral";
|
|
||||||
case type::BoxLinear:
|
|
||||||
return "BoxLinear";
|
|
||||||
case type::GaussianLinear:
|
|
||||||
return "GaussianLinear";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_color_converter_effect()
|
|
||||||
{
|
|
||||||
return color_converter_effect;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> filter::blur::blur_factory::get_mask_effect()
|
|
||||||
{
|
|
||||||
return mask_effect;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<gs::texture> filter::blur::blur_factory::get_kernel(filter::blur::type type)
|
|
||||||
{
|
|
||||||
return kernels.at(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<std::vector<float_t>> filter::blur::blur_factory::get_gaussian_kernel(uint8_t size)
|
|
||||||
{
|
|
||||||
return gaussian_kernels.at(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_scene_t* filter::blur::blur_factory::get_scene(std::string name)
|
|
||||||
{
|
|
||||||
auto kv = scenes.find(name);
|
|
||||||
if (kv != scenes.end()) {
|
|
||||||
return kv->second;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::enum_scenes(std::function<bool(obs_scene_t*)> fnc)
|
|
||||||
{
|
|
||||||
for (auto kv : scenes) {
|
|
||||||
if (!fnc(kv.second)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static filter::blur::blur_factory* factory_instance = nullptr;
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::initialize()
|
|
||||||
{
|
|
||||||
factory_instance = new filter::blur::blur_factory();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::blur::blur_factory::finalize()
|
|
||||||
{
|
|
||||||
delete factory_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter::blur::blur_factory* filter::blur::blur_factory::get()
|
|
||||||
{
|
|
||||||
return factory_instance;
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,10 +17,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef OBS_STREAM_EFFECTS_FILTER_BLUR_HPP
|
|
||||||
#define OBS_STREAM_EFFECTS_FILTER_BLUR_HPP
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -29,8 +26,8 @@
|
||||||
#include "gfx-source-texture.hpp"
|
#include "gfx-source-texture.hpp"
|
||||||
#include "gs-effect.hpp"
|
#include "gs-effect.hpp"
|
||||||
#include "gs-helper.hpp"
|
#include "gs-helper.hpp"
|
||||||
#include "gs-texture.hpp"
|
|
||||||
#include "gs-rendertarget.hpp"
|
#include "gs-rendertarget.hpp"
|
||||||
|
#include "gs-texture.hpp"
|
||||||
#include "plugin.hpp"
|
#include "plugin.hpp"
|
||||||
|
|
||||||
// OBS
|
// OBS
|
||||||
|
@ -45,6 +42,8 @@
|
||||||
|
|
||||||
namespace filter {
|
namespace filter {
|
||||||
namespace blur {
|
namespace blur {
|
||||||
|
class instance;
|
||||||
|
|
||||||
enum type : int64_t {
|
enum type : int64_t {
|
||||||
Box,
|
Box,
|
||||||
Gaussian,
|
Gaussian,
|
||||||
|
@ -59,7 +58,74 @@ namespace filter {
|
||||||
Source,
|
Source,
|
||||||
};
|
};
|
||||||
|
|
||||||
class blur_instance {
|
class factory {
|
||||||
|
friend class std::_Ptr_base<filter::blur::factory>;
|
||||||
|
|
||||||
|
obs_source_info source_info;
|
||||||
|
std::list<instance*> sources;
|
||||||
|
std::shared_ptr<gs::effect> color_converter_effect;
|
||||||
|
std::shared_ptr<gs::effect> mask_effect;
|
||||||
|
|
||||||
|
std::shared_ptr<gs::effect> blur_effect;
|
||||||
|
std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels;
|
||||||
|
std::map<uint8_t, std::shared_ptr<std::vector<float_t>>> gaussian_kernels;
|
||||||
|
|
||||||
|
std::map<std::string, obs_scene_t*> scenes;
|
||||||
|
|
||||||
|
public: // Singleton
|
||||||
|
static void initialize();
|
||||||
|
static void finalize();
|
||||||
|
static std::shared_ptr<factory> get();
|
||||||
|
|
||||||
|
public:
|
||||||
|
factory();
|
||||||
|
~factory();
|
||||||
|
|
||||||
|
void on_list_fill();
|
||||||
|
void on_list_empty();
|
||||||
|
|
||||||
|
void generate_gaussian_kernels();
|
||||||
|
void generate_kernel_textures();
|
||||||
|
|
||||||
|
static void* create(obs_data_t* settings, obs_source_t* self);
|
||||||
|
static void destroy(void* source);
|
||||||
|
|
||||||
|
static void get_defaults(obs_data_t* settings);
|
||||||
|
static obs_properties_t* get_properties(void* source);
|
||||||
|
static void update(void* source, obs_data_t* settings);
|
||||||
|
|
||||||
|
static const char* get_name(void* source);
|
||||||
|
static uint32_t get_width(void* source);
|
||||||
|
static uint32_t get_height(void* source);
|
||||||
|
|
||||||
|
static void activate(void* source);
|
||||||
|
static void deactivate(void* source);
|
||||||
|
|
||||||
|
static void video_tick(void* source, float delta);
|
||||||
|
static void video_render(void* source, gs_effect_t* effect);
|
||||||
|
|
||||||
|
static void scene_create_handler(void* ptr, calldata_t* data);
|
||||||
|
static void scene_destroy_handler(void* ptr, calldata_t* data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<gs::effect> get_effect(filter::blur::type type);
|
||||||
|
|
||||||
|
std::string get_technique(filter::blur::type type);
|
||||||
|
|
||||||
|
std::shared_ptr<gs::effect> get_color_converter_effect();
|
||||||
|
|
||||||
|
std::shared_ptr<gs::effect> get_mask_effect();
|
||||||
|
|
||||||
|
std::shared_ptr<gs::texture> get_kernel(filter::blur::type type);
|
||||||
|
|
||||||
|
std::shared_ptr<std::vector<float_t>> get_gaussian_kernel(uint8_t size);
|
||||||
|
|
||||||
|
obs_scene_t* get_scene(std::string name);
|
||||||
|
|
||||||
|
void enum_scenes(std::function<bool(obs_scene_t*)> fnc);
|
||||||
|
};
|
||||||
|
|
||||||
|
class instance {
|
||||||
obs_source_t* m_source;
|
obs_source_t* m_source;
|
||||||
std::shared_ptr<gs::rendertarget> rt_source;
|
std::shared_ptr<gs::rendertarget> rt_source;
|
||||||
std::shared_ptr<gs::rendertarget> rt_primary;
|
std::shared_ptr<gs::rendertarget> rt_primary;
|
||||||
|
@ -134,8 +200,8 @@ namespace filter {
|
||||||
bool can_log();
|
bool can_log();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
blur_instance(obs_data_t* settings, obs_source_t* self);
|
instance(obs_data_t* settings, obs_source_t* self);
|
||||||
~blur_instance();
|
~instance();
|
||||||
|
|
||||||
obs_properties_t* get_properties();
|
obs_properties_t* get_properties();
|
||||||
void update(obs_data_t*);
|
void update(obs_data_t*);
|
||||||
|
@ -149,75 +215,5 @@ namespace filter {
|
||||||
void video_tick(float);
|
void video_tick(float);
|
||||||
void video_render(gs_effect_t*);
|
void video_render(gs_effect_t*);
|
||||||
};
|
};
|
||||||
|
|
||||||
class blur_factory {
|
|
||||||
obs_source_info source_info;
|
|
||||||
std::list<blur_instance*> sources;
|
|
||||||
std::shared_ptr<gs::effect> color_converter_effect;
|
|
||||||
std::shared_ptr<gs::effect> mask_effect;
|
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> blur_effect;
|
|
||||||
std::map<filter::blur::type, std::shared_ptr<gs::texture>> kernels;
|
|
||||||
std::map<uint8_t, std::shared_ptr<std::vector<float_t>>> gaussian_kernels;
|
|
||||||
|
|
||||||
std::map<std::string, obs_scene_t*> scenes;
|
|
||||||
|
|
||||||
private:
|
|
||||||
blur_factory();
|
|
||||||
~blur_factory();
|
|
||||||
|
|
||||||
void on_list_fill();
|
|
||||||
void on_list_empty();
|
|
||||||
|
|
||||||
void generate_gaussian_kernels();
|
|
||||||
void generate_kernel_textures();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static void* create(obs_data_t* settings, obs_source_t* self);
|
|
||||||
static void destroy(void* source);
|
|
||||||
|
|
||||||
static void get_defaults(obs_data_t* settings);
|
|
||||||
static obs_properties_t* get_properties(void* source);
|
|
||||||
static void update(void* source, obs_data_t* settings);
|
|
||||||
|
|
||||||
static const char* get_name(void* source);
|
|
||||||
static uint32_t get_width(void* source);
|
|
||||||
static uint32_t get_height(void* source);
|
|
||||||
|
|
||||||
static void activate(void* source);
|
|
||||||
static void deactivate(void* source);
|
|
||||||
|
|
||||||
static void video_tick(void* source, float delta);
|
|
||||||
static void video_render(void* source, gs_effect_t* effect);
|
|
||||||
|
|
||||||
static void scene_create_handler(void* ptr, calldata_t* data);
|
|
||||||
static void scene_destroy_handler(void* ptr, calldata_t* data);
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::shared_ptr<gs::effect> get_effect(filter::blur::type type);
|
|
||||||
|
|
||||||
std::string get_technique(filter::blur::type type);
|
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> get_color_converter_effect();
|
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> get_mask_effect();
|
|
||||||
|
|
||||||
std::shared_ptr<gs::texture> get_kernel(filter::blur::type type);
|
|
||||||
|
|
||||||
std::shared_ptr<std::vector<float_t>> get_gaussian_kernel(uint8_t size);
|
|
||||||
|
|
||||||
obs_scene_t* get_scene(std::string name);
|
|
||||||
|
|
||||||
void enum_scenes(std::function<bool(obs_scene_t*)> fnc);
|
|
||||||
|
|
||||||
public: // Singleton
|
|
||||||
static void initialize();
|
|
||||||
static void finalize();
|
|
||||||
static blur_factory* get();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace blur
|
} // namespace blur
|
||||||
|
|
||||||
} // namespace filter
|
} // namespace filter
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -22,14 +22,30 @@
|
||||||
#include "strings.hpp"
|
#include "strings.hpp"
|
||||||
|
|
||||||
// Initializer & Finalizer
|
// Initializer & Finalizer
|
||||||
static filter::displacement_factory* filterDisplacementInstance;
|
|
||||||
INITIALIZER(FilterDisplacementInit)
|
INITIALIZER(FilterDisplacementInit)
|
||||||
{
|
{
|
||||||
initializerFunctions.push_back([] { filterDisplacementInstance = new filter::displacement_factory(); });
|
initializerFunctions.push_back([] { filter::displacement::factory::initialize(); });
|
||||||
finalizerFunctions.push_back([] { delete filterDisplacementInstance; });
|
finalizerFunctions.push_back([] { filter::displacement::factory::finalize(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::displacement_factory::displacement_factory()
|
static std::shared_ptr<filter::displacement::factory> factory_instance = nullptr;
|
||||||
|
|
||||||
|
void filter::displacement::factory::initialize()
|
||||||
|
{
|
||||||
|
factory_instance = std::make_shared<filter::displacement::factory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::displacement::factory::finalize()
|
||||||
|
{
|
||||||
|
factory_instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<filter::displacement::factory> filter::displacement::factory::get()
|
||||||
|
{
|
||||||
|
return factory_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter::displacement::factory::factory()
|
||||||
{
|
{
|
||||||
memset(&sourceInfo, 0, sizeof(obs_source_info));
|
memset(&sourceInfo, 0, sizeof(obs_source_info));
|
||||||
sourceInfo.id = "obs-stream-effects-filter-displacement";
|
sourceInfo.id = "obs-stream-effects-filter-displacement";
|
||||||
|
@ -52,34 +68,34 @@ filter::displacement_factory::displacement_factory()
|
||||||
obs_register_source(&sourceInfo);
|
obs_register_source(&sourceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::displacement_factory::~displacement_factory() {}
|
filter::displacement::factory::~factory() {}
|
||||||
|
|
||||||
const char* filter::displacement_factory::get_name(void*)
|
const char* filter::displacement::factory::get_name(void*)
|
||||||
{
|
{
|
||||||
return P_TRANSLATE(S_FILTER_DISPLACEMENT);
|
return P_TRANSLATE(S_FILTER_DISPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* filter::displacement_factory::create(obs_data_t* data, obs_source_t* source)
|
void* filter::displacement::factory::create(obs_data_t* data, obs_source_t* source)
|
||||||
{
|
{
|
||||||
return new displacement(data, source);
|
return new instance(data, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::destroy(void* ptr)
|
void filter::displacement::factory::destroy(void* ptr)
|
||||||
{
|
{
|
||||||
delete reinterpret_cast<displacement*>(ptr);
|
delete reinterpret_cast<instance*>(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::displacement_factory::get_width(void* ptr)
|
uint32_t filter::displacement::factory::get_width(void* ptr)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<displacement*>(ptr)->get_width();
|
return reinterpret_cast<instance*>(ptr)->get_width();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::displacement_factory::get_height(void* ptr)
|
uint32_t filter::displacement::factory::get_height(void* ptr)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<displacement*>(ptr)->get_height();
|
return reinterpret_cast<instance*>(ptr)->get_height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::get_defaults(obs_data_t* data)
|
void filter::displacement::factory::get_defaults(obs_data_t* data)
|
||||||
{
|
{
|
||||||
char* disp = obs_module_file("filter-displacement/neutral.png");
|
char* disp = obs_module_file("filter-displacement/neutral.png");
|
||||||
obs_data_set_default_string(data, S_FILTER_DISPLACEMENT_FILE, disp);
|
obs_data_set_default_string(data, S_FILTER_DISPLACEMENT_FILE, disp);
|
||||||
|
@ -88,13 +104,13 @@ void filter::displacement_factory::get_defaults(obs_data_t* data)
|
||||||
bfree(disp);
|
bfree(disp);
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_properties_t* filter::displacement_factory::get_properties(void* ptr)
|
obs_properties_t* filter::displacement::factory::get_properties(void* ptr)
|
||||||
{
|
{
|
||||||
obs_properties_t* pr = obs_properties_create();
|
obs_properties_t* pr = obs_properties_create();
|
||||||
|
|
||||||
std::string path = "";
|
std::string path = "";
|
||||||
if (ptr)
|
if (ptr)
|
||||||
path = reinterpret_cast<displacement*>(ptr)->get_file();
|
path = reinterpret_cast<instance*>(ptr)->get_file();
|
||||||
|
|
||||||
obs_properties_add_path(pr, S_FILTER_DISPLACEMENT_FILE, P_TRANSLATE(S_FILTER_DISPLACEMENT_FILE),
|
obs_properties_add_path(pr, S_FILTER_DISPLACEMENT_FILE, P_TRANSLATE(S_FILTER_DISPLACEMENT_FILE),
|
||||||
obs_path_type::OBS_PATH_FILE, P_TRANSLATE(S_FILTER_DISPLACEMENT_FILE_TYPES), path.c_str());
|
obs_path_type::OBS_PATH_FILE, P_TRANSLATE(S_FILTER_DISPLACEMENT_FILE_TYPES), path.c_str());
|
||||||
|
@ -105,42 +121,42 @@ obs_properties_t* filter::displacement_factory::get_properties(void* ptr)
|
||||||
return pr;
|
return pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::update(void* ptr, obs_data_t* data)
|
void filter::displacement::factory::update(void* ptr, obs_data_t* data)
|
||||||
{
|
{
|
||||||
reinterpret_cast<displacement*>(ptr)->update(data);
|
reinterpret_cast<instance*>(ptr)->update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::activate(void* ptr)
|
void filter::displacement::factory::activate(void* ptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<displacement*>(ptr)->activate();
|
reinterpret_cast<instance*>(ptr)->activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::deactivate(void* ptr)
|
void filter::displacement::factory::deactivate(void* ptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<displacement*>(ptr)->deactivate();
|
reinterpret_cast<instance*>(ptr)->deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::show(void* ptr)
|
void filter::displacement::factory::show(void* ptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<displacement*>(ptr)->show();
|
reinterpret_cast<instance*>(ptr)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::hide(void* ptr)
|
void filter::displacement::factory::hide(void* ptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<displacement*>(ptr)->hide();
|
reinterpret_cast<instance*>(ptr)->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::video_tick(void* ptr, float time)
|
void filter::displacement::factory::video_tick(void* ptr, float time)
|
||||||
{
|
{
|
||||||
reinterpret_cast<displacement*>(ptr)->video_tick(time);
|
reinterpret_cast<instance*>(ptr)->video_tick(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement_factory::video_render(void* ptr, gs_effect_t* effect)
|
void filter::displacement::factory::video_render(void* ptr, gs_effect_t* effect)
|
||||||
{
|
{
|
||||||
reinterpret_cast<displacement*>(ptr)->video_render(effect);
|
reinterpret_cast<instance*>(ptr)->video_render(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement::validate_file_texture(std::string file)
|
void filter::displacement::instance::validate_file_texture(std::string file)
|
||||||
{
|
{
|
||||||
bool do_update = false;
|
bool do_update = false;
|
||||||
|
|
||||||
|
@ -168,7 +184,7 @@ void filter::displacement::validate_file_texture(std::string file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::displacement::displacement(obs_data_t* data, obs_source_t* context)
|
filter::displacement::instance::instance(obs_data_t* data, obs_source_t* context)
|
||||||
: m_self(context), m_active(true), m_timer(0), m_effect(nullptr), m_distance(0), m_file_create_time(0),
|
: m_self(context), m_active(true), m_timer(0), m_effect(nullptr), m_distance(0), m_file_create_time(0),
|
||||||
m_file_modified_time(0), m_file_size(0)
|
m_file_modified_time(0), m_file_size(0)
|
||||||
{
|
{
|
||||||
|
@ -183,13 +199,13 @@ filter::displacement::displacement(obs_data_t* data, obs_source_t* context)
|
||||||
update(data);
|
update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::displacement::~displacement()
|
filter::displacement::instance::~instance()
|
||||||
{
|
{
|
||||||
m_effect.reset();
|
m_effect.reset();
|
||||||
m_file_texture.reset();
|
m_file_texture.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement::update(obs_data_t* data)
|
void filter::displacement::instance::update(obs_data_t* data)
|
||||||
{
|
{
|
||||||
validate_file_texture(obs_data_get_string(data, S_FILTER_DISPLACEMENT_FILE));
|
validate_file_texture(obs_data_get_string(data, S_FILTER_DISPLACEMENT_FILE));
|
||||||
|
|
||||||
|
@ -198,25 +214,25 @@ void filter::displacement::update(obs_data_t* data)
|
||||||
float_t(obs_data_get_double(data, S_FILTER_DISPLACEMENT_SCALE)));
|
float_t(obs_data_get_double(data, S_FILTER_DISPLACEMENT_SCALE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::displacement::get_width()
|
uint32_t filter::displacement::instance::get_width()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::displacement::get_height()
|
uint32_t filter::displacement::instance::get_height()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement::activate() {}
|
void filter::displacement::instance::activate() {}
|
||||||
|
|
||||||
void filter::displacement::deactivate() {}
|
void filter::displacement::instance::deactivate() {}
|
||||||
|
|
||||||
void filter::displacement::show() {}
|
void filter::displacement::instance::show() {}
|
||||||
|
|
||||||
void filter::displacement::hide() {}
|
void filter::displacement::instance::hide() {}
|
||||||
|
|
||||||
void filter::displacement::video_tick(float time)
|
void filter::displacement::instance::video_tick(float time)
|
||||||
{
|
{
|
||||||
m_timer += time;
|
m_timer += time;
|
||||||
if (m_timer >= 1.0) {
|
if (m_timer >= 1.0) {
|
||||||
|
@ -230,7 +246,7 @@ float interp(float a, float b, float v)
|
||||||
return (a * (1.0f - v)) + (b * v);
|
return (a * (1.0f - v)) + (b * v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::displacement::video_render(gs_effect_t*)
|
void filter::displacement::instance::video_render(gs_effect_t*)
|
||||||
{
|
{
|
||||||
obs_source_t* parent = obs_filter_get_parent(m_self);
|
obs_source_t* parent = obs_filter_get_parent(m_self);
|
||||||
obs_source_t* target = obs_filter_get_target(m_self);
|
obs_source_t* target = obs_filter_get_target(m_self);
|
||||||
|
@ -261,7 +277,7 @@ void filter::displacement::video_render(gs_effect_t*)
|
||||||
obs_source_process_filter_end(m_self, m_effect->get_object(), baseW, baseH);
|
obs_source_process_filter_end(m_self, m_effect->get_object(), baseW, baseH);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string filter::displacement::get_file()
|
std::string filter::displacement::instance::get_file()
|
||||||
{
|
{
|
||||||
return m_file_name;
|
return m_file_name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,20 @@
|
||||||
#define S_FILTER_DISPLACEMENT_SCALE "Filter.Displacement.Scale"
|
#define S_FILTER_DISPLACEMENT_SCALE "Filter.Displacement.Scale"
|
||||||
|
|
||||||
namespace filter {
|
namespace filter {
|
||||||
class displacement_factory {
|
namespace displacement {
|
||||||
|
class factory {
|
||||||
|
friend class std::_Ptr_base<filter::displacement::factory>;
|
||||||
|
|
||||||
obs_source_info sourceInfo;
|
obs_source_info sourceInfo;
|
||||||
|
|
||||||
|
public: // Singleton
|
||||||
|
static void initialize();
|
||||||
|
static void finalize();
|
||||||
|
static std::shared_ptr<factory> get();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
displacement_factory();
|
factory();
|
||||||
~displacement_factory();
|
~factory();
|
||||||
|
|
||||||
static const char* get_name(void*);
|
static const char* get_name(void*);
|
||||||
|
|
||||||
|
@ -65,7 +73,7 @@ namespace filter {
|
||||||
static void video_render(void*, gs_effect_t*);
|
static void video_render(void*, gs_effect_t*);
|
||||||
};
|
};
|
||||||
|
|
||||||
class displacement {
|
class instance {
|
||||||
obs_source_t* m_self;
|
obs_source_t* m_self;
|
||||||
bool m_active;
|
bool m_active;
|
||||||
float_t m_timer;
|
float_t m_timer;
|
||||||
|
@ -85,8 +93,8 @@ namespace filter {
|
||||||
void validate_file_texture(std::string file);
|
void validate_file_texture(std::string file);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
displacement(obs_data_t*, obs_source_t*);
|
instance(obs_data_t*, obs_source_t*);
|
||||||
~displacement();
|
~instance();
|
||||||
|
|
||||||
void update(obs_data_t*);
|
void update(obs_data_t*);
|
||||||
uint32_t get_width();
|
uint32_t get_width();
|
||||||
|
@ -100,4 +108,5 @@ namespace filter {
|
||||||
|
|
||||||
std::string get_file();
|
std::string get_file();
|
||||||
};
|
};
|
||||||
|
} // namespace displacement
|
||||||
} // namespace filter
|
} // namespace filter
|
||||||
|
|
|
@ -41,11 +41,28 @@
|
||||||
// Initializer & Finalizer
|
// Initializer & Finalizer
|
||||||
INITIALIZER(filterShadowFactoryInitializer)
|
INITIALIZER(filterShadowFactoryInitializer)
|
||||||
{
|
{
|
||||||
initializerFunctions.push_back([] { filter::shadow_sdf_factory::initialize(); });
|
initializerFunctions.push_back([] { filter::shadow_sdf::factory::initialize(); });
|
||||||
finalizerFunctions.push_back([] { filter::shadow_sdf_factory::finalize(); });
|
finalizerFunctions.push_back([] { filter::shadow_sdf::factory::finalize(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::shadow_sdf::cb_modified_inside(void*, obs_properties_t* props, obs_property*,
|
static std::shared_ptr<filter::shadow_sdf::factory> factory_instance = nullptr;
|
||||||
|
|
||||||
|
void filter::shadow_sdf::factory::initialize()
|
||||||
|
{
|
||||||
|
factory_instance = std::make_shared<filter::shadow_sdf::factory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::shadow_sdf::factory::finalize()
|
||||||
|
{
|
||||||
|
factory_instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<filter::shadow_sdf::factory> filter::shadow_sdf::factory::get()
|
||||||
|
{
|
||||||
|
return factory_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool filter::shadow_sdf::instance::cb_modified_inside(void*, obs_properties_t* props, obs_property*,
|
||||||
obs_data_t* settings)
|
obs_data_t* settings)
|
||||||
{
|
{
|
||||||
bool v = obs_data_get_bool(settings, P_INNER);
|
bool v = obs_data_get_bool(settings, P_INNER);
|
||||||
|
@ -58,7 +75,7 @@ bool filter::shadow_sdf::cb_modified_inside(void*, obs_properties_t* props, obs_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::shadow_sdf::cb_modified_outside(void*, obs_properties_t* props, obs_property*,
|
bool filter::shadow_sdf::instance::cb_modified_outside(void*, obs_properties_t* props, obs_property*,
|
||||||
obs_data_t* settings)
|
obs_data_t* settings)
|
||||||
{
|
{
|
||||||
bool v = obs_data_get_bool(settings, P_OUTER);
|
bool v = obs_data_get_bool(settings, P_OUTER);
|
||||||
|
@ -71,7 +88,7 @@ bool filter::shadow_sdf::cb_modified_outside(void*, obs_properties_t* props, obs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::shadow_sdf::shadow_sdf(obs_data_t* settings, obs_source_t* self)
|
filter::shadow_sdf::instance::instance(obs_data_t* settings, obs_source_t* self)
|
||||||
: m_self(self), m_source_rendered(false)
|
: m_self(self), m_source_rendered(false)
|
||||||
{
|
{
|
||||||
this->m_source_rt = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
this->m_source_rt = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||||
|
@ -86,9 +103,9 @@ filter::shadow_sdf::shadow_sdf(obs_data_t* settings, obs_source_t* self)
|
||||||
this->update(settings);
|
this->update(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::shadow_sdf::~shadow_sdf() {}
|
filter::shadow_sdf::instance::~instance() {}
|
||||||
|
|
||||||
obs_properties_t* filter::shadow_sdf::get_properties()
|
obs_properties_t* filter::shadow_sdf::instance::get_properties()
|
||||||
{
|
{
|
||||||
obs_properties_t* props = obs_properties_create();
|
obs_properties_t* props = obs_properties_create();
|
||||||
obs_property_t* p = nullptr;
|
obs_property_t* p = nullptr;
|
||||||
|
@ -144,7 +161,7 @@ obs_properties_t* filter::shadow_sdf::get_properties()
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf::update(obs_data_t* data)
|
void filter::shadow_sdf::instance::update(obs_data_t* data)
|
||||||
{
|
{
|
||||||
this->m_inner_shadow = obs_data_get_bool(data, P_INNER);
|
this->m_inner_shadow = obs_data_get_bool(data, P_INNER);
|
||||||
this->m_inner_range_min = float_t(obs_data_get_double(data, P_INNER_RANGE_MINIMUM));
|
this->m_inner_range_min = float_t(obs_data_get_double(data, P_INNER_RANGE_MINIMUM));
|
||||||
|
@ -169,27 +186,27 @@ void filter::shadow_sdf::update(obs_data_t* data)
|
||||||
| (int32_t(obs_data_get_double(data, P_OUTER_ALPHA) * 2.55) << 24);
|
| (int32_t(obs_data_get_double(data, P_OUTER_ALPHA) * 2.55) << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::shadow_sdf::get_width()
|
uint32_t filter::shadow_sdf::instance::get_width()
|
||||||
{
|
{
|
||||||
return uint32_t(0);
|
return uint32_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::shadow_sdf::get_height()
|
uint32_t filter::shadow_sdf::instance::get_height()
|
||||||
{
|
{
|
||||||
return uint32_t(0);
|
return uint32_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf::activate() {}
|
void filter::shadow_sdf::instance::activate() {}
|
||||||
|
|
||||||
void filter::shadow_sdf::deactivate() {}
|
void filter::shadow_sdf::instance::deactivate() {}
|
||||||
|
|
||||||
void filter::shadow_sdf::video_tick(float time)
|
void filter::shadow_sdf::instance::video_tick(float time)
|
||||||
{
|
{
|
||||||
this->m_tick += time;
|
this->m_tick += time;
|
||||||
m_source_rendered = false;
|
m_source_rendered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf::video_render(gs_effect_t*)
|
void filter::shadow_sdf::instance::video_render(gs_effect_t*)
|
||||||
{
|
{
|
||||||
obs_source_t* parent = obs_filter_get_parent(this->m_self);
|
obs_source_t* parent = obs_filter_get_parent(this->m_self);
|
||||||
obs_source_t* target = obs_filter_get_target(this->m_self);
|
obs_source_t* target = obs_filter_get_target(this->m_self);
|
||||||
|
@ -239,7 +256,7 @@ void filter::shadow_sdf::video_render(gs_effect_t*)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> sdf_effect =
|
std::shared_ptr<gs::effect> sdf_effect =
|
||||||
filter::shadow_sdf_factory::get()->get_sdf_generator_effect();
|
filter::shadow_sdf::factory::get()->get_sdf_generator_effect();
|
||||||
if (!sdf_effect) {
|
if (!sdf_effect) {
|
||||||
throw std::runtime_error("SDF Effect no loaded");
|
throw std::runtime_error("SDF Effect no loaded");
|
||||||
}
|
}
|
||||||
|
@ -275,7 +292,7 @@ void filter::shadow_sdf::video_render(gs_effect_t*)
|
||||||
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<gs::effect> shadow_effect =
|
std::shared_ptr<gs::effect> shadow_effect =
|
||||||
filter::shadow_sdf_factory::get()->get_sdf_shadow_effect();
|
filter::shadow_sdf::factory::get()->get_sdf_shadow_effect();
|
||||||
if (!shadow_effect) {
|
if (!shadow_effect) {
|
||||||
throw std::runtime_error("Shadow Effect no loaded");
|
throw std::runtime_error("Shadow Effect no loaded");
|
||||||
}
|
}
|
||||||
|
@ -339,7 +356,7 @@ void filter::shadow_sdf::video_render(gs_effect_t*)
|
||||||
gs_enable_depth_test(false);
|
gs_enable_depth_test(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::shadow_sdf_factory::shadow_sdf_factory()
|
filter::shadow_sdf::factory::factory()
|
||||||
{
|
{
|
||||||
memset(&source_info, 0, sizeof(obs_source_info));
|
memset(&source_info, 0, sizeof(obs_source_info));
|
||||||
source_info.id = "obs-stream-effects-filter-shadow-sdf";
|
source_info.id = "obs-stream-effects-filter-shadow-sdf";
|
||||||
|
@ -360,9 +377,9 @@ filter::shadow_sdf_factory::shadow_sdf_factory()
|
||||||
obs_register_source(&source_info);
|
obs_register_source(&source_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::shadow_sdf_factory::~shadow_sdf_factory() {}
|
filter::shadow_sdf::factory::~factory() {}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::on_list_fill()
|
void filter::shadow_sdf::factory::on_list_fill()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
char* file = obs_module_file("effects/sdf-generator.effect");
|
char* file = obs_module_file("effects/sdf-generator.effect");
|
||||||
|
@ -384,25 +401,25 @@ void filter::shadow_sdf_factory::on_list_fill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::on_list_empty()
|
void filter::shadow_sdf::factory::on_list_empty()
|
||||||
{
|
{
|
||||||
sdf_generator_effect.reset();
|
sdf_generator_effect.reset();
|
||||||
sdf_shadow_effect.reset();
|
sdf_shadow_effect.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* filter::shadow_sdf_factory::create(obs_data_t* data, obs_source_t* parent)
|
void* filter::shadow_sdf::factory::create(obs_data_t* data, obs_source_t* parent)
|
||||||
{
|
{
|
||||||
if (get()->sources.empty()) {
|
if (get()->sources.empty()) {
|
||||||
get()->on_list_fill();
|
get()->on_list_fill();
|
||||||
}
|
}
|
||||||
filter::shadow_sdf* ptr = new filter::shadow_sdf(data, parent);
|
filter::shadow_sdf::instance* ptr = new filter::shadow_sdf::instance(data, parent);
|
||||||
get()->sources.push_back(ptr);
|
get()->sources.push_back(ptr);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::destroy(void* inptr)
|
void filter::shadow_sdf::factory::destroy(void* inptr)
|
||||||
{
|
{
|
||||||
filter::shadow_sdf* ptr = reinterpret_cast<filter::shadow_sdf*>(inptr);
|
filter::shadow_sdf::instance* ptr = reinterpret_cast<filter::shadow_sdf::instance*>(inptr);
|
||||||
get()->sources.remove(ptr);
|
get()->sources.remove(ptr);
|
||||||
if (get()->sources.empty()) {
|
if (get()->sources.empty()) {
|
||||||
get()->on_list_empty();
|
get()->on_list_empty();
|
||||||
|
@ -410,7 +427,7 @@ void filter::shadow_sdf_factory::destroy(void* inptr)
|
||||||
delete ptr;
|
delete ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::get_defaults(obs_data_t* data)
|
void filter::shadow_sdf::factory::get_defaults(obs_data_t* data)
|
||||||
{
|
{
|
||||||
obs_data_set_bool(data, P_INNER, false);
|
obs_data_set_bool(data, P_INNER, false);
|
||||||
obs_data_set_double(data, P_INNER_RANGE_MINIMUM, 0.0);
|
obs_data_set_double(data, P_INNER_RANGE_MINIMUM, 0.0);
|
||||||
|
@ -429,74 +446,57 @@ void filter::shadow_sdf_factory::get_defaults(obs_data_t* data)
|
||||||
obs_data_set_double(data, P_OUTER_ALPHA, 100.0);
|
obs_data_set_double(data, P_OUTER_ALPHA, 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_properties_t* filter::shadow_sdf_factory::get_properties(void* inptr)
|
obs_properties_t* filter::shadow_sdf::factory::get_properties(void* inptr)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<filter::shadow_sdf*>(inptr)->get_properties();
|
return reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->get_properties();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::update(void* inptr, obs_data_t* settings)
|
void filter::shadow_sdf::factory::update(void* inptr, obs_data_t* settings)
|
||||||
{
|
{
|
||||||
reinterpret_cast<filter::shadow_sdf*>(inptr)->update(settings);
|
reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->update(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* filter::shadow_sdf_factory::get_name(void*)
|
const char* filter::shadow_sdf::factory::get_name(void*)
|
||||||
{
|
{
|
||||||
return P_TRANSLATE(SOURCE_NAME);
|
return P_TRANSLATE(SOURCE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::shadow_sdf_factory::get_width(void* inptr)
|
uint32_t filter::shadow_sdf::factory::get_width(void* inptr)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<filter::shadow_sdf*>(inptr)->get_width();
|
return reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->get_width();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::shadow_sdf_factory::get_height(void* inptr)
|
uint32_t filter::shadow_sdf::factory::get_height(void* inptr)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<filter::shadow_sdf*>(inptr)->get_height();
|
return reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->get_height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::activate(void* inptr)
|
void filter::shadow_sdf::factory::activate(void* inptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<filter::shadow_sdf*>(inptr)->activate();
|
reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::deactivate(void* inptr)
|
void filter::shadow_sdf::factory::deactivate(void* inptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<filter::shadow_sdf*>(inptr)->deactivate();
|
reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::video_tick(void* inptr, float delta)
|
void filter::shadow_sdf::factory::video_tick(void* inptr, float delta)
|
||||||
{
|
{
|
||||||
reinterpret_cast<filter::shadow_sdf*>(inptr)->video_tick(delta);
|
reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->video_tick(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::video_render(void* inptr, gs_effect_t* effect)
|
void filter::shadow_sdf::factory::video_render(void* inptr, gs_effect_t* effect)
|
||||||
{
|
{
|
||||||
reinterpret_cast<filter::shadow_sdf*>(inptr)->video_render(effect);
|
reinterpret_cast<filter::shadow_sdf::instance*>(inptr)->video_render(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> filter::shadow_sdf_factory::get_sdf_generator_effect()
|
std::shared_ptr<gs::effect> filter::shadow_sdf::factory::get_sdf_generator_effect()
|
||||||
{
|
{
|
||||||
return sdf_generator_effect;
|
return sdf_generator_effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> filter::shadow_sdf_factory::get_sdf_shadow_effect()
|
std::shared_ptr<gs::effect> filter::shadow_sdf::factory::get_sdf_shadow_effect()
|
||||||
{
|
{
|
||||||
return sdf_shadow_effect;
|
return sdf_shadow_effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
static filter::shadow_sdf_factory* factory_instance = nullptr;
|
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::initialize()
|
|
||||||
{
|
|
||||||
factory_instance = new filter::shadow_sdf_factory();
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter::shadow_sdf_factory::finalize()
|
|
||||||
{
|
|
||||||
delete factory_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter::shadow_sdf_factory* filter::shadow_sdf_factory::get()
|
|
||||||
{
|
|
||||||
return factory_instance;
|
|
||||||
}
|
|
||||||
|
|
|
@ -40,7 +40,53 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace filter {
|
namespace filter {
|
||||||
class shadow_sdf {
|
namespace shadow_sdf {
|
||||||
|
class instance;
|
||||||
|
|
||||||
|
class factory {
|
||||||
|
friend class std::_Ptr_base<filter::shadow_sdf::factory>;
|
||||||
|
|
||||||
|
obs_source_info source_info;
|
||||||
|
std::list<instance*> sources;
|
||||||
|
|
||||||
|
std::shared_ptr<gs::effect> sdf_generator_effect;
|
||||||
|
std::shared_ptr<gs::effect> sdf_shadow_effect;
|
||||||
|
|
||||||
|
public: // Singleton
|
||||||
|
static void initialize();
|
||||||
|
static void finalize();
|
||||||
|
static std::shared_ptr<factory> get();
|
||||||
|
|
||||||
|
public:
|
||||||
|
factory();
|
||||||
|
~factory();
|
||||||
|
|
||||||
|
void on_list_fill();
|
||||||
|
void on_list_empty();
|
||||||
|
|
||||||
|
static void* create(obs_data_t* settings, obs_source_t* self);
|
||||||
|
static void destroy(void* source);
|
||||||
|
|
||||||
|
static void get_defaults(obs_data_t* settings);
|
||||||
|
static obs_properties_t* get_properties(void* source);
|
||||||
|
static void update(void* source, obs_data_t* settings);
|
||||||
|
|
||||||
|
static const char* get_name(void* source);
|
||||||
|
static uint32_t get_width(void* source);
|
||||||
|
static uint32_t get_height(void* source);
|
||||||
|
|
||||||
|
static void activate(void* source);
|
||||||
|
static void deactivate(void* source);
|
||||||
|
|
||||||
|
static void video_tick(void* source, float delta);
|
||||||
|
static void video_render(void* source, gs_effect_t* effect);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<gs::effect> get_sdf_generator_effect();
|
||||||
|
std::shared_ptr<gs::effect> get_sdf_shadow_effect();
|
||||||
|
};
|
||||||
|
|
||||||
|
class instance {
|
||||||
obs_source_t* m_self;
|
obs_source_t* m_self;
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
|
@ -67,13 +113,15 @@ namespace filter {
|
||||||
float_t m_outer_offset_y;
|
float_t m_outer_offset_y;
|
||||||
uint32_t m_outer_color;
|
uint32_t m_outer_color;
|
||||||
|
|
||||||
static bool cb_modified_inside(void* ptr, obs_properties_t* props, obs_property* prop, obs_data_t* settings);
|
static bool cb_modified_inside(void* ptr, obs_properties_t* props, obs_property* prop,
|
||||||
|
obs_data_t* settings);
|
||||||
|
|
||||||
static bool cb_modified_outside(void* ptr, obs_properties_t* props, obs_property* prop, obs_data_t* settings);
|
static bool cb_modified_outside(void* ptr, obs_properties_t* props, obs_property* prop,
|
||||||
|
obs_data_t* settings);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shadow_sdf(obs_data_t* settings, obs_source_t* self);
|
instance(obs_data_t* settings, obs_source_t* self);
|
||||||
~shadow_sdf();
|
~instance();
|
||||||
|
|
||||||
obs_properties_t* get_properties();
|
obs_properties_t* get_properties();
|
||||||
void update(obs_data_t*);
|
void update(obs_data_t*);
|
||||||
|
@ -87,48 +135,7 @@ namespace filter {
|
||||||
void video_tick(float);
|
void video_tick(float);
|
||||||
void video_render(gs_effect_t*);
|
void video_render(gs_effect_t*);
|
||||||
};
|
};
|
||||||
|
} // namespace shadow_sdf
|
||||||
class shadow_sdf_factory {
|
|
||||||
obs_source_info source_info;
|
|
||||||
std::list<shadow_sdf*> sources;
|
|
||||||
|
|
||||||
std::shared_ptr<gs::effect> sdf_generator_effect;
|
|
||||||
std::shared_ptr<gs::effect> sdf_shadow_effect;
|
|
||||||
|
|
||||||
private:
|
|
||||||
shadow_sdf_factory();
|
|
||||||
~shadow_sdf_factory();
|
|
||||||
|
|
||||||
void on_list_fill();
|
|
||||||
void on_list_empty();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static void* create(obs_data_t* settings, obs_source_t* self);
|
|
||||||
static void destroy(void* source);
|
|
||||||
|
|
||||||
static void get_defaults(obs_data_t* settings);
|
|
||||||
static obs_properties_t* get_properties(void* source);
|
|
||||||
static void update(void* source, obs_data_t* settings);
|
|
||||||
|
|
||||||
static const char* get_name(void* source);
|
|
||||||
static uint32_t get_width(void* source);
|
|
||||||
static uint32_t get_height(void* source);
|
|
||||||
|
|
||||||
static void activate(void* source);
|
|
||||||
static void deactivate(void* source);
|
|
||||||
|
|
||||||
static void video_tick(void* source, float delta);
|
|
||||||
static void video_render(void* source, gs_effect_t* effect);
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::shared_ptr<gs::effect> get_sdf_generator_effect();
|
|
||||||
std::shared_ptr<gs::effect> get_sdf_shadow_effect();
|
|
||||||
|
|
||||||
public: // Singleton
|
|
||||||
static void initialize();
|
|
||||||
static void finalize();
|
|
||||||
static shadow_sdf_factory* get();
|
|
||||||
};
|
|
||||||
} // namespace filter
|
} // namespace filter
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,14 +33,6 @@
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initializer & Finalizer
|
|
||||||
static filter::transform_factory* filterTransformInstance;
|
|
||||||
INITIALIZER(FilterTransformInit)
|
|
||||||
{
|
|
||||||
initializerFunctions.push_back([] { filterTransformInstance = new filter::transform_factory(); });
|
|
||||||
finalizerFunctions.push_back([] { delete filterTransformInstance; });
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ST "Filter.Transform"
|
#define ST "Filter.Transform"
|
||||||
#define ST_CAMERA "Filter.Transform.Camera"
|
#define ST_CAMERA "Filter.Transform.Camera"
|
||||||
#define ST_CAMERA_ORTHOGRAPHIC "Filter.Transform.Camera.Orthographic"
|
#define ST_CAMERA_ORTHOGRAPHIC "Filter.Transform.Camera.Orthographic"
|
||||||
|
@ -83,7 +75,31 @@ enum RotationOrder : int64_t {
|
||||||
ZYX,
|
ZYX,
|
||||||
};
|
};
|
||||||
|
|
||||||
filter::transform_factory::transform_factory()
|
// Initializer & Finalizer
|
||||||
|
INITIALIZER(FilterTransformInit)
|
||||||
|
{
|
||||||
|
initializerFunctions.push_back([] { filter::transform::factory::initialize(); });
|
||||||
|
finalizerFunctions.push_back([] { filter::transform::factory::finalize(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<filter::transform::factory> factory_instance = nullptr;
|
||||||
|
|
||||||
|
void filter::transform::factory::initialize()
|
||||||
|
{
|
||||||
|
factory_instance = std::make_shared<filter::transform::factory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter::transform::factory::finalize()
|
||||||
|
{
|
||||||
|
factory_instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<filter::transform::factory> filter::transform::factory::get()
|
||||||
|
{
|
||||||
|
return factory_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter::transform::factory::factory()
|
||||||
{
|
{
|
||||||
memset(&sourceInfo, 0, sizeof(obs_source_info));
|
memset(&sourceInfo, 0, sizeof(obs_source_info));
|
||||||
sourceInfo.id = "obs-stream-effects-filter-transform";
|
sourceInfo.id = "obs-stream-effects-filter-transform";
|
||||||
|
@ -104,14 +120,14 @@ filter::transform_factory::transform_factory()
|
||||||
obs_register_source(&sourceInfo);
|
obs_register_source(&sourceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::transform_factory::~transform_factory() {}
|
filter::transform::factory::~factory() {}
|
||||||
|
|
||||||
const char* filter::transform_factory::get_name(void*)
|
const char* filter::transform::factory::get_name(void*)
|
||||||
{
|
{
|
||||||
return P_TRANSLATE(ST);
|
return P_TRANSLATE(ST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform_factory::get_defaults(obs_data_t* data)
|
void filter::transform::factory::get_defaults(obs_data_t* data)
|
||||||
{
|
{
|
||||||
obs_data_set_default_int(data, ST_CAMERA, (int64_t)CameraMode::Orthographic);
|
obs_data_set_default_int(data, ST_CAMERA, (int64_t)CameraMode::Orthographic);
|
||||||
obs_data_set_default_double(data, ST_CAMERA_FIELDOFVIEW, 90.0);
|
obs_data_set_default_double(data, ST_CAMERA_FIELDOFVIEW, 90.0);
|
||||||
|
@ -129,7 +145,7 @@ void filter::transform_factory::get_defaults(obs_data_t* data)
|
||||||
obs_data_set_default_int(data, ST_ROTATION_ORDER, RotationOrder::ZXY);
|
obs_data_set_default_int(data, ST_ROTATION_ORDER, RotationOrder::ZXY);
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_properties_t* filter::transform_factory::get_properties(void*)
|
obs_properties_t* filter::transform::factory::get_properties(void*)
|
||||||
{
|
{
|
||||||
obs_properties_t* pr = obs_properties_create();
|
obs_properties_t* pr = obs_properties_create();
|
||||||
obs_property_t* p = NULL;
|
obs_property_t* p = NULL;
|
||||||
|
@ -211,30 +227,25 @@ obs_properties_t* filter::transform_factory::get_properties(void*)
|
||||||
obs_property_set_modified_callback(p, modified_properties);
|
obs_property_set_modified_callback(p, modified_properties);
|
||||||
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(ST_MIPMAPPING)));
|
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(ST_MIPMAPPING)));
|
||||||
|
|
||||||
p = obs_properties_add_list(pr, S_MIPGENERATOR, P_TRANSLATE(S_MIPGENERATOR),
|
p = obs_properties_add_list(pr, S_MIPGENERATOR, P_TRANSLATE(S_MIPGENERATOR), OBS_COMBO_TYPE_LIST,
|
||||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
|
OBS_COMBO_FORMAT_INT);
|
||||||
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_MIPGENERATOR)));
|
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_MIPGENERATOR)));
|
||||||
|
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Point);
|
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Point);
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
|
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Linear);
|
||||||
(long long)gs::mipmapper::generator::Linear);
|
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Sharpen);
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
|
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Smoothen);
|
||||||
(long long)gs::mipmapper::generator::Sharpen);
|
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Bicubic);
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
|
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT), (long long)gs::mipmapper::generator::Lanczos);
|
||||||
(long long)gs::mipmapper::generator::Smoothen);
|
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
|
|
||||||
(long long)gs::mipmapper::generator::Bicubic);
|
|
||||||
obs_property_list_add_int(p, P_TRANSLATE(S_MIPGENERATOR_POINT),
|
|
||||||
(long long)gs::mipmapper::generator::Lanczos);
|
|
||||||
|
|
||||||
p = obs_properties_add_float_slider(pr, S_MIPGENERATOR_STRENGTH, P_TRANSLATE(S_MIPGENERATOR_STRENGTH), 0.0,
|
p = obs_properties_add_float_slider(pr, S_MIPGENERATOR_STRENGTH, P_TRANSLATE(S_MIPGENERATOR_STRENGTH), 0.0, 1000.0,
|
||||||
1000.0, 0.01);
|
0.01);
|
||||||
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_MIPGENERATOR_STRENGTH)));
|
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_MIPGENERATOR_STRENGTH)));
|
||||||
|
|
||||||
return pr;
|
return pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filter::transform_factory::modified_properties(obs_properties_t* pr, obs_property_t*, obs_data_t* d)
|
bool filter::transform::factory::modified_properties(obs_properties_t* pr, obs_property_t*, obs_data_t* d)
|
||||||
{
|
{
|
||||||
switch ((CameraMode)obs_data_get_int(d, ST_CAMERA)) {
|
switch ((CameraMode)obs_data_get_int(d, ST_CAMERA)) {
|
||||||
case CameraMode::Orthographic:
|
case CameraMode::Orthographic:
|
||||||
|
@ -258,52 +269,52 @@ bool filter::transform_factory::modified_properties(obs_properties_t* pr, obs_pr
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* filter::transform_factory::create(obs_data_t* data, obs_source_t* source)
|
void* filter::transform::factory::create(obs_data_t* data, obs_source_t* source)
|
||||||
{
|
{
|
||||||
return new transform(data, source);
|
return new instance(data, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform_factory::destroy(void* ptr)
|
void filter::transform::factory::destroy(void* ptr)
|
||||||
{
|
{
|
||||||
delete reinterpret_cast<transform*>(ptr);
|
delete reinterpret_cast<instance*>(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::transform_factory::get_width(void* ptr)
|
uint32_t filter::transform::factory::get_width(void* ptr)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<transform*>(ptr)->get_width();
|
return reinterpret_cast<instance*>(ptr)->get_width();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::transform_factory::get_height(void* ptr)
|
uint32_t filter::transform::factory::get_height(void* ptr)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<transform*>(ptr)->get_height();
|
return reinterpret_cast<instance*>(ptr)->get_height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform_factory::update(void* ptr, obs_data_t* data)
|
void filter::transform::factory::update(void* ptr, obs_data_t* data)
|
||||||
{
|
{
|
||||||
reinterpret_cast<transform*>(ptr)->update(data);
|
reinterpret_cast<instance*>(ptr)->update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform_factory::activate(void* ptr)
|
void filter::transform::factory::activate(void* ptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<transform*>(ptr)->activate();
|
reinterpret_cast<instance*>(ptr)->activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform_factory::deactivate(void* ptr)
|
void filter::transform::factory::deactivate(void* ptr)
|
||||||
{
|
{
|
||||||
reinterpret_cast<transform*>(ptr)->deactivate();
|
reinterpret_cast<instance*>(ptr)->deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform_factory::video_tick(void* ptr, float time)
|
void filter::transform::factory::video_tick(void* ptr, float time)
|
||||||
{
|
{
|
||||||
reinterpret_cast<transform*>(ptr)->video_tick(time);
|
reinterpret_cast<instance*>(ptr)->video_tick(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform_factory::video_render(void* ptr, gs_effect_t* effect)
|
void filter::transform::factory::video_render(void* ptr, gs_effect_t* effect)
|
||||||
{
|
{
|
||||||
reinterpret_cast<transform*>(ptr)->video_render(effect);
|
reinterpret_cast<instance*>(ptr)->video_render(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::transform::~transform()
|
filter::transform::instance::~instance()
|
||||||
{
|
{
|
||||||
m_shear.reset();
|
m_shear.reset();
|
||||||
m_scale.reset();
|
m_scale.reset();
|
||||||
|
@ -316,7 +327,7 @@ filter::transform::~transform()
|
||||||
m_source_rendertarget.reset();
|
m_source_rendertarget.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
filter::transform::transform(obs_data_t* data, obs_source_t* context)
|
filter::transform::instance::instance(obs_data_t* data, obs_source_t* context)
|
||||||
: m_active(true), m_self(context), m_source_rendered(false), m_mipmap_enabled(false), m_mipmap_strength(50.0),
|
: m_active(true), m_self(context), m_source_rendered(false), m_mipmap_enabled(false), m_mipmap_strength(50.0),
|
||||||
m_mipmap_generator(gs::mipmapper::generator::Linear), m_update_mesh(false), m_rotation_order(RotationOrder::ZXY),
|
m_mipmap_generator(gs::mipmapper::generator::Linear), m_update_mesh(false), m_rotation_order(RotationOrder::ZXY),
|
||||||
m_camera_orthographic(true), m_camera_fov(90.0)
|
m_camera_orthographic(true), m_camera_fov(90.0)
|
||||||
|
@ -337,17 +348,17 @@ filter::transform::transform(obs_data_t* data, obs_source_t* context)
|
||||||
update(data);
|
update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::transform::get_width()
|
uint32_t filter::transform::instance::get_width()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t filter::transform::get_height()
|
uint32_t filter::transform::instance::get_height()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform::update(obs_data_t* data)
|
void filter::transform::instance::update(obs_data_t* data)
|
||||||
{
|
{
|
||||||
// Camera
|
// Camera
|
||||||
m_camera_orthographic = obs_data_get_int(data, ST_CAMERA) == 0;
|
m_camera_orthographic = obs_data_get_int(data, ST_CAMERA) == 0;
|
||||||
|
@ -376,17 +387,17 @@ void filter::transform::update(obs_data_t* data)
|
||||||
m_update_mesh = true;
|
m_update_mesh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform::activate()
|
void filter::transform::instance::activate()
|
||||||
{
|
{
|
||||||
m_active = true;
|
m_active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform::deactivate()
|
void filter::transform::instance::deactivate()
|
||||||
{
|
{
|
||||||
m_active = false;
|
m_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform::video_tick(float)
|
void filter::transform::instance::video_tick(float)
|
||||||
{
|
{
|
||||||
// Update Mesh
|
// Update Mesh
|
||||||
if (m_update_mesh) {
|
if (m_update_mesh) {
|
||||||
|
@ -490,7 +501,7 @@ void filter::transform::video_tick(float)
|
||||||
this->m_source_rendered = false;
|
this->m_source_rendered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter::transform::video_render(gs_effect_t* paramEffect)
|
void filter::transform::instance::video_render(gs_effect_t* paramEffect)
|
||||||
{
|
{
|
||||||
if (!m_active) {
|
if (!m_active) {
|
||||||
obs_source_skip_video_filter(m_self);
|
obs_source_skip_video_filter(m_self);
|
||||||
|
|
|
@ -27,12 +27,20 @@
|
||||||
#include "plugin.hpp"
|
#include "plugin.hpp"
|
||||||
|
|
||||||
namespace filter {
|
namespace filter {
|
||||||
class transform_factory {
|
namespace transform {
|
||||||
|
class factory {
|
||||||
|
friend class std::_Ptr_base<filter::transform::factory>;
|
||||||
|
|
||||||
obs_source_info sourceInfo;
|
obs_source_info sourceInfo;
|
||||||
|
|
||||||
|
public: // Singleton
|
||||||
|
static void initialize();
|
||||||
|
static void finalize();
|
||||||
|
static std::shared_ptr<factory> get();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
transform_factory();
|
factory();
|
||||||
~transform_factory();
|
~factory();
|
||||||
|
|
||||||
static const char* get_name(void*);
|
static const char* get_name(void*);
|
||||||
static void get_defaults(obs_data_t*);
|
static void get_defaults(obs_data_t*);
|
||||||
|
@ -52,7 +60,7 @@ namespace filter {
|
||||||
static void video_render(void*, gs_effect_t*);
|
static void video_render(void*, gs_effect_t*);
|
||||||
};
|
};
|
||||||
|
|
||||||
class transform {
|
class instance {
|
||||||
bool m_active;
|
bool m_active;
|
||||||
obs_source_t* m_self;
|
obs_source_t* m_self;
|
||||||
|
|
||||||
|
@ -85,8 +93,8 @@ namespace filter {
|
||||||
float_t m_camera_fov;
|
float_t m_camera_fov;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~transform();
|
~instance();
|
||||||
transform(obs_data_t*, obs_source_t*);
|
instance(obs_data_t*, obs_source_t*);
|
||||||
|
|
||||||
uint32_t get_width();
|
uint32_t get_width();
|
||||||
uint32_t get_height();
|
uint32_t get_height();
|
||||||
|
@ -97,4 +105,5 @@ namespace filter {
|
||||||
void video_tick(float);
|
void video_tick(float);
|
||||||
void video_render(gs_effect_t*);
|
void video_render(gs_effect_t*);
|
||||||
};
|
};
|
||||||
|
} // namespace transform
|
||||||
} // namespace filter
|
} // namespace filter
|
||||||
|
|
|
@ -57,14 +57,30 @@
|
||||||
#define P_SCALING_BOUNDS_FILLHEIGHT "Source.Mirror.Scaling.Bounds.FillHeight"
|
#define P_SCALING_BOUNDS_FILLHEIGHT "Source.Mirror.Scaling.Bounds.FillHeight"
|
||||||
|
|
||||||
// Initializer & Finalizer
|
// Initializer & Finalizer
|
||||||
Source::mirror_factory* sourceMirrorInstance;
|
|
||||||
INITIALIZER(SourceMirrorInit)
|
INITIALIZER(SourceMirrorInit)
|
||||||
{
|
{
|
||||||
initializerFunctions.push_back([] { sourceMirrorInstance = new Source::mirror_factory(); });
|
initializerFunctions.push_back([] { source::mirror::factory::initialize(); });
|
||||||
finalizerFunctions.push_back([] { delete sourceMirrorInstance; });
|
finalizerFunctions.push_back([] { source::mirror::factory::finalize(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Source::mirror_factory::mirror_factory()
|
static std::shared_ptr<source::mirror::factory> factory_instance = nullptr;
|
||||||
|
|
||||||
|
void source::mirror::factory::initialize()
|
||||||
|
{
|
||||||
|
factory_instance = std::make_shared<source::mirror::factory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void source::mirror::factory::finalize()
|
||||||
|
{
|
||||||
|
factory_instance.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<source::mirror::factory> source::mirror::factory::get()
|
||||||
|
{
|
||||||
|
return factory_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
source::mirror::factory::factory()
|
||||||
{
|
{
|
||||||
memset(&osi, 0, sizeof(obs_source_info));
|
memset(&osi, 0, sizeof(obs_source_info));
|
||||||
osi.id = "obs-stream-effects-source-mirror";
|
osi.id = "obs-stream-effects-source-mirror";
|
||||||
|
@ -90,14 +106,14 @@ Source::mirror_factory::mirror_factory()
|
||||||
obs_register_source(&osi);
|
obs_register_source(&osi);
|
||||||
}
|
}
|
||||||
|
|
||||||
Source::mirror_factory::~mirror_factory() {}
|
source::mirror::factory::~factory() {}
|
||||||
|
|
||||||
const char* Source::mirror_factory::get_name(void*)
|
const char* source::mirror::factory::get_name(void*)
|
||||||
{
|
{
|
||||||
return P_TRANSLATE(S_SOURCE_MIRROR);
|
return P_TRANSLATE(S_SOURCE_MIRROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::get_defaults(obs_data_t* data)
|
void source::mirror::factory::get_defaults(obs_data_t* data)
|
||||||
{
|
{
|
||||||
obs_data_set_default_string(data, P_SOURCE, "");
|
obs_data_set_default_string(data, P_SOURCE, "");
|
||||||
obs_data_set_default_bool(data, P_SOURCE_AUDIO, false);
|
obs_data_set_default_bool(data, P_SOURCE_AUDIO, false);
|
||||||
|
@ -108,7 +124,7 @@ void Source::mirror_factory::get_defaults(obs_data_t* data)
|
||||||
obs_data_set_default_int(data, P_SCALING_BOUNDS, (int64_t)obs_bounds_type::OBS_BOUNDS_STRETCH);
|
obs_data_set_default_int(data, P_SCALING_BOUNDS, (int64_t)obs_bounds_type::OBS_BOUNDS_STRETCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Source::mirror_factory::modified_properties(obs_properties_t* pr, obs_property_t* p, obs_data_t* data)
|
bool source::mirror::factory::modified_properties(obs_properties_t* pr, obs_property_t* p, obs_data_t* data)
|
||||||
{
|
{
|
||||||
if (obs_properties_get(pr, P_SOURCE) == p) {
|
if (obs_properties_get(pr, P_SOURCE) == p) {
|
||||||
obs_source_t* target = obs_get_source_by_name(obs_data_get_string(data, P_SOURCE));
|
obs_source_t* target = obs_get_source_by_name(obs_data_get_string(data, P_SOURCE));
|
||||||
|
@ -151,7 +167,7 @@ static void UpdateSourceList(obs_property_t* p)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_properties_t* Source::mirror_factory::get_properties(void*)
|
obs_properties_t* source::mirror::factory::get_properties(void*)
|
||||||
{
|
{
|
||||||
obs_properties_t* pr = obs_properties_create();
|
obs_properties_t* pr = obs_properties_create();
|
||||||
obs_property_t* p = nullptr;
|
obs_property_t* p = nullptr;
|
||||||
|
@ -200,91 +216,91 @@ obs_properties_t* Source::mirror_factory::get_properties(void*)
|
||||||
return pr;
|
return pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Source::mirror_factory::create(obs_data_t* data, obs_source_t* source)
|
void* source::mirror::factory::create(obs_data_t* data, obs_source_t* source)
|
||||||
{
|
{
|
||||||
return new Source::mirror(data, source);
|
return new source::mirror::instance(data, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::destroy(void* p)
|
void source::mirror::factory::destroy(void* p)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
delete static_cast<Source::mirror*>(p);
|
delete static_cast<source::mirror::instance*>(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Source::mirror_factory::get_width(void* p)
|
uint32_t source::mirror::factory::get_width(void* p)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
return static_cast<Source::mirror*>(p)->get_width();
|
return static_cast<source::mirror::instance*>(p)->get_width();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Source::mirror_factory::get_height(void* p)
|
uint32_t source::mirror::factory::get_height(void* p)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
return static_cast<Source::mirror*>(p)->get_height();
|
return static_cast<source::mirror::instance*>(p)->get_height();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::update(void* p, obs_data_t* data)
|
void source::mirror::factory::update(void* p, obs_data_t* data)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->update(data);
|
static_cast<source::mirror::instance*>(p)->update(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::activate(void* p)
|
void source::mirror::factory::activate(void* p)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->activate();
|
static_cast<source::mirror::instance*>(p)->activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::deactivate(void* p)
|
void source::mirror::factory::deactivate(void* p)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->deactivate();
|
static_cast<source::mirror::instance*>(p)->deactivate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::video_tick(void* p, float t)
|
void source::mirror::factory::video_tick(void* p, float t)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->video_tick(t);
|
static_cast<source::mirror::instance*>(p)->video_tick(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::video_render(void* p, gs_effect_t* ef)
|
void source::mirror::factory::video_render(void* p, gs_effect_t* ef)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->video_render(ef);
|
static_cast<source::mirror::instance*>(p)->video_render(ef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::enum_active_sources(void* p, obs_source_enum_proc_t enum_callback, void* param)
|
void source::mirror::factory::enum_active_sources(void* p, obs_source_enum_proc_t enum_callback, void* param)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->enum_active_sources(enum_callback, param);
|
static_cast<source::mirror::instance*>(p)->enum_active_sources(enum_callback, param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::load(void* p, obs_data_t* d)
|
void source::mirror::factory::load(void* p, obs_data_t* d)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->load(d);
|
static_cast<source::mirror::instance*>(p)->load(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror_factory::save(void* p, obs_data_t* d)
|
void source::mirror::factory::save(void* p, obs_data_t* d)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
static_cast<Source::mirror*>(p)->save(d);
|
static_cast<source::mirror::instance*>(p)->save(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::release_input()
|
void source::mirror::instance::release_input()
|
||||||
{
|
{
|
||||||
// Clear any references to the previous source.
|
// Clear any references to the previous source.
|
||||||
if (this->m_source_item) {
|
if (this->m_source_item) {
|
||||||
|
@ -298,7 +314,7 @@ void Source::mirror::release_input()
|
||||||
this->m_source.reset();
|
this->m_source.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::acquire_input(std::string source_name)
|
void source::mirror::instance::acquire_input(std::string source_name)
|
||||||
{
|
{
|
||||||
// Acquire new reference to current source.
|
// Acquire new reference to current source.
|
||||||
obs_source_t* ref_source = obs_get_source_by_name(source_name.c_str());
|
obs_source_t* ref_source = obs_get_source_by_name(source_name.c_str());
|
||||||
|
@ -333,12 +349,12 @@ void Source::mirror::acquire_input(std::string source_name)
|
||||||
|
|
||||||
// If everything worked fine, we now set everything up.
|
// If everything worked fine, we now set everything up.
|
||||||
this->m_source = std::move(new_source);
|
this->m_source = std::move(new_source);
|
||||||
this->m_source->events.rename += std::bind(&Source::mirror::on_source_rename, this, std::placeholders::_1,
|
this->m_source->events.rename += std::bind(&source::mirror::instance::on_source_rename, this, std::placeholders::_1,
|
||||||
std::placeholders::_2, std::placeholders::_3);
|
std::placeholders::_2, std::placeholders::_3);
|
||||||
try {
|
try {
|
||||||
// Audio
|
// Audio
|
||||||
this->m_source_audio = std::make_shared<obs::audio_capture>(this->m_source);
|
this->m_source_audio = std::make_shared<obs::audio_capture>(this->m_source);
|
||||||
this->m_source_audio->on.data += std::bind(&Source::mirror::audio_capture_cb, this, std::placeholders::_1,
|
this->m_source_audio->on.data += std::bind(&source::mirror::instance::audio_capture_cb, this, std::placeholders::_1,
|
||||||
std::placeholders::_2, std::placeholders::_3);
|
std::placeholders::_2, std::placeholders::_3);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
P_LOG_ERROR("<Source Mirror:%s> Unexpected error during registering audio callback for '%s'.",
|
P_LOG_ERROR("<Source Mirror:%s> Unexpected error during registering audio callback for '%s'.",
|
||||||
|
@ -346,7 +362,7 @@ void Source::mirror::acquire_input(std::string source_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Source::mirror::mirror(obs_data_t* data, obs_source_t* src)
|
source::mirror::instance::instance(obs_data_t* data, obs_source_t* src)
|
||||||
: m_self(src), m_active(true), m_tick(0), m_scene_rendered(false), m_rescale_enabled(false),
|
: m_self(src), m_active(true), m_tick(0), m_scene_rendered(false), m_rescale_enabled(false),
|
||||||
m_rescale_keep_orig_size(false), m_rescale_width(1), m_rescale_height(1),
|
m_rescale_keep_orig_size(false), m_rescale_width(1), m_rescale_height(1),
|
||||||
m_rescale_type(obs_scale_type::OBS_SCALE_BICUBIC), m_rescale_bounds(obs_bounds_type::OBS_BOUNDS_STRETCH),
|
m_rescale_type(obs_scale_type::OBS_SCALE_BICUBIC), m_rescale_bounds(obs_bounds_type::OBS_BOUNDS_STRETCH),
|
||||||
|
@ -363,10 +379,10 @@ Source::mirror::mirror(obs_data_t* data, obs_source_t* src)
|
||||||
for (size_t idx = 0; idx < this->m_audio_data.size(); idx++) {
|
for (size_t idx = 0; idx < this->m_audio_data.size(); idx++) {
|
||||||
this->m_audio_data[idx].resize(AUDIO_OUTPUT_FRAMES);
|
this->m_audio_data[idx].resize(AUDIO_OUTPUT_FRAMES);
|
||||||
}
|
}
|
||||||
this->m_audio_thread = std::thread(std::bind(&Source::mirror::audio_output_cb, this));
|
this->m_audio_thread = std::thread(std::bind(&source::mirror::instance::audio_output_cb, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
Source::mirror::~mirror()
|
source::mirror::instance::~instance()
|
||||||
{
|
{
|
||||||
release_input();
|
release_input();
|
||||||
|
|
||||||
|
@ -382,7 +398,7 @@ Source::mirror::~mirror()
|
||||||
this->m_scene.reset();
|
this->m_scene.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Source::mirror::get_width()
|
uint32_t source::mirror::instance::get_width()
|
||||||
{
|
{
|
||||||
if (this->m_rescale_enabled && this->m_rescale_width > 0 && !this->m_rescale_keep_orig_size) {
|
if (this->m_rescale_enabled && this->m_rescale_width > 0 && !this->m_rescale_keep_orig_size) {
|
||||||
return this->m_rescale_width;
|
return this->m_rescale_width;
|
||||||
|
@ -394,7 +410,7 @@ uint32_t Source::mirror::get_width()
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Source::mirror::get_height()
|
uint32_t source::mirror::instance::get_height()
|
||||||
{
|
{
|
||||||
if (this->m_rescale_enabled && this->m_rescale_height > 0 && !this->m_rescale_keep_orig_size)
|
if (this->m_rescale_enabled && this->m_rescale_height > 0 && !this->m_rescale_keep_orig_size)
|
||||||
return this->m_rescale_height;
|
return this->m_rescale_height;
|
||||||
|
@ -405,7 +421,7 @@ uint32_t Source::mirror::get_height()
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::update(obs_data_t* data)
|
void source::mirror::instance::update(obs_data_t* data)
|
||||||
{
|
{
|
||||||
{ // User changed the source we are tracking.
|
{ // User changed the source we are tracking.
|
||||||
release_input();
|
release_input();
|
||||||
|
@ -455,7 +471,7 @@ void Source::mirror::update(obs_data_t* data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::activate()
|
void source::mirror::instance::activate()
|
||||||
{
|
{
|
||||||
this->m_active = true;
|
this->m_active = true;
|
||||||
|
|
||||||
|
@ -465,7 +481,7 @@ void Source::mirror::activate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::deactivate()
|
void source::mirror::instance::deactivate()
|
||||||
{
|
{
|
||||||
this->m_active = false;
|
this->m_active = false;
|
||||||
}
|
}
|
||||||
|
@ -480,7 +496,7 @@ static inline void mix_audio(float* p_out, float* p_in, size_t pos, size_t count
|
||||||
*(out++) += *(in++);
|
*(out++) += *(in++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::video_tick(float time)
|
void source::mirror::instance::video_tick(float time)
|
||||||
{
|
{
|
||||||
this->m_tick += time;
|
this->m_tick += time;
|
||||||
if (this->m_tick > 0.1f) {
|
if (this->m_tick > 0.1f) {
|
||||||
|
@ -521,7 +537,7 @@ void Source::mirror::video_tick(float time)
|
||||||
m_scene_rendered = false;
|
m_scene_rendered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::video_render(gs_effect_t* effect)
|
void source::mirror::instance::video_render(gs_effect_t* effect)
|
||||||
{
|
{
|
||||||
if ((this->m_rescale_width == 0) || (this->m_rescale_height == 0) || !this->m_source_item
|
if ((this->m_rescale_width == 0) || (this->m_rescale_height == 0) || !this->m_source_item
|
||||||
|| !this->m_scene_texture_renderer) {
|
|| !this->m_scene_texture_renderer) {
|
||||||
|
@ -554,7 +570,7 @@ void Source::mirror::video_render(gs_effect_t* effect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::audio_capture_cb(std::shared_ptr<obs::source> source, audio_data const* const audio, bool)
|
void source::mirror::instance::audio_capture_cb(std::shared_ptr<obs::source> source, audio_data const* const audio, bool)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> ulock(this->m_audio_lock);
|
std::unique_lock<std::mutex> ulock(this->m_audio_lock);
|
||||||
if (!this->m_audio_enabled) {
|
if (!this->m_audio_enabled) {
|
||||||
|
@ -592,7 +608,7 @@ void Source::mirror::audio_capture_cb(std::shared_ptr<obs::source> source, audio
|
||||||
this->m_audio_notify.notify_all();
|
this->m_audio_notify.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::audio_output_cb()
|
void source::mirror::instance::audio_output_cb()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> ulock(this->m_audio_lock);
|
std::unique_lock<std::mutex> ulock(this->m_audio_lock);
|
||||||
|
|
||||||
|
@ -606,26 +622,26 @@ void Source::mirror::audio_output_cb()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::enum_active_sources(obs_source_enum_proc_t enum_callback, void* param)
|
void source::mirror::instance::enum_active_sources(obs_source_enum_proc_t enum_callback, void* param)
|
||||||
{
|
{
|
||||||
if (this->m_scene) {
|
if (this->m_scene) {
|
||||||
enum_callback(this->m_self, this->m_scene->get(), param);
|
enum_callback(this->m_self, this->m_scene->get(), param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::load(obs_data_t* data)
|
void source::mirror::instance::load(obs_data_t* data)
|
||||||
{
|
{
|
||||||
this->update(data);
|
this->update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::save(obs_data_t* data)
|
void source::mirror::instance::save(obs_data_t* data)
|
||||||
{
|
{
|
||||||
if (this->m_source_item) {
|
if (this->m_source_item) {
|
||||||
obs_data_set_string(data, P_SOURCE, obs_source_get_name(m_source->get()));
|
obs_data_set_string(data, P_SOURCE, obs_source_get_name(m_source->get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::mirror::on_source_rename(obs::source* source, std::string, std::string)
|
void source::mirror::instance::on_source_rename(obs::source* source, std::string, std::string)
|
||||||
{
|
{
|
||||||
obs_data_t* ref = obs_source_get_settings(this->m_self);
|
obs_data_t* ref = obs_source_get_settings(this->m_self);
|
||||||
obs_data_set_string(ref, P_SOURCE, obs_source_get_name(source->get()));
|
obs_data_set_string(ref, P_SOURCE, obs_source_get_name(source->get()));
|
||||||
|
|
|
@ -40,13 +40,21 @@
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Source {
|
namespace source {
|
||||||
class mirror_factory {
|
namespace mirror {
|
||||||
|
class factory {
|
||||||
|
friend class std::_Ptr_base<source::mirror::factory>;
|
||||||
|
|
||||||
obs_source_info osi;
|
obs_source_info osi;
|
||||||
|
|
||||||
|
public: // Singleton
|
||||||
|
static void initialize();
|
||||||
|
static void finalize();
|
||||||
|
static std::shared_ptr<factory> get();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
mirror_factory();
|
factory();
|
||||||
~mirror_factory();
|
~factory();
|
||||||
|
|
||||||
static const char* get_name(void*);
|
static const char* get_name(void*);
|
||||||
static void get_defaults(obs_data_t*);
|
static void get_defaults(obs_data_t*);
|
||||||
|
@ -69,7 +77,7 @@ namespace Source {
|
||||||
static void save(void*, obs_data_t*);
|
static void save(void*, obs_data_t*);
|
||||||
};
|
};
|
||||||
|
|
||||||
class mirror {
|
class instance {
|
||||||
bool m_active;
|
bool m_active;
|
||||||
obs_source_t* m_self;
|
obs_source_t* m_self;
|
||||||
float_t m_tick;
|
float_t m_tick;
|
||||||
|
@ -109,8 +117,8 @@ namespace Source {
|
||||||
void acquire_input(std::string source_name);
|
void acquire_input(std::string source_name);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
mirror(obs_data_t*, obs_source_t*);
|
instance(obs_data_t*, obs_source_t*);
|
||||||
~mirror();
|
~instance();
|
||||||
|
|
||||||
uint32_t get_width();
|
uint32_t get_width();
|
||||||
uint32_t get_height();
|
uint32_t get_height();
|
||||||
|
@ -128,4 +136,5 @@ namespace Source {
|
||||||
|
|
||||||
void on_source_rename(obs::source* source, std::string new_name, std::string old_name);
|
void on_source_rename(obs::source* source, std::string new_name, std::string old_name);
|
||||||
};
|
};
|
||||||
}; // namespace Source
|
} // namespace mirror
|
||||||
|
}; // namespace source
|
||||||
|
|
Loading…
Reference in a new issue