Skip to content

Commit c598a47

Browse files
committed
Render drop shadow for active window
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 sysprog21#34 Signed-off-by: Wei-Hsin Yeh <weihsinyeh168@gmail.com>
1 parent 053a651 commit c598a47

File tree

10 files changed

+738
-5
lines changed

10 files changed

+738
-5
lines changed

apps/multi.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "apps_multi.h"
88

99
#define D(x) twin_double_to_fixed(x)
10+
#define ASSET_PATH "assets/"
1011

1112
static void apps_line_start(twin_screen_t *screen, int x, int y, int w, int h)
1213
{
@@ -272,6 +273,50 @@ static void apps_flower_start(twin_screen_t *screen, int x, int y, int w, int h)
272273
twin_window_show(window);
273274
}
274275

276+
static void apps_blur(twin_screen_t *screen, int x, int y, int w, int h)
277+
{
278+
twin_pixmap_t *raw_background =
279+
twin_pixmap_from_file(ASSET_PATH "tux.png", TWIN_ARGB32);
280+
twin_window_t *window = twin_window_create(
281+
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
282+
twin_window_set_name(window, "Blur");
283+
twin_pixmap_t *scaled_background = twin_pixmap_create(
284+
TWIN_ARGB32, window->pixmap->width, window->pixmap->height);
285+
twin_fixed_t sx, sy;
286+
sx = twin_fixed_div(
287+
twin_int_to_fixed(raw_background->width),
288+
twin_int_to_fixed(window->client.right - window->client.left));
289+
sy = twin_fixed_div(
290+
twin_int_to_fixed(raw_background->height),
291+
twin_int_to_fixed(window->client.bottom - window->client.top));
292+
293+
twin_matrix_scale(&raw_background->transform, sx, sy);
294+
twin_operand_t srcop = {
295+
.source_kind = TWIN_PIXMAP,
296+
.u.pixmap = raw_background,
297+
};
298+
299+
twin_composite(scaled_background, 0, 0, &srcop, 0, 0, 0, 0, 0, TWIN_SOURCE,
300+
screen->width, screen->height);
301+
302+
twin_pointer_t src, dst;
303+
for (int y = window->client.top; y < window->client.bottom; y++)
304+
for (int x = window->client.left; x < window->client.right; x++) {
305+
src =
306+
twin_pixmap_pointer(scaled_background, x - window->client.left,
307+
y - window->client.top);
308+
dst = twin_pixmap_pointer(window->pixmap, x, y);
309+
*dst.argb32 = *src.argb32 | 0xff000000;
310+
}
311+
twin_stack_blur(window->pixmap, 5, window->client.left,
312+
window->client.right, window->client.top,
313+
window->client.bottom);
314+
315+
twin_pixmap_destroy(scaled_background);
316+
twin_pixmap_destroy(raw_background);
317+
twin_window_show(window);
318+
}
319+
275320
void apps_multi_start(twin_screen_t *screen,
276321
const char *name,
277322
int x,
@@ -286,4 +331,5 @@ void apps_multi_start(twin_screen_t *screen,
286331
apps_ascii_start(screen, x += 20, y += 20, w, h);
287332
apps_jelly_start(screen, x += 20, y += 20, w / 2, h);
288333
apps_flower_start(screen, x += 20, y += 20, w, h);
334+
apps_blur(screen, x += 20, y += 20, w / 2, h / 2);
289335
}

configs/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ config CURSOR
5555
default n
5656
depends on !BACKEND_VNC
5757

58+
config DROP_SHADOW
59+
bool "Render drop shadow for active window"
60+
default y
61+
5862
endmenu
5963

6064
menu "Image Loaders"

include/twin.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@ typedef struct _twin_pixmap {
194194
* Pixels
195195
*/
196196
twin_animation_t *animation;
197+
#if defined(CONFIG_DROP_SHADOW)
198+
/*
199+
* When the pixel map is within the active window, it will have a drop
200+
* shadow to enhance its visual distinction.
201+
*/
202+
bool shadow;
203+
#endif
204+
197205
twin_pointer_t p;
198206
/*
199207
* When representing a window, this point
@@ -422,6 +430,13 @@ typedef void (*twin_destroy_func_t)(twin_window_t *window);
422430
struct _twin_window {
423431
twin_screen_t *screen;
424432
twin_pixmap_t *pixmap;
433+
434+
#if defined(CONFIG_DROP_SHADOW)
435+
/* Set the shadow range for horizontal and vertical directions. */
436+
twin_coord_t shadow_offset_x;
437+
twin_coord_t shadow_offset_y;
438+
#endif
439+
425440
twin_window_style_t style;
426441
twin_rect_t client;
427442
twin_rect_t damage;
@@ -626,6 +641,14 @@ void twin_dispatch(twin_context_t *ctx);
626641
* draw.c
627642
*/
628643

644+
/* Blur the specified area in the pixel map. */
645+
void twin_stack_blur(twin_pixmap_t *px,
646+
int radius,
647+
twin_coord_t left,
648+
twin_coord_t right,
649+
twin_coord_t top,
650+
twin_coord_t bottom);
651+
629652
void twin_composite(twin_pixmap_t *dst,
630653
twin_coord_t dst_x,
631654
twin_coord_t dst_y,
@@ -649,6 +672,15 @@ void twin_fill(twin_pixmap_t *dst,
649672

650673
void twin_premultiply_alpha(twin_pixmap_t *px);
651674

675+
/*
676+
* Overwrite the original pixel values of the specified area in the pixel map.
677+
*/
678+
void twin_cover(twin_pixmap_t *dst,
679+
twin_argb32_t color,
680+
twin_coord_t x,
681+
twin_coord_t y,
682+
twin_coord_t width);
683+
652684
/*
653685
* event.c
654686
*/

include/twin_private.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,25 @@ typedef int64_t twin_xfixed_t;
187187
((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
188188
((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)) | 0xff000000)
189189

190+
#ifndef min
191+
#define min(x, y) \
192+
({ \
193+
typeof(x) _x = (x); \
194+
typeof(y) _y = (y); \
195+
(void) (&_x == &_y); \
196+
_x < _y ? _x : _y; \
197+
})
198+
#endif
199+
#ifndef max
200+
#define max(x, y) \
201+
({ \
202+
typeof(x) _x = (x); \
203+
typeof(y) _y = (y); \
204+
(void) (&_x == &_y); \
205+
_x > _y ? _x : _y; \
206+
})
207+
#endif
208+
190209
typedef union {
191210
twin_pointer_t p;
192211
twin_argb32_t c;
@@ -467,7 +486,7 @@ void _twin_path_sfinish(twin_path_t *path);
467486
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
468487

469488
/*
470-
* dispatch stuff
489+
* Dispatch stuff
471490
*/
472491
typedef struct _twin_queue {
473492
struct _twin_queue *next;
@@ -592,6 +611,14 @@ void _twin_button_init(twin_button_t *button,
592611
twin_style_t font_style,
593612
twin_dispatch_proc_t dispatch);
594613

614+
/*
615+
* Visual effect stuff
616+
*/
617+
618+
#if defined(CONFIG_DROP_SHADOW)
619+
void twin_shadow_border(twin_pixmap_t *shadow);
620+
#endif
621+
595622
/* utility */
596623

597624
#ifdef _MSC_VER

0 commit comments

Comments
 (0)