project: Formatting

This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2018-11-07 15:24:25 +01:00
parent 16f55ca583
commit b87ca70796
32 changed files with 982 additions and 922 deletions

View File

@ -18,21 +18,21 @@
*/ */
#include "filter-custom-shader.h" #include "filter-custom-shader.h"
#include "strings.h"
#include <vector>
#include <tuple>
#include <fstream> #include <fstream>
#include <tuple>
#include <vector>
#include "strings.h"
extern "C" { extern "C" {
#pragma warning (push) #pragma warning(push)
#pragma warning (disable: 4201) #pragma warning(disable : 4201)
#include "util/platform.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"
#include "graphics/matrix4.h" #include "graphics/matrix4.h"
#pragma warning (pop) #include "util/platform.h"
#pragma warning(pop)
} }
#define S "Filter.CustomShader" #define S "Filter.CustomShader"
/** Shader Definitions /** Shader Definitions
* - Only one technique, any number of passes. * - Only one technique, any number of passes.
@ -53,36 +53,31 @@ extern "C" {
* - $(name)_Texel: Texture Texel Size (1/Texture Size) (float2). * - $(name)_Texel: Texture Texel Size (1/Texture Size) (float2).
**/ **/
enum class ShaderType : int64_t { enum class ShaderType : int64_t { Text, File };
Text,
File
};
static filter::CustomShader* handler; static filter::CustomShader* handler;
INITIALIZER(HandlerInit) { INITIALIZER(HandlerInit)
initializerFunctions.push_back([] { {
handler = new filter::CustomShader(); initializerFunctions.push_back([] { handler = new filter::CustomShader(); });
}); finalizerFunctions.push_back([] { delete handler; });
finalizerFunctions.push_back([] {
delete handler;
});
} }
filter::CustomShader::CustomShader() { filter::CustomShader::CustomShader()
{
memset(&sourceInfo, 0, sizeof(obs_source_info)); memset(&sourceInfo, 0, sizeof(obs_source_info));
sourceInfo.id = "obs-stream-effects-filter-custom-shader"; sourceInfo.id = "obs-stream-effects-filter-custom-shader";
sourceInfo.type = OBS_SOURCE_TYPE_FILTER; sourceInfo.type = OBS_SOURCE_TYPE_FILTER;
sourceInfo.output_flags = OBS_SOURCE_VIDEO; sourceInfo.output_flags = OBS_SOURCE_VIDEO;
sourceInfo.get_name = get_name; sourceInfo.get_name = get_name;
sourceInfo.get_defaults = get_defaults; sourceInfo.get_defaults = get_defaults;
sourceInfo.get_properties = get_properties; sourceInfo.get_properties = get_properties;
sourceInfo.create = create; sourceInfo.create = create;
sourceInfo.destroy = destroy; sourceInfo.destroy = destroy;
sourceInfo.update = update; sourceInfo.update = update;
sourceInfo.activate = activate; sourceInfo.activate = activate;
sourceInfo.deactivate = deactivate; sourceInfo.deactivate = deactivate;
sourceInfo.video_tick = video_tick; sourceInfo.video_tick = video_tick;
sourceInfo.video_render = video_render; sourceInfo.video_render = video_render;
obs_register_source(&sourceInfo); obs_register_source(&sourceInfo);
@ -90,59 +85,72 @@ filter::CustomShader::CustomShader() {
filter::CustomShader::~CustomShader() {} filter::CustomShader::~CustomShader() {}
const char * filter::CustomShader::get_name(void *) { const char* filter::CustomShader::get_name(void*)
{
return P_TRANSLATE(S); return P_TRANSLATE(S);
} }
void filter::CustomShader::get_defaults(obs_data_t *data) { void filter::CustomShader::get_defaults(obs_data_t* data)
{
gfx::effect_source::get_defaults(data); gfx::effect_source::get_defaults(data);
} }
obs_properties_t * filter::CustomShader::get_properties(void *ptr) { obs_properties_t* filter::CustomShader::get_properties(void* ptr)
obs_properties_t *pr = obs_properties_create_param(ptr, nullptr); {
obs_properties_t* pr = obs_properties_create_param(ptr, nullptr);
reinterpret_cast<Instance*>(ptr)->get_properties(pr); reinterpret_cast<Instance*>(ptr)->get_properties(pr);
return pr; return pr;
} }
void * filter::CustomShader::create(obs_data_t *data, obs_source_t *src) { void* filter::CustomShader::create(obs_data_t* data, obs_source_t* src)
{
return new Instance(data, src); return new Instance(data, src);
} }
void filter::CustomShader::destroy(void *ptr) { void filter::CustomShader::destroy(void* ptr)
{
delete reinterpret_cast<Instance*>(ptr); delete reinterpret_cast<Instance*>(ptr);
} }
uint32_t filter::CustomShader::get_width(void *ptr) { uint32_t filter::CustomShader::get_width(void* ptr)
{
return reinterpret_cast<Instance*>(ptr)->get_width(); return reinterpret_cast<Instance*>(ptr)->get_width();
} }
uint32_t filter::CustomShader::get_height(void *ptr) { uint32_t filter::CustomShader::get_height(void* ptr)
{
return reinterpret_cast<Instance*>(ptr)->get_height(); return reinterpret_cast<Instance*>(ptr)->get_height();
} }
void filter::CustomShader::update(void *ptr, obs_data_t *data) { void filter::CustomShader::update(void* ptr, obs_data_t* data)
{
reinterpret_cast<Instance*>(ptr)->update(data); reinterpret_cast<Instance*>(ptr)->update(data);
} }
void filter::CustomShader::activate(void *ptr) { void filter::CustomShader::activate(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->activate(); reinterpret_cast<Instance*>(ptr)->activate();
} }
void filter::CustomShader::deactivate(void *ptr) { void filter::CustomShader::deactivate(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->deactivate(); reinterpret_cast<Instance*>(ptr)->deactivate();
} }
void filter::CustomShader::video_tick(void *ptr, float time) { void filter::CustomShader::video_tick(void* ptr, float time)
{
reinterpret_cast<Instance*>(ptr)->video_tick(time); reinterpret_cast<Instance*>(ptr)->video_tick(time);
} }
void filter::CustomShader::video_render(void *ptr, gs_effect_t *effect) { void filter::CustomShader::video_render(void* ptr, gs_effect_t* effect)
{
reinterpret_cast<Instance*>(ptr)->video_render(effect); reinterpret_cast<Instance*>(ptr)->video_render(effect);
} }
filter::CustomShader::Instance::Instance(obs_data_t *data, obs_source_t *source) : gfx::effect_source(data, source) { filter::CustomShader::Instance::Instance(obs_data_t* data, obs_source_t* source) : gfx::effect_source(data, source)
{
m_defaultShaderPath = "shaders/filter/example.effect"; m_defaultShaderPath = "shaders/filter/example.effect";
m_renderTarget = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE); m_renderTarget = std::make_shared<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
update(data); update(data);
} }
@ -299,28 +307,27 @@ filter::CustomShader::Instance::~Instance() {}
// } // }
//} //}
uint32_t filter::CustomShader::Instance::get_width() { uint32_t filter::CustomShader::Instance::get_width()
{
return 0; return 0;
} }
uint32_t filter::CustomShader::Instance::get_height() { uint32_t filter::CustomShader::Instance::get_height()
{
return 0; return 0;
} }
bool filter::CustomShader::Instance::is_special_parameter(std::string name, gs::effect_parameter::type type) { bool filter::CustomShader::Instance::is_special_parameter(std::string name, gs::effect_parameter::type type)
{
std::pair<std::string, gs::effect_parameter::type> reservedParameters[] = { std::pair<std::string, gs::effect_parameter::type> reservedParameters[] = {
{ "ViewProj", gs::effect_parameter::type::Matrix }, {"ViewProj", gs::effect_parameter::type::Matrix}, {"ViewSize", gs::effect_parameter::type::Float2},
{ "ViewSize", gs::effect_parameter::type::Float2 }, {"ViewSizeI", gs::effect_parameter::type::Integer2}, {"Time", gs::effect_parameter::type::Float},
{ "ViewSizeI", gs::effect_parameter::type::Integer2 }, {"TimeActive", gs::effect_parameter::type::Float}, {"Image", gs::effect_parameter::type::Texture},
{ "Time", gs::effect_parameter::type::Float },
{ "TimeActive", gs::effect_parameter::type::Float },
{ "Image", gs::effect_parameter::type::Texture },
}; };
std::pair<std::string, gs::effect_parameter::type> textureParameters[] = { std::pair<std::string, gs::effect_parameter::type> textureParameters[] = {
{ "Size", gs::effect_parameter::type::Float2 }, {"Size", gs::effect_parameter::type::Float2},
{ "SizeI", gs::effect_parameter::type::Integer2 }, {"SizeI", gs::effect_parameter::type::Integer2},
{ "Texel", gs::effect_parameter::type::Float2 } {"Texel", gs::effect_parameter::type::Float2}};
};
for (auto& kv : reservedParameters) { for (auto& kv : reservedParameters) {
if ((name == kv.first) && (type == kv.second)) if ((name == kv.first) && (type == kv.second))
@ -331,7 +338,7 @@ bool filter::CustomShader::Instance::is_special_parameter(std::string name, gs::
size_t posUnderscore = name.find_last_of('_'); size_t posUnderscore = name.find_last_of('_');
if (posUnderscore != std::string::npos) { if (posUnderscore != std::string::npos) {
std::string firstPart, secondPart; std::string firstPart, secondPart;
firstPart = name.substr(0, posUnderscore); firstPart = name.substr(0, posUnderscore);
secondPart = name.substr(posUnderscore + 1); secondPart = name.substr(posUnderscore + 1);
try { try {
@ -350,7 +357,8 @@ bool filter::CustomShader::Instance::is_special_parameter(std::string name, gs::
return false; return false;
} }
bool filter::CustomShader::Instance::apply_special_parameters(uint32_t viewW, uint32_t viewH) { bool filter::CustomShader::Instance::apply_special_parameters(uint32_t viewW, uint32_t viewH)
{
std::unique_ptr<gs::texture> imageTexture; std::unique_ptr<gs::texture> imageTexture;
m_renderTarget->get_texture(imageTexture); m_renderTarget->get_texture(imageTexture);
@ -360,38 +368,37 @@ bool filter::CustomShader::Instance::apply_special_parameters(uint32_t viewW, ui
return false; return false;
} }
if (m_shader.effect->has_parameter("Image_Size", gs::effect_parameter::type::Float2)) { if (m_shader.effect->has_parameter("Image_Size", gs::effect_parameter::type::Float2)) {
m_shader.effect->get_parameter("Image_Size").set_float2( m_shader.effect->get_parameter("Image_Size")
float_t(imageTexture->get_width()), .set_float2(float_t(imageTexture->get_width()), float_t(imageTexture->get_height()));
float_t(imageTexture->get_height()));
} }
if (m_shader.effect->has_parameter("Image_SizeI"/*, gs::effect_parameter::type::Integer2*/)) { if (m_shader.effect->has_parameter("Image_SizeI" /*, gs::effect_parameter::type::Integer2*/)) {
m_shader.effect->get_parameter("Image_SizeI").set_int2( m_shader.effect->get_parameter("Image_SizeI").set_int2(imageTexture->get_width(), imageTexture->get_height());
imageTexture->get_width(),
imageTexture->get_height());
} }
if (m_shader.effect->has_parameter("Image_Texel", gs::effect_parameter::type::Float2)) { if (m_shader.effect->has_parameter("Image_Texel", gs::effect_parameter::type::Float2)) {
m_shader.effect->get_parameter("Image_Texel").set_float2( m_shader.effect->get_parameter("Image_Texel")
float_t(1.0 / imageTexture->get_width()), .set_float2(float_t(1.0 / imageTexture->get_width()), float_t(1.0 / imageTexture->get_height()));
float_t(1.0 / imageTexture->get_height()));
} }
return true; return true;
} }
bool filter::CustomShader::Instance::video_tick_impl(float_t time) { bool filter::CustomShader::Instance::video_tick_impl(float_t time)
{
return true; return true;
} }
bool filter::CustomShader::Instance::video_render_impl(gs_effect_t* parent_effect, uint32_t viewW, uint32_t viewH) { bool filter::CustomShader::Instance::video_render_impl(gs_effect_t* parent_effect, uint32_t viewW, uint32_t viewH)
{
// Render original source to render target. // Render original source to render target.
{ {
auto op = m_renderTarget->render(viewW, viewH); auto op = m_renderTarget->render(viewW, viewH);
vec4 black; vec4_zero(&black); vec4 black;
vec4_zero(&black);
gs_ortho(0, (float_t)viewW, 0, (float_t)viewH, 0, 1); gs_ortho(0, (float_t)viewW, 0, (float_t)viewH, 0, 1);
gs_clear(GS_CLEAR_COLOR, &black, 0, 0); gs_clear(GS_CLEAR_COLOR, &black, 0, 0);
if (obs_source_process_filter_begin(m_source, GS_RGBA, OBS_NO_DIRECT_RENDERING)) { if (obs_source_process_filter_begin(m_source, GS_RGBA, OBS_NO_DIRECT_RENDERING)) {
obs_source_process_filter_end(m_source, obs_source_process_filter_end(
parent_effect ? parent_effect : obs_get_base_effect(OBS_EFFECT_DEFAULT), viewW, viewH); m_source, parent_effect ? parent_effect : obs_get_base_effect(OBS_EFFECT_DEFAULT), viewW, viewH);
} }
} }
gs_texture_t* sourceTexture = m_renderTarget->get_object(); gs_texture_t* sourceTexture = m_renderTarget->get_object();

View File

@ -18,13 +18,13 @@
*/ */
#pragma once #pragma once
#include "plugin.h" #include <inttypes.h>
#include "gs-effect.h"
#include "gs-rendertarget.h"
#include <list> #include <list>
#include <vector> #include <vector>
#include <inttypes.h>
#include "gfx-effect-source.h" #include "gfx-effect-source.h"
#include "gs-effect.h"
#include "gs-rendertarget.h"
#include "plugin.h"
namespace filter { namespace filter {
class CustomShader { class CustomShader {
@ -32,19 +32,19 @@ namespace filter {
CustomShader(); CustomShader();
~CustomShader(); ~CustomShader();
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*);
static obs_properties_t *get_properties(void *); static obs_properties_t* get_properties(void*);
static void *create(obs_data_t *, obs_source_t *); static void* create(obs_data_t*, obs_source_t*);
static void destroy(void *); static void destroy(void*);
static uint32_t get_width(void *); static uint32_t get_width(void*);
static uint32_t get_height(void *); static uint32_t get_height(void*);
static void update(void *, obs_data_t *); static void update(void*, obs_data_t*);
static void activate(void *); static void activate(void*);
static void deactivate(void *); static void deactivate(void*);
static void video_tick(void *, float); static void video_tick(void*, float);
static void video_render(void *, gs_effect_t *); static void video_render(void*, gs_effect_t*);
private: private:
obs_source_info sourceInfo; obs_source_info sourceInfo;
@ -56,7 +56,7 @@ namespace filter {
std::shared_ptr<gs::rendertarget> m_renderTarget; std::shared_ptr<gs::rendertarget> m_renderTarget;
protected: protected:
bool apply_special_parameters(uint32_t viewW, uint32_t viewH); bool apply_special_parameters(uint32_t viewW, uint32_t viewH);
virtual bool is_special_parameter(std::string name, gs::effect_parameter::type type) override; virtual bool is_special_parameter(std::string name, gs::effect_parameter::type type) override;
virtual bool video_tick_impl(float_t time) override; virtual bool video_tick_impl(float_t time) override;
virtual bool video_render_impl(gs_effect_t* parent_effect, uint32_t viewW, uint32_t viewH) override; virtual bool video_render_impl(gs_effect_t* parent_effect, uint32_t viewW, uint32_t viewH) override;
@ -64,9 +64,9 @@ namespace filter {
public: public:
Instance(obs_data_t*, obs_source_t*); Instance(obs_data_t*, obs_source_t*);
~Instance(); ~Instance();
uint32_t get_width(); uint32_t get_width();
uint32_t get_height(); uint32_t get_height();
}; };
}; };
} } // namespace filter

View File

@ -22,62 +22,64 @@
// Initializer & Finalizer // Initializer & Finalizer
static filter::Displacement* filterDisplacementInstance; static filter::Displacement* filterDisplacementInstance;
INITIALIZER(FilterDisplacementInit) { INITIALIZER(FilterDisplacementInit)
initializerFunctions.push_back([] { {
filterDisplacementInstance = new filter::Displacement(); initializerFunctions.push_back([] { filterDisplacementInstance = new filter::Displacement(); });
}); finalizerFunctions.push_back([] { delete filterDisplacementInstance; });
finalizerFunctions.push_back([] {
delete filterDisplacementInstance;
});
} }
filter::Displacement::Displacement() { filter::Displacement::Displacement()
{
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";
sourceInfo.type = OBS_SOURCE_TYPE_FILTER; sourceInfo.type = OBS_SOURCE_TYPE_FILTER;
sourceInfo.output_flags = OBS_SOURCE_VIDEO; sourceInfo.output_flags = OBS_SOURCE_VIDEO;
sourceInfo.get_name = get_name; sourceInfo.get_name = get_name;
sourceInfo.get_defaults = get_defaults; sourceInfo.get_defaults = get_defaults;
sourceInfo.get_properties = get_properties; sourceInfo.get_properties = get_properties;
sourceInfo.create = create; sourceInfo.create = create;
sourceInfo.destroy = destroy; sourceInfo.destroy = destroy;
sourceInfo.update = update; sourceInfo.update = update;
sourceInfo.activate = activate; sourceInfo.activate = activate;
sourceInfo.deactivate = deactivate; sourceInfo.deactivate = deactivate;
sourceInfo.show = show; sourceInfo.show = show;
sourceInfo.hide = hide; sourceInfo.hide = hide;
sourceInfo.video_tick = video_tick; sourceInfo.video_tick = video_tick;
sourceInfo.video_render = video_render; sourceInfo.video_render = video_render;
obs_register_source(&sourceInfo); obs_register_source(&sourceInfo);
} }
filter::Displacement::~Displacement() { filter::Displacement::~Displacement() {}
} const char* filter::Displacement::get_name(void*)
{
const char * filter::Displacement::get_name(void *) {
return P_TRANSLATE(S_FILTER_DISPLACEMENT); return P_TRANSLATE(S_FILTER_DISPLACEMENT);
} }
void * filter::Displacement::create(obs_data_t *data, obs_source_t *source) { void* filter::Displacement::create(obs_data_t* data, obs_source_t* source)
{
return new Instance(data, source); return new Instance(data, source);
} }
void filter::Displacement::destroy(void *ptr) { void filter::Displacement::destroy(void* ptr)
{
delete reinterpret_cast<Instance*>(ptr); delete reinterpret_cast<Instance*>(ptr);
} }
uint32_t filter::Displacement::get_width(void *ptr) { uint32_t filter::Displacement::get_width(void* ptr)
{
return reinterpret_cast<Instance*>(ptr)->get_width(); return reinterpret_cast<Instance*>(ptr)->get_width();
} }
uint32_t filter::Displacement::get_height(void *ptr) { uint32_t filter::Displacement::get_height(void* ptr)
{
return reinterpret_cast<Instance*>(ptr)->get_height(); return reinterpret_cast<Instance*>(ptr)->get_height();
} }
void filter::Displacement::get_defaults(obs_data_t *data) { void filter::Displacement::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);
obs_data_set_default_double(data, S_FILTER_DISPLACEMENT_RATIO, 0); obs_data_set_default_double(data, S_FILTER_DISPLACEMENT_RATIO, 0);
@ -85,66 +87,71 @@ void filter::Displacement::get_defaults(obs_data_t *data) {
bfree(disp); bfree(disp);
} }
obs_properties_t * filter::Displacement::get_properties(void *ptr) { obs_properties_t* filter::Displacement::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<Instance*>(ptr)->get_file(); path = reinterpret_cast<Instance*>(ptr)->get_file();
obs_properties_add_path(pr, S_FILTER_DISPLACEMENT_FILE, obs_properties_add_path(pr, S_FILTER_DISPLACEMENT_FILE, P_TRANSLATE(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, obs_properties_add_float_slider(pr, S_FILTER_DISPLACEMENT_RATIO, P_TRANSLATE(S_FILTER_DISPLACEMENT_RATIO), 0, 1,
P_TRANSLATE(S_FILTER_DISPLACEMENT_FILE_TYPES), path.c_str()); 0.01);
obs_properties_add_float_slider(pr, S_FILTER_DISPLACEMENT_RATIO, obs_properties_add_float_slider(pr, S_FILTER_DISPLACEMENT_SCALE, P_TRANSLATE(S_FILTER_DISPLACEMENT_SCALE), -1000,
P_TRANSLATE(S_FILTER_DISPLACEMENT_RATIO), 0, 1, 0.01); 1000, 0.01);
obs_properties_add_float_slider(pr, S_FILTER_DISPLACEMENT_SCALE,
P_TRANSLATE(S_FILTER_DISPLACEMENT_SCALE), -1000, 1000, 0.01);
return pr; return pr;
} }
void filter::Displacement::update(void *ptr, obs_data_t *data) { void filter::Displacement::update(void* ptr, obs_data_t* data)
{
reinterpret_cast<Instance*>(ptr)->update(data); reinterpret_cast<Instance*>(ptr)->update(data);
} }
void filter::Displacement::activate(void *ptr) { void filter::Displacement::activate(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->activate(); reinterpret_cast<Instance*>(ptr)->activate();
} }
void filter::Displacement::deactivate(void *ptr) { void filter::Displacement::deactivate(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->deactivate(); reinterpret_cast<Instance*>(ptr)->deactivate();
} }
void filter::Displacement::show(void *ptr) { void filter::Displacement::show(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->show(); reinterpret_cast<Instance*>(ptr)->show();
} }
void filter::Displacement::hide(void *ptr) { void filter::Displacement::hide(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->hide(); reinterpret_cast<Instance*>(ptr)->hide();
} }
void filter::Displacement::video_tick(void *ptr, float time) { void filter::Displacement::video_tick(void* ptr, float time)
{
reinterpret_cast<Instance*>(ptr)->video_tick(time); reinterpret_cast<Instance*>(ptr)->video_tick(time);
} }
void filter::Displacement::video_render(void *ptr, gs_effect_t *effect) { void filter::Displacement::video_render(void* ptr, gs_effect_t* effect)
{
reinterpret_cast<Instance*>(ptr)->video_render(effect); reinterpret_cast<Instance*>(ptr)->video_render(effect);
} }
filter::Displacement::Instance::Instance(obs_data_t *data, filter::Displacement::Instance::Instance(obs_data_t* data, obs_source_t* context)
obs_source_t *context) { {
this->dispmap.texture = nullptr; this->dispmap.texture = nullptr;
this->dispmap.createTime = 0; this->dispmap.createTime = 0;
this->dispmap.modifiedTime = 0; this->dispmap.modifiedTime = 0;
this->dispmap.size = 0; this->dispmap.size = 0;
this->timer = 0; this->timer = 0;
this->context = context; this->context = context;
obs_enter_graphics(); obs_enter_graphics();
char* effectFile = obs_module_file("effects/displace.effect"); char* effectFile = obs_module_file("effects/displace.effect");
char* errorMessage = nullptr; char* errorMessage = nullptr;
this->customEffect = gs_effect_create_from_file(effectFile, this->customEffect = gs_effect_create_from_file(effectFile, &errorMessage);
&errorMessage);
bfree(effectFile); bfree(effectFile);
if (errorMessage != nullptr) { if (errorMessage != nullptr) {
P_LOG_ERROR("%s", errorMessage); P_LOG_ERROR("%s", errorMessage);
@ -155,30 +162,30 @@ filter::Displacement::Instance::Instance(obs_data_t *data,
update(data); update(data);
} }
filter::Displacement::Instance::~Instance() { filter::Displacement::Instance::~Instance()
{
obs_enter_graphics(); obs_enter_graphics();
gs_effect_destroy(customEffect); gs_effect_destroy(customEffect);
gs_texture_destroy(dispmap.texture); gs_texture_destroy(dispmap.texture);
obs_leave_graphics(); obs_leave_graphics();
} }
void filter::Displacement::Instance::update(obs_data_t *data) { void filter::Displacement::Instance::update(obs_data_t* data)
updateDisplacementMap(obs_data_get_string(data, {
S_FILTER_DISPLACEMENT_FILE)); updateDisplacementMap(obs_data_get_string(data, S_FILTER_DISPLACEMENT_FILE));
distance = float_t(obs_data_get_double(data, distance = float_t(obs_data_get_double(data, S_FILTER_DISPLACEMENT_RATIO));
S_FILTER_DISPLACEMENT_RATIO)); vec2_set(&displacementScale, float_t(obs_data_get_double(data, S_FILTER_DISPLACEMENT_SCALE)),
vec2_set(&displacementScale, float_t(obs_data_get_double(data, S_FILTER_DISPLACEMENT_SCALE)));
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::Instance::get_width() { uint32_t filter::Displacement::Instance::get_width()
{
return 0; return 0;
} }
uint32_t filter::Displacement::Instance::get_height() { uint32_t filter::Displacement::Instance::get_height()
{
return 0; return 0;
} }
@ -190,7 +197,8 @@ void filter::Displacement::Instance::show() {}
void filter::Displacement::Instance::hide() {} void filter::Displacement::Instance::hide() {}
void filter::Displacement::Instance::video_tick(float time) { void filter::Displacement::Instance::video_tick(float time)
{
timer += time; timer += time;
if (timer >= 1.0) { if (timer >= 1.0) {
timer -= 1.0; timer -= 1.0;
@ -198,34 +206,30 @@ void filter::Displacement::Instance::video_tick(float time) {
} }
} }
float interp(float a, float b, float v) { 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::Instance::video_render(gs_effect_t *) { void filter::Displacement::Instance::video_render(gs_effect_t*)
obs_source_t *parent = obs_filter_get_parent(context); {
obs_source_t *target = obs_filter_get_target(context); obs_source_t* parent = obs_filter_get_parent(context);
uint32_t obs_source_t* target = obs_filter_get_target(context);
baseW = obs_source_get_base_width(target), uint32_t baseW = obs_source_get_base_width(target), baseH = obs_source_get_base_height(target);
baseH = obs_source_get_base_height(target);
// Skip rendering if our target, parent or context is not valid. // Skip rendering if our target, parent or context is not valid.
if (!target || !parent || !context || !dispmap.texture if (!target || !parent || !context || !dispmap.texture || !baseW || !baseH) {
|| !baseW || !baseH) {
obs_source_skip_video_filter(context); obs_source_skip_video_filter(context);
return; return;
} }
if (!obs_source_process_filter_begin(context, GS_RGBA, if (!obs_source_process_filter_begin(context, GS_RGBA, OBS_ALLOW_DIRECT_RENDERING))
OBS_ALLOW_DIRECT_RENDERING))
return; return;
gs_eparam_t *param; gs_eparam_t* param;
vec2 texelScale; vec2 texelScale;
vec2_set(&texelScale, vec2_set(&texelScale, interp((1.0f / baseW), 1.0f, distance), interp((1.0f / baseH), 1.0f, distance));
interp((1.0f / baseW), 1.0f, distance),
interp((1.0f / baseH), 1.0f, distance));
param = gs_effect_get_param_by_name(customEffect, "texelScale"); param = gs_effect_get_param_by_name(customEffect, "texelScale");
if (param) if (param)
gs_effect_set_vec2(param, &texelScale); gs_effect_set_vec2(param, &texelScale);
@ -247,24 +251,25 @@ void filter::Displacement::Instance::video_render(gs_effect_t *) {
obs_source_process_filter_end(context, customEffect, baseW, baseH); obs_source_process_filter_end(context, customEffect, baseW, baseH);
} }
std::string filter::Displacement::Instance::get_file() { std::string filter::Displacement::Instance::get_file()
{
return dispmap.file; return dispmap.file;
} }
void filter::Displacement::Instance::updateDisplacementMap(std::string file) { void filter::Displacement::Instance::updateDisplacementMap(std::string file)
{
bool shouldUpdateTexture = false; bool shouldUpdateTexture = false;
// Different File // Different File
if (file != dispmap.file) { if (file != dispmap.file) {
dispmap.file = file; dispmap.file = file;
shouldUpdateTexture = true; shouldUpdateTexture = true;
} else { // Different Timestamps } else { // Different Timestamps
struct stat stats; struct stat stats;
if (os_stat(dispmap.file.c_str(), &stats) != 0) { if (os_stat(dispmap.file.c_str(), &stats) != 0) {
shouldUpdateTexture = shouldUpdateTexture || shouldUpdateTexture = shouldUpdateTexture || (dispmap.createTime != stats.st_ctime)
(dispmap.createTime != stats.st_ctime) || || (dispmap.modifiedTime != stats.st_mtime);
(dispmap.modifiedTime != stats.st_mtime); dispmap.createTime = stats.st_ctime;
dispmap.createTime = stats.st_ctime;
dispmap.modifiedTime = stats.st_mtime; dispmap.modifiedTime = stats.st_mtime;
} }
} }
@ -276,8 +281,7 @@ void filter::Displacement::Instance::updateDisplacementMap(std::string file) {
dispmap.texture = nullptr; dispmap.texture = nullptr;
} }
if (os_file_exists(file.c_str())) if (os_file_exists(file.c_str()))
dispmap.texture = dispmap.texture = gs_texture_create_from_file(dispmap.file.c_str());
gs_texture_create_from_file(dispmap.file.c_str());
obs_leave_graphics(); obs_leave_graphics();
} }
} }

View File

@ -21,20 +21,20 @@
#include "plugin.h" #include "plugin.h"
extern "C" { extern "C" {
#pragma warning (push) #pragma warning(push)
#pragma warning (disable: 4201) #pragma warning(disable : 4201)
#include <obs-source.h> #include <obs-source.h>
#include <util/platform.h> #include <util/platform.h>
#pragma warning (pop) #pragma warning(pop)
} }
#include <string> #include <string>
#define S_FILTER_DISPLACEMENT "Filter.Displacement" #define S_FILTER_DISPLACEMENT "Filter.Displacement"
#define S_FILTER_DISPLACEMENT_FILE "Filter.Displacement.File" #define S_FILTER_DISPLACEMENT_FILE "Filter.Displacement.File"
#define S_FILTER_DISPLACEMENT_FILE_TYPES "Filter.Displacement.File.Types" #define S_FILTER_DISPLACEMENT_FILE_TYPES "Filter.Displacement.File.Types"
#define S_FILTER_DISPLACEMENT_RATIO "Filter.Displacement.Ratio" #define S_FILTER_DISPLACEMENT_RATIO "Filter.Displacement.Ratio"
#define S_FILTER_DISPLACEMENT_SCALE "Filter.Displacement.Scale" #define S_FILTER_DISPLACEMENT_SCALE "Filter.Displacement.Scale"
namespace filter { namespace filter {
class Displacement { class Displacement {
@ -42,21 +42,21 @@ namespace filter {
Displacement(); Displacement();
~Displacement(); ~Displacement();
static const char *get_name(void *); static const char* get_name(void*);
static void *create(obs_data_t *, obs_source_t *); static void* create(obs_data_t*, obs_source_t*);
static void destroy(void *); static void destroy(void*);
static uint32_t get_width(void *); static uint32_t get_width(void*);
static uint32_t get_height(void *); static uint32_t get_height(void*);
static void get_defaults(obs_data_t *); static void get_defaults(obs_data_t*);
static obs_properties_t *get_properties(void *); static obs_properties_t* get_properties(void*);
static void update(void *, obs_data_t *); static void update(void*, obs_data_t*);
static void activate(void *); static void activate(void*);
static void deactivate(void *); static void deactivate(void*);
static void show(void *); static void show(void*);
static void hide(void *); static void hide(void*);
static void video_tick(void *, float); static void video_tick(void*, float);
static void video_render(void *, gs_effect_t *); static void video_render(void*, gs_effect_t*);
private: private:
obs_source_info sourceInfo; obs_source_info sourceInfo;
@ -67,35 +67,34 @@ namespace filter {
Instance(obs_data_t*, obs_source_t*); Instance(obs_data_t*, obs_source_t*);
~Instance(); ~Instance();
void update(obs_data_t*); void update(obs_data_t*);
uint32_t get_width(); uint32_t get_width();
uint32_t get_height(); uint32_t get_height();
void activate(); void activate();
void deactivate(); void deactivate();
void show(); void show();
void hide(); void hide();
void video_tick(float); void video_tick(float);
void video_render(gs_effect_t*); void video_render(gs_effect_t*);
std::string get_file(); std::string get_file();
private: private:
void updateDisplacementMap(std::string file); void updateDisplacementMap(std::string file);
obs_source_t *context; obs_source_t* context;
gs_effect_t *customEffect; gs_effect_t* customEffect;
float_t distance; float_t distance;
vec2 displacementScale; vec2 displacementScale;
struct { struct {
std::string file; std::string file;
gs_texture_t* texture; gs_texture_t* texture;
time_t createTime, time_t createTime, modifiedTime;
modifiedTime; size_t size;
size_t size;
} dispmap; } dispmap;
float_t timer; float_t timer;
}; };
}; };
} } // namespace filter

View File

@ -18,81 +18,70 @@
*/ */
#include "filter-shape.h" #include "filter-shape.h"
#include "strings.h"
#include <string>
#include <vector>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string>
#include <vector>
#include "strings.h"
extern "C" { extern "C" {
#pragma warning (push) #pragma warning(push)
#pragma warning (disable: 4201) #pragma warning(disable : 4201)
#include "util/platform.h"
#include "graphics/graphics.h" #include "graphics/graphics.h"
#include "graphics/matrix4.h" #include "graphics/matrix4.h"
#pragma warning (pop) #include "util/platform.h"
#pragma warning(pop)
} }
// Initializer & Finalizer // Initializer & Finalizer
static filter::Shape* filterShapeInstance; static filter::Shape* filterShapeInstance;
INITIALIZER(FilterShapeInit) { INITIALIZER(FilterShapeInit)
initializerFunctions.push_back([] { {
filterShapeInstance = new filter::Shape(); initializerFunctions.push_back([] { filterShapeInstance = new filter::Shape(); });
}); finalizerFunctions.push_back([] { delete filterShapeInstance; });
finalizerFunctions.push_back([] {
delete filterShapeInstance;
});
} }
typedef std::pair<uint32_t, std::string> cacheKey; typedef std::pair<uint32_t, std::string> cacheKey;
typedef std::pair<std::string, std::string> cacheValue; typedef std::pair<std::string, std::string> cacheValue;
static std::map<cacheKey, cacheValue> cache; static std::map<cacheKey, cacheValue> cache;
static const uint32_t minimumPoints = 3; static const uint32_t minimumPoints = 3;
static const uint32_t maximumPoints = 16; static const uint32_t maximumPoints = 16;
static void initialize() { static void initialize()
{
if (cache.size() != 0) if (cache.size() != 0)
return; return;
for (uint32_t point = 0; point < maximumPoints; point++) { for (uint32_t point = 0; point < maximumPoints; point++) {
std::vector<char> handle(1024), name(1024); std::vector<char> handle(1024), name(1024);
const char* vals[] = { const char* vals[] = {P_SHAPE_POINT_X, P_SHAPE_POINT_Y, P_SHAPE_POINT_U, P_SHAPE_POINT_V};
P_SHAPE_POINT_X,
P_SHAPE_POINT_Y,
P_SHAPE_POINT_U,
P_SHAPE_POINT_V
};
for (const char* v : vals) { for (const char* v : vals) {
snprintf(handle.data(), handle.size(), "%s.%" PRIu32, v, snprintf(handle.data(), handle.size(), "%s.%" PRIu32, v, point);
point); snprintf(name.data(), name.size(), P_TRANSLATE(v), point);
snprintf(name.data(), name.size(), P_TRANSLATE(v), cacheValue x = std::make_pair(std::string(handle.data()), std::string(name.data()));
point); cache.insert(std::make_pair(std::make_pair(point, v), x));
cacheValue x = std::make_pair(
std::string(handle.data()),
std::string(name.data()));
cache.insert(std::make_pair(std::make_pair(point, v),
x));
} }
} }
} }
filter::Shape::Shape() { filter::Shape::Shape()
{
return; // Disabled for the time being. 3D Transform is better for this. return; // Disabled for the time being. 3D Transform is better for this.
memset(&sourceInfo, 0, sizeof(obs_source_info)); memset(&sourceInfo, 0, sizeof(obs_source_info));
sourceInfo.id = "obs-stream-effects-filter-shape"; sourceInfo.id = "obs-stream-effects-filter-shape";
sourceInfo.type = OBS_SOURCE_TYPE_FILTER; sourceInfo.type = OBS_SOURCE_TYPE_FILTER;
sourceInfo.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_DEPRECATED; sourceInfo.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_DEPRECATED;
sourceInfo.get_name = get_name; sourceInfo.get_name = get_name;
sourceInfo.get_defaults = get_defaults; sourceInfo.get_defaults = get_defaults;
sourceInfo.get_properties = get_properties; sourceInfo.get_properties = get_properties;
sourceInfo.create = create; sourceInfo.create = create;
sourceInfo.destroy = destroy; sourceInfo.destroy = destroy;
sourceInfo.update = update; sourceInfo.update = update;
sourceInfo.activate = activate; sourceInfo.activate = activate;
sourceInfo.deactivate = deactivate; sourceInfo.deactivate = deactivate;
sourceInfo.show = show; sourceInfo.show = show;
sourceInfo.hide = hide; sourceInfo.hide = hide;
sourceInfo.video_tick = video_tick; sourceInfo.video_tick = video_tick;
sourceInfo.video_render = video_render; sourceInfo.video_render = video_render;
obs_register_source(&sourceInfo); obs_register_source(&sourceInfo);
@ -100,83 +89,57 @@ filter::Shape::Shape() {
initialize(); initialize();
} }
filter::Shape::~Shape() { filter::Shape::~Shape() {}
} const char* filter::Shape::get_name(void*)
{
const char * filter::Shape::get_name(void *) {
return "Shape"; return "Shape";
} }
void filter::Shape::get_defaults(obs_data_t *data) { void filter::Shape::get_defaults(obs_data_t* data)
{
obs_data_set_default_bool(data, P_SHAPE_LOOP, true); obs_data_set_default_bool(data, P_SHAPE_LOOP, true);
obs_data_set_default_int(data, P_SHAPE_POINTS, minimumPoints); obs_data_set_default_int(data, P_SHAPE_POINTS, minimumPoints);
for (uint32_t point = 0; point < maximumPoints; point++) { for (uint32_t point = 0; point < maximumPoints; point++) {
const char* vals[] = { const char* vals[] = {P_SHAPE_POINT_X, P_SHAPE_POINT_Y, P_SHAPE_POINT_U, P_SHAPE_POINT_V};
P_SHAPE_POINT_X,
P_SHAPE_POINT_Y,
P_SHAPE_POINT_U,
P_SHAPE_POINT_V
};
for (const char* v : vals) { for (const char* v : vals) {
auto strings = cache.find(std::make_pair(point, v)); auto strings = cache.find(std::make_pair(point, v));
if (strings != cache.end()) { if (strings != cache.end()) {
obs_data_set_default_double(data, obs_data_set_default_double(data, strings->second.first.c_str(), 0);
strings->second.first.c_str(), 0);
} }
} }
} }
} }
obs_properties_t * filter::Shape::get_properties(void *) { obs_properties_t* filter::Shape::get_properties(void*)
obs_properties_t *pr = obs_properties_create(); {
obs_property_t* p = NULL; obs_properties_t* pr = obs_properties_create();
obs_property_t* p = NULL;
p = obs_properties_add_bool(pr, P_SHAPE_LOOP, p = obs_properties_add_bool(pr, P_SHAPE_LOOP, P_TRANSLATE(P_SHAPE_LOOP));
P_TRANSLATE(P_SHAPE_LOOP));
obs_property_set_long_description(p, P_DESC(P_SHAPE_LOOP)); obs_property_set_long_description(p, P_DESC(P_SHAPE_LOOP));
p = obs_properties_add_list(pr, P_SHAPE_MODE, P_TRANSLATE(P_SHAPE_MODE), p = obs_properties_add_list(pr, P_SHAPE_MODE, P_TRANSLATE(P_SHAPE_MODE), obs_combo_type::OBS_COMBO_TYPE_LIST,
obs_combo_type::OBS_COMBO_TYPE_LIST, obs_combo_format::OBS_COMBO_FORMAT_INT);
obs_combo_format::OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHAPE_MODE))); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHAPE_MODE)));
obs_property_list_add_int(p, P_TRANSLATE(P_SHAPE_MODE_TRIS), GS_TRIS); obs_property_list_add_int(p, P_TRANSLATE(P_SHAPE_MODE_TRIS), GS_TRIS);
obs_property_list_add_int(p, P_TRANSLATE(P_SHAPE_MODE_TRISTRIP), obs_property_list_add_int(p, P_TRANSLATE(P_SHAPE_MODE_TRISTRIP), GS_TRISTRIP);
GS_TRISTRIP);
p = obs_properties_add_int_slider(pr, P_SHAPE_POINTS, p = obs_properties_add_int_slider(pr, P_SHAPE_POINTS, P_TRANSLATE(P_SHAPE_POINTS), minimumPoints, maximumPoints, 1);
P_TRANSLATE(P_SHAPE_POINTS), minimumPoints, maximumPoints, 1);
obs_property_set_long_description(p, P_DESC(P_SHAPE_POINTS)); obs_property_set_long_description(p, P_DESC(P_SHAPE_POINTS));
obs_property_set_modified_callback(p, modified_properties); obs_property_set_modified_callback(p, modified_properties);
for (uint32_t point = 0; point < maximumPoints; point++) { for (uint32_t point = 0; point < maximumPoints; point++) {
std::pair<const char*, const char*> vals[] = { std::pair<const char*, const char*> vals[] = {{P_SHAPE_POINT_X, P_TRANSLATE(P_DESC(P_SHAPE_POINT_X))},
{ {P_SHAPE_POINT_Y, P_TRANSLATE(P_DESC(P_SHAPE_POINT_Y))},
P_SHAPE_POINT_X, {P_SHAPE_POINT_U, P_TRANSLATE(P_DESC(P_SHAPE_POINT_U))},
P_TRANSLATE(P_DESC(P_SHAPE_POINT_X)) {P_SHAPE_POINT_V, P_TRANSLATE(P_DESC(P_SHAPE_POINT_V))}};
},
{
P_SHAPE_POINT_Y,
P_TRANSLATE(P_DESC(P_SHAPE_POINT_Y))
},
{
P_SHAPE_POINT_U,
P_TRANSLATE(P_DESC(P_SHAPE_POINT_U))
},
{
P_SHAPE_POINT_V,
P_TRANSLATE(P_DESC(P_SHAPE_POINT_V))
}
};
for (std::pair<const char*, const char*> v : vals) { for (std::pair<const char*, const char*> v : vals) {
auto strings = cache.find( auto strings = cache.find(std::make_pair(point, v.first));
std::make_pair(point, v.first));
if (strings != cache.end()) { if (strings != cache.end()) {
p = obs_properties_add_float_slider(pr, p = obs_properties_add_float_slider(pr, strings->second.first.c_str(), strings->second.second.c_str(),
strings->second.first.c_str(), 0, 100.0, 0.01);
strings->second.second.c_str(),
0, 100.0, 0.01);
obs_property_set_long_description(p, v.second); obs_property_set_long_description(p, v.second);
} }
} }
@ -185,75 +148,79 @@ obs_properties_t * filter::Shape::get_properties(void *) {
return pr; return pr;
} }
bool filter::Shape::modified_properties(obs_properties_t *pr, obs_property_t *, bool filter::Shape::modified_properties(obs_properties_t* pr, obs_property_t*, obs_data_t* data)
obs_data_t *data) { {
uint32_t points = (uint32_t)obs_data_get_int(data, P_SHAPE_POINTS); uint32_t points = (uint32_t)obs_data_get_int(data, P_SHAPE_POINTS);
for (uint32_t point = 0; point < maximumPoints; point++) { for (uint32_t point = 0; point < maximumPoints; point++) {
bool visible = point < points ? true : false; bool visible = point < points ? true : false;
const char* vals[] = { const char* vals[] = {P_SHAPE_POINT_X, P_SHAPE_POINT_Y, P_SHAPE_POINT_U, P_SHAPE_POINT_V};
P_SHAPE_POINT_X,
P_SHAPE_POINT_Y,
P_SHAPE_POINT_U,
P_SHAPE_POINT_V
};
for (const char* v : vals) { for (const char* v : vals) {
auto strings = cache.find(std::make_pair(point, v)); auto strings = cache.find(std::make_pair(point, v));
if (strings != cache.end()) { if (strings != cache.end()) {
obs_property_set_visible(obs_properties_get(pr, obs_property_set_visible(obs_properties_get(pr, strings->second.first.c_str()), visible);
strings->second.first.c_str()), visible
);
} }
} }
} }
return true; return true;
} }
void * filter::Shape::create(obs_data_t *data, obs_source_t *source) { void* filter::Shape::create(obs_data_t* data, obs_source_t* source)
{
return new Instance(data, source); return new Instance(data, source);
} }
void filter::Shape::destroy(void *ptr) { void filter::Shape::destroy(void* ptr)
{
delete reinterpret_cast<Instance*>(ptr); delete reinterpret_cast<Instance*>(ptr);
} }
uint32_t filter::Shape::get_width(void *ptr) { uint32_t filter::Shape::get_width(void* ptr)
{
return reinterpret_cast<Instance*>(ptr)->get_width(); return reinterpret_cast<Instance*>(ptr)->get_width();
} }
uint32_t filter::Shape::get_height(void *ptr) { uint32_t filter::Shape::get_height(void* ptr)
{
return reinterpret_cast<Instance*>(ptr)->get_height(); return reinterpret_cast<Instance*>(ptr)->get_height();
} }
void filter::Shape::update(void *ptr, obs_data_t *data) { void filter::Shape::update(void* ptr, obs_data_t* data)
{
reinterpret_cast<Instance*>(ptr)->update(data); reinterpret_cast<Instance*>(ptr)->update(data);
} }
void filter::Shape::activate(void *ptr) { void filter::Shape::activate(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->activate(); reinterpret_cast<Instance*>(ptr)->activate();
} }
void filter::Shape::deactivate(void *ptr) { void filter::Shape::deactivate(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->deactivate(); reinterpret_cast<Instance*>(ptr)->deactivate();
} }
void filter::Shape::show(void *ptr) { void filter::Shape::show(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->show(); reinterpret_cast<Instance*>(ptr)->show();
} }
void filter::Shape::hide(void *ptr) { void filter::Shape::hide(void* ptr)
{
reinterpret_cast<Instance*>(ptr)->hide(); reinterpret_cast<Instance*>(ptr)->hide();
} }
void filter::Shape::video_tick(void *ptr, float time) { void filter::Shape::video_tick(void* ptr, float time)
{
reinterpret_cast<Instance*>(ptr)->video_tick(time); reinterpret_cast<Instance*>(ptr)->video_tick(time);
} }
void filter::Shape::video_render(void *ptr, gs_effect_t *effect) { void filter::Shape::video_render(void* ptr, gs_effect_t* effect)
{
reinterpret_cast<Instance*>(ptr)->video_render(effect); reinterpret_cast<Instance*>(ptr)->video_render(effect);
} }
filter::Shape::Instance::Instance(obs_data_t *data, obs_source_t *context) filter::Shape::Instance::Instance(obs_data_t* data, obs_source_t* context) : context(context)
: context(context) { {
obs_enter_graphics(); obs_enter_graphics();
m_vertexHelper = new gs::vertex_buffer(maximumPoints); m_vertexHelper = new gs::vertex_buffer(maximumPoints);
m_vertexHelper->set_uv_layers(1); m_vertexHelper->set_uv_layers(1);
@ -263,50 +230,44 @@ filter::Shape::Instance::Instance(obs_data_t *data, obs_source_t *context)
update(data); update(data);
} }
filter::Shape::Instance::~Instance() { filter::Shape::Instance::~Instance()
{
obs_enter_graphics(); obs_enter_graphics();
delete m_vertexHelper; delete m_vertexHelper;
obs_leave_graphics(); obs_leave_graphics();
} }
void filter::Shape::Instance::update(obs_data_t *data) { void filter::Shape::Instance::update(obs_data_t* data)
{
uint32_t points = (uint32_t)obs_data_get_int(data, P_SHAPE_POINTS); uint32_t points = (uint32_t)obs_data_get_int(data, P_SHAPE_POINTS);
m_vertexHelper->resize(points); m_vertexHelper->resize(points);
for (uint32_t point = 0; point < points; point++) { for (uint32_t point = 0; point < points; point++) {
gs::vertex v = m_vertexHelper->at(point); gs::vertex v = m_vertexHelper->at(point);
{ {
auto strings = cache.find(std::make_pair(point, auto strings = cache.find(std::make_pair(point, P_SHAPE_POINT_X));
P_SHAPE_POINT_X));
if (strings != cache.end()) { if (strings != cache.end()) {
v.position->x = (float)(obs_data_get_double(data, v.position->x = (float)(obs_data_get_double(data, strings->second.first.c_str()) / 100.0);
strings->second.first.c_str()) / 100.0);
} }
} }
{ {
auto strings = cache.find(std::make_pair(point, auto strings = cache.find(std::make_pair(point, P_SHAPE_POINT_Y));
P_SHAPE_POINT_Y));
if (strings != cache.end()) { if (strings != cache.end()) {
v.position->y = (float)(obs_data_get_double(data, v.position->y = (float)(obs_data_get_double(data, strings->second.first.c_str()) / 100.0);
strings->second.first.c_str()) / 100.0);
} }
} }
{ {
auto strings = cache.find(std::make_pair(point, auto strings = cache.find(std::make_pair(point, P_SHAPE_POINT_U));
P_SHAPE_POINT_U));
if (strings != cache.end()) { if (strings != cache.end()) {
v.uv[0]->x = (float)(obs_data_get_double(data, v.uv[0]->x = (float)(obs_data_get_double(data, strings->second.first.c_str()) / 100.0);
strings->second.first.c_str()) / 100.0);
} }
} }
{ {
auto strings = cache.find(std::make_pair(point, auto strings = cache.find(std::make_pair(point, P_SHAPE_POINT_V));
P_SHAPE_POINT_V));
if (strings != cache.end()) { if (strings != cache.end()) {
v.uv[0]->y = (float)(obs_data_get_double(data, v.uv[0]->y = (float)(obs_data_get_double(data, strings->second.first.c_str()) / 100.0);
strings->second.first.c_str()) / 100.0);
} }
} }
*v.color = 0xFFFFFFFF; *v.color = 0xFFFFFFFF;
v.position->z = 0.0f; v.position->z = 0.0f;
} }
drawmode = (gs_draw_mode)obs_data_get_int(data, P_SHAPE_MODE); drawmode = (gs_draw_mode)obs_data_get_int(data, P_SHAPE_MODE);
@ -315,11 +276,13 @@ void filter::Shape::Instance::update(obs_data_t *data) {
obs_leave_graphics(); obs_leave_graphics();
} }
uint32_t filter::Shape::Instance::get_width() { uint32_t filter::Shape::Instance::get_width()
{
return 0; return 0;
} }
uint32_t filter::Shape::Instance::get_height() { uint32_t filter::Shape::Instance::get_height()
{
return 0; return 0;
} }
@ -333,16 +296,14 @@ void filter::Shape::Instance::hide() {}
void filter::Shape::Instance::video_tick(float) {} void filter::Shape::Instance::video_tick(float) {}
void filter::Shape::Instance::video_render(gs_effect_t *effect) { void filter::Shape::Instance::video_render(gs_effect_t* effect)
obs_source_t *parent = obs_filter_get_parent(context); {
obs_source_t *target = obs_filter_get_target(context); obs_source_t* parent = obs_filter_get_parent(context);
uint32_t obs_source_t* target = obs_filter_get_target(context);
baseW = obs_source_get_base_width(target), uint32_t baseW = obs_source_get_base_width(target), baseH = obs_source_get_base_height(target);
baseH = obs_source_get_base_height(target);
// Skip rendering if our target, parent or context is not valid. // Skip rendering if our target, parent or context is not valid.
if (!target || !parent || !context || !m_vertexBuffer if (!target || !parent || !context || !m_vertexBuffer || !m_texRender || !baseW || !baseH) {
|| !m_texRender || !baseW || !baseH) {
obs_source_skip_video_filter(context); obs_source_skip_video_filter(context);
return; return;
} }
@ -352,13 +313,10 @@ void filter::Shape::Instance::video_render(gs_effect_t *effect) {
obs_source_skip_video_filter(context); obs_source_skip_video_filter(context);
return; return;
} }
if (!obs_source_process_filter_begin(context, GS_RGBA, if (!obs_source_process_filter_begin(context, GS_RGBA, OBS_NO_DIRECT_RENDERING)) {
OBS_NO_DIRECT_RENDERING)) {
obs_source_skip_video_filter(context); obs_source_skip_video_filter(context);
} else { } else {
obs_source_process_filter_end(context, obs_source_process_filter_end(context, effect ? effect : obs_get_base_effect(OBS_EFFECT_OPAQUE), baseW, baseH);
effect ? effect : obs_get_base_effect(OBS_EFFECT_OPAQUE),
baseW, baseH);
} }
gs_texrender_end(m_texRender); gs_texrender_end(m_texRender);
gs_texture* tex = gs_texrender_get_texture(m_texRender); gs_texture* tex = gs_texrender_get_texture(m_texRender);
@ -382,8 +340,7 @@ void filter::Shape::Instance::video_render(gs_effect_t *effect) {
gs_effect_t* eff = obs_get_base_effect(OBS_EFFECT_OPAQUE); gs_effect_t* eff = obs_get_base_effect(OBS_EFFECT_OPAQUE);
while (gs_effect_loop(eff, "Draw")) { while (gs_effect_loop(eff, "Draw")) {
gs_effect_set_texture(gs_effect_get_param_by_name(eff, "image"), gs_effect_set_texture(gs_effect_get_param_by_name(eff, "image"), tex);
tex);
gs_load_vertexbuffer(m_vertexBuffer); gs_load_vertexbuffer(m_vertexBuffer);
gs_load_indexbuffer(nullptr); gs_load_indexbuffer(nullptr);
gs_draw(drawmode, 0, (uint32_t)m_vertexHelper->size()); gs_draw(drawmode, 0, (uint32_t)m_vertexHelper->size());

View File

@ -18,20 +18,20 @@
*/ */
#pragma once #pragma once
#include "plugin.h"
#include "gs-vertexbuffer.h" #include "gs-vertexbuffer.h"
#include "plugin.h"
#define P_SHAPE "Shape" #define P_SHAPE "Shape"
#define P_SHAPE_LOOP "Shape.Loop" #define P_SHAPE_LOOP "Shape.Loop"
#define P_SHAPE_MODE "Shape.Mode" #define P_SHAPE_MODE "Shape.Mode"
#define P_SHAPE_MODE_TRIS "Shape.Mode.Tris" #define P_SHAPE_MODE_TRIS "Shape.Mode.Tris"
#define P_SHAPE_MODE_TRISTRIP "Shape.Mode.TriStrip" #define P_SHAPE_MODE_TRISTRIP "Shape.Mode.TriStrip"
#define P_SHAPE_MODE "Shape.Mode" #define P_SHAPE_MODE "Shape.Mode"
#define P_SHAPE_POINTS "Shape.Points" #define P_SHAPE_POINTS "Shape.Points"
#define P_SHAPE_POINT_X "Shape.Point.X" #define P_SHAPE_POINT_X "Shape.Point.X"
#define P_SHAPE_POINT_Y "Shape.Point.Y" #define P_SHAPE_POINT_Y "Shape.Point.Y"
#define P_SHAPE_POINT_U "Shape.Point.U" #define P_SHAPE_POINT_U "Shape.Point.U"
#define P_SHAPE_POINT_V "Shape.Point.V" #define P_SHAPE_POINT_V "Shape.Point.V"
namespace filter { namespace filter {
class Shape { class Shape {
@ -39,22 +39,22 @@ namespace filter {
Shape(); Shape();
~Shape(); ~Shape();
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*);
static obs_properties_t *get_properties(void *); static obs_properties_t* get_properties(void*);
static bool modified_properties(obs_properties_t *, obs_property_t *, obs_data_t *); static bool modified_properties(obs_properties_t*, obs_property_t*, obs_data_t*);
static void *create(obs_data_t *, obs_source_t *); static void* create(obs_data_t*, obs_source_t*);
static void destroy(void *); static void destroy(void*);
static uint32_t get_width(void *); static uint32_t get_width(void*);
static uint32_t get_height(void *); static uint32_t get_height(void*);
static void update(void *, obs_data_t *); static void update(void*, obs_data_t*);
static void activate(void *); static void activate(void*);
static void deactivate(void *); static void deactivate(void*);
static void show(void *); static void show(void*);
static void hide(void *); static void hide(void*);
static void video_tick(void *, float); static void video_tick(void*, float);
static void video_render(void *, gs_effect_t *); static void video_render(void*, gs_effect_t*);
private: private:
obs_source_info sourceInfo; obs_source_info sourceInfo;
@ -65,23 +65,23 @@ namespace filter {
Instance(obs_data_t*, obs_source_t*); Instance(obs_data_t*, obs_source_t*);
~Instance(); ~Instance();
void update(obs_data_t*); void update(obs_data_t*);
uint32_t get_width(); uint32_t get_width();
uint32_t get_height(); uint32_t get_height();
void activate(); void activate();
void deactivate(); void deactivate();
void show(); void show();
void hide(); void hide();
void video_tick(float); void video_tick(float);
void video_render(gs_effect_t*); void video_render(gs_effect_t*);
private: private:
obs_source_t *context; obs_source_t* context;
gs_effect_t *customEffect; gs_effect_t* customEffect;
gs::vertex_buffer *m_vertexHelper; gs::vertex_buffer* m_vertexHelper;
gs_vertbuffer_t *m_vertexBuffer; gs_vertbuffer_t* m_vertexBuffer;
gs_draw_mode drawmode; gs_draw_mode drawmode;
gs_texrender_t *m_texRender; gs_texrender_t* m_texRender;
}; };
}; };
} } // namespace filter

View File

@ -204,13 +204,11 @@ obs_properties_t* filter::Transform::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, strings::MipGenerator::Name, p = obs_properties_add_list(pr, strings::MipGenerator::Name, P_TRANSLATE(strings::MipGenerator::Name),
P_TRANSLATE(strings::MipGenerator::Name), OBS_COMBO_TYPE_LIST, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
OBS_COMBO_FORMAT_INT);
obs_property_set_long_description(p, P_TRANSLATE(strings::MipGenerator::Description)); obs_property_set_long_description(p, P_TRANSLATE(strings::MipGenerator::Description));
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Point), obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Point), (long long)gs::mipmapper::generator::Point);
(long long)gs::mipmapper::generator::Point);
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Linear), obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Linear),
(long long)gs::mipmapper::generator::Linear); (long long)gs::mipmapper::generator::Linear);
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Sharpen), obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Sharpen),
@ -222,8 +220,8 @@ obs_properties_t* filter::Transform::get_properties(void*)
obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Lanczos), obs_property_list_add_int(p, P_TRANSLATE(strings::MipGenerator::Lanczos),
(long long)gs::mipmapper::generator::Lanczos); (long long)gs::mipmapper::generator::Lanczos);
p = obs_properties_add_float(pr, strings::MipGenerator::Strength, p = obs_properties_add_float(pr, strings::MipGenerator::Strength, P_TRANSLATE(strings::MipGenerator::Strength), 0.0,
P_TRANSLATE(strings::MipGenerator::Strength), 0.0, 100.0, 0.01); 100.0, 0.01);
return pr; return pr;
} }
@ -310,8 +308,8 @@ filter::Transform::Instance::Instance(obs_data_t* data, obs_source_t* context)
vec3_set(rotation.get(), 0, 0, 0); vec3_set(rotation.get(), 0, 0, 0);
vec3_set(scale.get(), 1, 1, 1); vec3_set(scale.get(), 1, 1, 1);
enable_mipmapping = false; enable_mipmapping = false;
generator = gs::mipmapper::generator::Linear; generator = gs::mipmapper::generator::Linear;
generator_strength = 50.0; generator_strength = 50.0;
obs_enter_graphics(); obs_enter_graphics();
@ -354,7 +352,7 @@ void filter::Transform::Instance::update(obs_data_t* data)
shear->z = 0.0f; shear->z = 0.0f;
// Mipmapping // Mipmapping
enable_mipmapping = obs_data_get_bool(data, ST_MIPMAPPING); enable_mipmapping = obs_data_get_bool(data, ST_MIPMAPPING);
generator_strength = obs_data_get_double(data, strings::MipGenerator::Strength); generator_strength = obs_data_get_double(data, strings::MipGenerator::Strength);
generator = (gs::mipmapper::generator)obs_data_get_int(data, strings::MipGenerator::Name); generator = (gs::mipmapper::generator)obs_data_get_int(data, strings::MipGenerator::Name);
@ -391,9 +389,9 @@ void filter::Transform::Instance::video_render(gs_effect_t* paramEffect)
obs_source_t* parent = obs_filter_get_parent(source_context); obs_source_t* parent = obs_filter_get_parent(source_context);
obs_source_t* target = obs_filter_get_target(source_context); obs_source_t* target = obs_filter_get_target(source_context);
uint32_t width = obs_source_get_base_width(target); uint32_t width = obs_source_get_base_width(target);
uint32_t height = obs_source_get_base_height(target); uint32_t height = obs_source_get_base_height(target);
uint32_t real_width = width; uint32_t real_width = width;
uint32_t real_height = height; uint32_t real_height = height;
gs_effect_t* default_effect = obs_get_base_effect(OBS_EFFECT_DEFAULT); gs_effect_t* default_effect = obs_get_base_effect(OBS_EFFECT_DEFAULT);
@ -493,7 +491,7 @@ void filter::Transform::Instance::video_render(gs_effect_t* paramEffect)
// Most GPUs cap out here, so let's not go higher. // Most GPUs cap out here, so let's not go higher.
double_t aspect = double_t(width) / double_t(height); double_t aspect = double_t(width) / double_t(height);
if (aspect > 1.0) { // height < width if (aspect > 1.0) { // height < width
real_width = 8192; real_width = 8192;
real_height = uint32_t(real_width / aspect); real_height = uint32_t(real_width / aspect);
} else if (aspect < 1.0) { // width > height } else if (aspect < 1.0) { // width > height
real_height = 8192; real_height = 8192;
@ -546,8 +544,8 @@ void filter::Transform::Instance::video_render(gs_effect_t* paramEffect)
} }
} }
source_texture = std::make_shared<gs::texture>(real_width, real_height, GS_RGBA, uint32_t(1u + mip_levels), nullptr, source_texture = std::make_shared<gs::texture>(real_width, real_height, GS_RGBA, uint32_t(1u + mip_levels),
gs::texture::flags::BuildMipMaps); nullptr, gs::texture::flags::BuildMipMaps);
} }
mipmapper.rebuild(source_tex, source_texture, generator, float_t(generator_strength)); mipmapper.rebuild(source_tex, source_texture, generator, float_t(generator_strength));

View File

@ -77,7 +77,7 @@ bool gfx::effect_source::property_texture_type_modified(void* priv, obs_properti
obs_property_set_visible(obs_properties_get(props, tpm->ui.names[2]), false); obs_property_set_visible(obs_properties_get(props, tpm->ui.names[2]), false);
} else { // Source } else { // Source
obs_property_set_visible(obs_properties_get(props, tpm->ui.names[1]), false); obs_property_set_visible(obs_properties_get(props, tpm->ui.names[1]), false);
obs_property_set_visible(obs_properties_get(props, tpm->ui.names[2]), true); obs_property_set_visible(obs_properties_get(props, tpm->ui.names[2]), true);
} }
return true; return true;
@ -427,7 +427,7 @@ bool gfx::effect_source::test_for_updates(const char* text, const char* path)
for (size_t i = 0; i <= 2; i++) { for (size_t i = 0; i <= 2; i++) {
bufsize += ui_name[i].size() + ui_desc[i].size() + 2; bufsize += ui_name[i].size() + ui_desc[i].size() + 2;
} }
nparam->ui.names.resize(3); nparam->ui.names.resize(3);
nparam->ui.descs.resize(3); nparam->ui.descs.resize(3);

