diff --git a/plugins/obs-transitions/CMakeLists.txt b/plugins/obs-transitions/CMakeLists.txt index 9ceac5e9d..bbf58a0a9 100644 --- a/plugins/obs-transitions/CMakeLists.txt +++ b/plugins/obs-transitions/CMakeLists.txt @@ -2,6 +2,7 @@ project(obs-transitions) set(obs-transitions_SOURCES obs-transitions.c + transition-swipe.c transition-fade.c transition-cut.c ) diff --git a/plugins/obs-transitions/data/locale/en-US.ini b/plugins/obs-transitions/data/locale/en-US.ini index 64dbed589..4740506bc 100644 --- a/plugins/obs-transitions/data/locale/en-US.ini +++ b/plugins/obs-transitions/data/locale/en-US.ini @@ -1,2 +1,9 @@ FadeTransition="Fade" CutTransition="Cut" +SwipeTransition="Swipe" +Direction="Direction" +Direction.Left="Left" +Direction.Right="Right" +Direction.Up="Up" +Direction.Down="Down" +SwipeIn="Swipe In" diff --git a/plugins/obs-transitions/data/swipe_transition.effect b/plugins/obs-transitions/data/swipe_transition.effect new file mode 100644 index 000000000..699db6611 --- /dev/null +++ b/plugins/obs-transitions/data/swipe_transition.effect @@ -0,0 +1,42 @@ +uniform float4x4 ViewProj; +uniform texture2d tex_a; +uniform texture2d tex_b; +uniform float2 swipe_val; + +sampler_state textureSampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertData VSDefault(VertData v_in) +{ + VertData vert_out; + vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = v_in.uv; + return vert_out; +} + +float4 PSSwipe(VertData v_in) : TARGET +{ + float2 swipe_uv = v_in.uv + swipe_val; + + return (swipe_uv.x - saturate(swipe_uv.x) != 0.0) || + (swipe_uv.y - saturate(swipe_uv.y) != 0.0) + ? tex_b.Sample(textureSampler, v_in.uv) + : tex_a.Sample(textureSampler, swipe_uv); +} + +technique Swipe +{ + pass + { + vertex_shader = VSDefault(v_in); + pixel_shader = PSSwipe(v_in); + } +} diff --git a/plugins/obs-transitions/obs-transitions.c b/plugins/obs-transitions/obs-transitions.c index 7e15a13fd..09ce19787 100644 --- a/plugins/obs-transitions/obs-transitions.c +++ b/plugins/obs-transitions/obs-transitions.c @@ -6,10 +6,12 @@ OBS_MODULE_USE_DEFAULT_LOCALE("obs-transitions", "en-US") extern struct obs_source_info cut_transition; extern struct obs_source_info fade_transition; +extern struct obs_source_info swipe_transition; bool obs_module_load(void) { obs_register_source(&cut_transition); obs_register_source(&fade_transition); + obs_register_source(&swipe_transition); return true; } diff --git a/plugins/obs-transitions/transition-swipe.c b/plugins/obs-transitions/transition-swipe.c new file mode 100644 index 000000000..a9b8e874c --- /dev/null +++ b/plugins/obs-transitions/transition-swipe.c @@ -0,0 +1,167 @@ +#include +#include + +struct swipe_info { + obs_source_t *source; + + gs_effect_t *effect; + gs_eparam_t *a_param; + gs_eparam_t *b_param; + gs_eparam_t *swipe_param; + + struct vec2 dir; + bool swipe_in; +}; + +#define S_DIRECTION "direction" +#define S_SWIPE_IN "swipe_in" + +static float get_easing(float t) +{ + if (t < 0.5f) { + return 4.0f * t * t * t; + } else { + float temp = (2.0f * t - 2.0f); + return (t - 1.0f) * temp * temp + 1.0f; + } +} + +static const char *swipe_get_name(void *type_data) +{ + UNUSED_PARAMETER(type_data); + return obs_module_text("SwipeTransition"); +} + +static void *swipe_create(obs_data_t *settings, obs_source_t *source) +{ + struct swipe_info *swipe; + char *file = obs_module_file("swipe_transition.effect"); + gs_effect_t *effect; + + obs_enter_graphics(); + effect = gs_effect_create_from_file(file, NULL); + obs_leave_graphics(); + bfree(file); + + if (!effect) { + blog(LOG_ERROR, "Could not find swipe_transition.effect"); + return NULL; + } + + swipe = bmalloc(sizeof(*swipe)); + swipe->source = source; + swipe->effect = effect; + swipe->a_param = gs_effect_get_param_by_name(effect, "tex_a"); + swipe->b_param = gs_effect_get_param_by_name(effect, "tex_b"); + swipe->swipe_param = gs_effect_get_param_by_name(effect, "swipe_val"); + + obs_source_update(source, settings); + + UNUSED_PARAMETER(settings); + return swipe; +} + +static void swipe_destroy(void *data) +{ + struct swipe_info *swipe = data; + bfree(swipe); +} + +static void swipe_update(void *data, obs_data_t *settings) +{ + struct swipe_info *swipe = data; + const char *dir = obs_data_get_string(settings, S_DIRECTION); + + swipe->swipe_in = obs_data_get_bool(settings, S_SWIPE_IN); + + if (strcmp(dir, "right") == 0) + swipe->dir = (struct vec2){-1.0f, 0.0f}; + else if (strcmp(dir, "up") == 0) + swipe->dir = (struct vec2){0.0f, 1.0f}; + else if (strcmp(dir, "down") == 0) + swipe->dir = (struct vec2){0.0f, -1.0f}; + else /* left */ + swipe->dir = (struct vec2){1.0f, 0.0f}; +} + +static void swipe_callback(void *data, gs_texture_t *a, gs_texture_t *b, + float t, uint32_t cx, uint32_t cy) +{ + struct swipe_info *swipe = data; + struct vec2 swipe_val = swipe->dir; + + if (swipe->swipe_in) + vec2_neg(&swipe_val, &swipe_val); + + t = get_easing(t); + + vec2_mulf(&swipe_val, &swipe_val, swipe->swipe_in ? 1.0f - t : t); + + gs_effect_set_texture(swipe->a_param, swipe->swipe_in ? b : a); + gs_effect_set_texture(swipe->b_param, swipe->swipe_in ? a : b); + gs_effect_set_vec2(swipe->swipe_param, &swipe_val); + + while (gs_effect_loop(swipe->effect, "Swipe")) + gs_draw_sprite(NULL, 0, cx, cy); +} + +static void swipe_video_render(void *data, gs_effect_t *effect) +{ + struct swipe_info *swipe = data; + obs_transition_video_render(swipe->source, swipe_callback); + UNUSED_PARAMETER(effect); +} + +static float mix_a(void *data, float t) +{ + UNUSED_PARAMETER(data); + return 1.0f - get_easing(t); +} + +static float mix_b(void *data, float t) +{ + UNUSED_PARAMETER(data); + return get_easing(t); +} + +static bool swipe_audio_render(void *data, uint64_t *ts_out, + struct obs_source_audio_mix *audio, uint32_t mixers, + size_t channels, size_t sample_rate) +{ + struct swipe_info *swipe = data; + return obs_transition_audio_render(swipe->source, ts_out, + audio, mixers, channels, sample_rate, mix_a, mix_b); +} + +static obs_properties_t *swipe_properties(void *data) +{ + obs_properties_t *ppts = obs_properties_create(); + obs_property_t *p; + + p = obs_properties_add_list(ppts, S_DIRECTION, + obs_module_text("Direction"), OBS_COMBO_TYPE_LIST, + OBS_COMBO_FORMAT_STRING); + obs_property_list_add_string(p, obs_module_text("Direction.Left"), + "left"); + obs_property_list_add_string(p, obs_module_text("Direction.Right"), + "right"); + obs_property_list_add_string(p, obs_module_text("Direction.Up"), + "up"); + obs_property_list_add_string(p, obs_module_text("Direction.Down"), + "down"); + + obs_properties_add_bool(ppts, S_SWIPE_IN, obs_module_text("SwipeIn")); + return ppts; +} + +struct obs_source_info swipe_transition = { + .id = "swipe_transition", + .type = OBS_SOURCE_TYPE_TRANSITION, + .get_name = swipe_get_name, + .create = swipe_create, + .destroy = swipe_destroy, + .update = swipe_update, + .video_render = swipe_video_render, + .audio_render = swipe_audio_render, + .get_properties = swipe_properties +};