mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-12-28 18:41:14 +00:00
filter-displacement: Refactor onto obs::source_factory
This drastically improves stability and prevents all exceptions from leaking into libobs C code, which prevents crashes and unexpected freezes from exception handlers further down the stack. Additionally minor work was done to further improve the quality and user experience for the filter.
This commit is contained in:
parent
aa170c7c54
commit
df8ebd94ea
4 changed files with 236 additions and 328 deletions
|
@ -1,55 +1,91 @@
|
|||
uniform float4x4 ViewProj;
|
||||
uniform texture2d image;
|
||||
uniform texture2d displacementMap;
|
||||
uniform float2 texelScale;
|
||||
uniform float2 displacementScale;
|
||||
// Provided by OBS
|
||||
uniform float4x4 ViewProj <
|
||||
bool visible = false;
|
||||
>;
|
||||
|
||||
sampler_state textureSampler {
|
||||
Filter = Linear;
|
||||
AddressU = Wrap;
|
||||
AddressV = Wrap;
|
||||
};
|
||||
sampler_state dispTextureSampler {
|
||||
Filter = Linear;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
uniform texture2d image <
|
||||
bool visible = false;
|
||||
>;
|
||||
|
||||
// Parameters
|
||||
uniform float2 image_size <
|
||||
bool visible = false;
|
||||
>;
|
||||
|
||||
uniform float2 image_inverse_size <
|
||||
bool visible = false;
|
||||
>;
|
||||
|
||||
uniform texture2d normal <
|
||||
bool visible = true;
|
||||
string name = "Normal Map";
|
||||
string description = "A normal map that is used for displacing the texture sample locations.";
|
||||
>;
|
||||
|
||||
uniform float2 scale <
|
||||
bool visible = true;
|
||||
string mode = "slider";
|
||||
float2 minimum = {0.0, 0.0};
|
||||
float2 maximum = {100.0, 100.0};
|
||||
float2 step = {0.01, 0.01};
|
||||
> = {0.0, 0.0};
|
||||
|
||||
uniform float scale_type <
|
||||
bool visible = true;
|
||||
string mode = "slider";
|
||||
string name = "Scale Mode";
|
||||
string description = "A value of 0.0 is in Texel Space, while a value of 100.0 is in Pixel Space.";
|
||||
float2 minimum = {0.0, 0.0};
|
||||
float2 maximum = {100.0, 100.0};
|
||||
float2 step = {0.01, 0.01};
|
||||
> = 0.0;
|
||||
|
||||
// Samplers
|
||||
sampler_state smp_linear_wrap {
|
||||
Filter = Linear;
|
||||
AddressU = Wrap;
|
||||
AddressV = Wrap;
|
||||
};
|
||||
|
||||
struct VertDataIn {
|
||||
sampler_state smp_linear_clamp {
|
||||
Filter = Linear;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
};
|
||||
|
||||
// Structs
|
||||
struct FunctionData {
|
||||
float4 pos : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VertDataOut {
|
||||
float4 pos : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
// Functions
|
||||
FunctionData vertex_shader(FunctionData v) {
|
||||
v.pos = mul(float4(v.pos.xyz, 1.0), ViewProj);
|
||||
return v;
|
||||
};
|
||||
|
||||
VertDataOut VSDefault(VertDataIn v_in)
|
||||
{
|
||||
VertDataOut vert_out;
|
||||
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
|
||||
vert_out.uv = v_in.uv;
|
||||
return vert_out;
|
||||
}
|
||||
float4 pixel_shader(FunctionData v) : TARGET {
|
||||
float4 v_normal = normal.Sample(smp_linear_wrap, v.uv);
|
||||
|
||||
float4 PSDisplace(VertDataOut v_in) : TARGET
|
||||
{
|
||||
float2 disp = displacementMap.Sample(dispTextureSampler, v_in.uv).rg - float2(.5, .5);
|
||||
float2 offset = v_normal.rg;
|
||||
offset -= float2(.5, .5);
|
||||
offset *= 255.0;
|
||||
offset = floor(abs(offset)) * sign(offset);
|
||||
offset /= 127.0;
|
||||
|
||||
// Method 1: Only Math
|
||||
disp = (floor(abs(disp * 255.0)) / 255.0) * sign(disp);
|
||||
offset *= lerp(float2(1.0, 1.0), image_inverse_size, scale_type);
|
||||
offset *= scale;
|
||||
|
||||
float2 uv = v_in.uv + (disp * texelScale * displacementScale);
|
||||
|
||||
return image.Sample(textureSampler, uv);
|
||||
}
|
||||
return image.Sample(smp_linear_clamp, v.uv + offset);
|
||||
};
|
||||
|
||||
// Techniques
|
||||
technique Draw
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_shader = VSDefault(v_in);
|
||||
pixel_shader = PSDisplace(v_in);
|
||||
vertex_shader = vertex_shader(v);
|
||||
pixel_shader = pixel_shader(v);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,9 +165,10 @@ Filter.ColorGrade.Correction.Contrast="Contrast"
|
|||
# Filter - Displacement
|
||||
Filter.Displacement="Displacement Mapping"
|
||||
Filter.Displacement.File="File"
|
||||
Filter.Displacement.File.Types="Images (*.png *.jpeg *.jpg *.bmp *.tga);;All Files (*)"
|
||||
Filter.Displacement.Ratio="Ratio"
|
||||
Filter.Displacement.Scale="Scale"
|
||||
Filter.Displacement.Scale.Description="Scale of the displacement, either in pixels (Scale Type = 100.0) or in UVs (Scale Type = 0.0)."
|
||||
Filter.Displacement.Scale.Type="Scaling Type"
|
||||
Filter.Displacement.Scale.Type.Description="Type of the displacement scale, with\nvalues closer to 0.00 being UV space and\nvalues closer to 100.00 being Pixel space."
|
||||
|
||||
# Filter - Dynamic Mask
|
||||
Filter.DynamicMask="Dynamic Mask"
|
||||
|
|
|
@ -24,276 +24,77 @@
|
|||
|
||||
#define ST "Filter.Displacement"
|
||||
#define ST_FILE "Filter.Displacement.File"
|
||||
#define ST_FILE_TYPES "Filter.Displacement.File.Types"
|
||||
#define ST_RATIO "Filter.Displacement.Ratio"
|
||||
#define ST_SCALE "Filter.Displacement.Scale"
|
||||
|
||||
static const char* get_name(void*) noexcept try {
|
||||
return D_TRANSLATE(ST);
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
return "";
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
return "";
|
||||
}
|
||||
|
||||
static void* create(obs_data_t* data, obs_source_t* source) noexcept try {
|
||||
return new filter::displacement::displacement_instance(data, source);
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void destroy(void* ptr) noexcept try {
|
||||
delete reinterpret_cast<filter::displacement::displacement_instance*>(ptr);
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static void get_defaults(obs_data_t* data) noexcept try {
|
||||
char* disp = obs_module_file("filter-displacement/neutral.png");
|
||||
obs_data_set_default_string(data, ST_FILE, disp);
|
||||
obs_data_set_default_double(data, ST_RATIO, 0);
|
||||
obs_data_set_default_double(data, ST_SCALE, 0);
|
||||
bfree(disp);
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static obs_properties_t* get_properties(void* ptr) noexcept try {
|
||||
obs_properties_t* pr = obs_properties_create();
|
||||
|
||||
std::string path = "";
|
||||
if (ptr)
|
||||
path = reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->get_file();
|
||||
|
||||
obs_properties_add_path(pr, ST_FILE, D_TRANSLATE(ST_FILE), obs_path_type::OBS_PATH_FILE, D_TRANSLATE(ST_FILE_TYPES),
|
||||
path.c_str());
|
||||
obs_properties_add_float_slider(pr, ST_RATIO, D_TRANSLATE(ST_RATIO), 0, 1, 0.01);
|
||||
obs_properties_add_float_slider(pr, ST_SCALE, D_TRANSLATE(ST_SCALE), -1000, 1000, 0.01);
|
||||
return pr;
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void update(void* ptr, obs_data_t* data) noexcept try {
|
||||
reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->update(data);
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static void activate(void* ptr) noexcept try {
|
||||
reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->activate();
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static void deactivate(void* ptr) noexcept try {
|
||||
reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->deactivate();
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static void show(void* ptr) noexcept try {
|
||||
reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->show();
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static void hide(void* ptr) noexcept try {
|
||||
reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->hide();
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static void video_tick(void* ptr, float time) noexcept try {
|
||||
reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->video_tick(time);
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static void video_render(void* ptr, gs_effect_t* effect) noexcept try {
|
||||
reinterpret_cast<filter::displacement::displacement_instance*>(ptr)->video_render(effect);
|
||||
} catch (const std::exception& ex) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s': %s.", __FUNCTION_NAME__, ex.what());
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
|
||||
}
|
||||
|
||||
static std::shared_ptr<filter::displacement::displacement_factory> factory_instance = nullptr;
|
||||
|
||||
void filter::displacement::displacement_factory::initialize()
|
||||
{
|
||||
factory_instance = std::make_shared<filter::displacement::displacement_factory>();
|
||||
}
|
||||
|
||||
void filter::displacement::displacement_factory::finalize()
|
||||
{
|
||||
factory_instance.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<filter::displacement::displacement_factory> filter::displacement::displacement_factory::get()
|
||||
{
|
||||
return factory_instance;
|
||||
}
|
||||
|
||||
filter::displacement::displacement_factory::displacement_factory()
|
||||
{
|
||||
memset(&_source_info, 0, sizeof(obs_source_info));
|
||||
_source_info.id = "obs-stream-effects-filter-displacement";
|
||||
_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.show = show;
|
||||
_source_info.hide = hide;
|
||||
_source_info.video_tick = video_tick;
|
||||
_source_info.video_render = video_render;
|
||||
|
||||
obs_register_source(&_source_info);
|
||||
}
|
||||
|
||||
filter::displacement::displacement_factory::~displacement_factory() {}
|
||||
|
||||
void filter::displacement::displacement_instance::validate_file_texture(std::string file)
|
||||
{
|
||||
bool do_update = false;
|
||||
|
||||
// Don't allow empty file names.
|
||||
if (file.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// File name different
|
||||
if (file != _file_name) {
|
||||
do_update = true;
|
||||
_file_name = file;
|
||||
}
|
||||
|
||||
// Timestamp verification
|
||||
struct stat stats;
|
||||
if (os_stat(_file_name.c_str(), &stats) != 0) {
|
||||
do_update = do_update || (stats.st_ctime != _file_create_time);
|
||||
do_update = do_update || (stats.st_mtime != _file_modified_time);
|
||||
do_update = do_update || (static_cast<size_t>(stats.st_size) != _file_size);
|
||||
_file_create_time = stats.st_ctime;
|
||||
_file_modified_time = stats.st_mtime;
|
||||
_file_size = static_cast<size_t>(stats.st_size);
|
||||
}
|
||||
|
||||
do_update = !_file_texture || do_update;
|
||||
|
||||
if (do_update) {
|
||||
try {
|
||||
_file_texture = std::make_shared<gs::texture>(_file_name);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#define ST_SCALE_TYPE "Filter.Displacment.Scale.Type"
|
||||
|
||||
filter::displacement::displacement_instance::displacement_instance(obs_data_t* data, obs_source_t* context)
|
||||
: _self(context), _timer(), _effect(), _distance(), _displacement_scale(), _file_create_time(),
|
||||
_file_modified_time(), _file_size()
|
||||
: obs::source_instance(data, context)
|
||||
{
|
||||
char* effectFile = obs_module_file("effects/displace.effect");
|
||||
if (effectFile) {
|
||||
try {
|
||||
_effect = gs::effect::create(effectFile);
|
||||
} catch (...) {
|
||||
P_LOG_ERROR("<Displacement Filter:%s> Failed to load displacement effect.", obs_source_get_name(_self));
|
||||
}
|
||||
bfree(effectFile);
|
||||
std::string effect = "";
|
||||
{
|
||||
char* buf = obs_module_file("effects/displace.effect");
|
||||
effect = buf;
|
||||
bfree(buf);
|
||||
}
|
||||
|
||||
update(data);
|
||||
_effect = gs::effect::create(effect);
|
||||
}
|
||||
|
||||
filter::displacement::displacement_instance::~displacement_instance()
|
||||
{
|
||||
_effect.reset();
|
||||
_file_texture.reset();
|
||||
_texture.reset();
|
||||
}
|
||||
|
||||
void filter::displacement::displacement_instance::update(obs_data_t* data)
|
||||
void filter::displacement::displacement_instance::load(obs_data_t* settings)
|
||||
{
|
||||
validate_file_texture(obs_data_get_string(data, ST_FILE));
|
||||
|
||||
_distance = float_t(obs_data_get_double(data, ST_RATIO));
|
||||
vec2_set(&_displacement_scale, float_t(obs_data_get_double(data, ST_SCALE)),
|
||||
float_t(obs_data_get_double(data, ST_SCALE)));
|
||||
update(settings);
|
||||
}
|
||||
|
||||
uint32_t filter::displacement::displacement_instance::get_width()
|
||||
inline void migrate_settings(obs_data_t* settings)
|
||||
{
|
||||
return 0;
|
||||
uint64_t version = static_cast<uint64_t>(obs_data_get_int(settings, S_VERSION));
|
||||
|
||||
switch (version & STREAMEFFECTS_MASK_COMPAT) {
|
||||
case 0:
|
||||
obs_data_set_double(settings, ST_SCALE, obs_data_get_double(settings, "Filter.Displacement.Scale") * 0.5);
|
||||
obs_data_set_double(settings, ST_SCALE_TYPE,
|
||||
obs_data_get_double(settings, "Filter.Displacement.Ratio") * 100.0);
|
||||
obs_data_unset_user_value(settings, "Filter.Displacement.Ratio");
|
||||
case STREAMEFFECTS_MAKE_VERSION(0, 8, 0, 0):
|
||||
break;
|
||||
}
|
||||
|
||||
obs_data_set_int(settings, S_VERSION, STREAMEFFECTS_VERSION);
|
||||
}
|
||||
|
||||
uint32_t filter::displacement::displacement_instance::get_height()
|
||||
void filter::displacement::displacement_instance::update(obs_data_t* settings)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
migrate_settings(settings);
|
||||
|
||||
void filter::displacement::displacement_instance::activate() {}
|
||||
_scale[0] = _scale[1] = static_cast<float_t>(obs_data_get_double(settings, ST_SCALE));
|
||||
_scale_type = static_cast<float_t>(obs_data_get_double(settings, ST_SCALE_TYPE) / 100.0);
|
||||
|
||||
void filter::displacement::displacement_instance::deactivate() {}
|
||||
|
||||
void filter::displacement::displacement_instance::show() {}
|
||||
|
||||
void filter::displacement::displacement_instance::hide() {}
|
||||
|
||||
void filter::displacement::displacement_instance::video_tick(float time)
|
||||
{
|
||||
_timer += time;
|
||||
if (_timer >= 1.0f) {
|
||||
_timer -= 1.0f;
|
||||
validate_file_texture(_file_name);
|
||||
std::string new_file = obs_data_get_string(settings, ST_FILE);
|
||||
if (new_file != _texture_file) {
|
||||
try {
|
||||
_texture = std::make_shared<gs::texture>(new_file);
|
||||
_texture_file = new_file;
|
||||
} catch (...) {
|
||||
_texture.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float interp(float a, float b, float v)
|
||||
void filter::displacement::displacement_instance::video_tick(float_t)
|
||||
{
|
||||
return (a * (1.0f - v)) + (b * v);
|
||||
_width = obs_source_get_base_width(_self);
|
||||
_height = obs_source_get_base_height(_self);
|
||||
}
|
||||
|
||||
void filter::displacement::displacement_instance::video_render(gs_effect_t*)
|
||||
{
|
||||
obs_source_t* parent = obs_filter_get_parent(_self);
|
||||
obs_source_t* target = obs_filter_get_target(_self);
|
||||
uint32_t baseW = obs_source_get_base_width(target), baseH = obs_source_get_base_height(target);
|
||||
|
||||
// Skip rendering if our target, parent or context is not valid.
|
||||
if (!parent || !target || !baseW || !baseH || !_file_texture) {
|
||||
if (!_texture) { // No displacement map, so just skip us for now.
|
||||
obs_source_skip_video_filter(_self);
|
||||
return;
|
||||
}
|
||||
|
@ -302,22 +103,82 @@ void filter::displacement::displacement_instance::video_render(gs_effect_t*)
|
|||
obs_source_skip_video_filter(_self);
|
||||
return;
|
||||
}
|
||||
|
||||
_effect->get_parameter("image_size")->set_float2(static_cast<float_t>(_width), static_cast<float_t>(_height));
|
||||
_effect->get_parameter("image_inverse_size")
|
||||
->set_float2(static_cast<float_t>(1.0 / _width), static_cast<float_t>(1.0 / _height));
|
||||
_effect->get_parameter("normal")->set_texture(_texture->get_object());
|
||||
_effect->get_parameter("scale")->set_float2(_scale[0], _scale[1]);
|
||||
_effect->get_parameter("scale_type")->set_float(_scale_type);
|
||||
|
||||
if (_effect->has_parameter("texelScale")) {
|
||||
_effect->get_parameter("texelScale")
|
||||
->set_float2(interp((1.0f / baseW), 1.0f, _distance), interp((1.0f / baseH), 1.0f, _distance));
|
||||
}
|
||||
if (_effect->has_parameter("displacementScale")) {
|
||||
_effect->get_parameter("displacementScale")->set_float2(_displacement_scale);
|
||||
}
|
||||
if (_effect->has_parameter("displacementMap")) {
|
||||
_effect->get_parameter("displacementMap")->set_texture(_file_texture);
|
||||
}
|
||||
|
||||
obs_source_process_filter_end(_self, _effect->get_object(), baseW, baseH);
|
||||
obs_source_process_filter_end(_self, _effect->get_object(), _width, _height);
|
||||
}
|
||||
|
||||
std::string filter::displacement::displacement_instance::get_file()
|
||||
{
|
||||
return _file_name;
|
||||
return _texture_file;
|
||||
}
|
||||
|
||||
std::shared_ptr<filter::displacement::displacement_factory>
|
||||
filter::displacement::displacement_factory::factory_instance = nullptr;
|
||||
|
||||
filter::displacement::displacement_factory::displacement_factory()
|
||||
{
|
||||
_info.id = "obs-stream-effects-filter-displacement";
|
||||
_info.type = OBS_SOURCE_TYPE_FILTER;
|
||||
_info.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW;
|
||||
|
||||
_info.get_width = _info.get_height = nullptr;
|
||||
|
||||
obs_register_source(&_info);
|
||||
}
|
||||
|
||||
filter::displacement::displacement_factory::~displacement_factory() {}
|
||||
|
||||
const char* filter::displacement::displacement_factory::get_name()
|
||||
{
|
||||
return D_TRANSLATE(ST);
|
||||
}
|
||||
|
||||
void filter::displacement::displacement_factory::get_defaults2(obs_data_t* data)
|
||||
{
|
||||
{
|
||||
char* disp = obs_module_file("examples/normal-maps/neutral.png");
|
||||
obs_data_set_default_string(data, ST_FILE, disp);
|
||||
bfree(disp);
|
||||
}
|
||||
|
||||
obs_data_set_default_double(data, ST_SCALE, 0.0);
|
||||
obs_data_set_default_double(data, ST_SCALE_TYPE, 0.0);
|
||||
}
|
||||
|
||||
obs_properties_t*
|
||||
filter::displacement::displacement_factory::get_properties2(filter::displacement::displacement_instance* data)
|
||||
{
|
||||
obs_properties_t* pr = obs_properties_create();
|
||||
|
||||
std::string path = "";
|
||||
if (data) {
|
||||
path = data->get_file();
|
||||
} else {
|
||||
char* buf = obs_module_file("examples/normal-maps/neutral.png");
|
||||
path = buf;
|
||||
bfree(buf);
|
||||
}
|
||||
|
||||
{
|
||||
auto p = obs_properties_add_path(pr, ST_FILE, D_TRANSLATE(ST_FILE), obs_path_type::OBS_PATH_FILE,
|
||||
D_TRANSLATE(S_FILEFILTERS_TEXTURE), path.c_str());
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_FILE)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_float(pr, ST_SCALE, D_TRANSLATE(ST_SCALE), -10000000.0, 10000000.0, 0.01);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_SCALE)));
|
||||
}
|
||||
{
|
||||
auto p = obs_properties_add_float_slider(pr, ST_SCALE_TYPE, D_TRANSLATE(ST_SCALE_TYPE), 0.0, 100.0, 0.01);
|
||||
obs_property_set_long_description(p, D_TRANSLATE(D_DESC(ST_SCALE_TYPE)));
|
||||
}
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include "obs/gs/gs-effect.hpp"
|
||||
#include "obs/obs-source-factory.hpp"
|
||||
#include "plugin.hpp"
|
||||
|
||||
// OBS
|
||||
|
@ -36,52 +37,61 @@
|
|||
|
||||
namespace filter {
|
||||
namespace displacement {
|
||||
class displacement_factory {
|
||||
obs_source_info _source_info;
|
||||
|
||||
public: // Singleton
|
||||
static void initialize();
|
||||
static void finalize();
|
||||
static std::shared_ptr<displacement_factory> get();
|
||||
|
||||
public:
|
||||
displacement_factory();
|
||||
~displacement_factory();
|
||||
};
|
||||
|
||||
class displacement_instance {
|
||||
obs_source_t* _self;
|
||||
float_t _timer;
|
||||
|
||||
// Rendering
|
||||
class displacement_instance : public obs::source_instance {
|
||||
std::shared_ptr<gs::effect> _effect;
|
||||
float_t _distance;
|
||||
vec2 _displacement_scale;
|
||||
|
||||
// Displacement Map
|
||||
std::string _file_name;
|
||||
std::shared_ptr<gs::texture> _file_texture;
|
||||
time_t _file_create_time;
|
||||
time_t _file_modified_time;
|
||||
size_t _file_size;
|
||||
std::shared_ptr<gs::texture> _texture;
|
||||
std::string _texture_file;
|
||||
float_t _scale[2];
|
||||
float_t _scale_type;
|
||||
|
||||
void validate_file_texture(std::string file);
|
||||
// Cache
|
||||
uint32_t _width;
|
||||
uint32_t _height;
|
||||
|
||||
public:
|
||||
displacement_instance(obs_data_t*, obs_source_t*);
|
||||
~displacement_instance();
|
||||
virtual ~displacement_instance();
|
||||
|
||||
void update(obs_data_t*);
|
||||
uint32_t get_width();
|
||||
uint32_t get_height();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void show();
|
||||
void hide();
|
||||
void video_tick(float);
|
||||
void video_render(gs_effect_t*);
|
||||
virtual void load(obs_data_t* settings) override;
|
||||
virtual void update(obs_data_t* settings) override;
|
||||
|
||||
virtual void video_tick(float_t) override;
|
||||
virtual void video_render(gs_effect_t*) override;
|
||||
|
||||
std::string get_file();
|
||||
};
|
||||
|
||||
class displacement_factory : public obs::source_factory<filter::displacement::displacement_factory,
|
||||
filter::displacement::displacement_instance> {
|
||||
static std::shared_ptr<filter::displacement::displacement_factory> factory_instance;
|
||||
|
||||
public: // Singleton
|
||||
static void initialize()
|
||||
{
|
||||
factory_instance = std::make_shared<filter::displacement::displacement_factory>();
|
||||
}
|
||||
|
||||
static void finalize()
|
||||
{
|
||||
factory_instance.reset();
|
||||
}
|
||||
|
||||
static std::shared_ptr<displacement_factory> get()
|
||||
{
|
||||
return factory_instance;
|
||||
}
|
||||
|
||||
public:
|
||||
displacement_factory();
|
||||
virtual ~displacement_factory();
|
||||
|
||||
virtual const char* get_name() override;
|
||||
|
||||
virtual void get_defaults2(obs_data_t* data) override;
|
||||
|
||||
virtual obs_properties_t* get_properties2(filter::displacement::displacement_instance* data) override;
|
||||
};
|
||||
} // namespace displacement
|
||||
} // namespace filter
|
||||
|
|
Loading…
Reference in a new issue