View File

@ -131,7 +131,7 @@ namespace gfx {
static bool property_texture_type_modified(void* priv, obs_properties_t* props, obs_property_t* prop, static bool property_texture_type_modified(void* priv, obs_properties_t* props, obs_property_t* prop,
obs_data_t* sett); obs_data_t* sett);
static bool property_texture_input_modified(void* priv, obs_properties_t* props, obs_property_t* prop, static bool property_texture_input_modified(void* priv, obs_properties_t* props, obs_property_t* prop,
obs_data_t* sett); obs_data_t* sett);
virtual bool is_special_parameter(std::string name, gs::effect_parameter::type type) = 0; virtual bool is_special_parameter(std::string name, gs::effect_parameter::type type) = 0;

View File

@ -30,9 +30,9 @@ extern "C" {
#pragma warning(disable : 4201) #pragma warning(disable : 4201)
#include <graphics/graphics.h> #include <graphics/graphics.h>
#include <graphics/matrix4.h> #include <graphics/matrix4.h>
#include <graphics/vec4.h>
#include <graphics/vec3.h>
#include <graphics/vec2.h> #include <graphics/vec2.h>
#include <graphics/vec3.h>
#include <graphics/vec4.h>
#pragma warning(pop) #pragma warning(pop)
} }

View File

