2023-02-28 01:15:26 +00:00
// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2019-2023 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// Copyright (C) 2021 coolsoft.rf <coolsoft.rf@gmail.com>
// AUTOGENERATED COPYRIGHT HEADER END
2017-11-06 11:36:01 +00:00
2019-08-07 16:05:49 +00:00
# include "filter-shader.hpp"
2020-04-05 04:13:14 +00:00
# include "strings.hpp"
2020-03-28 17:54:56 +00:00
# include "obs/gs/gs-helper.hpp"
2021-09-07 02:22:46 +00:00
# include "util/util-logging.hpp"
2022-08-29 10:29:44 +00:00
# include "warning-disable.hpp"
# include <stdexcept>
# include "warning-enable.hpp"
2021-09-07 02:22:46 +00:00
# ifdef _DEBUG
# define ST_PREFIX "<%s> "
# define D_LOG_ERROR(x, ...) P_LOG_ERROR(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# define D_LOG_WARNING(x, ...) P_LOG_WARN(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# define D_LOG_INFO(x, ...) P_LOG_INFO(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# define D_LOG_DEBUG(x, ...) P_LOG_DEBUG(ST_PREFIX##x, __FUNCTION_SIG__, __VA_ARGS__)
# else
# define ST_PREFIX "<filter::shader> "
# define D_LOG_ERROR(...) P_LOG_ERROR(ST_PREFIX __VA_ARGS__)
# define D_LOG_WARNING(...) P_LOG_WARN(ST_PREFIX __VA_ARGS__)
# define D_LOG_INFO(...) P_LOG_INFO(ST_PREFIX __VA_ARGS__)
# define D_LOG_DEBUG(...) P_LOG_DEBUG(ST_PREFIX __VA_ARGS__)
# endif
2017-11-06 11:36:01 +00:00
2021-06-08 03:08:51 +00:00
# define ST_I18N "Filter.Shader"
2017-11-06 11:36:01 +00:00
2020-04-05 16:52:06 +00:00
using namespace streamfx : : filter : : shader ;
2023-05-13 12:35:46 +00:00
static constexpr std : : string_view HELP_URL = " https://github.com/Xaymar/obs-StreamFX/wiki/Source-Filter-Transition-Shader " ;
2021-04-16 23:43:30 +00:00
2020-04-05 16:52:06 +00:00
shader_instance : : shader_instance ( obs_data_t * data , obs_source_t * self ) : obs : : source_instance ( data , self )
2019-08-07 15:15:46 +00:00
{
2021-06-08 02:47:04 +00:00
_fx = std : : make_shared < streamfx : : gfx : : shader : : shader > ( self , streamfx : : gfx : : shader : : shader_mode : : Filter ) ;
2021-06-08 02:38:24 +00:00
_rt = std : : make_shared < streamfx : : obs : : gs : : rendertarget > ( GS_RGBA , GS_ZS_NONE ) ;
2020-12-04 11:59:46 +00:00
update ( data ) ;
2019-08-07 15:15:46 +00:00
}
2017-11-06 11:36:01 +00:00
2020-04-05 16:52:06 +00:00
shader_instance : : ~ shader_instance ( ) { }
2017-11-06 11:36:01 +00:00
2020-08-10 01:29:05 +00:00
uint32_t shader_instance : : get_width ( )
2018-11-07 14:24:25 +00:00
{
2020-03-28 17:54:56 +00:00
return _fx - > width ( ) ;
2017-11-06 11:36:01 +00:00
}
2020-08-10 01:29:05 +00:00
uint32_t shader_instance : : get_height ( )
2018-11-07 14:24:25 +00:00
{
2020-03-28 17:54:56 +00:00
return _fx - > height ( ) ;
2019-09-05 16:42:28 +00:00
}
2020-04-05 16:52:06 +00:00
void shader_instance : : properties ( obs_properties_t * props )
2019-08-07 15:37:52 +00:00
{
2019-08-07 15:15:46 +00:00
_fx - > properties ( props ) ;
}
2017-11-06 11:36:01 +00:00
2020-04-05 16:52:06 +00:00
void shader_instance : : load ( obs_data_t * data )
2019-08-07 18:39:55 +00:00
{
update ( data ) ;
}
2020-08-10 01:29:05 +00:00
void shader_instance : : migrate ( obs_data_t * data , uint64_t version ) { }
2020-04-05 04:02:03 +00:00
2020-04-05 16:52:06 +00:00
void shader_instance : : update ( obs_data_t * data )
2019-08-07 15:37:52 +00:00
{
2019-08-07 15:15:46 +00:00
_fx - > update ( data ) ;
}
2017-11-06 11:36:01 +00:00
2020-04-05 16:52:06 +00:00
void shader_instance : : video_tick ( float_t sec_since_last )
2018-11-07 14:24:25 +00:00
{
2019-08-07 16:43:19 +00:00
if ( _fx - > tick ( sec_since_last ) ) {
obs_data_t * data = obs_source_get_settings ( _self ) ;
2020-03-28 17:54:56 +00:00
_fx - > update ( data ) ;
2019-08-07 16:43:19 +00:00
obs_data_release ( data ) ;
}
2019-08-07 15:37:52 +00:00
2020-03-31 20:26:50 +00:00
if ( obs_source_t * tgt = obs_filter_get_target ( _self ) ; tgt ! = nullptr ) {
2020-03-31 20:42:18 +00:00
_fx - > set_size ( obs_source_get_base_width ( tgt ) , obs_source_get_base_height ( tgt ) ) ;
2020-03-31 20:26:50 +00:00
} else if ( obs_source * src = obs_filter_get_parent ( _self ) ; src ! = nullptr ) {
_fx - > set_size ( obs_source_get_base_width ( src ) , obs_source_get_base_height ( src ) ) ;
}
2018-04-09 11:28:13 +00:00
}
2020-04-05 16:52:06 +00:00
void shader_instance : : video_render ( gs_effect_t * effect )
2018-11-07 14:24:25 +00:00
{
2020-07-05 20:21:55 +00:00
try {
if ( ! _fx | | ! _fx - > base_width ( ) | | ! _fx - > base_height ( ) ) {
throw std : : runtime_error ( " No effect, or invalid base size. " ) ;
}
2018-04-29 01:07:26 +00:00
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2023-05-13 12:35:46 +00:00
streamfx : : obs : : gs : : debug_marker gdmp { streamfx : : obs : : gs : : debug_color_source , " Shader Filter '%s' on '%s' " , obs_source_get_name ( _self ) , obs_source_get_name ( obs_filter_get_parent ( _self ) ) } ;
2020-04-25 23:04:04 +00:00
# endif
2020-07-05 20:21:55 +00:00
{
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2021-06-08 02:38:24 +00:00
streamfx : : obs : : gs : : debug_marker gdm { streamfx : : obs : : gs : : debug_color_source , " Cache " } ;
2020-04-25 23:04:04 +00:00
# endif
2020-07-05 20:21:55 +00:00
auto op = _rt - > render ( _fx - > base_width ( ) , _fx - > base_height ( ) ) ;
2020-03-28 17:54:56 +00:00
2020-07-05 20:21:55 +00:00
gs_ortho ( 0 , 1 , 0 , 1 , - 1 , 1 ) ;
2020-03-28 17:54:56 +00:00
2020-07-05 20:21:55 +00:00
/// Render original source
if ( obs_source_process_filter_begin ( _self , GS_RGBA , OBS_NO_DIRECT_RENDERING ) ) {
gs_blend_state_push ( ) ;
gs_reset_blend_state ( ) ;
gs_blend_function_separate ( GS_BLEND_ONE , GS_BLEND_ZERO , GS_BLEND_SRCALPHA , GS_BLEND_ZERO ) ;
gs_enable_blending ( false ) ;
gs_enable_depth_test ( false ) ;
gs_enable_stencil_test ( false ) ;
gs_enable_stencil_write ( false ) ;
gs_enable_color ( true , true , true , true ) ;
gs_set_cull_mode ( GS_NEITHER ) ;
2020-03-28 17:54:56 +00:00
2020-07-05 20:21:55 +00:00
obs_source_process_filter_end ( _self , obs_get_base_effect ( OBS_EFFECT_DEFAULT ) , 1 , 1 ) ;
2019-08-07 15:37:52 +00:00
2020-07-05 20:21:55 +00:00
gs_blend_state_pop ( ) ;
} else {
throw std : : runtime_error ( " Failed to render previous source. " ) ;
}
2019-08-07 17:20:32 +00:00
}
2020-07-05 20:21:55 +00:00
{
2023-04-05 16:24:26 +00:00
# if defined(ENABLE_PROFILING) && !defined(D_PLATFORM_MAC) && _DEBUG
2021-06-08 02:38:24 +00:00
streamfx : : obs : : gs : : debug_marker gdm { streamfx : : obs : : gs : : debug_color_render , " Render " } ;
2020-04-25 23:04:04 +00:00
# endif
2020-03-28 17:54:56 +00:00
2020-07-05 20:21:55 +00:00
_fx - > prepare_render ( ) ;
_fx - > set_input_a ( _rt - > get_texture ( ) ) ;
2021-03-28 12:29:37 +00:00
_fx - > render ( effect ) ;
2020-07-05 20:21:55 +00:00
}
} catch ( const std : : exception & ex ) {
obs_source_skip_video_filter ( _self ) ;
throw ex ;
2020-03-31 20:26:50 +00:00
}
}
2019-08-07 17:20:32 +00:00
2021-10-15 14:30:01 +00:00
void streamfx : : filter : : shader : : shader_instance : : show ( )
{
_fx - > set_visible ( true ) ;
}
void streamfx : : filter : : shader : : shader_instance : : hide ( )
{
_fx - > set_visible ( false ) ;
}
2020-07-05 21:00:09 +00:00
void streamfx : : filter : : shader : : shader_instance : : activate ( )
{
_fx - > set_active ( true ) ;
}
void streamfx : : filter : : shader : : shader_instance : : deactivate ( )
{
_fx - > set_active ( false ) ;
}
2020-04-05 16:52:06 +00:00
shader_factory : : shader_factory ( )
2020-03-28 17:54:56 +00:00
{
2021-06-08 02:16:33 +00:00
_info . id = S_PREFIX " filter-shader " ;
2020-03-28 17:54:56 +00:00
_info . type = OBS_SOURCE_TYPE_FILTER ;
2021-03-28 12:29:37 +00:00
_info . output_flags = OBS_SOURCE_VIDEO ;
2019-08-07 17:20:32 +00:00
2022-05-11 03:33:38 +00:00
support_activity_tracking ( true ) ;
support_visibility_tracking ( true ) ;
2020-03-28 17:54:56 +00:00
finish_setup ( ) ;
2020-06-14 02:53:15 +00:00
register_proxy ( " obs-stream-effects-filter-shader " ) ;
2020-03-28 17:54:56 +00:00
}
2020-04-05 16:52:06 +00:00
shader_factory : : ~ shader_factory ( ) { }
2020-03-28 17:54:56 +00:00
2020-04-05 16:52:06 +00:00
const char * shader_factory : : get_name ( )
2020-03-28 17:54:56 +00:00
{
2021-06-08 03:08:51 +00:00
return D_TRANSLATE ( ST_I18N ) ;
2020-03-28 17:54:56 +00:00
}
2020-04-05 16:52:06 +00:00
void shader_factory : : get_defaults2 ( obs_data_t * data )
2020-03-31 20:42:18 +00:00
{
2021-06-08 02:47:04 +00:00
streamfx : : gfx : : shader : : shader : : defaults ( data ) ;
2020-03-31 20:34:22 +00:00
}
2020-03-28 17:54:56 +00:00
2020-04-05 16:52:06 +00:00
obs_properties_t * shader_factory : : get_properties2 ( shader : : shader_instance * data )
2020-03-28 17:54:56 +00:00
{
auto pr = obs_properties_create ( ) ;
obs_properties_set_param ( pr , data , nullptr ) ;
2021-04-16 23:43:30 +00:00
# ifdef ENABLE_FRONTEND
{
2023-05-13 12:35:46 +00:00
auto p = obs_properties_add_button2 ( pr , S_MANUAL_OPEN , D_TRANSLATE ( S_MANUAL_OPEN ) , streamfx : : filter : : shader : : shader_factory : : on_manual_open , nullptr ) ;
2021-04-16 23:43:30 +00:00
}
# endif
2020-03-28 17:54:56 +00:00
if ( data ) {
reinterpret_cast < shader_instance * > ( data ) - > properties ( pr ) ;
2019-08-07 15:15:46 +00:00
}
2020-03-28 17:54:56 +00:00
return pr ;
2018-04-09 11:28:13 +00:00
}
2020-04-05 16:52:06 +00:00
2021-04-16 23:43:30 +00:00
# ifdef ENABLE_FRONTEND
bool shader_factory : : on_manual_open ( obs_properties_t * props , obs_property_t * property , void * data )
2022-08-27 11:17:47 +00:00
{
try {
streamfx : : open_url ( HELP_URL ) ;
return false ;
} catch ( const std : : exception & ex ) {
D_LOG_ERROR ( " Failed to open manual due to error: %s " , ex . what ( ) ) ;
return false ;
} catch ( . . . ) {
D_LOG_ERROR ( " Failed to open manual due to unknown error. " , " " ) ;
return false ;
}
2021-04-16 23:43:30 +00:00
}
# endif
2020-04-05 16:52:06 +00:00
std : : shared_ptr < shader_factory > _filter_shader_factory_instance = nullptr ;
void streamfx : : filter : : shader : : shader_factory : : initialize ( )
2022-08-27 11:17:47 +00:00
{
try {
if ( ! _filter_shader_factory_instance )
_filter_shader_factory_instance = std : : make_shared < shader_factory > ( ) ;
} catch ( const std : : exception & ex ) {
D_LOG_ERROR ( " Failed to initialize due to error: %s " , ex . what ( ) ) ;
} catch ( . . . ) {
D_LOG_ERROR ( " Failed to initialize due to unknown error. " , " " ) ;
}
2020-04-05 16:52:06 +00:00
}
void streamfx : : filter : : shader : : shader_factory : : finalize ( )
{
_filter_shader_factory_instance . reset ( ) ;
}
std : : shared_ptr < shader_factory > streamfx : : filter : : shader : : shader_factory : : get ( )
{
return _filter_shader_factory_instance ;
}