Skip to content

Commit

Permalink
Implement the drop shadow
Browse files Browse the repository at this point in the history
Add the stack blur function to blur the pixmap that is test on the test
window. Add the shadow pixel map under the window which has shadow
feature.
  • Loading branch information
weihsinyeh committed Nov 13, 2024
1 parent 182ebcf commit 3433384
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 12 deletions.
55 changes: 50 additions & 5 deletions apps/multi.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
#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)
{
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h, false);
twin_pixmap_t *pixmap = window->pixmap;
twin_path_t *stroke = twin_path_create();
twin_fixed_t fy;
Expand All @@ -38,7 +39,7 @@ static void apps_circletext_start(twin_screen_t *screen,
int h)
{
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h, false);
int wid = window->client.right - window->client.left;
int hei = window->client.bottom - window->client.top;
twin_pixmap_t *pixmap = window->pixmap;
Expand Down Expand Up @@ -83,7 +84,7 @@ static void apps_quickbrown_start(twin_screen_t *screen,
int h)
{
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h, false);
int wid = window->client.right - window->client.left;
int hei = window->client.bottom - window->client.top;
twin_pixmap_t *pixmap = window->pixmap;
Expand Down Expand Up @@ -126,7 +127,7 @@ static void apps_quickbrown_start(twin_screen_t *screen,
static void apps_ascii_start(twin_screen_t *screen, int x, int y, int w, int h)
{
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h, false);
int wid = window->client.right - window->client.left;
int hei = window->client.bottom - window->client.top;
twin_pixmap_t *pixmap = window->pixmap;
Expand Down Expand Up @@ -174,7 +175,7 @@ static void apps_ascii_start(twin_screen_t *screen, int x, int y, int w, int h)
static void apps_jelly_start(twin_screen_t *screen, int x, int y, int w, int h)
{
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h, false);
int wid = window->client.right - window->client.left;
int hei = window->client.bottom - window->client.top;
twin_pixmap_t *pixmap = window->pixmap;
Expand Down Expand Up @@ -220,6 +221,49 @@ static void apps_jelly_start(twin_screen_t *screen, int x, int y, int w, int h)
twin_window_show(window);
}

static void apps_test(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, true);
twin_window_set_name(window, "Test");
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_window_show(window);
twin_pixmap_destroy(scaled_background);
}