@ -19,76 +19,94 @@
#include "gs-helper.h" #include "gs-helper.h"
gs_effect_param* gs_effect_get_param(gs_effect_t* effect, const char* name) { gs_effect_param* gs_effect_get_param(gs_effect_t* effect, const char* name)
{
gs_effect_param* p = gs_effect_get_param_by_name(effect, name); gs_effect_param* p = gs_effect_get_param_by_name(effect, name);
if (!p) if (!p)
P_LOG_ERROR("Failed to find parameter %s in effect.", name); P_LOG_ERROR("Failed to find parameter %s in effect.", name);
return p; return p;
} }
bool gs_set_param_int(gs_effect_t* effect, const char* name, int value) { bool gs_set_param_int(gs_effect_t* effect, const char* name, int value)
{
gs_effect_param* p = nullptr; gs_effect_param* p = nullptr;
if (nullptr != (p = gs_effect_get_param(effect, name))) { if (nullptr != (p = gs_effect_get_param(effect, name))) {
gs_effect_set_int(p, value); gs_effect_set_int(p, value);
return true; return true;
} }
P_LOG_ERROR("Failed to set value %d for parameter %s in" P_LOG_ERROR(
" effect.", value, name); "Failed to set value %d for parameter %s in"
" effect.",
value, name);
return false; return false;
} }
bool gs_set_param_float(gs_effect_t* effect, const char* name, float value) { bool gs_set_param_float(gs_effect_t* effect, const char* name, float value)
{
gs_effect_param* p = nullptr; gs_effect_param* p = nullptr;
if (nullptr != (p = gs_effect_get_param(effect, name))) { if (nullptr != (p = gs_effect_get_param(effect, name))) {
gs_effect_set_float(p, value); gs_effect_set_float(p, value);
return true; return true;
} }
P_LOG_ERROR("Failed to set value %f for parameter %s in" P_LOG_ERROR(
" effect.", value, name); "Failed to set value %f for parameter %s in"
" effect.",
value, name);
return false; return false;
} }
bool gs_set_param_float2(gs_effect_t* effect, const char* name, vec2* value) { bool gs_set_param_float2(gs_effect_t* effect, const char* name, vec2* value)
{
gs_effect_param* p = nullptr; gs_effect_param* p = nullptr;
if (nullptr != (p = gs_effect_get_param(effect, name))) { if (nullptr != (p = gs_effect_get_param(effect, name))) {
gs_effect_set_vec2(p, value); gs_effect_set_vec2(p, value);
return true; return true;
} }
P_LOG_ERROR("Failed to set value {%f,%f} for parameter %s" P_LOG_ERROR(
" in effect.", value->x, value->y, name); "Failed to set value {%f,%f} for parameter %s"
" in effect.",
value->x, value->y, name);
return false; return false;
} }
bool gs_set_param_float3(gs_effect_t* effect, const char* name, vec3* value) { bool gs_set_param_float3(gs_effect_t* effect, const char* name, vec3* value)
{
gs_effect_param* p = nullptr; gs_effect_param* p = nullptr;
if (nullptr != (p = gs_effect_get_param(effect, name))) { if (nullptr != (p = gs_effect_get_param(effect, name))) {
gs_effect_set_vec3(p, value); gs_effect_set_vec3(p, value);
return true; return true;
} }
P_LOG_ERROR("Failed to set value {%f,%f,%f} for parameter" P_LOG_ERROR(
"%s in effect.", value->x, value->y, value->z, name); "Failed to set value {%f,%f,%f} for parameter"
"%s in effect.",
value->x, value->y, value->z, name);
return false; return false;
} }
bool gs_set_param_float4(gs_effect_t* effect, const char* name, vec4* value) { bool gs_set_param_float4(gs_effect_t* effect, const char* name, vec4* value)
{
gs_effect_param* p = nullptr; gs_effect_param* p = nullptr;
if (nullptr != (p = gs_effect_get_param(effect, name))) { if (nullptr != (p = gs_effect_get_param(effect, name))) {
gs_effect_set_vec4(p, value); gs_effect_set_vec4(p, value);
return true; return true;
} }
P_LOG_ERROR("Failed to set value {%f,%f,%f,%f} for" P_LOG_ERROR(
" parameter %s in effect.", value->x, value->y, value->z, "Failed to set value {%f,%f,%f,%f} for"
value->w, name); " parameter %s in effect.",
value->x, value->y, value->z, value->w, name);
return false; return false;
} }
bool gs_set_param_texture(gs_effect_t* effect, const char* name, gs_texture_t* value) { bool gs_set_param_texture(gs_effect_t* effect, const char* name, gs_texture_t* value)
{
gs_effect_param* p = nullptr; gs_effect_param* p = nullptr;
if (nullptr != (p = gs_effect_get_param(effect, name))) { if (nullptr != (p = gs_effect_get_param(effect, name))) {
gs_effect_set_texture(p, value); gs_effect_set_texture(p, value);
return true; return true;
} }
P_LOG_ERROR("Failed to set texture for" P_LOG_ERROR(
" parameter %s in effect.", name); "Failed to set texture for"
" parameter %s in effect.",
name);
return false; return false;
} }

