Last active
April 5, 2018 03:21
-
-
Save Andersama/225d0ff6a2ccc0f881562aa41f08ec8e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
uniform float4x4 ViewProj; | |
uniform texture2d a_tex; | |
uniform texture2d b_tex; | |
uniform texture2d c_tex; | |
uniform float4 color_target_a; | |
uniform float4 color_target_b; | |
uniform bool invert; | |
sampler_state textureSampler { | |
Filter = Linear; | |
AddressU = Clamp; | |
AddressV = Clamp; | |
}; | |
struct VertData { | |
float4 pos : POSITION; | |
float2 uv : TEXCOORD0; | |
}; | |
#include "premultiplied.inc" | |
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 PSAnimatedWipe(VertData v_in) : TARGET | |
{ | |
float2 uv = v_in.uv; | |
float4 a_color = convert_pmalpha(a_tex.Sample(textureSampler, uv)); | |
float4 b_color = convert_pmalpha(b_tex.Sample(textureSampler, uv)); | |
float4 c_color = c_tex.Sample(textureSampler, uv); | |
float4 ret_color; | |
if(invert){ | |
switch(c_color){ | |
case a_color: | |
ret_color = b_color; | |
break; | |
case b_color: | |
ret_color = a_color; | |
break; | |
default: | |
ret_color = c_color; | |
} | |
} else { | |
switch(c_color){ | |
case a_color: | |
ret_color = a_color; | |
break; | |
case b_color: | |
ret_color = b_color; | |
break; | |
default: | |
ret_color = c_color; | |
} | |
} | |
return ret_color; | |
} | |
technique AnimatedWipe | |
{ | |
pass | |
{ | |
vertex_shader = VSDefault(v_in); | |
pixel_shader = PSAnimatedWipe(v_in); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <obs-module.h> | |
#include <graphics/image-file.h> | |
#include <util/dstr.h> | |
#define S_INV "animated_wipe_invert" | |
#define S_TRANSITION "animated_wipe_transition" | |
#define S_COLOR_A "animated_wipe_color_target_a" | |
#define S_COLOR_B "animated_wipe_color_target_b" | |
#define T_TRANSITION obs_module_text("AnimatedWipe.Transition") | |
#define T_INV obs_module_text("AnimatedWipe.Invert") | |
#define T_COLOR_A obs_module_text("AnimatedWipe.ColorTargetA") | |
#define T_COLOR_B obs_module_text("AnimatedWipe.ColorTargetB") | |
struct animated_wipe_info { | |
obs_source_t *source; | |
gs_effect_t *effect; | |
gs_eparam_t *ep_a_tex; | |
gs_eparam_t *ep_b_tex; | |
gs_eparam_t *ep_c_tex; | |
//gs_eparam_t *ep_progress; | |
gs_eparam_t *ep_invert; | |
gs_eparam_t *ep_color_target_a; | |
gs_eparam_t *ep_color_target_b; | |
gs_image_file_t animated_image; | |
bool invert; | |
obs_data_t *wipes_list; | |
}; | |
static const char *animated_wipe_get_name(void *type_data) | |
{ | |
UNUSED_PARAMETER(type_data); | |
return obs_module_text("AnimatedWipeTransition"); | |
} | |
static void animated_wipe_update(void *data, obs_data_t *settings) | |
{ | |
struct animated_wipe_info *awipe = data; | |
const char *name = obs_data_get_string(settings, S_TRANSITION); | |
awipe->invert = obs_data_get_bool(settings, S_INV); | |
struct vec4 color_target_a; | |
struct vec4 color_target_b; | |
vec4_from_rgba(&color_target_a, (unsigned int)obs_data_get_int(settings,S_COLOR_A)); | |
gs_effect_set_vec4(awipe->ep_color_target_a, &color_target_a); | |
vec4_from_rgba(&color_target_b, (unsigned int)obs_data_get_int(settings, S_COLOR_B)); | |
gs_effect_set_vec4(awipe->ep_color_target_b, &color_target_b); | |
struct dstr path = {0}; | |
dstr_copy(&path, "animated_wipes/"); | |
dstr_cat(&path, name); | |
char *file = obs_module_file(path.array); | |
obs_enter_graphics(); | |
gs_image_file_free(&awipe->animated_image); | |
obs_leave_graphics(); | |
gs_image_file_init(&awipe->animated_image, file); | |
obs_enter_graphics(); | |
gs_image_file_init_texture(&awipe->animated_image); | |
obs_leave_graphics(); | |
bfree(file); | |
dstr_free(&path); | |
UNUSED_PARAMETER(settings); | |
} | |
static void animated_wipe_get_list(void *data) | |
{ | |
struct animated_wipe_info *awipe = data; | |
char *path = obs_module_file("animated_wipes/wipes.json"); | |
awipe->wipes_list = obs_data_create_from_json_file(path); | |
bfree(path); | |
} | |
static void *animated_wipe_create(obs_data_t *settings, obs_source_t *source) | |
{ | |
struct animated_wipe_info *awipe; | |
gs_effect_t *effect; | |
char *file = obs_module_file("animated_wipe_transition.effect"); | |
char *errors = NULL; | |
obs_enter_graphics(); | |
effect = gs_effect_create_from_file(file, errors); | |
obs_leave_graphics(); | |
if (!effect) { | |
blog(LOG_ERROR, "Could not open animated_wipe_transition.effect"); | |
blog(LOG_ERROR, "Unable to create effect.Errors returned from parser : \n%s", (errors == NULL || strlen(errors) == 0 ? "(None)" : errors)); | |
return NULL; | |
} | |
bfree(file); | |
awipe = bzalloc(sizeof(*awipe)); | |
awipe->effect = effect; | |
awipe->ep_a_tex = gs_effect_get_param_by_name(effect, "a_tex"); | |
awipe->ep_b_tex = gs_effect_get_param_by_name(effect, "b_tex"); | |
awipe->ep_c_tex = gs_effect_get_param_by_name(effect, "c_tex"); | |
awipe->ep_color_target_a = gs_effect_get_param_by_name(effect, "color_target_a"); | |
awipe->ep_color_target_b = gs_effect_get_param_by_name(effect, "color_target_b"); | |
awipe->ep_invert = gs_effect_get_param_by_name(effect, "invert"); | |
awipe->source = source; | |
animated_wipe_get_list(awipe); | |
animated_wipe_update(awipe, settings); | |
return awipe; | |
} | |
static void animated_wipe_destroy(void *data) | |
{ | |
struct animated_wipe_info *awipe = data; | |
obs_enter_graphics(); | |
gs_image_file_free(&awipe->animated_image); | |
obs_leave_graphics(); | |
obs_data_release(awipe->wipes_list); | |
bfree(awipe); | |
} | |
static obs_properties_t *animated_wipe_properties(void *data) | |
{ | |
obs_properties_t *props = obs_properties_create(); | |
struct animated_wipe_info *awipe = data; | |
obs_property_t *p; | |
p = obs_properties_add_list(props, S_TRANSITION, T_TRANSITION, | |
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); | |
obs_data_item_t *item = obs_data_first(awipe->wipes_list); | |
for (; item != NULL; obs_data_item_next(&item)) { | |
const char *name = obs_data_item_get_name(item); | |
const char *path = obs_data_item_get_string(item); | |
obs_property_list_add_string(p, obs_module_text(name), path); | |
} | |
obs_properties_add_color(props, S_COLOR_A, T_COLOR_A); | |
obs_properties_add_color(props, S_COLOR_B, T_COLOR_B); | |
obs_properties_add_bool(props, S_INV, T_INV); | |
return props; | |
} | |
static void animated_wipe_defaults(obs_data_t *settings) | |
{ | |
obs_data_set_default_string(settings, S_TRANSITION, "linear-h.gif"); | |
obs_data_set_default_bool(settings, S_INV, false); | |
obs_data_set_default_int(settings, S_COLOR_A, 0xff000000); | |
obs_data_set_default_int(settings, S_COLOR_B, 0xffffffff); | |
} | |
bool gs_image_file_smooth(gs_image_file_t *image, double percentage) | |
{ | |
int loops; | |
if (!image->is_animated_gif || !image->loaded) | |
return false; | |
loops = image->gif.loop_count; | |
if (loops >= 0xFFFF) | |
loops = 0; | |
//(image->gif.frame_count) * loops * percentage | |
if (!loops || image->cur_loop < loops) { | |
uint64_t total_frames = (image->gif.frame_count - 1) * (loops + 1); | |
double step = 1.0f / total_frames; | |
int new_frame = (int32_t)floor(percentage / step); | |
if (new_frame != image->cur_frame) { | |
//decode_new_frame(image, new_frame); | |
image->cur_frame = new_frame; | |
return true; | |
} | |
} | |
return false; | |
} | |
static void animated_wipe_callback(void *data, gs_texture_t *a, gs_texture_t *b, | |
float t, uint32_t cx, uint32_t cy) | |
{ | |
struct animated_wipe_info *awipe = data; | |
//t ranges from 0 (just started) to 1 (transition complete) | |
gs_effect_set_texture(awipe->ep_a_tex, a); | |
gs_effect_set_texture(awipe->ep_b_tex, b); | |
//image->gif.frame_count | |
//gs_image_file_tick(awipe->animated_image, ); | |
gs_image_file_smooth(&awipe->animated_image, t); | |
gs_image_file_update_texture(&awipe->animated_image); | |
gs_effect_set_texture(awipe->ep_c_tex, awipe->animated_image.texture); | |
gs_effect_set_bool(awipe->ep_invert, awipe->invert); | |
while (gs_effect_loop(awipe->effect, "AnimatedWipe")) | |
gs_draw_sprite(NULL, 0, cx, cy); | |
} | |
void animated_wipe_video_render(void *data, gs_effect_t *effect) | |
{ | |
struct animated_wipe_info *awipe = data; | |
obs_transition_video_render(awipe->source, animated_wipe_callback); | |
UNUSED_PARAMETER(effect); | |
} | |
static float mix_a(void *data, float t) | |
{ | |
UNUSED_PARAMETER(data); | |
return 1.0f - t; | |
} | |
static float mix_b(void *data, float t) | |
{ | |
UNUSED_PARAMETER(data); | |
return t; | |
} | |
bool animated_wipe_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 animated_wipe_info *awipe = data; | |
return obs_transition_audio_render(awipe->source, ts_out, audio, mixers, | |
channels, sample_rate, mix_a, mix_b); | |
} | |
struct obs_source_info animated_wipe_transition = { | |
.id = "animated_wipe_transition", | |
.type = OBS_SOURCE_TYPE_TRANSITION, | |
.get_name = animated_wipe_get_name, | |
.create = animated_wipe_create, | |
.destroy = animated_wipe_destroy, | |
.update = animated_wipe_update, | |
.video_render = animated_wipe_video_render, | |
.audio_render = animated_wipe_audio_render, | |
.get_properties = animated_wipe_properties, | |
.get_defaults = animated_wipe_defaults | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment