Skip to content

Commit 5f47a9a

Browse files
committed
Render drop shadow for active window
Implement the twin_window_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. Add the twin_stack_blur() function to implement Mario's Stack Blur algorithm, which blurs the target pixel map. Additionally, create a blur window in apps_blur() to show the effect of twin_stack_blur(). Implement the twin_shadow_border() function to create a darker border of the active window that gives a more dimensional appearance. The function twin_window_drop_shadow() will first apply the twin_shadow_border() and then apply twin_stack_blur() to blur the darker border. 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 <weihsinyeh168@gmail.com>
1 parent 122f696 commit 5f47a9a

File tree

9 files changed

+473
-9
lines changed

9 files changed

+473
-9
lines changed

apps/multi.c

Lines changed: 53 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,55 @@ 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+
#if defined(CONFIG_LOADER_PNG)
277+
static void apps_blur(twin_screen_t *screen, int x, int y, int w, int h)
278+
{
279+
twin_pixmap_t *raw_background =
280+
twin_pixmap_from_file(ASSET_PATH "tux.png", TWIN_ARGB32);
281+
if (!raw_background)
282+
return;
283+
twin_window_t *window = twin_window_create(
284+
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
285+
twin_window_set_name(window, "Blur");
286+
twin_pixmap_t *scaled_background = twin_pixmap_create(
287+
TWIN_ARGB32, window->pixmap->width, window->pixmap->height);
288+
twin_fixed_t sx, sy;
289+
sx = twin_fixed_div(
290+
twin_int_to_fixed(raw_background->width),
291+
twin_int_to_fixed(window->client.right - window->client.left));
292+
sy = twin_fixed_div(
293+
twin_int_to_fixed(raw_background->height),
294+
twin_int_to_fixed(window->client.bottom - window->client.top));
295+
296+
twin_matrix_scale(&raw_background->transform, sx, sy);
297+
twin_operand_t srcop = {
298+
.source_kind = TWIN_PIXMAP,
299+
.u.pixmap = raw_background,
300+
};
301+
302+
twin_composite(scaled_background, 0, 0, &srcop, 0, 0, 0, 0, 0, TWIN_SOURCE,
303+
scaled_background->width, scaled_background->height);
304+
305+
twin_pointer_t src, dst;
306+
for (int y = window->client.top; y < window->client.bottom; y++)
307+
for (int x = window->client.left; x < window->client.right; x++) {
308+
src =
309+
twin_pixmap_pointer(scaled_background, x - window->client.left,
310+
y - window->client.top);
311+
dst = twin_pixmap_pointer(window->pixmap, x, y);
312+
*dst.argb32 = *src.argb32 | 0xff000000;
313+
}
314+
twin_stack_blur(window->pixmap, 5, window->client.left,
315+
window->client.right, window->client.top,
316+
window->client.bottom);
317+
318+
twin_pixmap_destroy(scaled_background);
319+
twin_pixmap_destroy(raw_background);
320+
twin_window_show(window);
321+
return;
322+
}
323+
#endif
324+
275325
void apps_multi_start(twin_screen_t *screen,
276326
const char *name,
277327
int x,
@@ -286,4 +336,7 @@ void apps_multi_start(twin_screen_t *screen,
286336
apps_ascii_start(screen, x += 20, y += 20, w, h);
287337
apps_jelly_start(screen, x += 20, y += 20, w / 2, h);
288338
apps_flower_start(screen, x += 20, y += 20, w, h);
339+
#if defined(CONFIG_LOADER_PNG)
340+
apps_blur(screen, x += 20, y += 20, w / 2, h / 2);
341+
#endif
289342
}

configs/Kconfig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,28 @@ 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+
62+
config HORIZONTAL_OFFSET
63+
int "Horizontal offset"
64+
default 1
65+
range 1 10
66+
depends on DROP_SHADOW
67+
68+
config VERTICAL_OFFSET
69+
int "Vertical offset"
70+
default 1
71+
range 1 10
72+
depends on DROP_SHADOW
73+
74+
config SHADOW_BLUR
75+
int "Shadow blur radius"
76+
default 10
77+
range 1 10
78+
depends on DROP_SHADOW
79+
5880
endmenu
5981

6082
menu "Image Loaders"

include/twin.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@ typedef struct _twin_pixmap {
195195
* Pixels
196196
*/
197197
twin_animation_t *animation;
198+
199+
#if defined(CONFIG_DROP_SHADOW)
200+
/*
201+
* When the pixel map is within the active window, it will have a drop
202+
* shadow to enhance its visual distinction.
203+
*/
204+
bool shadow;
205+
#endif
206+
198207
twin_pointer_t p;
199208
/*
200209
* When representing a window, this point
@@ -423,6 +432,13 @@ typedef void (*twin_destroy_func_t)(twin_window_t *window);
423432
struct _twin_window {
424433
twin_screen_t *screen;
425434
twin_pixmap_t *pixmap;
435+
436+
#if defined(CONFIG_DROP_SHADOW)
437+
/* Set the shadow range for horizontal and vertical directions. */
438+
twin_coord_t shadow_x;
439+
twin_coord_t shadow_y;
440+
#endif
441+
426442
twin_window_style_t style;
427443
twin_rect_t client;
428444
twin_rect_t damage;
@@ -652,8 +668,26 @@ void twin_fill(twin_pixmap_t *dst,
652668
* draw-common.c
653669
*/
654670

671+
/* Blur the specified area in the pixel map. */
672+
void twin_stack_blur(twin_pixmap_t *px,
673+
int radius,
674+
twin_coord_t left,
675+
twin_coord_t right,
676+
twin_coord_t top,
677+
twin_coord_t bottom);
678+
655679
void twin_premultiply_alpha(twin_pixmap_t *px);
656680

681+
/*
682+
* Overwrite the original pixel values for a specified number of pixels in
683+
* width.
684+
*/
685+
void twin_cover(twin_pixmap_t *dst,
686+
twin_argb32_t color,
687+
twin_coord_t x,
688+
twin_coord_t y,
689+
twin_coord_t width);
690+
657691
/*
658692
* event.c
659693
*/

include/twin_private.h

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,46 @@ typedef int64_t twin_xfixed_t;
181181
(((t) = twin_get_8(d, i) + twin_get_8(s, i)), (twin_argb32_t) twin_sat(t) \
182182
<< (i))
183183

184+
#define _twin_add_ARGB(s, d, i, t) (((t) = (s) + twin_get_8(d, i)))
185+
#define _twin_add(s, d, t) (((t) = (s) + (d)))
186+
#define _twin_div(d, den, i, t) \
187+
(((t) = (d) / (den)), (t) = twin_get_8((t), 0), \
188+
(twin_argb32_t) twin_sat(t) << (i))
189+
#define _twin_sub_ARGB(s, d, i, t) (((t) = (s) - twin_get_8(d, i)))
190+
#define _twin_sub(s, d, t) (((t) = (s) - (d)))
191+
#define twin_put_8(d, i, t) (((t) = (d) << (i)))
192+
184193
#define twin_argb32_to_rgb16(s) \
185194
((((s) >> 3) & 0x001f) | (((s) >> 5) & 0x07e0) | (((s) >> 8) & 0xf800))
186195
#define twin_rgb16_to_argb32(s) \
187196
(((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
188197
((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
189198
((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)) | 0xff000000)
190199

200+
#if defined(__GNUC__) || defined(__clang__)
201+
#ifndef min
202+
#define min(x, y) \
203+
({ \
204+
typeof(x) _x = (x); \
205+
typeof(y) _y = (y); \
206+
(void) (&_x == &_y); \
207+
_x < _y ? _x : _y; \
208+
})
209+
#endif
210+
#ifndef max
211+
#define max(x, y) \
212+
({ \
213+
typeof(x) _x = (x); \
214+
typeof(y) _y = (y); \
215+
(void) (&_x == &_y); \
216+
_x > _y ? _x : _y; \
217+
})
218+
#endif
219+
#else /* generic implementation: potential side effects */
220+
#define min(x, y) ((x) < (y) ? (x) : (y))
221+
#define max(x, y) ((x) > (y) ? (x) : (y))
222+
#endif
223+
191224
typedef union {
192225
twin_pointer_t p;
193226
twin_argb32_t c;
@@ -468,7 +501,7 @@ void _twin_path_sfinish(twin_path_t *path);
468501
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
469502

470503
/*
471-
* dispatch stuff
504+
* Dispatch stuff
472505
*/
473506
typedef struct _twin_queue {
474507
struct _twin_queue *next;
@@ -593,6 +626,21 @@ void _twin_button_init(twin_button_t *button,
593626
twin_style_t font_style,
594627
twin_dispatch_proc_t dispatch);
595628

629+
/*
630+
* Visual effect stuff
631+
*/
632+
633+
#if defined(CONFIG_DROP_SHADOW)
634+
/*
635+
* Add a shadow with the specified color, horizontal offset, and vertical
636+
* offset.
637+
*/
638+
void twin_shadow_border(twin_pixmap_t *shadow,
639+
twin_argb32_t color,
640+
twin_coord_t shift_x,
641+
twin_coord_t shift_y);
642+
#endif
643+
596644
/* utility */
597645

598646
#ifdef _MSC_VER

0 commit comments

Comments
 (0)