View File

@ -18,19 +18,19 @@
*/ */
#pragma once #pragma once
#include "plugin.h"
#include <vector> #include <vector>
#include "plugin.h"
extern "C" { extern "C" {
#pragma warning (push) #pragma warning(push)
#pragma warning (disable: 4201) #pragma warning(disable : 4201)
#include "graphics/graphics.h" #include "graphics/graphics.h"
#pragma warning (pop) #pragma warning(pop)
} }
gs_effect_param* gs_effect_get_param(gs_effect_t* effect, const char* name); gs_effect_param* gs_effect_get_param(gs_effect_t* effect, const char* name);
bool gs_set_param_int(gs_effect_t* effect, const char* name, int value); bool gs_set_param_int(gs_effect_t* effect, const char* name, int value);
bool gs_set_param_float(gs_effect_t* effect, const char* name, float value); bool gs_set_param_float(gs_effect_t* effect, const char* name, float value);
bool gs_set_param_float2(gs_effect_t* effect, const char* name, vec2* value); bool gs_set_param_float2(gs_effect_t* effect, const char* name, vec2* value);
bool gs_set_param_float3(gs_effect_t* effect, const char* name, vec3* value); bool gs_set_param_float3(gs_effect_t* effect, const char* name, vec3* value);
bool gs_set_param_float4(gs_effect_t* effect, const char* name, vec4* value); bool gs_set_param_float4(gs_effect_t* effect, const char* name, vec4* value);
bool gs_set_param_texture(gs_effect_t* effect, const char* name, gs_texture_t* value); bool gs_set_param_texture(gs_effect_t* effect, const char* name, gs_texture_t* value);

