diff options
Diffstat (limited to 'src/modules/mixer')
| -rw-r--r-- | src/modules/mixer/mixer.c | 147 | 
1 files changed, 127 insertions, 20 deletions
diff --git a/src/modules/mixer/mixer.c b/src/modules/mixer/mixer.c index f0cb174..7de91e6 100644 --- a/src/modules/mixer/mixer.c +++ b/src/modules/mixer/mixer.c @@ -16,6 +16,7 @@  /* This implements a rudimentary mixing module for things like fades */  typedef enum mixer_style_t { +	MIXER_STYLE_FADE,  	MIXER_STYLE_FLICKER,  } mixer_style_t; @@ -38,6 +39,7 @@ typedef struct mixer_context_t {  	float			*T;  	mixer_input_t		inputs[2]; +	til_fb_fragment_t	*snapshots[2];  } mixer_context_t;  typedef struct mixer_setup_input_t { @@ -52,23 +54,7 @@ typedef struct mixer_setup_t {  	mixer_setup_input_t	inputs[2];  } mixer_setup_t; -#define MIXER_DEFAULT_STYLE	MIXER_STYLE_FLICKER - -static til_module_context_t * mixer_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup); -static void mixer_destroy_context(til_module_context_t *context); -static void mixer_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr); -static int mixer_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup); - - -til_module_t	mixer_module = { -	.create_context = mixer_create_context, -	.destroy_context = mixer_destroy_context, -	.render_fragment = mixer_render_fragment, -	.name = "mixer", -	.description = "Module blender", -	.setup = mixer_setup, -	.flags = TIL_MODULE_EXPERIMENTAL, -}; +#define MIXER_DEFAULT_STYLE	MIXER_STYLE_FADE  static til_module_context_t * mixer_create_context(const til_module_t *module, til_stream_t *stream, unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup) @@ -113,12 +99,15 @@ static inline float randf(unsigned *seed)  	return 1.f / ((float)RAND_MAX) * rand_r(seed);  } -static void mixer_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr) + +static void mixer_prepare_frame(til_module_context_t *context, til_stream_t *stream, unsigned ticks, til_fb_fragment_t **fragment_ptr, til_frame_plan_t *res_frame_plan)  {  	mixer_context_t		*ctxt = (mixer_context_t *)context;  	til_fb_fragment_t	*fragment = *fragment_ptr;  	size_t			i = 0; +	*res_frame_plan = (til_frame_plan_t){ .fragmenter = til_fragmenter_slice_per_cpu }; +  	if (!til_stream_tap_context(stream, context, NULL, &ctxt->taps.T))  		*ctxt->T = cosf(ticks * .001f) * .5f + .5f; @@ -128,18 +117,121 @@ static void mixer_render_fragment(til_module_context_t *context, til_stream_t *s  			i = 1;  		else  			i = 0; + +		til_module_render(ctxt->inputs[i].module_ctxt, stream, ticks, &fragment); +		break; + +	case MIXER_STYLE_FADE: +		if (*ctxt->T < 1.f) { +			til_module_render(ctxt->inputs[0].module_ctxt, stream, ticks, &fragment); + +			if (*ctxt->T > 0.f) +				ctxt->snapshots[0] = til_fb_fragment_snapshot(&fragment, 0); +		} + +		if (*ctxt->T > 0.f) { +			til_module_render(ctxt->inputs[1].module_ctxt, stream, ticks, &fragment); +			if (*ctxt->T < 1.f) +				ctxt->snapshots[1] = til_fb_fragment_snapshot(&fragment, 0); +		}  		break;  	default:  		assert(0);  	} -	til_module_render(ctxt->inputs[i].module_ctxt, stream, ticks, &fragment); +	*fragment_ptr = fragment; +} + + +/* derived from modules/drizzle pixel_mult_scalar(), there's definitely room for optimizations */ +static inline uint32_t pixels_lerp(uint32_t a_pixel, uint32_t b_pixel, float t) +{ +	uint32_t	pixel; +	float		a, b; + +	/* r */ +	a = (a_pixel >> 16) & 0xff; +	a *= 1.f - t; +	b = (b_pixel >> 16) & 0xff; +	b *= t; + +	pixel = (((uint32_t)(a+b)) << 16); + +	/* g */ +	a = (a_pixel >> 8) & 0xff; +	a *= 1.f - t; +	b = (b_pixel >> 8) & 0xff; +	b *= t; + +	pixel |= (((uint32_t)(a+b)) << 8); + +	/* b */ +	a = a_pixel & 0xff; +	a *= 1.f - t; +	b = b_pixel & 0xff; +	b *= t; + +	pixel |= ((uint32_t)(a+b)); + +	return pixel; +} + + +static void mixer_render_fragment(til_module_context_t *context, til_stream_t *stream, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr) +{ +	mixer_context_t		*ctxt = (mixer_context_t *)context; +	til_fb_fragment_t	*fragment = *fragment_ptr; + +	switch (((mixer_setup_t *)context->setup)->style) { +	case MIXER_STYLE_FLICKER: +		/* handled in prepare_frame() */ +		break; + +	case MIXER_STYLE_FADE: { +		float	T = *ctxt->T; + +		if (T <= 0.f || T  >= 1.f) +			break; + +		/* for the tweens, we already have snapshots sitting in ctxt->snapshots[], +		 * which we now interpolate the pixels out of in parallel +		 */ +		for (int y = fragment->y; y < fragment->y + fragment->height; y++) { +			for (int x = fragment->x; x < fragment->x + fragment->width; x++) { +				uint32_t	a_pixel = til_fb_fragment_get_pixel_unchecked(ctxt->snapshots[0], x, y); +				uint32_t	b_pixel = til_fb_fragment_get_pixel_unchecked(ctxt->snapshots[1], x, y); +				uint32_t	pixel; + +				pixel = pixels_lerp(a_pixel, b_pixel, T); +				til_fb_fragment_put_pixel_unchecked(fragment, 0, x, y, pixel); +			} +		} + +		break; +	} + +	default: +		assert(0); +	}  	*fragment_ptr = fragment;  } +static void mixer_finish_frame(til_module_context_t *context, til_stream_t *stream, unsigned int ticks, til_fb_fragment_t **fragment_ptr) +{ +	mixer_context_t	*ctxt = (mixer_context_t *)context; + +	for (int i = 0; i < 2; i++) { +		if (!ctxt->snapshots[i]) +			continue; + +		ctxt->snapshots[i] = til_fb_fragment_reclaim(ctxt->snapshots[i]); +	} +} + +  static void mixer_setup_free(til_setup_t *setup)  {  	mixer_setup_t	*s = (mixer_setup_t *)setup; @@ -157,6 +249,7 @@ static void mixer_setup_free(til_setup_t *setup)  static int mixer_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup)  {  	const char		*style_values[] = { +					"fade",  					"flicker",  					NULL  				}; @@ -185,6 +278,7 @@ static int mixer_setup(const til_settings_t *settings, til_setting_t **res_setti  		const char *input_names[2] = { "First module to mix", "Second module to mix" };  		const char *input_keys[2] = { "a_module", "b_module" };  		const char *input_module_name_names[2] = { "First module's name", "Second module's name" }; +		const char *input_preferred[2] = { "blank", "compose" };  		for (int i = 0; i < 2; i++) {  			const til_module_t	*mod; @@ -193,7 +287,7 @@ static int mixer_setup(const til_settings_t *settings, til_setting_t **res_setti  								&(til_setting_spec_t){  									.name = input_names[i],  									.key = input_keys[i], -									.preferred = "compose", +									.preferred = input_preferred[i],  									.annotations = NULL,  									.as_nested_settings = 1,  								}, @@ -282,3 +376,16 @@ static int mixer_setup(const til_settings_t *settings, til_setting_t **res_setti  	return 0;  } + + +til_module_t	mixer_module = { +	.create_context = mixer_create_context, +	.destroy_context = mixer_destroy_context, +	.prepare_frame = mixer_prepare_frame, +	.render_fragment = mixer_render_fragment, +	.finish_frame = mixer_finish_frame, +	.name = "mixer", +	.description = "Module blender", +	.setup = mixer_setup, +	.flags = TIL_MODULE_EXPERIMENTAL, +};  | 