void apps_multi_start(twin_screen_t *screen,
const char *name,
int x,
Expand All @@ -233,4 +277,5 @@ void apps_multi_start(twin_screen_t *screen,
apps_quickbrown_start(screen, x += 20, y += 20, w, h);
apps_ascii_start(screen, x += 20, y += 20, w, h);
apps_jelly_start(screen, x += 20, y += 20, w / 2, h);
apps_test(screen, x, y, w, h);
}
18 changes: 17 additions & 1 deletion include/twin.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ typedef struct _twin_pixmap {
* Pixels
*/
twin_animation_t *animation;
bool shadow;
twin_pointer_t p;
/*
* When representing a window, this point
Expand Down Expand Up @@ -422,6 +423,11 @@ typedef void (*twin_destroy_func_t)(twin_window_t *window);
struct _twin_window {
twin_screen_t *screen;
twin_pixmap_t *pixmap;
bool shadow;
twin_pixmap_t *shadow_pixmap;
twin_coord_t shadow_offset_x;
twin_coord_t shadow_offset_y;
twin_argb32_t shadow_color;
twin_window_style_t style;
twin_rect_t client;
twin_rect_t damage;
Expand Down Expand Up @@ -648,6 +654,13 @@ void twin_fill(twin_pixmap_t *dst,

void twin_premultiply_alpha(twin_pixmap_t *px);

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);

/*
* event.c
*/
Expand Down Expand Up @@ -1121,14 +1134,17 @@ twin_window_t *twin_window_create(twin_screen_t *screen,
twin_coord_t x,
twin_coord_t y,
twin_coord_t width,
twin_coord_t height);
twin_coord_t height,
bool shadow);

void twin_window_destroy(twin_window_t *window);

void twin_window_show(twin_window_t *window);

void twin_window_hide(twin_window_t *window);

void twin_shadow_visible(twin_pixmap_t *pixmap, twin_window_t *window);

void twin_window_configure(twin_window_t *window,
twin_window_style_t style,
twin_coord_t x,
Expand Down
147 changes: 147 additions & 0 deletions src/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,153 @@ static const twin_src_msk_op comp3[2][4][4][3] = {
#define operand_index(o) \
((o)->source_kind == TWIN_SOLID ? 3 : o->u.pixmap->format)

#define _twin_add_ARGB(s, d, i, t) (((t) = (s) + twin_get_8(d, i)))
#define _twin_add(s, d, t) (((t) = (s) + (d)))
#define _twin_div(d, den, i, t) \
(((t) = (d) / (den)), (t) = twin_get_8((t), 0), \
(twin_argb32_t) twin_sat(t) << (i))
#define _twin_sub_ARGB(s, d, i, t) (((t) = (s) - twin_get_8(d, i)))
#define _twin_sub(s, d, t) (((t) = (s) - (d)))
#define twin_put_8(d, i, t) (((t) = (d) << (i)))

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

void twin_stack(twin_pixmap_t *trg_px,
twin_pixmap_t *src_px,
int radius,
int first_str,
int first_end,
int second_str,
int second_end,
bool horiz_span)
{
int den = (radius + 1) * (radius + 1);
twin_pointer_t src_ptr, trg_ptr, old_ptr, new_ptr;
twin_argb32_t sumInR, sumOutR, sumR, sumInG, sumOutG, sumG, sumInB, sumOutB,
sumB, _cur, _old, _new, _src;
uint16_t t1, t2, t3;
for (int first = first_str; first < first_end; first++) {
sumInR = sumOutR = sumR = sumInG = sumOutG = sumG = sumInB = sumOutB =
sumB = 0x00000000;

/* Initialize SumOut by padding */
if (horiz_span)
src_ptr = twin_pixmap_pointer(src_px, second_str, first);
else
src_ptr = twin_pixmap_pointer(src_px, first, second_str);
_src = *src_ptr.argb32;

for (int i = second_str; i < second_str + radius; i++) {
sumOutR = _twin_add_ARGB(sumOutR, _src, 0, t1);
sumOutG = _twin_add_ARGB(sumOutG, _src, 8, t2);
sumOutB = _twin_add_ARGB(sumOutB, _src, 16, t3);
for (int j = 0; j < (i - second_str) + 1; j++) {
sumR = _twin_add_ARGB(sumR, _src, 0, t1);
sumG = _twin_add_ARGB(sumG, _src, 8, t2);
sumB = _twin_add_ARGB(sumB, _src, 16, t3);
}
}

/* Initialize SumIn */
for (int i = second_str; i < second_str + radius; i++) {
if (horiz_span)
src_ptr = twin_pixmap_pointer(src_px, i, first);
else
src_ptr = twin_pixmap_pointer(src_px, first, i);
_src = *src_ptr.argb32;
sumInR = _twin_add_ARGB(sumInR, _src, 0, t1);
sumInG = _twin_add_ARGB(sumInG, _src, 8, t2);
sumInB = _twin_add_ARGB(sumInB, _src, 16, t3);
for (int j = 0; j < radius - (i - second_str); j++) {
sumR = _twin_add_ARGB(sumR, _src, 0, t1);
sumG = _twin_add_ARGB(sumG, _src, 8, t2);
sumB = _twin_add_ARGB(sumB, _src, 16, t3);
}
}

for (int cur = second_str; cur < second_end; cur++) {
if (horiz_span) {
src_ptr = twin_pixmap_pointer(src_px, cur, first);
trg_ptr = twin_pixmap_pointer(trg_px, cur, first);
old_ptr = twin_pixmap_pointer(
src_px, max(cur - radius, second_str), first);
new_ptr = twin_pixmap_pointer(
src_px, min(cur + radius, second_end - 1), first);
} else {
src_ptr = twin_pixmap_pointer(src_px, first, cur);
trg_ptr = twin_pixmap_pointer(trg_px, first, cur);
old_ptr = twin_pixmap_pointer(src_px, first,
max(cur - radius, second_str));
new_ptr = twin_pixmap_pointer(
src_px, first, min(cur + radius, second_end - 1));
}
_cur = *src_ptr.argb32;
_old = *old_ptr.argb32;
_new = *new_ptr.argb32;
/* STEP 1 : sum_out + current */
sumOutR = _twin_add_ARGB(sumOutR, _cur, 0, t1);
sumOutG = _twin_add_ARGB(sumOutG, _cur, 8, t2);
sumOutB = _twin_add_ARGB(sumOutB, _cur, 16, t3);
/* STEP 2 : sum_in + new */
sumInR = _twin_add_ARGB(sumInR, _new, 0, t1);
sumInG = _twin_add_ARGB(sumInG, _new, 8, t2);
sumInB = _twin_add_ARGB(sumInB, _new, 16, t3);
/* STEP 3: sum + sum_in */
sumR = _twin_add(sumR, sumInR, t1);
sumG = _twin_add(sumG, sumInG, t2);
sumB = _twin_add(sumB, sumInB, t3);
/* STEP 4 : sum / denominator */
*trg_ptr.argb32 =
(_twin_div(sumR, den, 0, t1) | _twin_div(sumG, den, 8, t2) |
_twin_div(sumB, den, 16, t3) | (*src_ptr.argb32 & 0xff000000));
/* STEP 5 : sum - sum_out */
sumR = _twin_sub(sumR, sumOutR, t1);
sumG = _twin_sub(sumG, sumOutG, t2);
sumB = _twin_sub(sumB, sumOutB, t3);
/* STEP 6 : sum_out - old */
sumOutR = _twin_sub_ARGB(sumOutR, _old, 0, t1);
sumOutG = _twin_sub_ARGB(sumOutG, _old, 8, t2);
sumOutB = _twin_sub_ARGB(sumOutB, _old, 16, t3);
/* STEP 7 : sum_in - current */
sumInR = _twin_sub_ARGB(sumInR, _cur, 0, t1);
sumInG = _twin_sub_ARGB(sumInG, _cur, 8, t2);
sumInB = _twin_sub_ARGB(sumInB, _cur, 16, t3);
}
}
}

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 (px->format != TWIN_ARGB32)
return;
twin_pixmap_t *tmp_px =
twin_pixmap_create(px->format, px->width, px->height);
memcpy(tmp_px->p.v, px->p.v,
px->width * px->height * twin_bytes_per_pixel(px->format));
twin_stack(tmp_px, px, radius, top, bottom, left, right, true);
twin_stack(px, tmp_px, radius, left, right, top, bottom, false);
twin_pixmap_destroy(tmp_px);
return;
}

/* FIXME: source clipping is busted */
static void _twin_composite_simple(twin_pixmap_t *dst,
twin_coord_t dst_x,
Expand Down
1 change: 1 addition & 0 deletions src/pixmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ twin_pixmap_t *twin_pixmap_create(twin_format_t format,
pixmap->stride = stride;
pixmap->disable = 0;
pixmap->animation = NULL;
pixmap->shadow = false;
pixmap->p.v = pixmap + 1;
memset(pixmap->p.v, '\0', space);
return pixmap;
Expand Down
8 changes: 5 additions & 3 deletions src/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,8 @@ bool twin_screen_dispatch(twin_screen_t *screen, twin_event_t *event)
evt = *event;
evt.kind = TwinEventLeave;
_twin_adj_mouse_evt(&evt, pixmap);
twin_pixmap_dispatch(pixmap, &evt);
if (!pixmap->shadow)
twin_pixmap_dispatch(pixmap, &evt);
}

pixmap = screen->target = ntarget;
Expand All @@ -365,7 +366,8 @@ bool twin_screen_dispatch(twin_screen_t *screen, twin_event_t *event)
evt = *event;
_twin_adj_mouse_evt(&evt, pixmap);
evt.kind = TwinEventEnter;
twin_pixmap_dispatch(pixmap, &evt);
if (!pixmap->shadow)
twin_pixmap_dispatch(pixmap, &evt);
}
}

Expand All @@ -389,7 +391,7 @@ bool twin_screen_dispatch(twin_screen_t *screen, twin_event_t *event)
pixmap = NULL;
break;
}
if (pixmap)
if (pixmap && !pixmap->shadow)
return twin_pixmap_dispatch(pixmap, event);
return false;
}
2 changes: 1 addition & 1 deletion src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ twin_toplevel_t *twin_toplevel_create(twin_screen_t *screen,
{
twin_toplevel_t *toplevel;
twin_window_t *window =
twin_window_create(screen, format, style, x, y, width, height);
twin_window_create(screen, format, style, x, y, width, height, false);

if (!window)
return NULL;
Expand Down
Loading

0 comments on commit 3433384

Please sign in to comment.