View File

@ -20,13 +20,14 @@
#include "gs-indexbuffer.h" #include "gs-indexbuffer.h"
#include "gs-limits.h" #include "gs-limits.h"
extern "C" { extern "C" {
#pragma warning( push ) #pragma warning(push)
#pragma warning( disable: 4201 ) #pragma warning(disable : 4201)
#include <obs.h> #include <obs.h>
#pragma warning( pop ) #pragma warning(pop)
} }
gs::index_buffer::index_buffer(uint32_t maximumVertices) { gs::index_buffer::index_buffer(uint32_t maximumVertices)
{
this->reserve(maximumVertices); this->reserve(maximumVertices);
obs_enter_graphics(); obs_enter_graphics();
@ -36,25 +37,30 @@ gs::index_buffer::index_buffer(uint32_t maximumVertices) {
gs::index_buffer::index_buffer() : index_buffer(MAXIMUM_VERTICES) {} gs::index_buffer::index_buffer() : index_buffer(MAXIMUM_VERTICES) {}
gs::index_buffer::index_buffer(index_buffer& other) : index_buffer((uint32_t)other.size()) { gs::index_buffer::index_buffer(index_buffer& other) : index_buffer((uint32_t)other.size())
{
std::copy(other.begin(), other.end(), this->end()); std::copy(other.begin(), other.end(), this->end());
} }
gs::index_buffer::index_buffer(std::vector<uint32_t>& other) : index_buffer((uint32_t)other.size()) { gs::index_buffer::index_buffer(std::vector<uint32_t>& other) : index_buffer((uint32_t)other.size())
{
std::copy(other.begin(), other.end(), this->end()); std::copy(other.begin(), other.end(), this->end());
} }
gs::index_buffer::~index_buffer() { gs::index_buffer::~index_buffer()
{
obs_enter_graphics(); obs_enter_graphics();
gs_indexbuffer_destroy(m_indexBuffer); gs_indexbuffer_destroy(m_indexBuffer);
obs_leave_graphics(); obs_leave_graphics();
} }
gs_indexbuffer_t* gs::index_buffer::get() { gs_indexbuffer_t* gs::index_buffer::get()
{
return get(true); return get(true);
} }
gs_indexbuffer_t* gs::index_buffer::get(bool refreshGPU) { gs_indexbuffer_t* gs::index_buffer::get(bool refreshGPU)
{
if (refreshGPU) { if (refreshGPU) {
obs_enter_graphics(); obs_enter_graphics();
gs_indexbuffer_flush(m_indexBuffer); gs_indexbuffer_flush(m_indexBuffer);

View File

@ -21,10 +21,10 @@
#include <inttypes.h> #include <inttypes.h>
#include <vector> #include <vector>
extern "C" { extern "C" {
#pragma warning( push ) #pragma warning(push)
#pragma warning( disable: 4201 ) #pragma warning(disable : 4201)
#include <graphics/graphics.h> #include <graphics/graphics.h>
#pragma warning( pop ) #pragma warning(pop)
} }
namespace gs { namespace gs {
@ -43,4 +43,4 @@ namespace gs {
protected: protected:
gs_indexbuffer_t* m_indexBuffer; gs_indexbuffer_t* m_indexBuffer;
}; };
} } // namespace gs

View File

@ -21,6 +21,6 @@
#include <inttypes.h> #include <inttypes.h>
namespace gs { namespace gs {
static const uint32_t MAXIMUM_VERTICES = 0xFFFFFFu; static const uint32_t MAXIMUM_VERTICES = 0xFFFFFFu;
static const uint32_t MAXIMUM_UVW_LAYERS = 8u; static const uint32_t MAXIMUM_UVW_LAYERS = 8u;
} } // namespace gs

View File

@ -216,7 +216,7 @@ void gs::mipmapper::rebuild(std::shared_ptr<gs::texture> source, std::shared_ptr
texture_height = 1; texture_height = 1;
} }
texel_width = 1.0 / texture_width; texel_width = 1.0 / texture_width;
texel_height = 1.0 / texture_height; texel_height = 1.0 / texture_height;
// Draw mipmap layer // Draw mipmap layer

View File

@ -37,7 +37,7 @@ namespace gs {
gs_texrender_t* render_target; gs_texrender_t* render_target;
bool is_being_rendered; bool is_being_rendered;
gs_color_format color_format; gs_color_format color_format;
gs_zstencil_format zstencil_format; gs_zstencil_format zstencil_format;
public: public:

View File

@ -19,77 +19,93 @@
#include "gs-sampler.h" #include "gs-sampler.h"
gs::sampler::sampler() { gs::sampler::sampler()
m_dirty = true; {
m_samplerInfo = { GS_FILTER_LINEAR, GS_ADDRESS_WRAP, GS_ADDRESS_WRAP, GS_ADDRESS_WRAP, 1, 0 }; m_dirty = true;
m_samplerInfo = {GS_FILTER_LINEAR, GS_ADDRESS_WRAP, GS_ADDRESS_WRAP, GS_ADDRESS_WRAP, 1, 0};
m_samplerState = nullptr; m_samplerState = nullptr;
} }
gs::sampler::~sampler() { gs::sampler::~sampler()
{
if (m_samplerState) if (m_samplerState)
gs_samplerstate_destroy(m_samplerState); gs_samplerstate_destroy(m_samplerState);
} }
void gs::sampler::set_filter(gs_sample_filter v) { void gs::sampler::set_filter(gs_sample_filter v)
m_dirty = true; {
m_dirty = true;
m_samplerInfo.filter = v; m_samplerInfo.filter = v;
} }
gs_sample_filter gs::sampler::get_filter() { gs_sample_filter gs::sampler::get_filter()
{
return m_samplerInfo.filter; return m_samplerInfo.filter;
} }
void gs::sampler::set_address_mode_u(gs_address_mode v) { void gs::sampler::set_address_mode_u(gs_address_mode v)
m_dirty = true; {
m_dirty = true;
m_samplerInfo.address_u = v; m_samplerInfo.address_u = v;
} }
gs_address_mode gs::sampler::get_address_mode_u() { gs_address_mode gs::sampler::get_address_mode_u()
{
return m_samplerInfo.address_u; return m_samplerInfo.address_u;
} }
void gs::sampler::set_address_mode_v(gs_address_mode v) { void gs::sampler::set_address_mode_v(gs_address_mode v)
m_dirty = true; {
m_dirty = true;
m_samplerInfo.address_v = v; m_samplerInfo.address_v = v;
} }
gs_address_mode gs::sampler::get_address_mode_v() { gs_address_mode gs::sampler::get_address_mode_v()
{
return m_samplerInfo.address_v; return m_samplerInfo.address_v;
} }
void gs::sampler::set_address_mode_w(gs_address_mode v) { void gs::sampler::set_address_mode_w(gs_address_mode v)
m_dirty = true; {
m_dirty = true;
m_samplerInfo.address_w = v; m_samplerInfo.address_w = v;
} }
gs_address_mode gs::sampler::get_address_mode_w() { gs_address_mode gs::sampler::get_address_mode_w()
{
return m_samplerInfo.address_w; return m_samplerInfo.address_w;
} }
void gs::sampler::set_max_anisotropy(int v) { void gs::sampler::set_max_anisotropy(int v)
m_dirty = true; {
m_dirty = true;
m_samplerInfo.max_anisotropy = v; m_samplerInfo.max_anisotropy = v;
} }
int gs::sampler::get_max_anisotropy() { int gs::sampler::get_max_anisotropy()
{
return m_samplerInfo.max_anisotropy; return m_samplerInfo.max_anisotropy;
} }
void gs::sampler::set_border_color(uint32_t v) { void gs::sampler::set_border_color(uint32_t v)
m_dirty = true; {
m_dirty = true;
m_samplerInfo.border_color = v; m_samplerInfo.border_color = v;
} }
void gs::sampler::set_border_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { void gs::sampler::set_border_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
m_dirty = true; {
m_dirty = true;
m_samplerInfo.border_color = a << 24 | r << 16 | g << 8 | b; m_samplerInfo.border_color = a << 24 | r << 16 | g << 8 | b;
} }
uint32_t gs::sampler::get_border_color() { uint32_t gs::sampler::get_border_color()
{
return m_samplerInfo.border_color; return m_samplerInfo.border_color;
} }
uint8_t gs::sampler::get_border_color(bool r, bool g, bool b, bool a) { uint8_t gs::sampler::get_border_color(bool r, bool g, bool b, bool a)
{
if (a) if (a)
return (m_samplerInfo.border_color >> 24) & 0xFF; return (m_samplerInfo.border_color >> 24) & 0xFF;
if (r) if (r)
@ -101,14 +117,16 @@ uint8_t gs::sampler::get_border_color(bool r, bool g, bool b, bool a) {
return 0; return 0;
} }
gs_sampler_state* gs::sampler::refresh() { gs_sampler_state* gs::sampler::refresh()
{
gs_samplerstate_destroy(m_samplerState); gs_samplerstate_destroy(m_samplerState);
m_samplerState = gs_samplerstate_create(&m_samplerInfo); m_samplerState = gs_samplerstate_create(&m_samplerInfo);
m_dirty = false; m_dirty = false;
return m_samplerState; return m_samplerState;
} }
gs_sampler_state* gs::sampler::get_object() { gs_sampler_state* gs::sampler::get_object()
{
if (m_dirty) if (m_dirty)
return refresh(); return refresh();
return m_samplerState; return m_samplerState;

View File

@ -20,10 +20,10 @@
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>
extern "C" { extern "C" {
#pragma warning( push ) #pragma warning(push)
#pragma warning( disable: 4201 ) #pragma warning(disable : 4201)
#include <graphics/graphics.h> #include <graphics/graphics.h>
#pragma warning( pop ) #pragma warning(pop)
} }
namespace gs { namespace gs {
@ -32,33 +32,33 @@ namespace gs {
sampler(); sampler();
~sampler(); ~sampler();
void set_filter(gs_sample_filter v); void set_filter(gs_sample_filter v);
gs_sample_filter get_filter(); gs_sample_filter get_filter();
void set_address_mode_u(gs_address_mode v); void set_address_mode_u(gs_address_mode v);
gs_address_mode get_address_mode_u(); gs_address_mode get_address_mode_u();
void set_address_mode_v(gs_address_mode v); void set_address_mode_v(gs_address_mode v);
gs_address_mode get_address_mode_v(); gs_address_mode get_address_mode_v();
void set_address_mode_w(gs_address_mode v); void set_address_mode_w(gs_address_mode v);
gs_address_mode get_address_mode_w(); gs_address_mode get_address_mode_w();
void set_max_anisotropy(int v); void set_max_anisotropy(int v);
int get_max_anisotropy(); int get_max_anisotropy();
void set_border_color(uint32_t v); void set_border_color(uint32_t v);
void set_border_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a); void set_border_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
uint32_t get_border_color(); uint32_t get_border_color();
uint8_t get_border_color(bool r, bool g, bool b, bool a); uint8_t get_border_color(bool r, bool g, bool b, bool a);
gs_sampler_state* refresh(); gs_sampler_state* refresh();
gs_sampler_state* get_object(); gs_sampler_state* get_object();
private: private:
bool m_dirty; bool m_dirty;
gs_sampler_info m_samplerInfo; gs_sampler_info m_samplerInfo;
gs_sampler_state* m_samplerState; gs_sampler_state* m_samplerState;
}; };
} } // namespace gs

View File

@ -19,26 +19,31 @@
#include "obs-audio-capture.h" #include "obs-audio-capture.h"
void obs::audio_capture::audio_capture_cb(void* data, obs_source_t*, const struct audio_data* audio, bool muted) { void obs::audio_capture::audio_capture_cb(void* data, obs_source_t*, const struct audio_data* audio, bool muted)
{
auto self = reinterpret_cast<obs::audio_capture*>(data); auto self = reinterpret_cast<obs::audio_capture*>(data);
self->cb(self->cb_data, audio, muted); self->cb(self->cb_data, audio, muted);
} }
obs::audio_capture::audio_capture(obs_source_t* source) { obs::audio_capture::audio_capture(obs_source_t* source)
{
this->source = source; this->source = source;
obs_source_add_audio_capture_callback(this->source, audio_capture_cb, this); obs_source_add_audio_capture_callback(this->source, audio_capture_cb, this);
} }
obs::audio_capture::~audio_capture() { obs::audio_capture::~audio_capture()
{
obs_source_remove_audio_capture_callback(this->source, audio_capture_cb, this); obs_source_remove_audio_capture_callback(this->source, audio_capture_cb, this);
} }
void obs::audio_capture::set_callback(audio_capture_callback_t cb, void* data) { void obs::audio_capture::set_callback(audio_capture_callback_t cb, void* data)
this->cb = cb; {
this->cb = cb;
this->cb_data = data; this->cb_data = data;
} }
void obs::audio_capture::set_callback(audio_capture_callback_t cb) { void obs::audio_capture::set_callback(audio_capture_callback_t cb)
this->cb = cb; {
this->cb = cb;
this->cb_data = nullptr; this->cb_data = nullptr;
} }

View File

@ -18,18 +18,18 @@
*/ */
#pragma once #pragma once
#include <obs.h>
#include <functional> #include <functional>
#include <obs.h>
namespace obs { namespace obs {
typedef std::function<void(void* data, struct audio_data const *audio, bool muted)> audio_capture_callback_t; typedef std::function<void(void* data, struct audio_data const* audio, bool muted)> audio_capture_callback_t;
class audio_capture { class audio_capture {
obs_source_t* source; obs_source_t* source;
audio_capture_callback_t cb; audio_capture_callback_t cb;
void* cb_data; void* cb_data;
static void audio_capture_cb(void*, obs_source_t*, struct audio_data const *, bool); static void audio_capture_cb(void*, obs_source_t*, struct audio_data const*, bool);
public: public:
audio_capture(obs_source_t* source); audio_capture(obs_source_t* source);
@ -38,4 +38,4 @@ namespace obs {
void set_callback(audio_capture_callback_t cb, void* data); void set_callback(audio_capture_callback_t cb, void* data);
void set_callback(audio_capture_callback_t cb); void set_callback(audio_capture_callback_t cb);
}; };
} } // namespace obs

View File

@ -29,7 +29,7 @@ obs::source::~source()
obs::source::source(std::string name, bool track_ownership, bool add_reference) obs::source::source(std::string name, bool track_ownership, bool add_reference)
{ {
this->self = obs_get_source_by_name(name.c_str()); this->self = obs_get_source_by_name(name.c_str());
this->track_ownership = track_ownership; this->track_ownership = track_ownership;
if (!add_reference) { if (!add_reference) {
obs_source_release(this->self); obs_source_release(this->self);
@ -86,7 +86,8 @@ uint32_t obs::source::height()
return obs_source_get_height(self); return obs_source_get_height(self);
} }
void obs::source::clear() { void obs::source::clear()
{
self = nullptr; self = nullptr;
} }

View File

@ -21,8 +21,8 @@
#include <map> #include <map>
struct scs_searchdata { struct scs_searchdata {
obs_source_t* source; obs_source_t* source;
bool found = false; bool found = false;
std::map<obs_source_t*, bool> visited; std::map<obs_source_t*, bool> visited;
}; };

View File

@ -27,37 +27,39 @@ OBS_DECLARE_MODULE();
OBS_MODULE_AUTHOR("Michael Fabian Dirks"); OBS_MODULE_AUTHOR("Michael Fabian Dirks");
OBS_MODULE_USE_DEFAULT_LOCALE("obs-stream-effects", "en-US"); OBS_MODULE_USE_DEFAULT_LOCALE("obs-stream-effects", "en-US");
filter::Displacement *filterDisplacement; filter::Displacement* filterDisplacement;
filter::Shape *filterShape; filter::Shape* filterShape;
filter::Transform *filterTransform; filter::Transform* filterTransform;
std::list<std::function<void()>> initializerFunctions; std::list<std::function<void()>> initializerFunctions;
std::list<std::function<void()>> finalizerFunctions; std::list<std::function<void()>> finalizerFunctions;
MODULE_EXPORT bool obs_module_load(void) { MODULE_EXPORT bool obs_module_load(void)
P_LOG_INFO("[" PLUGIN_NAME "] Loading Version %u.%u.%u (Build %u)", {
PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH, P_LOG_INFO("[" PLUGIN_NAME "] Loading Version %u.%u.%u (Build %u)", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR,
PROJECT_VERSION_TWEAK); PROJECT_VERSION_PATCH, PROJECT_VERSION_TWEAK);
for (auto func : initializerFunctions) { for (auto func : initializerFunctions) {
func(); func();
} }
return true; return true;
} }
MODULE_EXPORT void obs_module_unload(void) { MODULE_EXPORT void obs_module_unload(void)
P_LOG_INFO("[" PLUGIN_NAME "] Unloading Version %u.%u.%u (Build %u)", {
PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH, P_LOG_INFO("[" PLUGIN_NAME "] Unloading Version %u.%u.%u (Build %u)", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR,
PROJECT_VERSION_TWEAK); PROJECT_VERSION_PATCH, PROJECT_VERSION_TWEAK);
for (auto func : finalizerFunctions) { for (auto func : finalizerFunctions) {
func(); func();
} }
} }
MODULE_EXPORT const char* obs_module_name() { MODULE_EXPORT const char* obs_module_name()
{
return PLUGIN_NAME; return PLUGIN_NAME;
} }
MODULE_EXPORT const char* obs_module_description() { MODULE_EXPORT const char* obs_module_description()
{
return PLUGIN_NAME; return PLUGIN_NAME;
} }
@ -67,8 +69,8 @@ MODULE_EXPORT const char* obs_module_description() {
#include <windows.h> #include <windows.h>
BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
{
return TRUE; return TRUE;
} }
#endif #endif

View File

@ -18,71 +18,76 @@
*/ */
#pragma once #pragma once
#include <functional>
#include <inttypes.h> #include <inttypes.h>
#include <list> #include <list>
#include <functional>
extern "C" { extern "C" {
#pragma warning (push) #pragma warning(push)
#pragma warning (disable: 4201) #pragma warning(disable : 4201)
#include "obs-module.h" #include "obs-module.h"
#include "util/platform.h" #include "util/platform.h"
#pragma warning (pop) #pragma warning(pop)
} }
// Plugin // Plugin
#define PLUGIN_NAME "Stream Effects" #define PLUGIN_NAME "Stream Effects"
#include "version.h" #include "version.h"
#define P_LOG(level, ...) blog(level, "[" PLUGIN_NAME "] " __VA_ARGS__); #define P_LOG(level, ...) blog(level, "[" PLUGIN_NAME "] " __VA_ARGS__);
#define P_LOG_ERROR(...) P_LOG(LOG_ERROR, __VA_ARGS__) #define P_LOG_ERROR(...) P_LOG(LOG_ERROR, __VA_ARGS__)
#define P_LOG_WARNING(...) P_LOG(LOG_WARNING, __VA_ARGS__) #define P_LOG_WARNING(...) P_LOG(LOG_WARNING, __VA_ARGS__)
#define P_LOG_INFO(...) P_LOG(LOG_INFO, __VA_ARGS__) #define P_LOG_INFO(...) P_LOG(LOG_INFO, __VA_ARGS__)
#define P_LOG_DEBUG(...) P_LOG(LOG_DEBUG, __VA_ARGS__) #define P_LOG_DEBUG(...) P_LOG(LOG_DEBUG, __VA_ARGS__)
// Utility // Utility
#define vstr(s) dstr(s) #define vstr(s) dstr(s)
#define dstr(s) #s #define dstr(s) #s
#define clamp(val,low,high) (val > high ? high : (val < low ? low : val)) #define clamp(val, low, high) (val > high ? high : (val < low ? low : val))
#ifdef max #ifdef max
#undef max #undef max
#endif #endif
#define max(val,high) (val > high ? val : high) #define max(val, high) (val > high ? val : high)
#ifdef min #ifdef min
#undef min #undef min
#endif #endif
#define min(val,low ) (val < low ? val : low) #define min(val, low) (val < low ? val : low)
#ifndef __FUNCTION_NAME__ #ifndef __FUNCTION_NAME__
#if defined(_WIN32) || defined(_WIN64) //WINDOWS #if defined(_WIN32) || defined(_WIN64) //WINDOWS
#define __FUNCTION_NAME__ __FUNCTION__ #define __FUNCTION_NAME__ __FUNCTION__
#else //*NIX #else //*NIX
#define __FUNCTION_NAME__ __func__ #define __FUNCTION_NAME__ __func__
#endif #endif
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
#define INITIALIZER(f) \ #define INITIALIZER(f) \
static void f(void); \ static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \ struct f##_t_ { \
static void f(void) f##_t_(void) \
{ \
f(); \
} \
}; \
static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read) #pragma section(".CRT$XCU", read)
#define INITIALIZER2_(f,p) \ #define INITIALIZER2_(f, p) \
static void f(void); \ static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \ __pragma(comment(linker, "/include:" p #f "_")) static void f(void)
static void f(void)
#ifdef _WIN64 #ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"") #define INITIALIZER(f) INITIALIZER2_(f, "")
#else #else
#define INITIALIZER(f) INITIALIZER2_(f,"_") #define INITIALIZER(f) INITIALIZER2_(f, "_")
#endif #endif
#else #else
#define INITIALIZER(f) \ #define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \ static void f(void) __attribute__((constructor)); \
static void f(void) static void f(void)
#endif #endif
// Initializer & Finalizer // Initializer & Finalizer

View File

@ -18,28 +18,28 @@
*/ */
#include "source-mirror.h" #include "source-mirror.h"
#include "strings.h"
#include <memory>
#include <cstring>
#include <vector>
#include <bitset> #include <bitset>
#include <media-io/audio-io.h> #include <cstring>
#include <functional> #include <functional>
#include <media-io/audio-io.h>
#include <memory>
#include <vector>
#include "obs-tools.hpp" #include "obs-tools.hpp"
#include "strings.h"
#define S_SOURCE_MIRROR "Source.Mirror" #define S_SOURCE_MIRROR "Source.Mirror"
#define P_SOURCE "Source.Mirror.Source" #define P_SOURCE "Source.Mirror.Source"
#define P_SOURCE_SIZE "Source.Mirror.Source.Size" #define P_SOURCE_SIZE "Source.Mirror.Source.Size"
#define P_SOURCE_AUDIO "Source.Mirror.Source.Audio" #define P_SOURCE_AUDIO "Source.Mirror.Source.Audio"
#define P_SCALING "Source.Mirror.Scaling" #define P_SCALING "Source.Mirror.Scaling"
#define P_SCALING_METHOD "Source.Mirror.Scaling.Method" #define P_SCALING_METHOD "Source.Mirror.Scaling.Method"
#define P_SCALING_METHOD_POINT "Source.Mirror.Scaling.Method.Point" #define P_SCALING_METHOD_POINT "Source.Mirror.Scaling.Method.Point"
#define P_SCALING_METHOD_BILINEAR "Source.Mirror.Scaling.Method.Bilinear" #define P_SCALING_METHOD_BILINEAR "Source.Mirror.Scaling.Method.Bilinear"
#define P_SCALING_METHOD_BILINEARLOWRES "Source.Mirror.Scaling.Method.BilinearLowRes" #define P_SCALING_METHOD_BILINEARLOWRES "Source.Mirror.Scaling.Method.BilinearLowRes"
#define P_SCALING_METHOD_BICUBIC "Source.Mirror.Scaling.Method.Bicubic" #define P_SCALING_METHOD_BICUBIC "Source.Mirror.Scaling.Method.Bicubic"
#define P_SCALING_METHOD_LANCZOS "Source.Mirror.Scaling.Method.Lanczos" #define P_SCALING_METHOD_LANCZOS "Source.Mirror.Scaling.Method.Lanczos"
#define P_SCALING_SIZE "Source.Mirror.Scaling.Size" #define P_SCALING_SIZE "Source.Mirror.Scaling.Size"
#define P_SCALING_TRANSFORMKEEPORIGINAL "Source.Mirror.Scaling.TransformKeepOriginal" #define P_SCALING_TRANSFORMKEEPORIGINAL "Source.Mirror.Scaling.TransformKeepOriginal"
enum class ScalingMethod : int64_t { enum class ScalingMethod : int64_t {
Point, Point,
@ -51,33 +51,31 @@ enum class ScalingMethod : int64_t {
// Initializer & Finalizer // Initializer & Finalizer
Source::MirrorAddon* sourceMirrorInstance; Source::MirrorAddon* sourceMirrorInstance;
INITIALIZER(SourceMirrorInit) { INITIALIZER(SourceMirrorInit)
initializerFunctions.push_back([] { {
sourceMirrorInstance = new Source::MirrorAddon(); initializerFunctions.push_back([] { sourceMirrorInstance = new Source::MirrorAddon(); });
}); finalizerFunctions.push_back([] { delete sourceMirrorInstance; });
finalizerFunctions.push_back([] {
delete sourceMirrorInstance;
});
} }
Source::MirrorAddon::MirrorAddon() { Source::MirrorAddon::MirrorAddon()
{
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";
osi.type = OBS_SOURCE_TYPE_INPUT; osi.type = OBS_SOURCE_TYPE_INPUT;
osi.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_AUDIO | OBS_SOURCE_CUSTOM_DRAW; osi.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_AUDIO | OBS_SOURCE_CUSTOM_DRAW;
osi.get_name = get_name; osi.get_name = get_name;
osi.get_defaults = get_defaults; osi.get_defaults = get_defaults;
osi.get_properties = get_properties; osi.get_properties = get_properties;
osi.get_width = get_width; osi.get_width = get_width;
osi.get_height = get_height; osi.get_height = get_height;
osi.create = create; osi.create = create;
osi.destroy = destroy; osi.destroy = destroy;
osi.update = update; osi.update = update;
osi.activate = activate; osi.activate = activate;
osi.deactivate = deactivate; osi.deactivate = deactivate;
osi.video_tick = video_tick; osi.video_tick = video_tick;
osi.video_render = video_render; osi.video_render = video_render;
osi.enum_active_sources = enum_active_sources; osi.enum_active_sources = enum_active_sources;
obs_register_source(&osi); obs_register_source(&osi);
@ -85,11 +83,13 @@ Source::MirrorAddon::MirrorAddon() {
Source::MirrorAddon::~MirrorAddon() {} Source::MirrorAddon::~MirrorAddon() {}
const char * Source::MirrorAddon::get_name(void *) { const char* Source::MirrorAddon::get_name(void*)
{
return P_TRANSLATE(S_SOURCE_MIRROR); return P_TRANSLATE(S_SOURCE_MIRROR);
} }
void Source::MirrorAddon::get_defaults(obs_data_t *data) { void Source::MirrorAddon::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);
obs_data_set_default_bool(data, P_SCALING, false); obs_data_set_default_bool(data, P_SCALING, false);
@ -97,13 +97,13 @@ void Source::MirrorAddon::get_defaults(obs_data_t *data) {
obs_data_set_default_int(data, P_SCALING_METHOD, (int64_t)ScalingMethod::Bilinear); obs_data_set_default_int(data, P_SCALING_METHOD, (int64_t)ScalingMethod::Bilinear);
} }
bool Source::MirrorAddon::modified_properties(obs_properties_t *pr, obs_property_t *p, obs_data_t *data) { bool Source::MirrorAddon::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));
if (target) { if (target) {
std::vector<char> buf(256); std::vector<char> buf(256);
sprintf_s(buf.data(), buf.size(), "%ldx%ld\0", sprintf_s(buf.data(), buf.size(), "%ldx%ld\0", obs_source_get_width(target), obs_source_get_height(target));
obs_source_get_width(target), obs_source_get_height(target));
obs_data_set_string(data, P_SOURCE_SIZE, buf.data()); obs_data_set_string(data, P_SOURCE_SIZE, buf.data());
} else { } else {
obs_data_set_string(data, P_SOURCE_SIZE, "0x0"); obs_data_set_string(data, P_SOURCE_SIZE, "0x0");
@ -120,24 +120,26 @@ bool Source::MirrorAddon::modified_properties(obs_properties_t *pr, obs_property
return false; return false;
} }
static bool UpdateSourceListCB(void *ptr, obs_source_t* src) { static bool UpdateSourceListCB(void* ptr, obs_source_t* src)
{
obs_property_t* p = (obs_property_t*)ptr; obs_property_t* p = (obs_property_t*)ptr;
obs_property_list_add_string(p, obs_source_get_name(src), obs_source_get_name(src)); obs_property_list_add_string(p, obs_source_get_name(src), obs_source_get_name(src));
return true; return true;
} }
static void UpdateSourceList(obs_property_t* p) { static void UpdateSourceList(obs_property_t* p)
{
obs_property_list_clear(p); obs_property_list_clear(p);
obs_enum_sources(UpdateSourceListCB, p); obs_enum_sources(UpdateSourceListCB, p);
obs_enum_scenes(UpdateSourceListCB, p); obs_enum_scenes(UpdateSourceListCB, p);
} }
obs_properties_t * Source::MirrorAddon::get_properties(void *) { obs_properties_t* Source::MirrorAddon::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;
p = obs_properties_add_list(pr, P_SOURCE, P_TRANSLATE(P_SOURCE), p = obs_properties_add_list(pr, P_SOURCE, P_TRANSLATE(P_SOURCE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SOURCE))); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SOURCE)));
obs_property_set_modified_callback(p, modified_properties); obs_property_set_modified_callback(p, modified_properties);
UpdateSourceList(p); UpdateSourceList(p);
@ -153,8 +155,8 @@ obs_properties_t * Source::MirrorAddon::get_properties(void *) {
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SCALING))); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SCALING)));
obs_property_set_modified_callback(p, modified_properties); obs_property_set_modified_callback(p, modified_properties);
p = obs_properties_add_list(pr, P_SCALING_METHOD, P_TRANSLATE(P_SCALING_METHOD), p = obs_properties_add_list(pr, P_SCALING_METHOD, P_TRANSLATE(P_SCALING_METHOD), 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(P_SCALING_METHOD))); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SCALING_METHOD)));
obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_POINT), (int64_t)ScalingMethod::Point); obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_POINT), (int64_t)ScalingMethod::Point);
obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_BILINEAR), (int64_t)ScalingMethod::Bilinear); obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_BILINEAR), (int64_t)ScalingMethod::Bilinear);
@ -162,8 +164,7 @@ obs_properties_t * Source::MirrorAddon::get_properties(void *) {
obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_BICUBIC), (int64_t)ScalingMethod::Bicubic); obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_BICUBIC), (int64_t)ScalingMethod::Bicubic);
obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_LANCZOS), (int64_t)ScalingMethod::Lanczos); obs_property_list_add_int(p, P_TRANSLATE(P_SCALING_METHOD_LANCZOS), (int64_t)ScalingMethod::Lanczos);
p = obs_properties_add_text(pr, P_SCALING_SIZE, P_TRANSLATE(P_SCALING_SIZE), p = obs_properties_add_text(pr, P_SCALING_SIZE, P_TRANSLATE(P_SCALING_SIZE), OBS_TEXT_DEFAULT);
OBS_TEXT_DEFAULT);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SCALING_SIZE))); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SCALING_SIZE)));
p = obs_properties_add_bool(pr, P_SCALING_TRANSFORMKEEPORIGINAL, P_TRANSLATE(P_SCALING_TRANSFORMKEEPORIGINAL)); p = obs_properties_add_bool(pr, P_SCALING_TRANSFORMKEEPORIGINAL, P_TRANSLATE(P_SCALING_TRANSFORMKEEPORIGINAL));
@ -172,166 +173,181 @@ obs_properties_t * Source::MirrorAddon::get_properties(void *) {
return pr; return pr;
} }
void * Source::MirrorAddon::create(obs_data_t *data, obs_source_t *source) { void* Source::MirrorAddon::create(obs_data_t* data, obs_source_t* source)
{
return new Source::Mirror(data, source); return new Source::Mirror(data, source);
} }
void Source::MirrorAddon::destroy(void *p) { void Source::MirrorAddon::destroy(void* p)
{
if (p) { if (p) {
delete static_cast<Source::Mirror*>(p); delete static_cast<Source::Mirror*>(p);
} }
} }
uint32_t Source::MirrorAddon::get_width(void *p) { uint32_t Source::MirrorAddon::get_width(void* p)
{
if (p) { if (p) {
return static_cast<Source::Mirror*>(p)->get_width(); return static_cast<Source::Mirror*>(p)->get_width();
} }
return 0; return 0;
} }
uint32_t Source::MirrorAddon::get_height(void *p) { uint32_t Source::MirrorAddon::get_height(void* p)
{
if (p) { if (p) {
return static_cast<Source::Mirror*>(p)->get_height(); return static_cast<Source::Mirror*>(p)->get_height();
} }
return 0; return 0;
} }
void Source::MirrorAddon::update(void *p, obs_data_t *data) { void Source::MirrorAddon::update(void* p, obs_data_t* data)
{
if (p) { if (p) {
static_cast<Source::Mirror*>(p)->update(data); static_cast<Source::Mirror*>(p)->update(data);
} }
} }
void Source::MirrorAddon::activate(void *p) { void Source::MirrorAddon::activate(void* p)
{
if (p) { if (p) {
static_cast<Source::Mirror*>(p)->activate(); static_cast<Source::Mirror*>(p)->activate();
} }
} }
void Source::MirrorAddon::deactivate(void *p) { void Source::MirrorAddon::deactivate(void* p)
{
if (p) { if (p) {
static_cast<Source::Mirror*>(p)->deactivate(); static_cast<Source::Mirror*>(p)->deactivate();
} }
} }
void Source::MirrorAddon::video_tick(void *p, float t) { void Source::MirrorAddon::video_tick(void* p, float t)
{
if (p) { if (p) {
static_cast<Source::Mirror*>(p)->video_tick(t); static_cast<Source::Mirror*>(p)->video_tick(t);
} }
} }
void Source::MirrorAddon::video_render(void *p, gs_effect_t *ef) { void Source::MirrorAddon::video_render(void* p, gs_effect_t* ef)
{
if (p) { if (p) {
static_cast<Source::Mirror*>(p)->video_render(ef); static_cast<Source::Mirror*>(p)->video_render(ef);
} }
} }
void Source::MirrorAddon::enum_active_sources(void* p, obs_source_enum_proc_t enum_callback, void* param)
void Source::MirrorAddon::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*>(p)->enum_active_sources(enum_callback, param);
} }
} }
Source::Mirror::Mirror(obs_data_t* data, obs_source_t* src) { Source::Mirror::Mirror(obs_data_t* data, obs_source_t* src)
m_source = src; {
this->m_source = src;
this->m_rescale = false;
this->m_width = 1;
this->m_height = this->m_width;
this->m_render_target_scale = std::make_unique<gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
this->m_sampler = std::make_shared<gs::sampler>();
this->m_scaling_effect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_DEFAULT);
m_rescale = false; this->m_audio_data.resize(MAX_AUDIO_CHANNELS);
m_width = m_height = 1; for (size_t idx = 0; idx < this->m_audio_data.size(); idx++) {
m_renderTargetScale = std::make_unique<gs::rendertarget>(GS_RGBA, GS_ZS_NONE); this->m_audio_data[idx].resize(AUDIO_OUTPUT_FRAMES);
m_sampler = std::make_shared<gs::sampler>();
m_scalingEffect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_DEFAULT);
m_audioData.resize(MAX_AUDIO_CHANNELS);
for (size_t idx = 0; idx < m_audioData.size(); idx++) {
m_audioData[idx].resize(AUDIO_OUTPUT_FRAMES);
} }
m_audioThread = std::thread(std::bind(&Source::Mirror::audio_output_cb, this)); this->m_audio_thread = std::thread(std::bind(&Source::Mirror::audio_output_cb, this));
update(data); update(data);
m_active = true; m_active = true;
} }
Source::Mirror::~Mirror() { Source::Mirror::~Mirror()
if (m_audioCapture) { {
m_audioCapture.reset(); if (this->m_audio_capture) {
this->m_audio_capture.reset();
} }
if (m_source_texture) { if (this->m_source_texture) {
m_source_texture.reset(); this->m_source_texture.reset();
} }
if (m_scene) { if (this->m_scene) {
obs_scene_release(m_scene); obs_scene_release(this->m_scene);
} }
m_killAudioThread = true; this->m_kill_audio_thread = true;
m_audioNotify.notify_all(); this->m_audio_notify.notify_all();
if (m_audioThread.joinable()) if (this->m_audio_thread.joinable()) {
m_audioThread.join(); this->m_audio_thread.join();
}
} }
uint32_t Source::Mirror::get_width() { uint32_t Source::Mirror::get_width()
if (m_rescale && m_width > 0 && !m_keepOriginalSize) { {
return m_width; if (this->m_rescale && this->m_width > 0 && !this->m_keep_original_size) {
return this->m_width;
} }
obs_source_t* source = obs_sceneitem_get_source(m_sceneitem); obs_source_t* source = obs_sceneitem_get_source(this->m_sceneitem);
if (source) { if (source) {
return obs_source_get_width(source); return obs_source_get_width(source);
} }
return 1; return 1;
} }
uint32_t Source::Mirror::get_height() { uint32_t Source::Mirror::get_height()
if (m_rescale && m_height > 0 && !m_keepOriginalSize) {
return m_height; if (this->m_rescale && this->m_height > 0 && !this->m_keep_original_size)
obs_source_t* source = obs_sceneitem_get_source(m_sceneitem); return this->m_height;
obs_source_t* source = obs_sceneitem_get_source(this->m_sceneitem);
if (source) { if (source) {
return obs_source_get_height(source); return obs_source_get_height(source);
} }
return 1; return 1;
} }
void Source::Mirror::update(obs_data_t* data) { void Source::Mirror::update(obs_data_t* data)
if (!this->m_scene && m_active) { {
m_scene = obs_scene_create_private("localscene"); if (!this->m_scene && this->m_active) {
m_scene_source = std::make_shared<obs::source>(obs_scene_get_source(m_scene), false, false); this->m_scene = obs_scene_create_private("localscene");
m_source_texture = std::make_unique<gfx::source_texture>(m_scene_source, m_source); this->m_scene_source = std::make_shared<obs::source>(obs_scene_get_source(this->m_scene), false, false);
this->m_source_texture = std::make_unique<gfx::source_texture>(this->m_scene_source, this->m_source);
} }
// Update selected source. // Update selected source.
const char* sourceName = obs_data_get_string(data, P_SOURCE); const char* new_source_name = obs_data_get_string(data, P_SOURCE);
if (sourceName != m_mirrorName) { if (new_source_name != m_source_name) {
if (m_scene) { if (m_scene) {
if (m_sceneitem) { if (this->m_sceneitem) {
obs_sceneitem_remove(m_sceneitem); obs_sceneitem_remove(this->m_sceneitem);
m_sceneitem = nullptr; this->m_sceneitem = nullptr;
} }
obs_source_t* source = obs_get_source_by_name(sourceName); obs_source_t* source = obs_get_source_by_name(new_source_name);
if (source) { if (source) {
bool allow = true; bool allow = true;
if (strcmp(obs_source_get_id(source), "scene") == 0) { if (strcmp(obs_source_get_id(source), "scene") == 0) {
if (obs::tools::scene_contains_source(obs_scene_from_source(source), m_source)) { if (obs::tools::scene_contains_source(obs_scene_from_source(source), this->m_source)) {
allow = false; allow = false;
} }
} }
if (allow) { if (allow) {
m_sceneitem = obs_scene_add(m_scene, source); this->m_sceneitem = obs_scene_add(m_scene, source);
try { try {
m_audioCapture = std::make_unique<obs::audio_capture>(source); this->m_audio_capture = std::make_unique<obs::audio_capture>(source);
m_audioCapture->set_callback(std::bind(&Source::Mirror::audio_capture_cb, this, this->m_audio_capture->set_callback(std::bind(&Source::Mirror::audio_capture_cb, this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3)); std::placeholders::_3));
} catch(...) { } catch (...) {
} }
} }
obs_source_release(source); obs_source_release(source);
} }
} }
} }
m_enableAudio = obs_data_get_bool(data, P_SOURCE_AUDIO); this->m_enable_audio = obs_data_get_bool(data, P_SOURCE_AUDIO);
// Rescaling // Rescaling
m_rescale = obs_data_get_bool(data, P_SCALING); this->m_rescale = obs_data_get_bool(data, P_SCALING);
if (m_rescale) { // Parse rescaling settings. if (this->m_rescale) { // Parse rescaling settings.
uint32_t width, height; uint32_t width, height;
// Read value. // Read value.
@ -341,101 +357,105 @@ void Source::Mirror::update(obs_data_t* data) {
// Width // Width
width = strtoul(size, nullptr, 10); width = strtoul(size, nullptr, 10);
if (errno == ERANGE || width == 0) { if (errno == ERANGE || width == 0) {
m_rescale = false; this->m_rescale = false;
m_width = 1; this->m_width = 1;
} else { } else {
m_width = width; this->m_width = width;
} }
height = strtoul(xpos + 1, nullptr, 10); height = strtoul(xpos + 1, nullptr, 10);
if (errno == ERANGE || height == 0) { if (errno == ERANGE || height == 0) {
m_rescale = false; this->m_rescale = false;
m_height = 1; this->m_height = 1;
} else { } else {
m_height = height; this->m_height = height;
} }
} else { } else {
m_rescale = false; this->m_rescale = false;
m_width = 1; this->m_width = 1;
m_height = 1; this->m_height = 1;
} }
ScalingMethod scaler = (ScalingMethod)obs_data_get_int(data, P_SCALING_METHOD); ScalingMethod scaler = (ScalingMethod)obs_data_get_int(data, P_SCALING_METHOD);
switch (scaler) { switch (scaler) {
case ScalingMethod::Point: case ScalingMethod::Point:
default: default:
m_scalingEffect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_DEFAULT); this->m_scaling_effect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_DEFAULT);
m_sampler->set_filter(GS_FILTER_POINT); this->m_sampler->set_filter(GS_FILTER_POINT);
break; break;
case ScalingMethod::Bilinear: case ScalingMethod::Bilinear:
m_scalingEffect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_DEFAULT); this->m_scaling_effect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_DEFAULT);
m_sampler->set_filter(GS_FILTER_LINEAR); this->m_sampler->set_filter(GS_FILTER_LINEAR);
break; break;
case ScalingMethod::BilinearLowRes: case ScalingMethod::BilinearLowRes:
m_scalingEffect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_BILINEAR_LOWRES); this->m_scaling_effect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_BILINEAR_LOWRES);
m_sampler->set_filter(GS_FILTER_LINEAR); this->m_sampler->set_filter(GS_FILTER_LINEAR);
break; break;
case ScalingMethod::Bicubic: case ScalingMethod::Bicubic:
m_scalingEffect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_BICUBIC); this->m_scaling_effect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_BICUBIC);
m_sampler->set_filter(GS_FILTER_LINEAR); this->m_sampler->set_filter(GS_FILTER_LINEAR);
break; break;
case ScalingMethod::Lanczos: case ScalingMethod::Lanczos:
m_scalingEffect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_LANCZOS); this->m_scaling_effect = obs_get_base_effect(obs_base_effect::OBS_EFFECT_LANCZOS);
m_sampler->set_filter(GS_FILTER_LINEAR); this->m_sampler->set_filter(GS_FILTER_LINEAR);
break; break;
} }
m_keepOriginalSize = obs_data_get_bool(data, P_SCALING_TRANSFORMKEEPORIGINAL); this->m_keep_original_size = obs_data_get_bool(data, P_SCALING_TRANSFORMKEEPORIGINAL);
} }
} }
void Source::Mirror::activate() { void Source::Mirror::activate()
m_active = true; {
if (!m_sceneitem) { this->m_active = true;
obs_data_t* ref = obs_source_get_settings(m_source); if (!this->m_sceneitem) {
obs_data_t* ref = obs_source_get_settings(this->m_source);
update(ref); update(ref);
obs_data_release(ref); obs_data_release(ref);
} }
} }
void Source::Mirror::deactivate() { void Source::Mirror::deactivate()
m_active = false; {
this->m_active = false;
} }
static inline void mix_audio(float *p_out, float *p_in, static inline void mix_audio(float* p_out, float* p_in, size_t pos, size_t count)
size_t pos, size_t count) { {
register float *out = p_out; register float* out = p_out;
register float *in = p_in + pos; register float* in = p_in + pos;
register float *end = in + count; register float* end = in + count;
while (in < end) while (in < end)
*(out++) += *(in++); *(out++) += *(in++);
} }
void Source::Mirror::video_tick(float time) { void Source::Mirror::video_tick(float time)
m_tick += time; {
this->m_tick += time;
if (m_sceneitem) { if (this->m_sceneitem) {
m_mirrorName = obs_source_get_name(obs_sceneitem_get_source(m_sceneitem)); this->m_source_name = obs_source_get_name(obs_sceneitem_get_source(this->m_sceneitem));
} else { } else {
if (m_tick > 0.1f) { if (this->m_tick > 0.1f) {
obs_data_t* ref = obs_source_get_settings(m_source); obs_data_t* ref = obs_source_get_settings(this->m_source);
update(ref); update(ref);
obs_data_release(ref); obs_data_release(ref);
m_tick -= 0.1f; this->m_tick -= 0.1f;
} }
} }
} }
void Source::Mirror::video_render(gs_effect_t*) { void Source::Mirror::video_render(gs_effect_t*)
if ((m_width == 0) || (m_height == 0) || !m_source_texture || (m_source_texture->get_object() == m_source) {
|| !m_scene || !m_sceneitem) { if ((this->m_width == 0) || (this->m_height == 0) || !this->m_source_texture || !this->m_scene
|| !this->m_sceneitem) {
return; return;
} }
if (m_rescale && m_width > 0 && m_height > 0 && m_scalingEffect) { if (this->m_rescale && this->m_width > 0 && this->m_height > 0 && this->m_scaling_effect) {
// Get Size of source. // Get Size of source.
obs_source_t* source = obs_sceneitem_get_source(m_sceneitem); obs_source_t* source = obs_sceneitem_get_source(this->m_sceneitem);
uint32_t sw, sh; uint32_t sw, sh;
sw = obs_source_get_width(source); sw = obs_source_get_width(source);
@ -444,57 +464,56 @@ void Source::Mirror::video_render(gs_effect_t*) {
vec2 bounds; vec2 bounds;
bounds.x = sw; bounds.x = sw;
bounds.y = sh; bounds.y = sh;
obs_sceneitem_set_bounds(m_sceneitem, &bounds); obs_sceneitem_set_bounds(this->m_sceneitem, &bounds);
// Store original Source Texture // Store original Source Texture
std::shared_ptr<gs::texture> tex; std::shared_ptr<gs::texture> tex;
try { try {
tex = m_source_texture->render(sw, sh); tex = this->m_source_texture->render(sw, sh);
} catch (...) { } catch (...) {
return; return;
} }
gs_eparam_t *scale_param = gs_effect_get_param_by_name(m_scalingEffect, "base_dimension_i"); gs_eparam_t* scale_param = gs_effect_get_param_by_name(this->m_scaling_effect, "base_dimension_i");
if (scale_param) { if (scale_param) {
struct vec2 base_res_i = { struct vec2 base_res_i = {1.0f / float_t(sw), 1.0f / float_t(sh)};
1.0f / (float)sw,
1.0f / (float)sh
};
gs_effect_set_vec2(scale_param, &base_res_i); gs_effect_set_vec2(scale_param, &base_res_i);
} }
if (m_keepOriginalSize) { if (this->m_keep_original_size) {
{ {
vec4 black; vec4_zero(&black); vec4 black;
auto op = m_renderTargetScale->render(m_width, m_height); vec4_zero(&black);
gs_ortho(0, (float_t)m_width, 0, (float_t)m_height, 0, 1); auto op = m_render_target_scale->render(this->m_width, this->m_height);
gs_ortho(0, float_t(this->m_width), 0, float_t(this->m_height), 0, 1);
gs_clear(GS_CLEAR_COLOR, &black, 0, 0); gs_clear(GS_CLEAR_COLOR, &black, 0, 0);
while (gs_effect_loop(m_scalingEffect, "Draw")) { while (gs_effect_loop(this->m_scaling_effect, "Draw")) {
gs_eparam_t* image = gs_effect_get_param_by_name(m_scalingEffect, "image"); gs_eparam_t* image = gs_effect_get_param_by_name(this->m_scaling_effect, "image");
gs_effect_set_next_sampler(image, m_sampler->get_object()); gs_effect_set_next_sampler(image, this->m_sampler->get_object());
obs_source_draw(tex->get_object(), 0, 0, m_width, m_height, false); obs_source_draw(tex->get_object(), 0, 0, this->m_width, this->m_height, false);
} }
} }
while (gs_effect_loop(obs_get_base_effect(OBS_EFFECT_DEFAULT), "Draw")) { while (gs_effect_loop(obs_get_base_effect(OBS_EFFECT_DEFAULT), "Draw")) {
gs_eparam_t* image = gs_effect_get_param_by_name(obs_get_base_effect(OBS_EFFECT_DEFAULT), "image"); gs_eparam_t* image = gs_effect_get_param_by_name(obs_get_base_effect(OBS_EFFECT_DEFAULT), "image");
gs_effect_set_next_sampler(image, m_sampler->get_object()); gs_effect_set_next_sampler(image, this->m_sampler->get_object());
obs_source_draw(m_renderTargetScale->get_object(), 0, 0, sw, sh, false); obs_source_draw(this->m_render_target_scale->get_object(), 0, 0, sw, sh, false);
} }
} else { } else {
while (gs_effect_loop(m_scalingEffect, "Draw")) { while (gs_effect_loop(this->m_scaling_effect, "Draw")) {
gs_eparam_t* image = gs_effect_get_param_by_name(m_scalingEffect, "image"); gs_eparam_t* image = gs_effect_get_param_by_name(this->m_scaling_effect, "image");
gs_effect_set_next_sampler(image, m_sampler->get_object()); gs_effect_set_next_sampler(image, this->m_sampler->get_object());
obs_source_draw(tex->get_object(), 0, 0, m_width, m_height, false); obs_source_draw(tex->get_object(), 0, 0, this->m_width, this->m_height, false);
} }
} }
} else { } else {
obs_source_video_render(m_source_texture->get_object()); obs_source_video_render(this->m_source_texture->get_object());
} }
} }
void Source::Mirror::audio_capture_cb(void*, const audio_data* audio, bool) { void Source::Mirror::audio_capture_cb(void*, const audio_data* audio, bool)
std::unique_lock<std::mutex> ulock(m_audioLock); {
if (!m_enableAudio) { std::unique_lock<std::mutex> ulock(this->m_audio_lock);
if (!this->m_enable_audio) {
return; return;
} }
@ -509,40 +528,42 @@ void Source::Mirror::audio_capture_cb(void*, const audio_data* audio, bool) {
std::bitset<8> layout; std::bitset<8> layout;
for (size_t plane = 0; plane < MAX_AV_PLANES; plane++) { for (size_t plane = 0; plane < MAX_AV_PLANES; plane++) {
float *samples = (float*)audio->data[plane]; float* samples = (float*)audio->data[plane];
if (!samples) { if (!samples) {
m_audioOutput.data[plane] = nullptr; this->m_audio_output.data[plane] = nullptr;
continue; continue;
} }
layout.set(plane); layout.set(plane);
memcpy(m_audioData[plane].data(), audio->data[plane], audio->frames * sizeof(float_t)); memcpy(this->m_audio_data[plane].data(), audio->data[plane], audio->frames * sizeof(float_t));
m_audioOutput.data[plane] = (uint8_t*)m_audioData[plane].data(); this->m_audio_output.data[plane] = reinterpret_cast<uint8_t*>(this->m_audio_data[plane].data());
} }
m_audioOutput.format = aoi->format; this->m_audio_output.format = aoi->format;
m_audioOutput.frames = audio->frames; this->m_audio_output.frames = audio->frames;
m_audioOutput.timestamp = audio->timestamp; this->m_audio_output.timestamp = audio->timestamp;
m_audioOutput.samples_per_sec = aoi->samples_per_sec; this->m_audio_output.samples_per_sec = aoi->samples_per_sec;
m_audioOutput.speakers = aoi->speakers; this->m_audio_output.speakers = aoi->speakers;
m_haveAudioOutput = true; this->m_have_audio_output = true;
m_audioNotify.notify_all(); this->m_audio_notify.notify_all();
} }
void Source::Mirror::audio_output_cb() { void Source::Mirror::audio_output_cb()
std::unique_lock<std::mutex> ulock(m_audioLock); {
std::unique_lock<std::mutex> ulock(this->m_audio_lock);
while (!m_killAudioThread) { while (!this->m_kill_audio_thread) {
if (m_haveAudioOutput) { if (this->m_have_audio_output) {
obs_source_output_audio(m_source, &m_audioOutput); obs_source_output_audio(this->m_source, &this->m_audio_output);
m_haveAudioOutput = false; this->m_have_audio_output = false;
} }
m_audioNotify.wait(ulock, [this]() { return m_haveAudioOutput || m_killAudioThread; }); this->m_audio_notify.wait(ulock, [this]() { return this->m_have_audio_output || this->m_kill_audio_thread; });
} }
} }
void Source::Mirror::enum_active_sources(obs_source_enum_proc_t enum_callback, void *param) { void Source::Mirror::enum_active_sources(obs_source_enum_proc_t enum_callback, void* param)
if (m_sceneitem) { {
enum_callback(m_source, obs_sceneitem_get_source(m_sceneitem), param); if (this->m_sceneitem) {
enum_callback(this->m_source, obs_sceneitem_get_source(this->m_sceneitem), param);
} }
} }

View File

@ -42,57 +42,58 @@ namespace Source {
MirrorAddon(); MirrorAddon();
~MirrorAddon(); ~MirrorAddon();
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*);
static bool modified_properties(obs_properties_t *, obs_property_t *, obs_data_t *); static bool modified_properties(obs_properties_t*, obs_property_t*, obs_data_t*);
static obs_properties_t *get_properties(void *); static obs_properties_t* get_properties(void*);
static void *create(obs_data_t *, obs_source_t *); static void* create(obs_data_t*, obs_source_t*);
static void destroy(void *); static void destroy(void*);
static uint32_t get_width(void *); static uint32_t get_width(void*);
static uint32_t get_height(void *); static uint32_t get_height(void*);
static void update(void *, obs_data_t *); static void update(void*, obs_data_t*);
static void activate(void *); static void activate(void*);
static void deactivate(void *); static void deactivate(void*);
static void video_tick(void *, float); static void video_tick(void*, float);
static void video_render(void *, gs_effect_t *); static void video_render(void*, gs_effect_t*);
static void enum_active_sources(void *, obs_source_enum_proc_t, void *); static void enum_active_sources(void*, obs_source_enum_proc_t, void*);
}; };
class Mirror { class Mirror {
bool m_active = false; bool m_active = false;
obs_source_t* m_source = nullptr; obs_source_t* m_source = nullptr;
float_t m_tick = 0; float_t m_tick = 0;
// Input // Input
obs_scene_t* m_scene = nullptr; obs_scene_t* m_scene = nullptr;
std::shared_ptr<obs::source> m_scene_source; std::shared_ptr<obs::source> m_scene_source;
std::unique_ptr<gfx::source_texture> m_source_texture; std::unique_ptr<gfx::source_texture> m_source_texture;
// Input Source // Input Source
obs_sceneitem_t* m_sceneitem = nullptr; obs_sceneitem_t* m_sceneitem = nullptr;
std::string m_mirrorName; std::string m_source_name;
// Scaling // Scaling
bool m_rescale = false; bool m_rescale = false;
uint32_t m_width, m_height; uint32_t m_width;
gs_effect_t* m_scalingEffect = nullptr; uint32_t m_height;
bool m_keepOriginalSize = false; gs_effect_t* m_scaling_effect = nullptr;
std::unique_ptr<gs::rendertarget> m_renderTargetScale; bool m_keep_original_size = false;
std::shared_ptr<gs::sampler> m_sampler; std::unique_ptr<gs::rendertarget> m_render_target_scale;
std::shared_ptr<gs::sampler> m_sampler;
// Audio // Audio
bool m_enableAudio = false; bool m_enable_audio = false;
std::unique_ptr<obs::audio_capture> m_audioCapture; std::unique_ptr<obs::audio_capture> m_audio_capture;
std::mutex m_audioLock; std::mutex m_audio_lock;
std::condition_variable m_audioNotify; std::condition_variable m_audio_notify;
obs_source_audio m_audioOutput; obs_source_audio m_audio_output;
std::vector<std::vector<float_t>> m_audioData; std::vector<std::vector<float_t>> m_audio_data;
std::thread m_audioThread; std::thread m_audio_thread;
bool m_killAudioThread = false; bool m_kill_audio_thread = false;
bool m_haveAudioOutput = false; bool m_have_audio_output = false;
public: public:
Mirror(obs_data_t*, obs_source_t*); Mirror(obs_data_t*, obs_source_t*);
@ -108,6 +109,6 @@ namespace Source {
void video_render(gs_effect_t*); void video_render(gs_effect_t*);
void audio_capture_cb(void* data, const audio_data* audio, bool muted); void audio_capture_cb(void* data, const audio_data* audio, bool muted);
void audio_output_cb(); void audio_output_cb();
void enum_active_sources(obs_source_enum_proc_t, void *); void enum_active_sources(obs_source_enum_proc_t, void*);
}; };
}; }; // namespace Source

