Skip to content

Commit

Permalink
Render drop shadow for active window
Browse files Browse the repository at this point in the history
Add the twin_stack_blur() function to implement Mario's Stack Blur
algorithm, which blurs the target pixel map. Additionally, create a blur
window to show the effect of twin_stack_blur(). Implement the
twin_drop_shadow() function to handle the pixels within the drop shadow
area of the active window's pixel map. The drop shadow effect of the
window is only visible when the window is on the top layer, ensuring the
active window stands out visually.

Implement the twin_shadow_border() function to create a darker border of
the active window that gives a more dimensional appearance.

In the twin_drop_shadow() function, twin_stack_blur() will apply a blur
effect to the pixels beneath the active window's pixel map, which aims
to create a frosted glass appearance.

Furthermore, implement the twin_cover() function to cover the target
pixels with the desired color.

Ref: https://melatonin.dev/blog/implementing-marios-stack-blur-15-times-in-cpp/
Close #34

Signed-off-by: Wei-Hsin Yeh <[email protected]>
  • Loading branch information
weihsinyeh committed Jan 12, 2025
1 parent 053a651 commit 4a2aff8
Show file tree
Hide file tree
Showing 10 changed files with 732 additions and 6 deletions.
46 changes: 46 additions & 0 deletions apps/multi.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "apps_multi.h"

#define D(x) twin_double_to_fixed(x)
#define ASSET_PATH "assets/"

static void apps_line_start(twin_screen_t *screen, int x, int y, int w, int h)
{
Expand Down Expand Up @@ -272,6 +273,50 @@ static void apps_flower_start(twin_screen_t *screen, int x, int y, int w, int h)
twin_window_show(window);
}

static void apps_blur(twin_screen_t *screen, int x, int y, int w, int h)
{
twin_pixmap_t *raw_background =
twin_pixmap_from_file(ASSET_PATH "tux.png", TWIN_ARGB32);
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
twin_window_set_name(window, "Blur");
twin_pixmap_t *scaled_background = twin_pixmap_create(
TWIN_ARGB32, window->pixmap->width, window->pixmap->height);
twin_fixed_t sx, sy;
sx = twin_fixed_div(
twin_int_to_fixed(raw_background->width),
twin_int_to_fixed(window->client.right - window->client.left));
sy = twin_fixed_div(
twin_int_to_fixed(raw_background->height),
twin_int_to_fixed(window->client.bottom - window->client.top));

twin_matrix_scale(&raw_background->transform, sx, sy);
twin_operand_t srcop = {
.source_kind = TWIN_PIXMAP,
.u.pixmap = raw_background,
};

twin_composite(scaled_background, 0, 0, &srcop, 0, 0, 0, 0, 0, TWIN_SOURCE,
screen->width, screen->height);

twin_pointer_t src, dst;
for (int y = window->client.top; y < window->client.bottom; y++)
for (int x = window->client.left; x < window->client.right; x++) {
src =
twin_pixmap_pointer(scaled_background, x - window->client.left,
y - window->client.top);
dst = twin_pixmap_pointer(window->pixmap, x, y);
*dst.argb32 = *src.argb32 | 0xff000000;
}
twin_stack_blur(window->pixmap, 5, window->client.left,
window->client.right, window->client.top,
window->client.bottom);

twin_pixmap_destroy(scaled_background);
twin_pixmap_destroy(raw_background);
twin_window_show(window);
}

void apps_multi_start(twin_screen_t *screen,
const char *name,
int x,
Expand All @@ -286,4 +331,5 @@ void apps_multi_start(twin_screen_t *screen,
apps_ascii_start(screen, x += 20, y += 20, w, h);
apps_jelly_start(screen, x += 20, y += 20, w / 2, h);
apps_flower_start(screen, x += 20, y += 20, w, h);
apps_blur(screen, x += 20, y += 20, w / 2, h / 2);
}
4 changes: 4 additions & 0 deletions configs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ config CURSOR
default n
depends on !BACKEND_VNC

config DROP_SHADOW
bool "Render drop shadow for active window"
default y

endmenu

menu "Image Loaders"
Expand Down
19 changes: 19 additions & 0 deletions include/twin.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ typedef struct _twin_pixmap {
* Pixels
*/
twin_animation_t *animation;
#if defined(CONFIG_DROP_SHADOW)
/*
* When the pixel map is within the active window, it will have a drop
* shadow to enhance its visual distinction.
*/
bool shadow;
#endif

twin_pointer_t p;
/*
* When representing a window, this point
Expand Down Expand Up @@ -422,6 +430,11 @@ typedef void (*twin_destroy_func_t)(twin_window_t *window);
struct _twin_window {
twin_screen_t *screen;
twin_pixmap_t *pixmap;

/* Set the shadow range for horizontal and vertical directions. */
twin_coord_t shadow_offset_x;
twin_coord_t shadow_offset_y;

twin_window_style_t style;
twin_rect_t client;
twin_rect_t damage;
Expand Down Expand Up @@ -649,6 +662,12 @@ void twin_fill(twin_pixmap_t *dst,

void twin_premultiply_alpha(twin_pixmap_t *px);

void twin_cover(twin_pixmap_t *dst,
twin_argb32_t color,
twin_coord_t x,
twin_coord_t y,
twin_coord_t width);

/*
* event.c
*/
Expand Down
35 changes: 34 additions & 1 deletion include/twin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,25 @@ typedef int64_t twin_xfixed_t;
((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)) | 0xff000000)

#ifndef min
#define min(x, y) \
({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; \
})
#endif
#ifndef max
#define max(x, y) \
({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; \
})
#endif

typedef union {
twin_pointer_t p;
twin_argb32_t c;
Expand Down Expand Up @@ -467,7 +486,7 @@ void _twin_path_sfinish(twin_path_t *path);
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))

/*
* dispatch stuff
* Dispatch stuff
*/
typedef struct _twin_queue {
struct _twin_queue *next;
Expand Down Expand Up @@ -592,6 +611,20 @@ void _twin_button_init(twin_button_t *button,
twin_style_t font_style,
twin_dispatch_proc_t dispatch);

/*
* Visual effect stuff
*/
void twin_stack_blur(twin_pixmap_t *px,
int radius,
twin_coord_t left,
twin_coord_t right,
twin_coord_t top,
twin_coord_t bottom);

#if defined(CONFIG_DROP_SHADOW)
void twin_shadow_border(twin_pixmap_t *shadow);
#endif

/* utility */

#ifdef _MSC_VER
Expand Down
Loading

0 comments on commit 4a2aff8

Please sign in to comment.