diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/modules/drizzle/drizzle.c | 186 | ||||
| -rw-r--r-- | src/til_fb.h | 17 | 
2 files changed, 188 insertions, 15 deletions
| diff --git a/src/modules/drizzle/drizzle.c b/src/modules/drizzle/drizzle.c index 57b2664..f8aabcd 100644 --- a/src/modules/drizzle/drizzle.c +++ b/src/modules/drizzle/drizzle.c @@ -15,6 +15,7 @@   */  #include <errno.h> +#include <math.h>  #include <stdlib.h>  #include <unistd.h> @@ -24,9 +25,16 @@  #include "puddle/puddle.h" +/* TODO: make size a setting from like 128-1024, and cnt something settable for a fraction per frame (one every Nth frame) up to 20 per frame, though it should probably be less framerate dependent */  #define PUDDLE_SIZE		512  #define DRIZZLE_CNT		20  #define DEFAULT_VISCOSITY	.01 +#define DEFAULT_STYLE		DRIZZLE_STYLE_MASK + +typedef enum drizzle_style_t { +	DRIZZLE_STYLE_MASK, +	DRIZZLE_STYLE_MAP, +} drizzle_style_t;  typedef struct v3f_t {  	float	x, y, z; @@ -39,6 +47,7 @@ typedef struct v2f_t {  typedef struct drizzle_setup_t {  	til_setup_t	til_setup;  	float		viscosity; +	drizzle_style_t	style;  } drizzle_setup_t;  typedef struct drizzle_context_t { @@ -50,6 +59,7 @@ typedef struct drizzle_context_t {  static drizzle_setup_t drizzle_default_setup = {  	.viscosity = DEFAULT_VISCOSITY, +	.style = DEFAULT_STYLE,  }; @@ -156,6 +166,89 @@ static inline uint32_t pixel_mult_scalar(uint32_t pixel, float t)  } +/* TOD: libs should probably just get v[23]f.h added already instead of constantly + * duplicating these + */ +static inline float v3f_dot(const v3f_t *a, const v3f_t *b) +{ +	return (a->x * b->x + a->y * b->y + a->z * b->z); +} + + +static inline float v3f_len(const v3f_t *v) +{ +	return sqrtf(v3f_dot(v, v)); +} + + +static inline v3f_t * v3f_mult_scalar(v3f_t *res, const v3f_t *v, float s) +{ +	res->x = v->x * s; +	res->y = v->y * s; +	res->z = v->z * s; + +	return res; +} + + +static inline v3f_t * v3f_norm(v3f_t *res, const v3f_t *v) +{ +	return v3f_mult_scalar(res, v, 1.f / v3f_len(v)); +} + + +static inline v3f_t * v3f_cross(v3f_t *res, const v3f_t *a, const v3f_t *b) +{ +	res->x = a->y * b->z - a->z * b->y; +	res->y = a->z * b->x - a->x * b->z; +	res->z = a->x * b->y - a->y * b->x; + +	return res; +} + + +/* Similar to puddle_sample() except instead of returning an interpolated scalar + * a 3d normal vector is produced by treating the normally interpolated values as + * gradient samples on a 2d height map. + */ +static void puddle_sample_normal(const puddle_t *puddle, const v2f_t *coordinate, v3f_t *res_normal) +{ +	float	s0, sa, sb; + +	/* take three samples surrounding coordinate to create gradient vectors */ +	s0 = puddle_sample(puddle,	&(v2f_t){ +						.x = coordinate->x, +						.y = coordinate->y - .0001f	/* TODO: when PUDDLE_SIZE is small these need to be larger, revisit when size becomes runtime settable */ +					}); + +	sa = puddle_sample(puddle,	&(v2f_t){ +						.x = coordinate->x - .0001f, +						.y = coordinate->y + .0001f +					}); + +	sb = puddle_sample(puddle,	&(v2f_t){ +						.x = coordinate->x + .0001f, +						.y = coordinate->y + .0001f +					}); + +	/* cross product them to produce a normal */ +	(void) v3f_norm(res_normal, +		v3f_cross(&(v3f_t){}, +			&(v3f_t){ +				.x = -.0001f, +				.y = .0002f, +				.z = sa - s0 +			}, +			&(v3f_t){ +				.x = .0001f, +				.y = .0002f, +				.z = sb - s0 +			} +		) +	); +} + +  static void drizzle_render_fragment(til_module_context_t *context, unsigned ticks, unsigned cpu, til_fb_fragment_t **fragment_ptr)  {  	drizzle_context_t	*ctxt = (drizzle_context_t *)context; @@ -165,7 +258,30 @@ static void drizzle_render_fragment(til_module_context_t *context, unsigned tick  	float			yf = 1.f / (float)fragment->frame_height;  	v2f_t			coord; -	if (ctxt->snapshot) { +	if (!ctxt->snapshot) { +		coord.y = yf * (float)fragment->y; +		for (int y = fragment->y; y < fragment->y + fragment->height; y++) { + +			coord.x = xf * (float)fragment->x; +			for (int x = fragment->x; x < fragment->x + fragment->width; x++) { +				v3f_t		color = {}; +				uint32_t	pixel; + +				color.z = puddle_sample(ctxt->puddle, &coord); + +				pixel = color_to_uint32(color); +				til_fb_fragment_put_pixel_unchecked(fragment, 0, x, y, pixel); + +				coord.x += xf; +			} + +			coord.y += yf; +		} +		return; +	} + +	switch (ctxt->setup.style) { +	case DRIZZLE_STYLE_MASK:  		coord.y = yf * (float)fragment->y;  		for (int y = fragment->y; y < fragment->y + fragment->height; y++) { @@ -183,26 +299,33 @@ static void drizzle_render_fragment(til_module_context_t *context, unsigned tick  		}  		return; -	} -	coord.y = yf * (float)fragment->y; -	for (int y = fragment->y; y < fragment->y + fragment->height; y++) { +	case DRIZZLE_STYLE_MAP: +		coord.y = yf * (float)fragment->y; +		for (int y = fragment->y; y < fragment->y + fragment->height; y++) { + +			coord.x = xf * (float)fragment->x; +			for (int x = fragment->x; x < fragment->x + fragment->width; x++) { +				v3f_t		norm; +				uint32_t	pixel; -		coord.x = xf * (float)fragment->x; -		for (int x = fragment->x; x < fragment->x + fragment->width; x++) { -			v3f_t		color = {}; -			uint32_t	pixel; +				puddle_sample_normal(ctxt->puddle, &coord, &norm); +				//printf("norm.x=%f norm.y=%f norm.z=%f\n", norm.x, norm.y, norm.z); -			color.z = puddle_sample(ctxt->puddle, &coord); +				pixel = til_fb_fragment_get_pixel_clipped(ctxt->snapshot, x + (norm.x * 10.f), y + (norm.y * 10.f)); +				pixel = pixel_mult_scalar(pixel, 1.f - v3f_dot(&norm, &(v3f_t){.x = 0.f, .y = 0, .z = -1.f})); -			pixel = color_to_uint32(color); -			til_fb_fragment_put_pixel_unchecked(fragment, 0, x, y, pixel); +				til_fb_fragment_put_pixel_unchecked(fragment, 0, x, y, pixel); + +				coord.x += xf; +			} -			coord.x += xf; +			coord.y += yf;  		} -		coord.y += yf; +		return;  	} +  } @@ -218,13 +341,19 @@ static void drizzle_finish_frame(til_module_context_t *context, unsigned int tic  static int drizzle_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	*viscosity; -	const char	*values[] = { +	const char	*style; +	const char	*viscosity_values[] = {  				".005",  				".01",  				".03",  				".05",  				NULL  			}; +	const char	*style_values[] = { +				"mask", +				"map", +				NULL +			};  	int		r;  	r = til_settings_get_and_describe_value(settings, @@ -233,7 +362,7 @@ static int drizzle_setup(const til_settings_t *settings, til_setting_t **res_set  							.key = "viscosity",  							.regex = "\\.[0-9]+",  							.preferred = TIL_SETTINGS_STR(DEFAULT_VISCOSITY), -							.values = values, +							.values = viscosity_values,  							.annotations = NULL  						},  						&viscosity, @@ -242,8 +371,24 @@ static int drizzle_setup(const til_settings_t *settings, til_setting_t **res_set  	if (r)  		return r; +	r = til_settings_get_and_describe_value(settings, +						&(til_setting_desc_t){ +							.name = "Overlay style", +							.key = "style", +							.regex = "[a-z]+", +							.preferred = style_values[DEFAULT_STYLE], +							.values = style_values, +							.annotations = NULL +						}, +						&style, +						res_setting, +						res_desc); +	if (r) +		return r; +  	if (res_setup) {  		drizzle_setup_t	*setup; +		int		i;  		setup = til_setup_new(sizeof(*setup), (void(*)(til_setup_t *))free);  		if (!setup) @@ -251,6 +396,17 @@ static int drizzle_setup(const til_settings_t *settings, til_setting_t **res_set  		sscanf(viscosity, "%f", &setup->viscosity); +		/* TODO: til should prolly have a helper for this */ +		for (i = 0; i < nelems(style_values); i++) { +			if (!strcasecmp(style_values[i], style)) { +				setup->style = i; +				break; +			} +		} + +		if (i >= nelems(style_values)) +			return -EINVAL; +  		*res_setup = &setup->til_setup;  	} diff --git a/src/til_fb.h b/src/til_fb.h index da86605..80ffeb4 100644 --- a/src/til_fb.h +++ b/src/til_fb.h @@ -80,6 +80,23 @@ static inline uint32_t til_fb_fragment_get_pixel_unchecked(til_fb_fragment_t *fr  } +/* gets a pixel from the fragment, coordinates are clipped to the fragment's frame bounds */ +static inline uint32_t til_fb_fragment_get_pixel_clipped(til_fb_fragment_t *fragment, int x, int y) +{ +	if (x < 0) +		x = 0; +	else if (x >= fragment->frame_width) +		x = fragment->frame_width - 1; + +	if (y < 0) +		y = 0; +	else if (y >= fragment->frame_height) +		y = fragment->frame_height - 1; + +	return til_fb_fragment_get_pixel_unchecked(fragment, x, y); +} + +  /* puts a pixel into the fragment, no bounds checking is performed. */  static inline void til_fb_fragment_put_pixel_unchecked(til_fb_fragment_t *fragment, uint32_t flags, int x, int y, uint32_t pixel)  { | 