View File

@ -18,53 +18,62 @@
*/ */
#include "util-math.h" #include "util-math.h"
#include "util-memory.h" #include <cctype>
#include <malloc.h> #include <malloc.h>
#include <stdlib.h> #include <stdlib.h>
#include <cctype> #include "util-memory.h"
void* util::vec3a::operator new(size_t count) { void* util::vec3a::operator new(size_t count)
{
return _aligned_malloc(count, 16); return _aligned_malloc(count, 16);
} }
void* util::vec3a::operator new[](size_t count) { void* util::vec3a::operator new[](size_t count)
{
return _aligned_malloc(count, 16); return _aligned_malloc(count, 16);
} }
void util::vec3a::operator delete(void* p) { void util::vec3a::operator delete(void* p)
{
_aligned_free(p); _aligned_free(p);
} }
void util::vec3a::operator delete[](void* p) { void util::vec3a::operator delete[](void* p)
{
_aligned_free(p); _aligned_free(p);
} }
void* util::vec4a::operator new(size_t count) { void* util::vec4a::operator new(size_t count)
{
return _aligned_malloc(count, 16); return _aligned_malloc(count, 16);
} }
void* util::vec4a::operator new[](size_t count) { void* util::vec4a::operator new[](size_t count)
{
return _aligned_malloc(count, 16); return _aligned_malloc(count, 16);
} }
void util::vec4a::operator delete(void* p) { void util::vec4a::operator delete(void* p)
{
_aligned_free(p); _aligned_free(p);
} }
void util::vec4a::operator delete[](void* p) { void util::vec4a::operator delete[](void* p)
{
_aligned_free(p); _aligned_free(p);
} }
std::pair<int64_t, int64_t> util::SizeFromString(std::string text, bool allowSquare) { std::pair<int64_t, int64_t> util::SizeFromString(std::string text, bool allowSquare)
{
int64_t width, height; int64_t width, height;
const char* begin = text.c_str(); const char* begin = text.c_str();
const char* end = text.c_str() + text.size() + 1; const char* end = text.c_str() + text.size() + 1;
char* here = const_cast<char*>(end); char* here = const_cast<char*>(end);
long long res = strtoll(begin, &here, 0); long long res = strtoll(begin, &here, 0);
if (errno == ERANGE) { if (errno == ERANGE) {
return { 0, 0 }; return {0, 0};
} }
width = res; width = res;
@ -78,18 +87,18 @@ std::pair<int64_t, int64_t> util::SizeFromString(std::string text, bool allowSqu
// Are we allowed to return a square? // Are we allowed to return a square?
if (allowSquare) { if (allowSquare) {
// Yes: Return width,width. // Yes: Return width,width.
return { width, width }; return {width, width};
} else { } else {
// No: Return width,0. // No: Return width,0.
return { width, 0 }; return {width, 0};
} }
} }
res = strtoll(here, nullptr, 0); res = strtoll(here, nullptr, 0);
if (errno == ERANGE) { if (errno == ERANGE) {
return { width, 0 }; return {width, 0};
} }
height = res; height = res;
return { width, height }; return {width, height};
} }

