Skip to content

Commit d493323

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 <[email protected]>
1 parent 122f696 commit d493323

File tree

9 files changed

+477
-9
lines changed

9 files changed

+477
-9
lines changed

apps/multi.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
* All rights reserved.
55
*/
66

7+
#include <stddef.h>
78
#include "apps_multi.h"
89

910
#define D(x) twin_double_to_fixed(x)
11+
#define ASSET_PATH "assets/"
1012

1113
static void apps_line_start(twin_screen_t *screen, int x, int y, int w, int h)
1214
{
@@ -272,6 +274,55 @@ static void apps_flower_start(twin_screen_t *screen, int x, int y, int w, int h)
272274
twin_window_show(window);
273275
}
274276

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

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: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,51 @@ 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+
#ifndef min
201+
#if defined(__GNUC__) || defined(__clang__)
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+
#else
210+
/* Generic implementation: potential side effects */
211+
#define min(x, y) ((x) < (y) ? (x) : (y))
212+
#endif
213+
#endif
214+
#ifndef max
215+
#if defined(__GNUC__) || defined(__clang__)
216+
#define max(x, y) \
217+
({ \
218+
typeof(x) _x = (x); \
219+
typeof(y) _y = (y); \
220+
(void) (&_x == &_y); \
221+
_x > _y ? _x : _y; \
222+
})
223+
#else
224+
/* Generic implementation: potential side effects */
225+
#define max(x, y) ((x) > (y) ? (x) : (y))
226+
#endif
227+
#endif
228+
191229
typedef union {
192230
twin_pointer_t p;
193231
twin_argb32_t c;
@@ -468,7 +506,7 @@ void _twin_path_sfinish(twin_path_t *path);
468506
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
469507

470508
/*
471-
* dispatch stuff
509+
* Dispatch stuff
472510
*/
473511
typedef struct _twin_queue {
474512
struct _twin_queue *next;
@@ -593,6 +631,21 @@ void _twin_button_init(twin_button_t *button,
593631
twin_style_t font_style,
594632
twin_dispatch_proc_t dispatch);
595633

634+
/*
635+
* Visual effect stuff
636+
*/
637+
638+
#if defined(CONFIG_DROP_SHADOW)
639+
/*
640+
* Add a shadow with the specified color, horizontal offset, and vertical
641+
* offset.
642+
*/
643+
void twin_shadow_border(twin_pixmap_t *shadow,
644+
twin_argb32_t color,
645+
twin_coord_t shift_x,
646+
twin_coord_t shift_y);
647+
#endif
648+
596649
/* utility */
597650

598651
#ifdef _MSC_VER

0 commit comments

Comments
 (0)