View File

@ -21,7 +21,8 @@
#include <cstdlib> #include <cstdlib>
#define USE_STD_ALLOC_FREE #define USE_STD_ALLOC_FREE
void* util::malloc_aligned(size_t align, size_t size) { void* util::malloc_aligned(size_t align, size_t size)
{
#ifdef USE_STD_ALLOC_FREE #ifdef USE_STD_ALLOC_FREE
#if defined(_MSC_VER) #if defined(_MSC_VER)
return _aligned_malloc(size, align); return _aligned_malloc(size, align);
@ -46,7 +47,8 @@ void* util::malloc_aligned(size_t align, size_t size) {
#endif #endif
} }
void util::free_aligned(void* mem) { void util::free_aligned(void* mem)
{
#ifdef USE_STD_ALLOC_FREE #ifdef USE_STD_ALLOC_FREE
#if defined(_MSC_VER) #if defined(_MSC_VER)
_aligned_free(mem); _aligned_free(mem);

View File

@ -18,81 +18,91 @@
*/ */
#pragma once #pragma once
#include <stdlib.h>
#include <malloc.h> #include <malloc.h>
#include <stdlib.h>
namespace util { namespace util {
inline size_t aligned_offset(size_t align, size_t pos) { inline size_t aligned_offset(size_t align, size_t pos)
{
return ((pos / align) + 1) * align; return ((pos / align) + 1) * align;
} }
void* malloc_aligned(size_t align, size_t size); void* malloc_aligned(size_t align, size_t size);
void free_aligned(void* mem); void free_aligned(void* mem);
template <typename T, size_t N = 16> template<typename T, size_t N = 16>
class AlignmentAllocator { class AlignmentAllocator {
public: public:
typedef T value_type; typedef T value_type;
typedef size_t size_type; typedef size_t size_type;
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type;
typedef T * pointer; typedef T* pointer;
typedef const T * const_pointer; typedef const T* const_pointer;
typedef T & reference; typedef T& reference;
typedef const T & const_reference; typedef const T& const_reference;
public: public:
inline AlignmentAllocator() throw () {} inline AlignmentAllocator() throw() {}
template <typename T2> template<typename T2>
inline AlignmentAllocator(const AlignmentAllocator<T2, N> &) throw () {} inline AlignmentAllocator(const AlignmentAllocator<T2, N>&) throw()
{}
inline ~AlignmentAllocator() throw () {} inline ~AlignmentAllocator() throw() {}
inline pointer adress(reference r) { inline pointer adress(reference r)
{
return &r; return &r;
} }
inline const_pointer adress(const_reference r) const { inline const_pointer adress(const_reference r) const
{
return &r; return &r;
} }
inline pointer allocate(size_type n) { inline pointer allocate(size_type n)
return (pointer)malloc_aligned(n*sizeof(value_type), N); {
return (pointer)malloc_aligned(n * sizeof(value_type), N);
} }
inline void deallocate(pointer p, size_type) { inline void deallocate(pointer p, size_type)
{
free_aligned(p); free_aligned(p);
} }
inline void construct(pointer p, const value_type & wert) { inline void construct(pointer p, const value_type& wert)
new (p)value_type(wert); {
new (p) value_type(wert);
} }
inline void destroy(pointer p) { inline void destroy(pointer p)
{
p->~value_type(); p->~value_type();
p; p;
} }
inline size_type max_size() const throw () { inline size_type max_size() const throw()
{
return size_type(-1) / sizeof(value_type); return size_type(-1) / sizeof(value_type);
} }
template <typename T2> template<typename T2>
struct rebind { struct rebind {
typedef AlignmentAllocator<T2, N> other; typedef AlignmentAllocator<T2, N> other;
}; };
bool operator!=(const AlignmentAllocator<T, N>& other) const { bool operator!=(const AlignmentAllocator<T, N>& other) const
{
return !(*this == other); return !(*this == other);
} }
// Returns true if and only if storage allocated from *this // Returns true if and only if storage allocated from *this
// can be deallocated from other, and vice versa. // can be deallocated from other, and vice versa.
// Always returns true for stateless allocators. // Always returns true for stateless allocators.
bool operator==(const AlignmentAllocator<T, N>& other) const { bool operator==(const AlignmentAllocator<T, N>& other) const
{
return true; return true;
} }
}; };
}; }; // namespace util

View File

@ -18,4 +18,3 @@
*/ */
#include "utility.h" #include "utility.h"

View File

@ -26,23 +26,21 @@ struct enable_bitmask_operators {
}; };
template<typename Enum> template<typename Enum>
typename std::enable_if<enable_bitmask_operators<Enum>::enable, Enum>::type typename std::enable_if<enable_bitmask_operators<Enum>::enable, Enum>::type operator|(Enum lhs, Enum rhs)
operator |(Enum lhs, Enum rhs) { {
using underlying = typename std::underlying_type<Enum>::type; using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> ( return static_cast<Enum>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
static_cast<underlying>(lhs) |
static_cast<underlying>(rhs)
);
} }
template<typename Enum> template<typename Enum>
typename std::enable_if<enable_bitmask_operators<Enum>::enable, Enum>::type typename std::enable_if<enable_bitmask_operators<Enum>::enable, Enum>::type operator&(Enum lhs, Enum rhs)
operator &(Enum lhs, Enum rhs) { {
using underlying = typename std::underlying_type<Enum>::type; using underlying = typename std::underlying_type<Enum>::type;
return static_cast<Enum> ( return static_cast<Enum>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
static_cast<underlying>(lhs) &
static_cast<underlying>(rhs)
);
} }
#define ENABLE_BITMASK_OPERATORS(x) template<> struct enable_bitmask_operators<x> { static const bool enable = true; }; #define ENABLE_BITMASK_OPERATORS(x) \
template<> \
struct enable_bitmask_operators<x> { \
static const bool enable = true; \
};